# HG changeset patch # User duke # Date 1499265565 -7200 # Node ID 1ee6203fb4056fafca6f432f4a25f837cb2f6c70 # Parent aded486da6fda2467ff0096d51d5d888ea7d38d1# Parent 9ea588fb78bfa574524446de7085641f3a517e69 Merge diff -r aded486da6fd -r 1ee6203fb405 .hgtags-top-repo --- a/.hgtags-top-repo Tue Jul 22 11:41:45 2008 -0700 +++ b/.hgtags-top-repo Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ 56652b46f328937f6b9b5130f1e4cd80f48868ef jdk7-b28 31e08f70e88d77c2053f91c21b49a04296bdc59a jdk7-b29 2dab2f712e1832c92acfa63ec0337048b9422c20 jdk7-b30 +3300a35a0bd56d695b92fe0b34f03ebbfc939064 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 README-builds.html --- a/README-builds.html Tue Jul 22 11:41:45 2008 -0700 +++ b/README-builds.html Wed Jul 05 16:39:25 2017 +0200 @@ -5,15 +5,12 @@ - + +
@@ -54,6 +51,7 @@
  • Bootstrap JDK
  • Binary Plugs
  • Optional Import JDK
  • +
  • Ant
  • Certificate Authority File (cacert)
  • Compilers

    @@ -507,6 +518,11 @@ Install or upgrade the FreeType development package.

  • +
  • + Install + Ant, set + ANT_HOME. +
  • @@ -567,6 +583,11 @@ CUPS Include files, set ALT_CUPS_HEADERS_PATH. +
  • + Install + Ant, set + ANT_HOME. +
  • @@ -654,6 +675,11 @@ Install Microsoft DirectX SDK. +
  • + Install + Ant, set + ANT_HOME. +
  • @@ -736,6 +762,22 @@ and the build will copy the needed files from this import area. +

    Ant

    +
    + All OpenJDK builds require access to least Ant 1.6.5. + The Ant tool is available from the + + Ant download site. + You should always set + ANT_HOME + to point to the location of + the Ant installation, this is the directory pathname + that contains a bin and lib. + It's also a good idea to also place its bin directory + in the PATH environment variable, although it's + not absolutely required. +
    +

    Certificate Authority File (cacert)

    See @@ -915,6 +957,21 @@ and ALT_FREETYPE_HEADERS_PATH to refer to place where library and header files are installed. +

    + Building the freetype 2 libraries from scratch is also possible, + however on Windows refer to the + + Windows FreeType DLL build instructions. +

    + Note that by default FreeType is built with byte code hinting + support disabled due to licensing restrictions. + In this case, text appearance and metrics are expected to + differ from Sun's official JDK build. + See + + the SourceForge FreeType2 Home Page + + for more information.

    Advanced Linux Sound Architecture (ALSA) (Linux only)

    @@ -1036,7 +1093,8 @@ - + @@ -1050,7 +1108,7 @@ - + @@ -1061,17 +1119,17 @@ - + - + - + @@ -1224,46 +1282,6 @@ document) that can impact the build are:
    -
    PATH
    -
    Typically you want to set the PATH to include: -
      -
    • The location of the GNU make binary
    • -
    • The location of the Bootstrap JDK java - (see Bootstrap JDK)
    • -
    • The location of the C/C++ compilers - (see compilers)
    • -
    • The location or locations for the Unix command utilities - (e.g. /usr/bin)
    • -
    -
    -
    MILESTONE
    -
    - The milestone name for the build (e.g."beta"). - The default value is "internal". -
    -
    BUILD_NUMBER
    -
    - The build number for the build (e.g. "b27"). - The default value is "b00". -
    -
    ARCH_DATA_MODEL
    -
    The ARCH_DATA_MODEL variable - is used to specify whether the build is to generate 32-bit or 64-bit - binaries. - The Solaris build supports either 32-bit or 64-bit builds, but - Windows and Linux will support only one, depending on the specific - OS being used. - Normally, setting this variable is only necessary on Solaris. - Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, - or to 64 for generating 64-bit binaries. -
    -
    ALT_BOOTDIR
    -
    - The location of the bootstrap JDK installation. - See Bootstrap JDK for more information. - You should always install your own local Bootstrap JDK and - always set ALT_BOOTDIR explicitly. -
    ALT_BINARY_PLUGS_PATH
    The location of the binary plugs installation. @@ -1272,98 +1290,32 @@ recent Binary Plugs install image and set this variable to that location.
    -
    ALT_JDK_IMPORT_PATH
    -
    - The location of a previously built JDK installation. - See Optional Import JDK for more information. -
    -
    ALT_OUTPUTDIR
    -
    - An override for specifying the (absolute) path of where the - build output is to go. - The default output directory will be build/platform. -
    -
    ALT_COMPILER_PATH
    -
    - The location of the C/C++ compiler. - The default varies depending on the platform. -
    -
    ALT_CACERTS_FILE
    +
    ALT_BOOTDIR
    - The location of the cacerts file. - The default will refer to - jdk/src/share/lib/security/cacerts. -
    -
    ALT_CUPS_HEADERS_PATH
    -
    - The location of the CUPS header files. - See CUPS information for more information. - If this path does not exist the fallback path is - /usr/include. -
    -
    ALT_FREETYPE_LIB_PATH
    -
    - The location of the FreeType shared library. - See FreeType information for details. -
    -
    ALT_FREETYPE_HEADERS_PATH
    -
    - The location of the FreeType header files. - See FreeType information for details. -
    -
    ALT_JDK_DEVTOOLS_PATH
    -
    - The default root location of the devtools. - The default value is - $(ALT_SLASH_JAVA)/devtools. + The location of the bootstrap JDK installation. + See Bootstrap JDK for more information. + You should always install your own local Bootstrap JDK and + always set ALT_BOOTDIR explicitly.
    -
    ALT_DEVTOOLS_PATH
    -
    - The location of tools like the - zip and unzip - binaries, but might also contain the GNU make utility - (gmake). - So this area is a bit of a grab bag, especially on Windows. - The default value depends on the platform and - Unix Commands being used. - On Linux the default will be - $(ALT_JDK_DEVTOOLS_PATH)/linux/bin, - on Solaris - $(ALT_JDK_DEVTOOLS_PATH)/{sparc,i386}/bin, - on Windows with MKS - %SYSTEMDRIVE%/UTILS, - and on Windows with CYGWIN - /usr/bin. -
    -
    ALT_UNIXCOMMAND_PATH
    +
    ALT_BUILD_BINARY_PLUGS_PATH
    - An override for specifying where the - Unix command set are located. - The default location varies depending on the platform, - "%SYSTEMDRIVE%/MKSNT" or - $(ROOTDIR) on Windows with MKS, otherwise it's - "/bin" or /usr/bin. -
    -
    ALT_UNIXCCS_PATH
    -
    - Solaris only: - An override for specifying where the Unix CCS - command set are located. - The default location is /usr/ccs/bin -
    -
    ALT_USRBIN_PATH
    -
    - An override for specifying where the - Unix /usr/bin commands are located. You usually do not need - to set this variable: the default location is /usr/bin) -
    -
    ALT_SLASHJAVA
    -
    - The default root location for many of the ALT path locations - of the following ALT variables. - The default value is - "/java" on Solaris and Linux, - "J:" on Windows. + These are useful in managing builds on multiple platforms. + The default network location for all of the binary plug images + for all platforms. + If ALT_BINARY_PLUGS_PATH + is not set, this directory will be used and should contain + the following directories: + solaris-sparc, + solaris-i586, + solaris-sparcv9, + solaris-amd64, + linux-i586, + linux-amd64, + windows-i586, + and + windows-amd64. + Where each of these directories contain the binary plugs image + for that platform.
    ALT_BUILD_JDK_IMPORT_PATH
    @@ -1385,56 +1337,166 @@ Where each of these directories contain the import JDK image for that platform.
    -
    ALT_BUILD_BINARY_PLUGS_PATH
    +
    ALT_CACERTS_FILE
    +
    + The location of the cacerts file. + The default will refer to + jdk/src/share/lib/security/cacerts. +
    +
    ALT_COMPILER_PATH
    +
    + The location of the C/C++ compiler. + The default varies depending on the platform. +
    +
    ALT_CUPS_HEADERS_PATH
    +
    + The location of the CUPS header files. + See CUPS information for more information. + If this path does not exist the fallback path is + /usr/include. +
    +
    ALT_DEVTOOLS_PATH
    +
    + The location of tools like the + zip and unzip + binaries, but might also contain the GNU make utility + (gmake). + So this area is a bit of a grab bag, especially on Windows. + The default value depends on the platform and + Unix Commands being used. + On Linux the default will be + $(ALT_JDK_DEVTOOLS_PATH)/linux/bin, + on Solaris + $(ALT_JDK_DEVTOOLS_PATH)/{sparc,i386}/bin, + on Windows with MKS + %SYSTEMDRIVE%/UTILS, + and on Windows with CYGWIN + /usr/bin. +
    +
    ALT_DXSDK_PATH
    - These are useful in managing builds on multiple platforms. - The default network location for all of the binary plug images - for all platforms. - If ALT_BINARY_PLUGS_PATH - is not set, this directory will be used and should contain - the following directories: - solaris-sparc, - solaris-i586, - solaris-sparcv9, - solaris-amd64, - linux-i586, - linux-amd64, - windows-i586, - and - windows-amd64. - Where each of these directories contain the binary plugs image - for that platform. + Windows Only: + The location of the + Microsoft DirectX 9 SDK. + The default will be to try and use the DirectX environment + variable DXSDK_DIR, + failing that, look in C:/DXSDK. +
    +
    ALT_FREETYPE_HEADERS_PATH
    +
    + The location of the FreeType header files. + See FreeType information for details. +
    +
    ALT_FREETYPE_LIB_PATH
    +
    + The location of the FreeType shared library. + See FreeType information for details.
    -
    Windows specific:
    +
    ALT_JDK_DEVTOOLS_PATH
    +
    + The default root location of the devtools. + The default value is + $(ALT_SLASH_JAVA)/devtools. +
    +
    ALT_JDK_IMPORT_PATH
    +
    + The location of a previously built JDK installation. + See Optional Import JDK for more information. +
    +
    ALT_MSDEVTOOLS_PATH
    +
    + Windows Only: + The location of the Microsoft Visual Studio .NET 2003 + tools 'bin' directory. + The default is usually derived from + ALT_COMPILER_PATH. +
    +
    ALT_MSVCR71_DLL_PATH
    -
    -
    ALT_MSDEVTOOLS_PATH
    -
    - The location of the Microsoft Visual Studio .NET 2003 - tools 'bin' directory. - The default is usually derived from - ALT_COMPILER_PATH. -
    -
    ALT_DXSDK_PATH
    -
    - The location of the - Microsoft DirectX 9 SDK. - The default will be to try and use the DirectX environment - variable DXSDK_DIR, - failing that, look in C:/DXSDK. -
    -
    ALT_MSVCRT_DLL_PATH
    -
    - The location of the - MSVCRT.DLL. -
    -
    ALT_MSVCR71_DLL_PATH
    -
    - i586 only: - The location of the - MSVCR71.DLL. -
    -
    + Windows i586 only: + The location of the + MSVCR71.DLL. +
    +
    ALT_MSVCRT_DLL_PATH
    +
    + Windows Only: + The location of the + MSVCRT.DLL. +
    +
    ALT_OUTPUTDIR
    +
    + An override for specifying the (absolute) path of where the + build output is to go. + The default output directory will be build/platform. +
    +
    ALT_SLASHJAVA
    +
    + The default root location for many of the ALT path locations + of the following ALT variables. + The default value is + "/java" on Solaris and Linux, + "J:" on Windows. +
    +
    ALT_UNIXCCS_PATH
    +
    + Solaris only: + An override for specifying where the Unix CCS + command set are located. + The default location is /usr/ccs/bin +
    +
    ALT_UNIXCOMMAND_PATH
    +
    + An override for specifying where the + Unix command set are located. + The default location varies depending on the platform, + "%SYSTEMDRIVE%/MKSNT" or + $(ROOTDIR) on Windows with MKS, otherwise it's + "/bin" or /usr/bin. +
    +
    ALT_USRBIN_PATH
    +
    + An override for specifying where the + Unix /usr/bin commands are located. You usually do not need + to set this variable: the default location is /usr/bin) +
    +
    ANT_HOME
    +
    + The location of the Ant installation. + See Ant for more information. + You should always set ANT_HOME explicitly. +
    +
    ARCH_DATA_MODEL
    +
    The ARCH_DATA_MODEL variable + is used to specify whether the build is to generate 32-bit or 64-bit + binaries. + The Solaris build supports either 32-bit or 64-bit builds, but + Windows and Linux will support only one, depending on the specific + OS being used. + Normally, setting this variable is only necessary on Solaris. + Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, + or to 64 for generating 64-bit binaries. +
    +
    BUILD_NUMBER
    +
    + The build number for the build (e.g. "b27"). + The default value is "b00". +
    +
    MILESTONE
    +
    + The milestone name for the build (e.g."beta"). + The default value is "internal". +
    +
    PATH
    +
    Typically you want to set the PATH to include: +
      +
    • The location of the GNU make binary
    • +
    • The location of the Bootstrap JDK java + (see Bootstrap JDK)
    • +
    • The location of the C/C++ compilers + (see compilers)
    • +
    • The location or locations for the Unix command utilities + (e.g. /usr/bin)
    • +
    diff -r aded486da6fd -r 1ee6203fb405 corba/.hgtags --- a/corba/.hgtags Tue Jul 22 11:41:45 2008 -0700 +++ b/corba/.hgtags Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ 27509b7d21ed783b3f6eb7b7612781c675a30c2f jdk7-b28 8b71960f79ce0a6fb8ddfeec03f03d400a361747 jdk7-b29 c0252adbb2abbfdd6c35595429ac6fbdd98e20ac jdk7-b30 +ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 hotspot/.hgtags --- a/hotspot/.hgtags Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/.hgtags Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ c14dab40ed9bf45ad21150bd70c9c80cdf655415 jdk7-b28 4f91c08b3e4498213a9c5a24898f7d9c38cf86fb jdk7-b29 d1605aabd0a15ecf93787c47de63073c33fba52d jdk7-b30 +9c2ecc2ffb125f14fab3857fe7689598956348a0 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -2414,8 +2414,20 @@ 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 @@ // 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() { diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -2965,10 +2965,21 @@ return retVal == 0; } -// Protect memory (make it read-only. (Used to pass readonly pages through +// Protect memory (Used to pass readonly pages through // JNI GetArrayElements 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. diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -2170,6 +2170,7 @@ // 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 @@ 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) { diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp --- a/hotspot/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -27,12 +27,6 @@ #include -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(); diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -39,10 +39,3 @@ 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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -65,22 +65,3 @@ 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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -28,18 +28,6 @@ #include // For trap numbers #include // 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. diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -79,9 +79,3 @@ 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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -85,22 +85,3 @@ 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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -58,7 +58,3 @@ "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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -65,19 +65,3 @@ 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; -} diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/asm/assembler.cpp --- a/hotspot/src/share/vm/asm/assembler.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/asm/assembler.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -246,6 +246,24 @@ } } +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 { diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -61,6 +61,8 @@ if (_virtual_space != NULL) { delete _virtual_space; _virtual_space = NULL; + // Release memory reserved in the space. + rs.release(); } return false; } diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -108,8 +108,8 @@ // 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, diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -422,6 +422,8 @@ return vspace; } delete vspace; + // Release memory reserved in the space. + rs.release(); } return 0; diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -71,13 +71,8 @@ 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; diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/memory/genCollectedHeap.cpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -222,8 +222,8 @@ *_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; } diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -2173,8 +2173,7 @@ 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; diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -1176,8 +1176,7 @@ // 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 { diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -922,8 +922,9 @@ // 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); } diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 16:39:25 2017 +0200 @@ -193,7 +193,11 @@ 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, diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 16:39:25 2017 +0200 @@ -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 @@ 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 @@ 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 @@ _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 @@ } 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 @@ _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 @@ _size = 0; _special = false; _alignment = 0; + _noaccess_prefix = 0; if (size == 0) { return; } @@ -220,7 +235,8 @@ // 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 @@ _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 @@ _base = base; _size = size; _alignment = alignment; + _noaccess_prefix = 0; _special = special; } @@ -320,17 +342,58 @@ 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 @@ _lower_alignment = 0; _middle_alignment = 0; _upper_alignment = 0; + _special = false; } @@ -402,7 +466,8 @@ 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; diff -r aded486da6fd -r 1ee6203fb405 hotspot/src/share/vm/runtime/virtualspace.hpp --- a/hotspot/src/share/vm/runtime/virtualspace.hpp Tue Jul 22 11:41:45 2008 -0700 +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp Wed Jul 05 16:39:25 2017 +0200 @@ -29,13 +29,15 @@ 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 @@ 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 @@ 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 @@ 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 { diff -r aded486da6fd -r 1ee6203fb405 jaxp/.hgtags --- a/jaxp/.hgtags Tue Jul 22 11:41:45 2008 -0700 +++ b/jaxp/.hgtags Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ b996318955c0ad8e9fa0ffb56c74f626786e863f jdk7-b28 617ee8607cfd5fd81f233f3c0b690f85084687a0 jdk7-b29 2d94a238a1641d074e6032dcdceed461d6f85d6a jdk7-b30 +255d64ee287e926e8629dd80bc67690e65eeba30 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 jaxws/.hgtags --- a/jaxws/.hgtags Tue Jul 22 11:41:45 2008 -0700 +++ b/jaxws/.hgtags Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ eefcd5204500a11d6aa802dca9f961cf10ab64c2 jdk7-b28 836c55713abab186e4de0c6eabd06ff008c7b8d0 jdk7-b29 7f2466f8cc7009702e548d1a763254f546024d7e jdk7-b30 +f978623825364a2ad9c6f51d02fc9424a8b0bc86 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 jdk/.hgtags --- a/jdk/.hgtags Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/.hgtags Wed Jul 05 16:39:25 2017 +0200 @@ -5,3 +5,4 @@ 02e4c5348592a8d7fc2cba28bc5f8e35c0e17277 jdk7-b28 e21f4266466cd1306b176aaa08b2cd8337a9be3d jdk7-b29 b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30 +b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/com/sun/java/pack/Makefile --- a/jdk/make/com/sun/java/pack/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/com/sun/java/pack/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -97,9 +97,6 @@ /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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/com/sun/security/auth/module/Makefile --- a/jdk/make/com/sun/security/auth/module/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/com/sun/security/auth/module/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -55,9 +55,6 @@ 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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/Defs-linux.gmk --- a/jdk/make/common/Defs-linux.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/Defs-linux.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -149,10 +149,9 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/Defs-solaris.gmk --- a/jdk/make/common/Defs-solaris.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/Defs-solaris.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -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 @@ # 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 @@ 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 @@ # 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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/Defs-windows.gmk --- a/jdk/make/common/Defs-windows.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/Defs-windows.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -283,7 +283,7 @@ 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 @@ -293,16 +293,23 @@ 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 @@ # 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 @@ 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 @@ 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)" diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/Defs.gmk --- a/jdk/make/common/Defs.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/Defs.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -703,7 +703,7 @@ 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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/shared/Compiler-gcc.gmk --- a/jdk/make/common/shared/Compiler-gcc.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/shared/Compiler-gcc.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -73,23 +73,18 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/shared/Defs-java.gmk --- a/jdk/make/common/shared/Defs-java.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/shared/Defs-java.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -107,7 +107,10 @@ 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 @@ # 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/shared/Defs.gmk --- a/jdk/make/common/shared/Defs.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/shared/Defs.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -188,16 +188,18 @@ 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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/common/shared/Platform.gmk --- a/jdk/make/common/shared/Platform.gmk Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/common/shared/Platform.gmk Wed Jul 05 16:39:25 2017 +0200 @@ -373,35 +373,41 @@ 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 @@ # 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/fdlibm/Makefile --- a/jdk/make/java/fdlibm/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/fdlibm/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -46,8 +46,6 @@ _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 # diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/hpi/windows/Makefile --- a/jdk/make/java/hpi/windows/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/hpi/windows/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -37,8 +37,6 @@ # 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 = \ diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/java/Makefile --- a/jdk/make/java/java/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/java/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -37,8 +37,6 @@ # 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/java_crw_demo/Makefile --- a/jdk/make/java/java_crw_demo/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/java_crw_demo/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -48,11 +48,6 @@ OTHER_INCLUDES = -I$(SRCDIR) # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # Library to compile. # include $(BUILDDIR)/common/Library.gmk diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/java_hprof_demo/Makefile --- a/jdk/make/java/java_hprof_demo/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/java_hprof_demo/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -92,11 +92,6 @@ INIT += $(LIBDIR)/jvm.hprof.txt # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # This puts logging code in # CPPFLAGS_DBG += -DHPROF_LOGGING diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/jli/Makefile --- a/jdk/make/java/jli/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/jli/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -115,9 +115,6 @@ -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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/net/Makefile --- a/jdk/make/java/net/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/net/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -94,8 +94,6 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/nio/Makefile --- a/jdk/make/java/nio/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/nio/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -134,7 +134,6 @@ $(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) diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/npt/Makefile --- a/jdk/make/java/npt/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/npt/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -53,11 +53,6 @@ OTHER_INCLUDES = -I$(SRCDIR) -I$(PSRCDIR) # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # Library to compile. # include $(BUILDDIR)/common/Library.gmk diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/verify/Makefile --- a/jdk/make/java/verify/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/verify/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -43,8 +43,6 @@ # JAVALIB = EXTRA_LIBS = - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif # diff -r aded486da6fd -r 1ee6203fb405 jdk/make/java/zip/Makefile --- a/jdk/make/java/zip/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/java/zip/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -49,9 +49,6 @@ 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 # diff -r aded486da6fd -r 1ee6203fb405 jdk/make/jpda/back/Makefile --- a/jdk/make/jpda/back/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/jpda/back/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -53,11 +53,6 @@ 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. # CPPFLAGS_DBG += -DJDWP_LOGGING diff -r aded486da6fd -r 1ee6203fb405 jdk/make/jpda/transport/shmem/Makefile --- a/jdk/make/jpda/transport/shmem/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/jpda/transport/shmem/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -36,13 +36,6 @@ 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 \ diff -r aded486da6fd -r 1ee6203fb405 jdk/make/jpda/transport/socket/Makefile --- a/jdk/make/jpda/transport/socket/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/jpda/transport/socket/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -36,11 +36,6 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/sun/cmm/kcms/Makefile --- a/jdk/make/sun/cmm/kcms/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/sun/cmm/kcms/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -47,8 +47,6 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/sun/font/Makefile --- a/jdk/make/sun/font/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/sun/font/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -77,9 +77,6 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/sun/font/t2k/Makefile --- a/jdk/make/sun/font/t2k/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/sun/font/t2k/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -64,9 +64,6 @@ 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/make/sun/jdbc/Makefile --- a/jdk/make/sun/jdbc/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/sun/jdbc/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -69,11 +69,6 @@ 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 # diff -r aded486da6fd -r 1ee6203fb405 jdk/make/sun/jpeg/Makefile --- a/jdk/make/sun/jpeg/Makefile Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/make/sun/jpeg/Makefile Wed Jul 05 16:39:25 2017 +0200 @@ -73,10 +73,5 @@ # 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/back/eventFilter.c --- a/jdk/src/share/back/eventFilter.c Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/back/eventFilter.c Wed Jul 05 16:39:25 2017 +0200 @@ -492,14 +492,17 @@ 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; } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Wed Jul 05 16:39:25 2017 +0200 @@ -84,8 +84,13 @@ import com.sun.jmx.mbeanserver.Repository; import com.sun.jmx.mbeanserver.NamedObject; import com.sun.jmx.mbeanserver.Introspector; +import com.sun.jmx.mbeanserver.MBeanInjector; +import com.sun.jmx.mbeanserver.NotifySupport; +import com.sun.jmx.mbeanserver.Repository.RegistrationContext; import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.remote.util.EnvHelp; +import javax.management.DynamicWrapperMBean; +import javax.management.NotificationBroadcasterSupport; /** * This is the default class for MBean manipulation on the agent side. It @@ -433,36 +438,26 @@ if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); - repository.remove(name); - // may throw InstanceNotFoundException - - /** - * Checks if the unregistered MBean is a ClassLoader - * If so, it removes the MBean from the default loader repository. - */ + final Object resource = getResource(instance); - Object resource = getResource(instance); - if (resource instanceof ClassLoader - && resource != server.getClass().getClassLoader()) { - final ModifiableClassLoaderRepository clr = - instantiator.getClassLoaderRepository(); - if (clr != null) clr.removeClassLoader(name); - } + // Unregisters the MBean from the repository. + // Returns the resource context that was used. + // The returned context does nothing for regular MBeans. + // For ClassLoader MBeans and JMXNamespace (and JMXDomain) + // MBeans - the context makes it possible to unregister these + // objects from the appropriate framework artifacts, such as + // the CLR or the dispatcher, from within the repository lock. + // In case of success, we also need to call context.done() at the + // end of this method. + // + final ResourceContext context = + unregisterFromRepository(resource, instance, name); - // --------------------- - // Send deletion event - // --------------------- - if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { - MBEANSERVER_LOGGER.logp(Level.FINER, - DefaultMBeanServerInterceptor.class.getName(), - "unregisterMBean", "Send delete notification of object " + - name.getCanonicalName()); - } - sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, - name); if (instance instanceof MBeanRegistration) postDeregisterInvoke((MBeanRegistration) instance); + + context.done(); } public ObjectInstance getObjectInstance(ObjectName name) @@ -939,15 +934,22 @@ } ObjectName logicalName = name; + logicalName = preRegister(mbean, server, name); - if (mbean instanceof MBeanRegistration) { - MBeanRegistration reg = (MBeanRegistration) mbean; - logicalName = preRegisterInvoke(reg, name, server); + // preRegister returned successfully, so from this point on we + // must call postRegister(false) if there is any problem. + boolean registered = false; + boolean registerFailed = false; + ResourceContext context = null; + + try { + mbean = injectResources(mbean, server, logicalName); + if (mbean instanceof DynamicMBean2) { try { ((DynamicMBean2) mbean).preRegister2(server, logicalName); + registerFailed = true; // until we succeed } catch (Exception e) { - postRegisterInvoke(reg, false, false); if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof InstanceAlreadyExistsException) @@ -960,86 +962,102 @@ logicalName = ObjectName.getInstance(nonDefaultDomain(logicalName)); } - } + + checkMBeanPermission(classname, null, logicalName, "registerMBean"); - checkMBeanPermission(classname, null, logicalName, "registerMBean"); + if (logicalName == null) { + final RuntimeException wrapped = + new IllegalArgumentException("No object name specified"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register the MBean"); + } + + final Object resource = getResource(mbean); - final ObjectInstance result; - if (logicalName!=null) { - result = new ObjectInstance(logicalName, classname); - internal_addObject(mbean, logicalName); - } else { - if (mbean instanceof MBeanRegistration) - postRegisterInvoke((MBeanRegistration) mbean, false, true); - final RuntimeException wrapped = - new IllegalArgumentException("No object name specified"); - throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean"); + // Register the MBean with the repository. + // Returns the resource context that was used. + // The returned context does nothing for regular MBeans. + // For ClassLoader MBeans and JMXNamespace (and JMXDomain) + // MBeans - the context makes it possible to register these + // objects with the appropriate framework artifacts, such as + // the CLR or the dispatcher, from within the repository lock. + // In case of success, we also need to call context.done() at the + // end of this method. + // + context = registerWithRepository(resource, mbean, logicalName); + + registerFailed = false; + registered = true; + } finally { + postRegister(mbean, registered, registerFailed); } - if (mbean instanceof MBeanRegistration) - postRegisterInvoke((MBeanRegistration) mbean, true, false); - - /** - * Checks if the newly registered MBean is a ClassLoader - * If so, tell the ClassLoaderRepository (CLR) about it. We do - * this even if the object is a PrivateClassLoader. In that - * case, the CLR remembers the loader for use when it is - * explicitly named (e.g. as the loader in createMBean) but - * does not add it to the list that is consulted by - * ClassLoaderRepository.loadClass. - */ - final Object resource = getResource(mbean); - if (resource instanceof ClassLoader) { - final ModifiableClassLoaderRepository clr = - instantiator.getClassLoaderRepository(); - if (clr == null) { - final RuntimeException wrapped = - new IllegalArgumentException( - "Dynamic addition of class loaders is not supported"); - throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean as a class loader"); - } - clr.addClassLoader(logicalName, (ClassLoader) resource); - } - - return result; + context.done(); + return new ObjectInstance(logicalName, classname); } - private static ObjectName preRegisterInvoke(MBeanRegistration moi, - ObjectName name, - MBeanServer mbs) - throws InstanceAlreadyExistsException, MBeanRegistrationException { - - final ObjectName newName; - + private static void throwMBeanRegistrationException(Throwable t, String where) + throws MBeanRegistrationException { try { - newName = moi.preRegister(mbs, name); + throw t; } catch (RuntimeException e) { - throw new RuntimeMBeanException(e, - "RuntimeException thrown in preRegister method"); + throw new RuntimeMBeanException( + e, "RuntimeException thrown " + where); } catch (Error er) { - throw new RuntimeErrorException(er, - "Error thrown in preRegister method"); + throw new RuntimeErrorException(er, "Error thrown " + where); } catch (MBeanRegistrationException r) { throw r; } catch (Exception ex) { - throw new MBeanRegistrationException(ex, - "Exception thrown in preRegister method"); + throw new MBeanRegistrationException(ex, "Exception thrown " + where); + } catch (Throwable t1) { + throw new RuntimeException(t); // neither Error nor Exception?? + } + } + + private static ObjectName preRegister( + DynamicMBean mbean, MBeanServer mbs, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException { + + ObjectName newName = null; + + try { + if (mbean instanceof MBeanRegistration) + newName = ((MBeanRegistration) mbean).preRegister(mbs, name); + } catch (Throwable t) { + throwMBeanRegistrationException(t, "in preRegister method"); } if (newName != null) return newName; else return name; } - private static void postRegisterInvoke(MBeanRegistration moi, - boolean registrationDone, - boolean registerFailed) { + private static DynamicMBean injectResources( + DynamicMBean mbean, MBeanServer mbs, ObjectName name) + throws MBeanRegistrationException { + try { + Object resource = getResource(mbean); + MBeanInjector.inject(resource, mbs, name); + if (MBeanInjector.injectsSendNotification(resource)) { + NotificationBroadcasterSupport nbs = + new NotificationBroadcasterSupport(); + MBeanInjector.injectSendNotification(resource, nbs); + mbean = NotifySupport.wrap(mbean, nbs); + } + return mbean; + } catch (Throwable t) { + throwMBeanRegistrationException(t, "injecting @Resources"); + return null; // not reached + } + } - if (registerFailed && moi instanceof DynamicMBean2) - ((DynamicMBean2) moi).registerFailed(); + private static void postRegister( + DynamicMBean mbean, boolean registrationDone, boolean registerFailed) { + + if (registerFailed && mbean instanceof DynamicMBean2) + ((DynamicMBean2) mbean).registerFailed(); try { - moi.postRegister(registrationDone); + if (mbean instanceof MBeanRegistration) + ((MBeanRegistration) mbean).postRegister(registrationDone); } catch (RuntimeException e) { throw new RuntimeMBeanException(e, "RuntimeException thrown in postRegister method"); @@ -1053,17 +1071,8 @@ throws MBeanRegistrationException { try { moi.preDeregister(); - } catch (RuntimeException e) { - throw new RuntimeMBeanException(e, - "RuntimeException thrown in preDeregister method"); - } catch (Error er) { - throw new RuntimeErrorException(er, - "Error thrown in preDeregister method"); - } catch (MBeanRegistrationException t) { - throw t; - } catch (Exception ex) { - throw new MBeanRegistrationException(ex, - "Exception thrown in preDeregister method"); + } catch (Throwable t) { + throwMBeanRegistrationException(t, "in preDeregister method"); } } @@ -1104,12 +1113,19 @@ } private static Object getResource(DynamicMBean mbean) { - if (mbean instanceof DynamicMBean2) - return ((DynamicMBean2) mbean).getResource(); + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedObject(); else return mbean; } + private static ClassLoader getResourceLoader(DynamicMBean mbean) { + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); + else + return mbean.getClass().getClassLoader(); + } + private ObjectName nonDefaultDomain(ObjectName name) { if (name == null || name.getDomain().length() > 0) return name; @@ -1123,14 +1139,7 @@ if one is supplied where it shouldn't be). */ final String completeName = domain + name; - try { - return new ObjectName(completeName); - } catch (MalformedObjectNameException e) { - final String msg = - "Unexpected default domain problem: " + completeName + ": " + - e; - throw EnvHelp.initCause(new IllegalArgumentException(msg), e); - } + return Util.newObjectName(completeName); } public String getDefaultDomain() { @@ -1211,7 +1220,7 @@ } NotificationListener listenerWrapper = - getListenerWrapper(listener, name, broadcaster, true); + getListenerWrapper(listener, name, instance, true); broadcaster.addNotificationListener(listenerWrapper, filter, handback); } @@ -1335,7 +1344,6 @@ DynamicMBean instance = getMBean(name); checkMBeanPermission(instance, null, name, "removeNotificationListener"); - Object resource = getResource(instance); /* We could simplify the code by assigning broadcaster after assigning listenerWrapper, but that would change the error @@ -1348,7 +1356,7 @@ getNotificationBroadcaster(name, instance, reqClass); NotificationListener listenerWrapper = - getListenerWrapper(listener, name, resource, false); + getListenerWrapper(listener, name, instance, false); if (listenerWrapper == null) throw new ListenerNotFoundException("Unknown listener"); @@ -1366,8 +1374,10 @@ private static T getNotificationBroadcaster(ObjectName name, Object instance, Class reqClass) { - if (instance instanceof DynamicMBean2) - instance = ((DynamicMBean2) instance).getResource(); + if (reqClass.isInstance(instance)) + return reqClass.cast(instance); + if (instance instanceof DynamicWrapperMBean) + instance = ((DynamicWrapperMBean) instance).getWrappedObject(); if (reqClass.isInstance(instance)) return reqClass.cast(instance); final RuntimeException exc = @@ -1415,24 +1425,31 @@ checkMBeanPermission(instance, null, name, "isInstanceOf"); try { - if (instance instanceof DynamicMBean2) { - Object resource = ((DynamicMBean2) instance).getResource(); - ClassLoader loader = resource.getClass().getClassLoader(); - Class c = Class.forName(className, false, loader); - return c.isInstance(resource); - } + Object resource = getResource(instance); - final String cn = getClassName(instance); - if (cn.equals(className)) + final String resourceClassName = + (resource instanceof DynamicMBean) ? + getClassName((DynamicMBean) resource) : + resource.getClass().getName(); + + if (resourceClassName.equals(className)) return true; - final ClassLoader cl = instance.getClass().getClassLoader(); + final ClassLoader cl = getResourceLoader(instance); final Class classNameClass = Class.forName(className, false, cl); - if (classNameClass.isInstance(instance)) + if (classNameClass.isInstance(resource)) return true; - final Class instanceClass = Class.forName(cn, false, cl); - return classNameClass.isAssignableFrom(instanceClass); + // Ensure that isInstanceOf(NotificationEmitter) is true when + // the MBean is a NotificationEmitter by virtue of a @Resource + // annotation specifying a SendNotification resource. + // This is a hack. + if (instance instanceof NotificationBroadcaster && + classNameClass.isAssignableFrom(NotificationEmitter.class)) + return true; + + final Class resourceClass = Class.forName(resourceClassName, false, cl); + return classNameClass.isAssignableFrom(resourceClass); } catch (Exception x) { /* Could be SecurityException or ClassNotFoundException */ if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { @@ -1457,7 +1474,7 @@ DynamicMBean instance = getMBean(mbeanName); checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); - return getResource(instance).getClass().getClassLoader(); + return getResourceLoader(instance); } /** @@ -1489,40 +1506,6 @@ } /** - * Adds a MBean in the repository - */ - private void internal_addObject(DynamicMBean object, ObjectName logicalName) - throws InstanceAlreadyExistsException { - - // ------------------------------ - // ------------------------------ - - // Let the repository do the work. - - try { - repository.addMBean(object, logicalName); - } catch (InstanceAlreadyExistsException e) { - if (object instanceof MBeanRegistration) { - postRegisterInvoke((MBeanRegistration) object, false, true); - } - throw e; - } - - // --------------------- - // Send create event - // --------------------- - if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { - MBEANSERVER_LOGGER.logp(Level.FINER, - DefaultMBeanServerInterceptor.class.getName(), - "addObject", "Send create notification of object " + - logicalName.getCanonicalName()); - } - - sendNotification(MBeanServerNotification.REGISTRATION_NOTIFICATION, - logicalName ) ; - } - - /** * Sends an MBeanServerNotifications with the specified type for the * MBean with the specified ObjectName */ @@ -1712,9 +1695,10 @@ */ private NotificationListener getListenerWrapper(NotificationListener l, ObjectName name, - Object mbean, + DynamicMBean mbean, boolean create) { - ListenerWrapper wrapper = new ListenerWrapper(l, name, mbean); + Object resource = getResource(mbean); + ListenerWrapper wrapper = new ListenerWrapper(l, name, resource); synchronized (listenerWrappers) { WeakReference ref = listenerWrappers.get(wrapper); if (ref != null) { @@ -1758,6 +1742,7 @@ listener.handleNotification(notification, handback); } + @Override public boolean equals(Object o) { if (!(o instanceof ListenerWrapper)) return false; @@ -1774,6 +1759,7 @@ */ } + @Override public int hashCode() { return (System.identityHashCode(listener) ^ System.identityHashCode(mbean)); @@ -1851,4 +1837,213 @@ } } + // ------------------------------------------------------------------ + // + // Dealing with registration of special MBeans in the repository. + // + // ------------------------------------------------------------------ + + /** + * A RegistrationContext that makes it possible to perform additional + * post registration actions (or post unregistration actions) outside + * of the repository lock, once postRegister (or postDeregister) has + * been called. + * The method {@code done()} will be called in registerMBean or + * unregisterMBean, at the end. + */ + private static interface ResourceContext extends RegistrationContext { + public void done(); + /** An empty ResourceContext which does nothing **/ + public static final ResourceContext NONE = new ResourceContext() { + public void done() {} + public void registering() {} + public void unregistered() {} + }; + } + + /** + * Adds a MBean in the repository, + * sends MBeanServerNotification.REGISTRATION_NOTIFICATION, + * returns ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. For regular MBean this method returns + * ResourceContext.NONE. + * @return a ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. + */ + private ResourceContext registerWithRepository( + final Object resource, + final DynamicMBean object, + final ObjectName logicalName) + throws InstanceAlreadyExistsException, + MBeanRegistrationException { + + // Creates a registration context, if needed. + // + final ResourceContext context = + makeResourceContextFor(resource, logicalName); + + + repository.addMBean(object, logicalName, context); + // May throw InstanceAlreadyExistsException + + // --------------------- + // Send create event + // --------------------- + if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { + MBEANSERVER_LOGGER.logp(Level.FINER, + DefaultMBeanServerInterceptor.class.getName(), + "addObject", "Send create notification of object " + + logicalName.getCanonicalName()); + } + + sendNotification( + MBeanServerNotification.REGISTRATION_NOTIFICATION, + logicalName); + + return context; + } + + /** + * Removes a MBean in the repository, + * sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + * returns ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces, or null. For regular MBean this method returns + * ResourceContext.NONE. + * + * @return a ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. + */ + private ResourceContext unregisterFromRepository( + final Object resource, + final DynamicMBean object, + final ObjectName logicalName) + throws InstanceNotFoundException { + + // Creates a registration context, if needed. + // + final ResourceContext context = + makeResourceContextFor(resource, logicalName); + + + repository.remove(logicalName, context); + + // --------------------- + // Send deletion event + // --------------------- + if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { + MBEANSERVER_LOGGER.logp(Level.FINER, + DefaultMBeanServerInterceptor.class.getName(), + "unregisterMBean", "Send delete notification of object " + + logicalName.getCanonicalName()); + } + + sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + logicalName); + return context; + } + + /** + * Registers a ClassLoader with the CLR. + * This method is called by the ResourceContext from within the + * repository lock. + * @param loader The ClassLoader. + * @param logicalName The ClassLoader MBean ObjectName. + */ + private void addClassLoader(ClassLoader loader, + final ObjectName logicalName) { + /** + * Called when the newly registered MBean is a ClassLoader + * If so, tell the ClassLoaderRepository (CLR) about it. We do + * this even if the loader is a PrivateClassLoader. In that + * case, the CLR remembers the loader for use when it is + * explicitly named (e.g. as the loader in createMBean) but + * does not add it to the list that is consulted by + * ClassLoaderRepository.loadClass. + */ + final ModifiableClassLoaderRepository clr = + instantiator.getClassLoaderRepository(); + if (clr == null) { + final RuntimeException wrapped = + new IllegalArgumentException( + "Dynamic addition of class loaders" + + " is not supported"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register" + + " the MBean as a class loader"); + } + clr.addClassLoader(logicalName, loader); + } + + /** + * Unregisters a ClassLoader from the CLR. + * This method is called by the ResourceContext from within the + * repository lock. + * @param loader The ClassLoader. + * @param logicalName The ClassLoader MBean ObjectName. + */ + private void removeClassLoader(ClassLoader loader, + final ObjectName logicalName) { + /** + * Removes the MBean from the default loader repository. + */ + if (loader != server.getClass().getClassLoader()) { + final ModifiableClassLoaderRepository clr = + instantiator.getClassLoaderRepository(); + if (clr != null) { + clr.removeClassLoader(logicalName); + } + } + } + + /** + * Creates a ResourceContext for a ClassLoader MBean. + * The resource context makes it possible to add the ClassLoader to + * (ResourceContext.registering) or resp. remove the ClassLoader from + * (ResourceContext.unregistered) the CLR + * when the associated MBean is added to or resp. removed from the + * repository. + * + * @param loader The ClassLoader MBean being registered or + * unregistered. + * @param logicalName The name of the ClassLoader MBean. + * @return a ResourceContext that takes in charge the addition or removal + * of the loader to or from the CLR. + */ + private ResourceContext createClassLoaderContext( + final ClassLoader loader, + final ObjectName logicalName) { + return new ResourceContext() { + + public void registering() { + addClassLoader(loader, logicalName); + } + + public void unregistered() { + removeClassLoader(loader, logicalName); + } + + public void done() { + } + }; + } + + /** + * Creates a ResourceContext for the given resource. + * If the resource does not need a ResourceContext, returns + * ResourceContext.NONE. + * At this time, only JMXNamespaces and ClassLoaders need a + * ResourceContext. + * + * @param resource The resource being registered or unregistered. + * @param logicalName The name of the associated MBean. + * @return + */ + private ResourceContext makeResourceContextFor(Object resource, + ObjectName logicalName) { + if (resource instanceof ClassLoader) { + return createClassLoaderContext((ClassLoader) resource, + logicalName); + } + return ResourceContext.NONE; + } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java Wed Jul 05 16:39:25 2017 +0200 @@ -686,7 +686,7 @@ 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 @@ 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(); diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java Wed Jul 05 16:39:25 2017 +0200 @@ -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 @@ * * @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(). diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Wed Jul 05 16:39:25 2017 +0200 @@ -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 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 @@ } 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); } + /** + *

    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}.

    + * @param mbean the object to convert to a DynamicMBean. + * @param 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 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 c = null; try { c = Util.cast(getStandardMBeanInterface(mbeanClass)); @@ -270,7 +308,7 @@ * Return null 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 @@ * @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 Class getStandardMBeanInterface(Class baseClass) + throws NotCompliantMBeanException { + if (baseClass.isAnnotationPresent(MBean.class)) + return baseClass; + Class current = baseClass; + Class mbeanInterface = null; while (current != null) { mbeanInterface = findMBeanInterface(current, current.getName()); @@ -321,8 +361,10 @@ * @throws NotCompliantMBeanException The specified class is * not a JMX compliant MXBean. */ - public static Class getMXBeanInterface(Class baseClass) + public static Class getMXBeanInterface(Class baseClass) throws NotCompliantMBeanException { + if (hasMXBeanAnnotation(baseClass)) + return baseClass; try { return MXBeanSupport.findMXBeanInterface(baseClass); } catch (Exception e) { @@ -345,19 +387,24 @@ * ------------------------------------------ */ + 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. aNameMBean, from within aClass and its superclasses. **/ - private static Class findMBeanInterface(Class aClass, String aName) { - Class current = aClass; + private static Class findMBeanInterface( + Class aClass, String aName) { + Class 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 inter = Util.cast(interfaces[i]); + inter = implementsMBean(inter, aName); if (inter != null) return inter; } current = current.getSuperclass(); @@ -365,6 +412,48 @@ 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 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 @@ 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 descriptorMap = new HashMap(); for (Annotation a : annots) { - Class 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 @@ return new ImmutableDescriptor(descriptorMap); } + private static void addDescriptorFieldsToMap( + Map 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 descriptorMap, Annotation a) { + Class 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 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 @@ // 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 @@ * @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 Class implementsMBean(Class 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; diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java Wed Jul 05 16:39:25 2017 +0200 @@ -33,6 +33,10 @@ 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 @@ 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 am = attrMap.get(attrName); @@ -153,7 +165,7 @@ 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 am = attrMap.get(attrName); @@ -166,6 +178,9 @@ } 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 cms = opMap.get(name); diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,291 @@ +/* + * 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, List> fields; + private Map, List> 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); + } + + void inject(Object instance, Class type, T resource) + throws Exception { + List fs = fields.get(type); + if (fs != null) { + for (Field f : fs) + f.set(instance, resource); + } + List 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, List> entry : methods.entrySet()) { + List 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() { + 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() { + public Void run() { + member.setAccessible(true); + return null; + } + }); + addToMap(fields, injectedClass, field); + addToMap(methods, injectedClass, method); + } + } + } + } + } + + private static void addToMap(Map> map, K key, V value) { + if (value == null) + return; + List list = map.get(key); + if (list == null) + list = Collections.singletonList(value); + else { + if (list.size() == 1) + list = new ArrayList(list); + list.add(value); + } + map.put(key, list); + } + } + + private static synchronized ClassInjector injectorForClass(Class c) + throws NotCompliantMBeanException { + WeakReference wr = injectorMap.get(c); + ClassInjector ci = (wr == null) ? null : wr.get(); + if (ci == null) { + ci = new ClassInjector(c); + injectorMap.put(c, new WeakReference(ci)); + } + return ci; + } + + private static Map, WeakReference> injectorMap = + new WeakHashMap, WeakReference>(); +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Wed Jul 05 16:39:25 2017 +0200 @@ -36,20 +36,28 @@ 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 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 @@ } 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 @@ * Get the methods to be analyzed to build the MBean interface. */ List getMethods(final Class mbeanType) throws Exception { - return Arrays.asList(mbeanType.getMethods()); + if (mbeanType.isInterface()) + return Arrays.asList(mbeanType.getMethods()); + + final List methods = newList(); + getAnnotatedMethods(mbeanType, methods); + return methods; } final PerInterface getPerInterface(Class mbeanInterface) @@ -232,8 +268,11 @@ MBeanAnalyzer 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 @@ 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 @@ } } + /* + * 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 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 @@ 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 list = newList(); + if (ni != null) + list.add(ni); + if (nis != null) + list.addAll(Arrays.asList(nis.value())); + if (list.isEmpty()) + return null; + List 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, WeakReference>> + annotatedNotificationInfoClasses = newWeakHashMap(); + + private static Class getAnnotatedNotificationInfoClass(Class baseClass) { + synchronized (annotatedNotificationInfoClasses) { + WeakReference> 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>(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; diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java Wed Jul 05 16:39:25 2017 +0200 @@ -263,10 +263,14 @@ 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(); } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Wed Jul 05 16:39:25 2017 +0200 @@ -35,6 +35,7 @@ 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.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 @@ 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 @@ 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 @@ 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 = diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java Wed Jul 05 16:39:25 2017 +0200 @@ -161,7 +161,7 @@ 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 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,186 @@ +/* + * 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; + } +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Wed Jul 05 16:39:25 2017 +0200 @@ -29,6 +29,7 @@ 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 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 @@ */ 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 @@ /** * 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 @@ } } - private void addNewDomMoi(final DynamicMBean object, final String dom, - final ObjectName name) { - final Map moiTb = - new HashMap(); - 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 ?, standing for any one character, and *, standing for any string of @@ -306,6 +316,50 @@ } } + private void addNewDomMoi(final DynamicMBean object, + final String dom, + final ObjectName name, + final RegistrationContext context) { + final Map moiTb = + new HashMap(); + 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 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 @@ domainTb = new HashMap>(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()); + // Creates a new hashtable for the default domain + domainTb.put(this.domain, new HashMap()); } /** @@ -395,10 +449,21 @@ /** * 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 @@ 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 @@ "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 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 @@ // ":*", ":[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 @@ // 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 @@ return result; } + if (!name.isDomainPattern()) { + final Map 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 moiTb = domainTb.get(domain); + final Map moiTb = domainTb.get(dom); if (allNames) result.addAll(moiTb.values()); else @@ -599,11 +673,21 @@ * 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 @@ if (dom == domain) domainTb.put(domain, new HashMap()); } + + unregistering(context,name); + } finally { lock.writeLock().unlock(); } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java Wed Jul 05 16:39:25 2017 +0200 @@ -35,6 +35,7 @@ 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 @@ @Override MBeanAttributeInfo getMBeanAttributeInfo(String attributeName, - Method getter, Method setter) { + Method getter, Method setter) throws IntrospectionException { - 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 - } + 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 diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java Wed Jul 05 16:39:25 2017 +0200 @@ -41,26 +41,24 @@ public class StandardMBeanSupport extends MBeanSupport { /** -

    Construct a Standard MBean that wraps the given resource using the - given Standard MBean interface.

    - - @param resource the underlying resource for the new MBean. - - @param mbeanInterface the interface to be used to determine - the MBean's management interface. - - @param 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 StandardMBeanSupport(T resource, Class mbeanInterface) + *

    Construct a Standard MBean that wraps the given resource using the + * given Standard MBean interface.

    + * + * @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 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 StandardMBeanSupport(T resource, Class mbeanInterfaceType) throws NotCompliantMBeanException { - super(resource, mbeanInterface, (MXBeanMappingFactory) null); + super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null); } @Override @@ -86,13 +84,14 @@ @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()); } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Wed Jul 05 16:39:25 2017 +0200 @@ -38,6 +38,7 @@ 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 @@ return new LinkedHashMap(); } + static WeakHashMap newWeakHashMap() { + return new WeakHashMap(); + } + static Set newSet() { return new HashSet(); } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/EventSetImpl.java --- a/jdk/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Wed Jul 05 16:39:25 2017 +0200 @@ -208,8 +208,9 @@ } public String toString() { - return eventName() + "@" + location().toString() + - " in thread " + thread().name(); + return eventName() + "@" + + ((location() == null) ? " null" : location().toString()) + + " in thread " + thread().name(); } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java --- a/jdk/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java Wed Jul 05 16:39:25 2017 +0200 @@ -40,11 +40,12 @@ 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); } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java --- a/jdk/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java Wed Jul 05 16:39:25 2017 +0200 @@ -35,12 +35,34 @@ 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 frames = null; int framesStart = -1; @@ -52,6 +74,17 @@ 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 @@ // Listeners - synchronized on vm.state() private List> listeners = new ArrayList>(); + ThreadReferenceImpl(VirtualMachine aVm, long aRef) { super(aVm,aRef); + resetLocalCache(); vm.state().addListener(this); } @@ -72,10 +107,24 @@ * 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 @@ } 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 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 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 @@ throw exc.toJDIException(); } } - return frameCount; + return localCache.frameCount; } public List frames() throws IncompatibleThreadStateException { @@ -297,23 +332,25 @@ /** * 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 frames(int start, int length) @@ -329,51 +366,42 @@ * Private version of frames() allows "-1" to specify all * remaining frames. */ - private List privateFrames(int start, int length) + synchronized private List privateFrames(int start, int length) throws IncompatibleThreadStateException { - List frames = null; + + // 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 { - Cache local = (Cache)getCache(); - - if (local != null) { - frames = local.frames; - } - if (frames == null || !isSubrange(local, start, length, frames)) { + 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(count); + localCache.frames = new ArrayList(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 ownedMonitors() throws IncompatibleThreadStateException { - List 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 @@ 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 @@ throw exc.toJDIException(); } } - return monitor; + return localCache.contendedMonitor; } public List ownedMonitorsAndFrames() throws IncompatibleThreadStateException { - List 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(minfo.length); + localCache.ownedMonitorsInfo = new ArrayList(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 @@ throw exc.toJDIException(); } } - return monitors; + return localCache.ownedMonitorsInfo; } public void popFrames(StackFrame frame) throws IncompatibleThreadStateException { @@ -511,7 +513,7 @@ } public void forceEarlyReturn(Value returnValue) throws InvalidTypeException, - ClassNotLoadedException, + ClassNotLoadedException, IncompatibleThreadStateException { if (!vm.canForceEarlyReturn()) { throw new UnsupportedOperationException( @@ -604,6 +606,9 @@ iter.remove(); } } + + // Discard our local cache + resetLocalCache(); } } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/VMAction.java --- a/jdk/src/share/classes/com/sun/tools/jdi/VMAction.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VMAction.java Wed Jul 05 16:39:25 2017 +0200 @@ -38,10 +38,18 @@ 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 @@ int id() { return id; } + + ThreadReference resumingThread() { + return resumingThread; + } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/VMState.java --- a/jdk/src/share/classes/com/sun/tools/jdi/VMState.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VMState.java Wed Jul 05 16:39:25 2017 +0200 @@ -116,16 +116,25 @@ } /** - * Tell listeners to invalidate suspend-sensitive caches. + * All threads are resuming */ - synchronized void thaw() { + void thaw() { + thaw(null); + } + + /** + * Tell listeners to invalidate suspend-sensitive caches. + * If resumingThread != null, then only that thread is being + * resumed. + */ + 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) { diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java --- a/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Wed Jul 05 16:39:25 2017 +0200 @@ -146,8 +146,9 @@ 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; } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/java/nio/channels/SelectionKey.java --- a/jdk/src/share/classes/java/nio/channels/SelectionKey.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/SelectionKey.java Wed Jul 05 16:39:25 2017 +0200 @@ -191,7 +191,7 @@ * @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 - * set & ~(channel().validOps()) != 0 + * (ops & ~channel().validOps()) != 0 * * @throws CancelledKeyException * If this key has been cancelled diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/BinaryRelQueryExp.java --- a/jdk/src/share/classes/javax/management/BinaryRelQueryExp.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/BinaryRelQueryExp.java Wed Jul 05 16:39:25 2017 +0200 @@ -192,6 +192,7 @@ return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")"; } + @Override String toQueryString() { return exp1 + " " + relOpString() + " " + exp2; } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/Description.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/Description.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,180 @@ +/* + * 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; + +/** + *

    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.

    + * + *

    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:

    + * + *
    + * {@code @Description}("Application configuration")
    + * public interface ConfigurationMBean {
    + *     {@code @Description}("Cache size in bytes")
    + *     public int getCacheSize();
    + *     public void setCacheSize(int size);
    + *
    + *     {@code @Description}("Last time the configuration was changed, " +
    + *                  "in milliseconds since 1 Jan 1970")
    + *     public long getLastChangedTime();
    + *
    + *     {@code @Description}("Save the configuration to a file")
    + *     public void save(
    + *         {@code @Description}("Optional name of the file, or null for the default name")
    + *         String fileName);
    + * }
    + * 
    + * + *

    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.

    + * + *

    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"}.

    + * + *

    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:

    + * + *
    + * public class Configuration implements ConfigurationMBean {
    + *     {@code @Description}("A Configuration MBean with the default file name")
    + *     public Configuration() {
    + *         this(DEFAULT_FILE_NAME);
    + *     }
    + *
    + *     {@code @Description}("A Configuration MBean with a specified file name")
    + *     public Configuration(
    + *         {@code @Description}("Name of the file the configuration is stored in")
    + *         String fileName) {...}
    + *     ...
    + * }
    + * 
    + * + *

    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.

    + * + *
    + * {@code @MBean}
    + * {@code @Description}("Application configuration")
    + * public class Configuration {
    + *     {@code @Description}("A Configuration MBean with the default file name")
    + *     public Configuration() {
    + *         this(DEFAULT_FILE_NAME);
    + *     }
    + *
    + *     {@code @Description}("A Configuration MBean with a specified file name")
    + *     public Configuration(
    + *         {@code @Description}("Name of the file the configuration is stored in")
    + *         String fileName) {...}
    + *
    + *     {@code @ManagedAttribute}
    + *     {@code @Description}("Cache size in bytes")
    + *     public int getCacheSize() {...}
    + *     {@code @ManagedAttribute}
    + *     public void setCacheSize(int size) {...}
    + *
    + *     {@code @ManagedOperation}
    + *     {@code @Description}("Last time the configuration was changed, " +
    + *                  "in milliseconds since 1 Jan 1970")
    + *     public long getLastChangedTime() {...}
    + *
    + *     {@code @ManagedOperation}
    + *     {@code @Description}("Save the configuration to a file")
    + *     public void save(
    + *         {@code @Description}("Optional name of the file, or null for the default name")
    + *         String fileName) {...}
    + *     ...
    + * }
    + * 
    + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, + ElementType.TYPE}) +public @interface Description { + /** + *

    The description.

    + */ + String value(); + + /** + *

    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 + * {@code Descriptor} for the annotated item.

    + */ + @DescriptorKey( + value = "descriptionResourceBundleBaseName", omitIfDefault = true) + String bundleBaseName() default ""; + + /** + *

    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 + * {@code Descriptor} for the annotated item.

    + */ + @DescriptorKey(value = "descriptionResourceKey", omitIfDefault = true) + String key() default ""; +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/Descriptor.java --- a/jdk/src/share/classes/javax/management/Descriptor.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/Descriptor.java Wed Jul 05 16:39:25 2017 +0200 @@ -38,6 +38,7 @@ 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 @@ * deprecation, for example {@code "1.3 Replaced by the Capacity * attribute"}. * - *
    + * + * * * + * {@code "com.example.myapp.MBeanResources"}. * - * + * + * * * + * this can be used to find a localized version of the description. * * * @@ -216,6 +215,14 @@ * StandardMBean} class will have this field in its MBeanInfo * Descriptor. * + * + * + * + * + * * * * diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/DescriptorFields.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/DescriptorFields.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,137 @@ +/* + * 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; + +/** + *

    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.

    + * + *

    Consider this Standard MBean interface, for example:

    + * + *
    + * public interface CacheControlMBean {
    + *     @DescriptorFields("units=bytes")
    + *     public long getCacheSize();
    + * }
    + * 
    + * + *

    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}.

    + * + *

    Similarly, if the interface looks like this:

    + * + *
    + * public interface CacheControlMBean {
    + *     @DescriptorFields({"units=bytes", "since=1.5"})
    + *     public long getCacheSize();
    + * }
    + * 
    + * + *

    then the resulting {@code Descriptor} will contain the following + * fields:

    + * + *
    - - OpenJDK - + OpenJDK
    make.exe Develmake: The GNU version of the 'make' utilitymake: The GNU version of the 'make' utility
    + NOTE: See the GNU make section
    m4.execpio: A program to manage archives of files
    awk.exegawk.exe Utils awk: Pattern-directed scanning and processing language
    zip.exeUtilsArchive zip: Package and compress (archive) files
    unzip.exeUtilsArchive unzip: Extract compressed files in a ZIP archive
    free.exeUtilsProcps free: Display amount of free and used memory in the system
    descriptionResource
    BundleBaseName
    StringAny
    descriptionResource
    BundleBaseName
    StringAnyThe 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.
    descriptionResourceKeyStringAny
    descriptionResourceKeyStringAnyA 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.
    enabledStringMBeanAttributeInfo
    MBeanNotificationInfo
    MBeanOperationInfo
    mxbeanMappingFactoryClass + * StringMBeanInfoThe name of the {@link MXBeanMappingFactory} class that was used for this + * MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default} + * one.
    openType{@link OpenType}MBeanAttributeInfo
    MBeanOperationInfo
    MBeanParameterInfo
    + * + * + * + *
    NameValue
    units"bytes"
    since"1.5"
    + * + *

    The {@code @DescriptorFields} annotation can be applied to:

    + * + * + * + *

    Other uses of the annotation will either fail to compile or be + * ignored.

    + * + *

    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. + * + *

    The Descriptor fields contributed in this way must be consistent + * with each other and with any fields contributed by {@link + * DescriptorKey @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.

    + * + *

    The Descriptor resulting from these annotations will be merged + * with any Descriptor fields provided by the implementation, such as + * the {@code + * immutableInfo} field for an MBean. The fields from the annotations + * must be consistent with these fields provided by the implementation.

    + * + *

    {@literal @DescriptorFields and @DescriptorKey}

    + * + *

    The {@link DescriptorKey @DescriptorKey} annotation provides + * another way to use annotations to define Descriptor fields. + * @DescriptorKey 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. + * @DescriptorFields is more convenient but includes + * those risks. @DescriptorFields 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 @DescriptorKey. + * + * @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 { + /** + *

    The descriptor fields. Each element of the string looks like + * {@code "name=value"}.

    + */ + public String[] value(); +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/DescriptorKey.java --- a/jdk/src/share/classes/javax/management/DescriptorKey.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/DescriptorKey.java Wed Jul 05 16:39:25 2017 +0200 @@ -33,6 +33,11 @@ * an MBean, or for an attribute, operation, or constructor in an * MBean, or for a parameter of an operation or constructor.

    * + *

    (The {@link DescriptorFields @DescriptorFields} annotation + * provides another way to add fields to a {@code Descriptor}. See + * the documentation for that annotation for a comparison of the + * two possibilities.)

    + * *

    Consider this annotation for example:

    * *
    @@ -57,7 +62,7 @@
      * 

    When a Standard MBean is made from the {@code CacheControlMBean}, * the usual rules mean that it will have an attribute called * {@code CacheSize} of type {@code long}. The {@code @Units} - * attribute, given the above definition, will ensure that the + * annotation, given the above definition, 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}.

    @@ -125,12 +130,13 @@ * the method in the child interface are considered. * *

    The Descriptor fields contributed in this way by different - * annotations on the same program element must be consistent. 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.

    + * annotations on the same program element must be consistent with + * each other and with any fields contributed by a {@link + * DescriptorFields @DescriptorFields} annotation. 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.

    * *

    The Descriptor resulting from these annotations will be merged * with any Descriptor fields provided by the implementation, such as @@ -169,4 +175,36 @@ @Target(ElementType.METHOD) public @interface DescriptorKey { String value(); + + /** + *

    Do not include this field in the Descriptor if the annotation + * element has its default value. For example, suppose {@code @Units} is + * defined like this:

    + * + *
    +     * @Documented
    +     * @Target(ElementType.METHOD)
    +     * @Retention(RetentionPolicy.RUNTIME)
    +     * public @interface Units {
    +     *     @DescriptorKey("units")
    +     *     String value();
    +     *
    +     *     @DescriptorKey(value = "descriptionResourceKey",
    +     *                    omitIfDefault = true)
    +     *     String resourceKey() default "";
    +     *
    +     *     @DescriptorKey(value = "descriptionResourceBundleBaseName",
    +     *                    omitIfDefault = true)
    +     *     String resourceBundleBaseName() default "";
    +     * }
    +     * 
    + * + *

    Then consider a usage such as {@code @Units("bytes")} or + * {@code @Units(value = "bytes", resourceKey = "")}, where the + * {@code resourceKey} and {@code resourceBundleBaseNames} elements + * have their default values. In this case the Descriptor resulting + * from these annotations will not include a {@code descriptionResourceKey} + * or {@code descriptionResourceBundleBaseName} field.

    + */ + boolean omitIfDefault() default false; } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/DynamicWrapperMBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/DynamicWrapperMBean.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2005 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; + +/** + *

    An MBean can implement this interface to affect how the MBeanServer's + * {@link MBeanServer#getClassLoaderFor getClassLoaderFor} and + * {@link MBeanServer#isInstanceOf isInstanceOf} methods behave. + * If these methods should refer to a wrapped object rather than the + * MBean object itself, then the {@link #getWrappedObject} method should + * return that wrapped object.

    + * + * @see MBeanServer#getClassLoaderFor + * @see MBeanServer#isInstanceOf + */ +public interface DynamicWrapperMBean extends DynamicMBean { + /** + *

    The resource corresponding to this MBean. This is the object whose + * class name should be reflected by the MBean's + * {@link MBeanServer#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} for example. For a "plain" + * DynamicMBean it will be "this". For an MBean that wraps another + * object, in the manner of {@link javax.management.StandardMBean}, it will be the + * wrapped object.

    + * + * @return The resource corresponding to this MBean. + */ + public Object getWrappedObject(); + + /** + *

    The {@code ClassLoader} for this MBean, which can be used to + * retrieve resources associated with the MBean for example. Usually, + * it will be + * {@link #getWrappedObject()}.{@code getClass().getClassLoader()}. + * + * @return The {@code ClassLoader} for this MBean. + */ + public ClassLoader getWrappedClassLoader(); +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/Impact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/Impact.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,105 @@ +/* + * 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; + +/** + *

    Defines the impact of an MBean operation, in particular whether it + * has an effect on the MBean or simply returns information. This enum + * is used in the {@link ManagedOperation @ManagedOperation} annotation. + * Its {@link #getCode()} method can be used to get an {@code int} suitable + * for use as the {@code impact} parameter in an {@link MBeanOperationInfo} + * constructor.

    + */ +public enum Impact { + /** + * The operation is read-like: it returns information but does not change + * any state. + * @see MBeanOperationInfo#INFO + */ + INFO(MBeanOperationInfo.INFO), + + /** + * The operation is write-like: it has an effect but does not return + * any information from the MBean. + * @see MBeanOperationInfo#ACTION + */ + ACTION(MBeanOperationInfo.ACTION), + + /** + * The operation is both read-like and write-like: it has an effect, + * and it also returns information from the MBean. + * @see MBeanOperationInfo#ACTION_INFO + */ + ACTION_INFO(MBeanOperationInfo.ACTION_INFO), + + /** + * The impact of the operation is unknown or cannot be expressed + * using one of the other values. + * @see MBeanOperationInfo#UNKNOWN + */ + UNKNOWN(MBeanOperationInfo.UNKNOWN); + + private final int code; + + /** + * An instance of this enumeration, with the corresponding {@code int} + * code used by the {@link MBeanOperationInfo} constructors. + * + * @param code the code used by the {@code MBeanOperationInfo} constructors. + */ + Impact(int code) { + this.code = code; + } + + /** + * The equivalent {@code int} code used by the {@link MBeanOperationInfo} + * constructors. + * @return the {@code int} code. + */ + public int getCode() { + return code; + } + + /** + * Return the {@code Impact} value corresponding to the given {@code int} + * code. The {@code code} is the value that would be used in an + * {@code MBeanOperationInfo} constructor. + * + * @param code the {@code int} code. + * + * @return an {@code Impact} value {@code x} such that + * {@code code == x.}{@link #getCode()}, or {@code Impact.UNKNOWN} + * if there is no such value. + */ + public static Impact forCode(int code) { + switch (code) { + case MBeanOperationInfo.ACTION: return ACTION; + case MBeanOperationInfo.INFO: return INFO; + case MBeanOperationInfo.ACTION_INFO: return ACTION_INFO; + default: return UNKNOWN; + } + } +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/JMX.java --- a/jdk/src/share/classes/javax/management/JMX.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/JMX.java Wed Jul 05 16:39:25 2017 +0200 @@ -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 @@ *
    * * @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 @@ // exactly the string "MXBean" since that would mean there // was no package name, which is pretty unlikely in practice. } + + /** + *

    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 resource + * injection to obtain an instance of {@link SendNotification} + * through which it can send notifications.

    + * + * @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)); + } } diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/MBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/MBean.java Wed Jul 05 16:39:25 2017 +0200 @@ -0,0 +1,68 @@ +/* + * 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.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

    Indicates that the annotated class is a Standard MBean. A Standard + * MBean class can be defined as in this example:

    + * + *
    + * {@code @MBean}
    + * public class Configuration {
    + *     {@link ManagedAttribute @ManagedAttribute}
    + *     public int getCacheSize() {...}
    + *     {@code @ManagedAttribute}
    + *     public void setCacheSize(int size);
    + *
    + *     {@code @ManagedAttribute}
    + *     public long getLastChangedTime();
    + *
    + *     {@link ManagedOperation @ManagedOperation}
    + *     public void save();
    + * }
    + * 
    + * + *

    The class must be public. Public methods within the class can be + * annotated with {@code @ManagedOperation} to indicate that they are + * MBean operations. Public getter and setter methods within the class + * can be annotated with {@code @ManagedAttribute} to indicate that they define + * MBean attributes.

    + * + *

    If the MBean is to be an MXBean rather than a Standard MBean, then + * the {@link MXBean @MXBean} annotation must be used instead of + * {@code @MBean}.

    + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface MBean { +} diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/MBeanOperationInfo.java --- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Wed Jul 05 16:39:25 2017 +0200 @@ -46,25 +46,30 @@ new MBeanOperationInfo[0]; /** - * Indicates that the operation is read-like, - * it basically returns information. + * Indicates that the operation is read-like: + * it returns information but does not change any state. + * @see Impact#INFO */ public static final int INFO = 0; /** - * Indicates that the operation is a write-like, - * and would modify the MBean in some way, typically by writing some value - * or changing a configuration. + * Indicates that the operation is write-like: it has an effect but does + * not return any information from the MBean. + * @see Impact#ACTION */ public static final int ACTION = 1; /** - * Indicates that the operation is both read-like and write-like. + * Indicates that the operation is both read-like and write-like: + * it has an effect, and it also returns information from the MBean. + * @see Impact#ACTION_INFO */ public static final int ACTION_INFO = 2; /** - * Indicates that the operation has an "unknown" nature. + * Indicates that the impact of the operation is unknown or cannot be + * expressed using one of the other values. + * @see Impact#UNKNOWN */ public static final int UNKNOWN = 3; @@ -120,8 +125,9 @@ * describing the parameters(arguments) of the method. This may be * null with the same effect as a zero-length array. * @param type The type of the method's return value. - * @param impact The impact of the method, one of INFO, - * ACTION, ACTION_INFO, UNKNOWN. + * @param impact The impact of the method, one of + * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, + * {@link #UNKNOWN}. */ public MBeanOperationInfo(String name, String description, @@ -140,8 +146,9 @@ * describing the parameters(arguments) of the method. This may be * null with the same effect as a zero-length array. * @param type The type of the method's return value. - * @param impact The impact of the method, one of INFO, - * ACTION, ACTION_INFO, UNKNOWN. + * @param impact The impact of the method, one of + * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, + * {@link #UNKNOWN}. * @param descriptor The descriptor for the operation. This may be null * which is equivalent to an empty descriptor. * @@ -319,9 +326,14 @@ for (int i = 0; i < classes.length; i++) { Descriptor d = Introspector.descriptorForAnnotations(annots[i]); - final String pn = "p" + (i + 1); - params[i] = - new MBeanParameterInfo(pn, classes[i].getName(), "", d); + String description = Introspector.descriptionForParameter(annots[i]); + if (description == null) + description = ""; + String name = Introspector.nameForParameter(annots[i]); + if (name == null) + name = "p" + (i + 1); + params[i] = new MBeanParameterInfo( + name, classes[i].getName(), description, d); } return params; diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/MBeanRegistration.java --- a/jdk/src/share/classes/javax/management/MBeanRegistration.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanRegistration.java Wed Jul 05 16:39:25 2017 +0200 @@ -27,9 +27,101 @@ /** - * Can be implemented by an MBean in order to + *

    Can be implemented by an MBean in order to * carry out operations before and after being registered or unregistered from - * the MBean server. + * the MBean Server. An MBean can also implement this interface in order + * to get a reference to the MBean Server and/or its name within that + * MBean Server.

    + * + *

    Resource injection

    + * + *

    As an alternative to implementing {@code MBeanRegistration}, if all that + * is needed is the MBean Server or ObjectName then an MBean can use + * resource injection.

    + * + *

    If a field in the MBean object has type {@link ObjectName} and has + * the {@link javax.annotation.Resource @Resource} annotation, + * then the {@code ObjectName} under which the MBean is registered is + * assigned to that field during registration. Likewise, if a field has type + * {@link MBeanServer} and the @Resource annotation, then it will + * be set to the {@code MBeanServer} in which the MBean is registered.

    + * + *

    For example:

    + * + *
    + * public Configuration implements ConfigurationMBean {
    + *     @Resource
    + *     private volatile MBeanServer mbeanServer;
    + *     @Resource
    + *     private volatile ObjectName objectName;
    + *     ...
    + *     void unregisterSelf() throws Exception {
    + *         mbeanServer.unregisterMBean(objectName);
    + *     }
    + * }
    + * 
    + * + *

    Resource injection can also be used on fields of type + * {@link SendNotification} to simplify notification sending. Such a field + * will get a reference to an object of type {@code SendNotification} when + * the MBean is registered, and it can use this reference to send notifications. + * For example:

    + * + *
    + * public Configuration implements ConfigurationMBean {
    + *     @Resource
    + *     private volatile SendNotification sender;
    + *     ...
    + *     private void updated() {
    + *         Notification n = new Notification(...);
    + *         sender.sendNotification(n);
    + *     }
    + * }
    + * 
    + * + *

    A field to be injected must not be static. It is recommended that + * such fields be declared {@code volatile}.

    + * + *

    It is also possible to use the @Resource annotation on + * methods. Such a method must have a {@code void} return type and a single + * argument of the appropriate type, for example {@code ObjectName}.

    + * + *

    Any number of fields and methods may have the @Resource + * annotation. All fields and methods with type {@code ObjectName} + * (for example) will receive the same {@code ObjectName} value.

    + * + *

    Resource injection is available for all types of MBeans, not just + * Standard MBeans.

    + * + *

    If an MBean implements the {@link DynamicWrapperMBean} interface then + * resource injection happens on the object returned by that interface's + * {@link DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method + * rather than on the MBean object itself. + * + *

    Resource injection happens after the {@link #preRegister preRegister} + * method is called (if any), and before the MBean is actually registered + * in the MBean Server. If a @Resource method throws + * an exception, the effect is the same as if {@code preRegister} had + * thrown the exception. In particular it will prevent the MBean from being + * registered.

    + * + *

    Resource injection can be used on a field or method where the type + * is a parent of the injected type, if the injected type is explicitly + * specified in the @Resource annotation. For example:

    + * + *
    + *     @Resource(type = MBeanServer.class)
    + *     private volatile MBeanServerConnection mbsc;
    + * 
    + * + *

    Formally, suppose R is the type in the @Resource + * annotation and T is the type of the method parameter or field. + * Then one of R and T must be a subtype of the other + * (or they must be the same type). Injection happens if this subtype + * is {@code MBeanServer}, {@code ObjectName}, or {@code SendNotification}. + * Otherwise the @Resource annotation is ignored.

    + * + *

    Resource injection in MBeans is new in version 2.0 of the JMX API.

    * * @since 1.5 */ @@ -38,12 +130,12 @@ /** * Allows the MBean to perform any operations it needs before - * being registered in the MBean server. If the name of the MBean + * being registered in the MBean Server. If the name of the MBean * is not specified, the MBean can provide a name for its * registration. If any exception is raised, the MBean will not be - * registered in the MBean server. + * registered in the MBean Server. * - * @param server The MBean server in which the MBean will be registered. + * @param server The MBean Server in which the MBean will be registered. * * @param name The object name of the MBean. This name is null if * the name parameter to one of the createMBean or @@ -57,7 +149,7 @@ * the returned value. * * @exception java.lang.Exception This exception will be caught by - * the MBean server and re-thrown as an {@link + * the MBean Server and re-thrown as an {@link * MBeanRegistrationException}. */ public ObjectName preRegister(MBeanServer server, diff -r aded486da6fd -r 1ee6203fb405 jdk/src/share/classes/javax/management/MBeanServer.java --- a/jdk/src/share/classes/javax/management/MBeanServer.java Tue Jul 22 11:41:45 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServer.java Wed Jul 05 16:39:25 2017 +0200 @@ -61,7 +61,7 @@ * ObjectName is:
    * JMImplementation:type=MBeanServerDelegate.

    * - *

    An object obtained from the {@link + *

    An object obtained from the {@link * MBeanServerFactory#createMBeanServer(String) createMBeanServer} or * {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer} * methods of the {@link MBeanServerFactory} class applies security @@ -661,13 +661,16 @@ ReflectionException; /** - *

    Return the {@link java.lang.ClassLoader} that was used for - * loading the class of the named MBean.

    + *

    Return the {@link java.lang.ClassLoader} that was used for loading + * the class of the named MBean. If the MBean implements the {@link + * DynamicWrapperMBean} interface, then the returned value is the + * result of the {@link DynamicWrapperMBean#getWrappedClassLoader()} + * method.

    * * @param mbeanName The ObjectName of the MBean. * * @return The ClassLoader used for that MBean. If l - * is the MBean's actual ClassLoader, and r is the + * is the value specified by the rules above, and r is the * returned value, then either: * *