# HG changeset patch # User chegar # Date 1382360889 -3600 # Node ID 6795fcebbf421944dd30a90b067199d3b77c41c1 # Parent 6fa574bfd32ac559142d046606390354e68e4960# Parent e39b138b2518cd7c880637fee2b18c349995e8e4 Merge diff -r 6fa574bfd32a -r 6795fcebbf42 .hgtags --- a/.hgtags Thu Oct 03 19:13:12 2013 +0100 +++ b/.hgtags Mon Oct 21 14:08:09 2013 +0100 @@ -382,3 +382,7 @@ c81dd5393a5e333df7cb1f6621f5897ada6522b5 jdk8-b109 58043478c26d4e8bf48700acea5f97aba8b417d4 hs25-b52 6209b0ed51c086d4127bac0e086c8f326d1764d7 jdk8-b110 +562a3d356de67670b4172b82aca2d30743449e04 hs25-b53 +f6962730bbde82f279a0ae3a1c14bc5e58096c6e jdk8-b111 +4a845c7a463844cead9e1e1641d6bcfb8a77f1c7 hs25-b54 +0ed9a90f45e1b392c671005f9ee22ce1acf02984 jdk8-b112 diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/bsd/ps_core.c --- a/agent/src/os/bsd/ps_core.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/bsd/ps_core.c Mon Oct 21 14:08:09 2013 +0100 @@ -44,6 +44,7 @@ // close all file descriptors static void close_files(struct ps_prochandle* ph) { lib_info* lib = NULL; + // close core file descriptor if (ph->core->core_fd >= 0) close(ph->core->core_fd); @@ -149,8 +150,7 @@ // Return the map_info for the given virtual address. We keep a sorted // array of pointers in ph->map_array, so we can binary search. -static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) -{ +static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { int mid, lo = 0, hi = ph->core->num_maps - 1; map_info *mp; @@ -230,9 +230,9 @@ size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with - // the C type matching the C++ bool type on any given platform. For - // Hotspot on BSD we assume the corresponding C type is char but - // licensees on BSD versions may need to adjust the type of these fields. + // the C type matching the C++ bool type on any given platform. + // We assume the corresponding C type is char but licensees + // may need to adjust the type of these fields. char _read_only; // read only space? char _allow_exec; // executable code in space? @@ -286,10 +286,12 @@ #define USE_SHARED_SPACES_SYM "_UseSharedSpaces" // mangled name of Arguments::SharedArchivePath #define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" +#define LIBJVM_NAME "/libjvm.dylib" #else #define USE_SHARED_SPACES_SYM "UseSharedSpaces" // mangled name of Arguments::SharedArchivePath #define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" +#define LIBJVM_NAME "/libjvm.so" #endif // __APPLE_ static bool init_classsharing_workaround(struct ps_prochandle* ph) { @@ -300,12 +302,7 @@ // we are iterating over shared objects from the core dump. look for // libjvm.so. const char *jvm_name = 0; -#ifdef __APPLE__ - if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0) -#else - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) -#endif // __APPLE__ - { + if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) { char classes_jsa[PATH_MAX]; struct FileMapHeader header; int fd = -1; @@ -399,8 +396,8 @@ } } return true; - } - lib = lib->next; + } + lib = lib->next; } return true; } @@ -432,8 +429,8 @@ // allocate map_array map_info** array; if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); - return false; + print_debug("can't allocate memory for map array\n"); + return false; } // add maps to array @@ -450,7 +447,7 @@ ph->core->map_array = array; // sort the map_info array by base virtual address. qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), - core_cmp_mapping); + core_cmp_mapping); // print map if (is_debug()) { @@ -458,7 +455,7 @@ print_debug("---- sorted virtual address map ----\n"); for (j = 0; j < ph->core->num_maps; j++) { print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, - ph->core->map_array[j]->memsz); + ph->core->map_array[j]->memsz); } } @@ -1091,9 +1088,9 @@ notep->n_type, notep->n_descsz); if (notep->n_type == NT_PRSTATUS) { - if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { - return false; - } + if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { + return false; + } } p = descdata + ROUNDUP(notep->n_descsz, 4); } @@ -1121,7 +1118,7 @@ * contains a set of saved /proc structures), and PT_LOAD (which * represents a memory mapping from the process's address space). * - * Difference b/w Solaris PT_NOTE and BSD PT_NOTE: + * Difference b/w Solaris PT_NOTE and Linux/BSD PT_NOTE: * * In Solaris there are two PT_NOTE segments the first PT_NOTE (if present) * contains /proc structs in the pre-2.6 unstructured /proc format. the last @@ -1167,32 +1164,61 @@ // read segments of a shared object static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) { - int i = 0; - ELF_PHDR* phbuf; - ELF_PHDR* lib_php = NULL; + int i = 0; + ELF_PHDR* phbuf; + ELF_PHDR* lib_php = NULL; + + int page_size=sysconf(_SC_PAGE_SIZE); - if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) - return false; + if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) { + return false; + } + + // we want to process only PT_LOAD segments that are not writable. + // i.e., text segments. The read/write/exec (data) segments would + // have been already added from core file segments. + for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) { + if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) { + + uintptr_t target_vaddr = lib_php->p_vaddr + lib_base; + map_info *existing_map = core_lookup(ph, target_vaddr); - // we want to process only PT_LOAD segments that are not writable. - // i.e., text segments. The read/write/exec (data) segments would - // have been already added from core file segments. - for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) { - if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) { - if (add_map_info(ph, lib_fd, lib_php->p_offset, lib_php->p_vaddr + lib_base, lib_php->p_filesz) == NULL) - goto err; + if (existing_map == NULL){ + if (add_map_info(ph, lib_fd, lib_php->p_offset, + target_vaddr, lib_php->p_filesz) == NULL) { + goto err; + } + } else { + if ((existing_map->memsz != page_size) && + (existing_map->fd != lib_fd) && + (existing_map->memsz != lib_php->p_filesz)){ + + print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)", + target_vaddr, lib_php->p_filesz, lib_php->p_flags); + goto err; + } + + /* replace PT_LOAD segment with library segment */ + print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n", + existing_map->memsz, lib_php->p_filesz); + + existing_map->fd = lib_fd; + existing_map->offset = lib_php->p_offset; + existing_map->memsz = lib_php->p_filesz; } - lib_php++; - } + } + + lib_php++; + } - free(phbuf); - return true; + free(phbuf); + return true; err: - free(phbuf); - return false; + free(phbuf); + return false; } -// process segments from interpreter (ld-elf.so.1) +// process segments from interpreter (ld.so or ld-linux.so or ld-elf.so) static bool read_interp_segments(struct ps_prochandle* ph) { ELF_EHDR interp_ehdr; @@ -1303,32 +1329,34 @@ debug_base = dyn.d_un.d_ptr; // at debug_base we have struct r_debug. This has first link map in r_map field if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, - &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { + &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { print_debug("can't read first link map address\n"); return false; } // read ld_base address from struct r_debug - // XXX: There is no r_ldbase member on BSD - /* +#if 0 // There is no r_ldbase member on BSD if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, sizeof(uintptr_t)) != PS_OK) { print_debug("can't read ld base address\n"); return false; } ph->core->ld_base_addr = ld_base_addr; - */ +#else ph->core->ld_base_addr = 0; +#endif print_debug("interpreter base address is 0x%lx\n", ld_base_addr); - // now read segments from interp (i.e ld-elf.so.1) - if (read_interp_segments(ph) != true) + // now read segments from interp (i.e ld.so or ld-linux.so or ld-elf.so) + if (read_interp_segments(ph) != true) { return false; + } // after adding interpreter (ld.so) mappings sort again - if (sort_map_array(ph) != true) + if (sort_map_array(ph) != true) { return false; + } print_debug("first link map is at 0x%lx\n", first_link_map_addr); @@ -1380,8 +1408,9 @@ add_lib_info_fd(ph, lib_name, lib_fd, lib_base); // Map info is added for the library (lib_name) so // we need to re-sort it before calling the p_pdread. - if (sort_map_array(ph) != true) + if (sort_map_array(ph) != true) { return false; + } } else { print_debug("can't read ELF header for shared object %s\n", lib_name); close(lib_fd); @@ -1392,7 +1421,7 @@ // read next link_map address if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, - &link_map_addr, sizeof(uintptr_t)) != PS_OK) { + &link_map_addr, sizeof(uintptr_t)) != PS_OK) { print_debug("can't read next link in link_map\n"); return false; } @@ -1408,7 +1437,7 @@ struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); if (ph == NULL) { - print_debug("cant allocate ps_prochandle\n"); + print_debug("can't allocate ps_prochandle\n"); return NULL; } @@ -1444,38 +1473,45 @@ } if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { - print_debug("executable file is not a valid ELF ET_EXEC file\n"); - goto err; + print_debug("executable file is not a valid ELF ET_EXEC file\n"); + goto err; } // process core file segments - if (read_core_segments(ph, &core_ehdr) != true) - goto err; + if (read_core_segments(ph, &core_ehdr) != true) { + goto err; + } // process exec file segments - if (read_exec_segments(ph, &exec_ehdr) != true) - goto err; + if (read_exec_segments(ph, &exec_ehdr) != true) { + goto err; + } // exec file is also treated like a shared object for symbol search if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, - (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) - goto err; + (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) { + goto err; + } // allocate and sort maps into map_array, we need to do this // here because read_shared_lib_info needs to read from debuggee // address space - if (sort_map_array(ph) != true) + if (sort_map_array(ph) != true) { goto err; + } - if (read_shared_lib_info(ph) != true) + if (read_shared_lib_info(ph) != true) { goto err; + } // sort again because we have added more mappings from shared objects - if (sort_map_array(ph) != true) + if (sort_map_array(ph) != true) { goto err; + } - if (init_classsharing_workaround(ph) != true) + if (init_classsharing_workaround(ph) != true) { goto err; + } print_debug("Leave Pgrab_core\n"); return ph; diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Mon Oct 21 14:08:09 2013 +0100 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -80,7 +81,7 @@ (JNIEnv *env, jclass cls) { jclass listClass; - if (init_libproc(getenv("LIBSAPROC_DEBUG")) != true) { + if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) { THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc"); } diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/linux/ps_core.c --- a/agent/src/os/linux/ps_core.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/linux/ps_core.c Mon Oct 21 14:08:09 2013 +0100 @@ -41,155 +41,158 @@ // ps_prochandle cleanup helper functions // close all file descriptors -static void close_elf_files(struct ps_prochandle* ph) { - lib_info* lib = NULL; +static void close_files(struct ps_prochandle* ph) { + lib_info* lib = NULL; - // close core file descriptor - if (ph->core->core_fd >= 0) - close(ph->core->core_fd); + // close core file descriptor + if (ph->core->core_fd >= 0) + close(ph->core->core_fd); - // close exec file descriptor - if (ph->core->exec_fd >= 0) - close(ph->core->exec_fd); + // close exec file descriptor + if (ph->core->exec_fd >= 0) + close(ph->core->exec_fd); - // close interp file descriptor - if (ph->core->interp_fd >= 0) - close(ph->core->interp_fd); + // close interp file descriptor + if (ph->core->interp_fd >= 0) + close(ph->core->interp_fd); - // close class share archive file - if (ph->core->classes_jsa_fd >= 0) - close(ph->core->classes_jsa_fd); + // close class share archive file + if (ph->core->classes_jsa_fd >= 0) + close(ph->core->classes_jsa_fd); - // close all library file descriptors - lib = ph->libs; - while (lib) { - int fd = lib->fd; - if (fd >= 0 && fd != ph->core->exec_fd) close(fd); - lib = lib->next; - } + // close all library file descriptors + lib = ph->libs; + while (lib) { + int fd = lib->fd; + if (fd >= 0 && fd != ph->core->exec_fd) { + close(fd); + } + lib = lib->next; + } } // clean all map_info stuff static void destroy_map_info(struct ps_prochandle* ph) { map_info* map = ph->core->maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } if (ph->core->map_array) { - free(ph->core->map_array); + free(ph->core->map_array); } // Part of the class sharing workaround map = ph->core->class_share_maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } } // ps_prochandle operations static void core_release(struct ps_prochandle* ph) { - if (ph->core) { - close_elf_files(ph); - destroy_map_info(ph); - free(ph->core); - } + if (ph->core) { + close_files(ph); + destroy_map_info(ph); + free(ph->core); + } } static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { - print_debug("can't allocate memory for map_info\n"); - return NULL; - } + map_info* map; + if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { + print_debug("can't allocate memory for map_info\n"); + return NULL; + } - // initialize map - map->fd = fd; - map->offset = offset; - map->vaddr = vaddr; - map->memsz = memsz; - return map; + // initialize map + map->fd = fd; + map->offset = offset; + map->vaddr = vaddr; + map->memsz = memsz; + return map; } // add map info with given fd, offset, vaddr and memsz static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { - return NULL; - } + map_info* map; + if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { + return NULL; + } - // add this to map list - map->next = ph->core->maps; - ph->core->maps = map; - ph->core->num_maps++; + // add this to map list + map->next = ph->core->maps; + ph->core->maps = map; + ph->core->num_maps++; - return map; + return map; } // Part of the class sharing workaround -static void add_class_share_map_info(struct ps_prochandle* ph, off_t offset, +static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(ph->core->classes_jsa_fd, - offset, vaddr, memsz)) == NULL) { - return; - } + map_info* map; + if ((map = allocate_init_map(ph->core->classes_jsa_fd, + offset, vaddr, memsz)) == NULL) { + return NULL; + } - map->next = ph->core->class_share_maps; - ph->core->class_share_maps = map; + map->next = ph->core->class_share_maps; + ph->core->class_share_maps = map; + return map; } // Return the map_info for the given virtual address. We keep a sorted // array of pointers in ph->map_array, so we can binary search. -static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) -{ - int mid, lo = 0, hi = ph->core->num_maps - 1; - map_info *mp; +static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { + int mid, lo = 0, hi = ph->core->num_maps - 1; + map_info *mp; - while (hi - lo > 1) { - mid = (lo + hi) / 2; - if (addr >= ph->core->map_array[mid]->vaddr) - lo = mid; - else - hi = mid; - } + while (hi - lo > 1) { + mid = (lo + hi) / 2; + if (addr >= ph->core->map_array[mid]->vaddr) { + lo = mid; + } else { + hi = mid; + } + } - if (addr < ph->core->map_array[hi]->vaddr) - mp = ph->core->map_array[lo]; - else - mp = ph->core->map_array[hi]; + if (addr < ph->core->map_array[hi]->vaddr) { + mp = ph->core->map_array[lo]; + } else { + mp = ph->core->map_array[hi]; + } - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) - return (mp); + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + return (mp); + } - // Part of the class sharing workaround - // Unfortunately, we have no way of detecting -Xshare state. - // Check out the share maps atlast, if we don't find anywhere. - // This is done this way so to avoid reading share pages - // ahead of other normal maps. For eg. with -Xshare:off we don't - // want to prefer class sharing data to data from core. - mp = ph->core->class_share_maps; - if (mp) { - print_debug("can't locate map_info at 0x%lx, trying class share maps\n", - addr); - } - while (mp) { - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { - print_debug("located map_info at 0x%lx from class share maps\n", - addr); - return (mp); - } - mp = mp->next; - } + // Part of the class sharing workaround + // Unfortunately, we have no way of detecting -Xshare state. + // Check out the share maps atlast, if we don't find anywhere. + // This is done this way so to avoid reading share pages + // ahead of other normal maps. For eg. with -Xshare:off we don't + // want to prefer class sharing data to data from core. + mp = ph->core->class_share_maps; + if (mp) { + print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); + } + while (mp) { + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + print_debug("located map_info at 0x%lx from class share maps\n", addr); + return (mp); + } + mp = mp->next; + } - print_debug("can't locate map_info at 0x%lx\n", addr); - return (NULL); + print_debug("can't locate map_info at 0x%lx\n", addr); + return (NULL); } //--------------------------------------------------------------- @@ -226,9 +229,9 @@ size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with - // the C type matching the C++ bool type on any given platform. For - // Hotspot on Linux we assume the corresponding C type is char but - // licensees on Linux versions may need to adjust the type of these fields. + // the C type matching the C++ bool type on any given platform. + // We assume the corresponding C type is char but licensees + // may need to adjust the type of these fields. char _read_only; // read only space? char _allow_exec; // executable code in space? @@ -238,154 +241,159 @@ }; static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { - jboolean i; - if (ps_pdread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { - *pvalue = i; - return true; - } else { - return false; - } + jboolean i; + if (ps_pdread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { + *pvalue = i; + return true; + } else { + return false; + } } static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { - uintptr_t uip; - if (ps_pdread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) { - *pvalue = uip; - return true; - } else { - return false; - } + uintptr_t uip; + if (ps_pdread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { + *pvalue = uip; + return true; + } else { + return false; + } } // used to read strings from debuggee static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { - size_t i = 0; - char c = ' '; + size_t i = 0; + char c = ' '; - while (c != '\0') { - if (ps_pdread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) - return false; - if (i < size - 1) - buf[i] = c; - else // smaller buffer - return false; - i++; addr++; - } + while (c != '\0') { + if (ps_pdread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { + return false; + } + if (i < size - 1) { + buf[i] = c; + } else { + // smaller buffer + return false; + } + i++; addr++; + } - buf[i] = '\0'; - return true; + buf[i] = '\0'; + return true; } #define USE_SHARED_SPACES_SYM "UseSharedSpaces" // mangled name of Arguments::SharedArchivePath #define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" +#define LIBJVM_NAME "/libjvm.so" static bool init_classsharing_workaround(struct ps_prochandle* ph) { - lib_info* lib = ph->libs; - while (lib != NULL) { - // we are iterating over shared objects from the core dump. look for - // libjvm.so. - const char *jvm_name = 0; - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) { - char classes_jsa[PATH_MAX]; - struct FileMapHeader header; - size_t n = 0; - int fd = -1, m = 0; - uintptr_t base = 0, useSharedSpacesAddr = 0; - uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; - jboolean useSharedSpaces = 0; - map_info* mi = 0; + lib_info* lib = ph->libs; + while (lib != NULL) { + // we are iterating over shared objects from the core dump. look for + // libjvm.so. + const char *jvm_name = 0; + if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) { + char classes_jsa[PATH_MAX]; + struct FileMapHeader header; + int fd = -1; + int m = 0; + size_t n = 0; + uintptr_t base = 0, useSharedSpacesAddr = 0; + uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; + jboolean useSharedSpaces = 0; + map_info* mi = 0; - memset(classes_jsa, 0, sizeof(classes_jsa)); - jvm_name = lib->name; - useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); - if (useSharedSpacesAddr == 0) { - print_debug("can't lookup 'UseSharedSpaces' flag\n"); - return false; - } + memset(classes_jsa, 0, sizeof(classes_jsa)); + jvm_name = lib->name; + useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); + if (useSharedSpacesAddr == 0) { + print_debug("can't lookup 'UseSharedSpaces' flag\n"); + return false; + } - // Hotspot vm types are not exported to build this library. So - // using equivalent type jboolean to read the value of - // UseSharedSpaces which is same as hotspot type "bool". - if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { - print_debug("can't read the value of 'UseSharedSpaces' flag\n"); - return false; - } + // Hotspot vm types are not exported to build this library. So + // using equivalent type jboolean to read the value of + // UseSharedSpaces which is same as hotspot type "bool". + if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { + print_debug("can't read the value of 'UseSharedSpaces' flag\n"); + return false; + } - if ((int)useSharedSpaces == 0) { - print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); - return true; - } + if ((int)useSharedSpaces == 0) { + print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); + return true; + } - sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); - if (sharedArchivePathAddrAddr == 0) { - print_debug("can't lookup shared archive path symbol\n"); - return false; - } + sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); + if (sharedArchivePathAddrAddr == 0) { + print_debug("can't lookup shared archive path symbol\n"); + return false; + } - if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { - print_debug("can't read shared archive path pointer\n"); - return false; - } + if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { + print_debug("can't read shared archive path pointer\n"); + return false; + } - if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { - print_debug("can't read shared archive path value\n"); - return false; - } + if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { + print_debug("can't read shared archive path value\n"); + return false; + } - print_debug("looking for %s\n", classes_jsa); - // open the class sharing archive file - fd = pathmap_open(classes_jsa); - if (fd < 0) { - print_debug("can't open %s!\n", classes_jsa); - ph->core->classes_jsa_fd = -1; - return false; - } else { - print_debug("opened %s\n", classes_jsa); - } + print_debug("looking for %s\n", classes_jsa); + // open the class sharing archive file + fd = pathmap_open(classes_jsa); + if (fd < 0) { + print_debug("can't open %s!\n", classes_jsa); + ph->core->classes_jsa_fd = -1; + return false; + } else { + print_debug("opened %s\n", classes_jsa); + } - // read FileMapHeader from the file - memset(&header, 0, sizeof(struct FileMapHeader)); - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) - != sizeof(struct FileMapHeader)) { - print_debug("can't read shared archive file map header from %s\n", classes_jsa); - close(fd); - return false; - } + // read FileMapHeader from the file + memset(&header, 0, sizeof(struct FileMapHeader)); + if ((n = read(fd, &header, sizeof(struct FileMapHeader))) + != sizeof(struct FileMapHeader)) { + print_debug("can't read shared archive file map header from %s\n", classes_jsa); + close(fd); + return false; + } - // check file magic - if (header._magic != 0xf00baba2) { - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", - classes_jsa, header._magic); - close(fd); - return false; - } + // check file magic + if (header._magic != 0xf00baba2) { + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", + classes_jsa, header._magic); + close(fd); + return false; + } - // check version - if (header._version != CURRENT_ARCHIVE_VERSION) { - print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); - close(fd); - return false; - } + // check version + if (header._version != CURRENT_ARCHIVE_VERSION) { + print_debug("%s has wrong shared archive file version %d, expecting %d\n", + classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); + close(fd); + return false; + } - ph->core->classes_jsa_fd = fd; - // add read-only maps from classes.jsa to the list of maps - for (m = 0; m < NUM_SHARED_MAPS; m++) { - if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; - // no need to worry about the fractional pages at-the-end. - // possible fractional pages are handled by core_read_data. - add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, - base, (size_t) header._space[m]._used); - print_debug("added a share archive map at 0x%lx\n", base); - } - } - return true; + ph->core->classes_jsa_fd = fd; + // add read-only maps from classes.jsa to the list of maps + for (m = 0; m < NUM_SHARED_MAPS; m++) { + if (header._space[m]._read_only) { + base = (uintptr_t) header._space[m]._base; + // no need to worry about the fractional pages at-the-end. + // possible fractional pages are handled by core_read_data. + add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, + base, (size_t) header._space[m]._used); + print_debug("added a share archive map at 0x%lx\n", base); + } } - lib = lib->next; + return true; } - return true; + lib = lib->next; + } + return true; } @@ -396,54 +404,58 @@ // callback for sorting the array of map_info pointers. static int core_cmp_mapping(const void *lhsp, const void *rhsp) { - const map_info *lhs = *((const map_info **)lhsp); - const map_info *rhs = *((const map_info **)rhsp); + const map_info *lhs = *((const map_info **)lhsp); + const map_info *rhs = *((const map_info **)rhsp); - if (lhs->vaddr == rhs->vaddr) - return (0); + if (lhs->vaddr == rhs->vaddr) { + return (0); + } - return (lhs->vaddr < rhs->vaddr ? -1 : 1); + return (lhs->vaddr < rhs->vaddr ? -1 : 1); } // we sort map_info by starting virtual address so that we can do // binary search to read from an address. static bool sort_map_array(struct ps_prochandle* ph) { - size_t num_maps = ph->core->num_maps; - map_info* map = ph->core->maps; - int i = 0; + size_t num_maps = ph->core->num_maps; + map_info* map = ph->core->maps; + int i = 0; - // allocate map_array - map_info** array; - if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); - return false; - } + // allocate map_array + map_info** array; + if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { + print_debug("can't allocate memory for map array\n"); + return false; + } - // add maps to array - while (map) { - array[i] = map; - i++; - map = map->next; - } + // add maps to array + while (map) { + array[i] = map; + i++; + map = map->next; + } - // sort is called twice. If this is second time, clear map array - if (ph->core->map_array) free(ph->core->map_array); - ph->core->map_array = array; - // sort the map_info array by base virtual address. - qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), - core_cmp_mapping); + // sort is called twice. If this is second time, clear map array + if (ph->core->map_array) { + free(ph->core->map_array); + } + + ph->core->map_array = array; + // sort the map_info array by base virtual address. + qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), + core_cmp_mapping); - // print map - if (is_debug()) { - int j = 0; - print_debug("---- sorted virtual address map ----\n"); - for (j = 0; j < ph->core->num_maps; j++) { - print_debug("base = 0x%lx\tsize = %zu\n", ph->core->map_array[j]->vaddr, - ph->core->map_array[j]->memsz); - } - } + // print map + if (is_debug()) { + int j = 0; + print_debug("---- sorted virtual address map ----\n"); + for (j = 0; j < ph->core->num_maps; j++) { + print_debug("base = 0x%lx\tsize = %zu\n", ph->core->map_array[j]->vaddr, + ph->core->map_array[j]->memsz); + } + } - return true; + return true; } #ifndef MIN @@ -460,16 +472,18 @@ off_t off; int fd; - if (mp == NULL) + if (mp == NULL) { break; /* No mapping for this address */ + } fd = mp->fd; mapoff = addr - mp->vaddr; len = MIN(resid, mp->memsz - mapoff); off = mp->offset + mapoff; - if ((len = pread(fd, buf, len, off)) <= 0) + if ((len = pread(fd, buf, len, off)) <= 0) { break; + } resid -= len; addr += len; @@ -625,8 +639,9 @@ notep->n_type, notep->n_descsz); if (notep->n_type == NT_PRSTATUS) { - if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) - return false; + if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { + return false; + } } p = descdata + ROUNDUP(notep->n_descsz, 4); } @@ -654,7 +669,7 @@ * contains a set of saved /proc structures), and PT_LOAD (which * represents a memory mapping from the process's address space). * - * Difference b/w Solaris PT_NOTE and Linux PT_NOTE: + * Difference b/w Solaris PT_NOTE and Linux/BSD PT_NOTE: * * In Solaris there are two PT_NOTE segments the first PT_NOTE (if present) * contains /proc structs in the pre-2.6 unstructured /proc format. the last @@ -674,7 +689,9 @@ for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) { switch (core_php->p_type) { case PT_NOTE: - if (core_handle_note(ph, core_php) != true) goto err; + if (core_handle_note(ph, core_php) != true) { + goto err; + } break; case PT_LOAD: { @@ -832,60 +849,62 @@ // read shared library info from runtime linker's data structures. // This work is done by librtlb_db in Solaris static bool read_shared_lib_info(struct ps_prochandle* ph) { - uintptr_t addr = ph->core->dynamic_addr; - uintptr_t debug_base; - uintptr_t first_link_map_addr; - uintptr_t ld_base_addr; - uintptr_t link_map_addr; - uintptr_t lib_base_diff; - uintptr_t lib_base; - uintptr_t lib_name_addr; - char lib_name[BUF_SIZE]; - ELF_DYN dyn; - ELF_EHDR elf_ehdr; - int lib_fd; + uintptr_t addr = ph->core->dynamic_addr; + uintptr_t debug_base; + uintptr_t first_link_map_addr; + uintptr_t ld_base_addr; + uintptr_t link_map_addr; + uintptr_t lib_base_diff; + uintptr_t lib_base; + uintptr_t lib_name_addr; + char lib_name[BUF_SIZE]; + ELF_DYN dyn; + ELF_EHDR elf_ehdr; + int lib_fd; - // _DYNAMIC has information of the form - // [tag] [data] [tag] [data] ..... - // Both tag and data are pointer sized. - // We look for dynamic info with DT_DEBUG. This has shared object info. - // refer to struct r_debug in link.h + // _DYNAMIC has information of the form + // [tag] [data] [tag] [data] ..... + // Both tag and data are pointer sized. + // We look for dynamic info with DT_DEBUG. This has shared object info. + // refer to struct r_debug in link.h + + dyn.d_tag = DT_NULL; + while (dyn.d_tag != DT_DEBUG) { + if (ps_pdread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { + print_debug("can't read debug info from _DYNAMIC\n"); + return false; + } + addr += sizeof(ELF_DYN); + } - dyn.d_tag = DT_NULL; - while (dyn.d_tag != DT_DEBUG) { - if (ps_pdread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { - print_debug("can't read debug info from _DYNAMIC\n"); - return false; - } - addr += sizeof(ELF_DYN); - } - - // we have got Dyn entry with DT_DEBUG - debug_base = dyn.d_un.d_ptr; - // at debug_base we have struct r_debug. This has first link map in r_map field - if (ps_pdread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, + // we have got Dyn entry with DT_DEBUG + debug_base = dyn.d_un.d_ptr; + // at debug_base we have struct r_debug. This has first link map in r_map field + if (ps_pdread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read first link map address\n"); - return false; - } + print_debug("can't read first link map address\n"); + return false; + } - // read ld_base address from struct r_debug - if (ps_pdread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, + // read ld_base address from struct r_debug + if (ps_pdread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read ld base address\n"); - return false; - } - ph->core->ld_base_addr = ld_base_addr; + print_debug("can't read ld base address\n"); + return false; + } + ph->core->ld_base_addr = ld_base_addr; + + print_debug("interpreter base address is 0x%lx\n", ld_base_addr); - print_debug("interpreter base address is 0x%lx\n", ld_base_addr); - - // now read segments from interp (i.e ld.so or ld-linux.so) - if (read_interp_segments(ph) != true) + // now read segments from interp (i.e ld.so or ld-linux.so or ld-elf.so) + if (read_interp_segments(ph) != true) { return false; + } - // after adding interpreter (ld.so) mappings sort again - if (sort_map_array(ph) != true) - return false; + // after adding interpreter (ld.so) mappings sort again + if (sort_map_array(ph) != true) { + return false; + } print_debug("first link map is at 0x%lx\n", first_link_map_addr); @@ -950,95 +969,102 @@ } } - // read next link_map address - if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, - &link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read next link in link_map\n"); - return false; - } - } + // read next link_map address + if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, + &link_map_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read next link in link_map\n"); + return false; + } + } - return true; + return true; } // the one and only one exposed stuff from this file struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { - ELF_EHDR core_ehdr; - ELF_EHDR exec_ehdr; - ELF_EHDR lib_ehdr; + ELF_EHDR core_ehdr; + ELF_EHDR exec_ehdr; + ELF_EHDR lib_ehdr; - struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); - if (ph == NULL) { - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); + if (ph == NULL) { + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } - if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { - free(ph); - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { + free(ph); + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } - // initialize ph - ph->ops = &core_ops; - ph->core->core_fd = -1; - ph->core->exec_fd = -1; - ph->core->interp_fd = -1; + // initialize ph + ph->ops = &core_ops; + ph->core->core_fd = -1; + ph->core->exec_fd = -1; + ph->core->interp_fd = -1; - // open the core file - if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { - print_debug("can't open core file\n"); - goto err; - } + // open the core file + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { + print_debug("can't open core file\n"); + goto err; + } - // read core file ELF header - if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { - print_debug("core file is not a valid ELF ET_CORE file\n"); - goto err; - } + // read core file ELF header + if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { + print_debug("core file is not a valid ELF ET_CORE file\n"); + goto err; + } + + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { + print_debug("can't open executable file\n"); + goto err; + } - if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { - print_debug("can't open executable file\n"); - goto err; - } + if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { + print_debug("executable file is not a valid ELF ET_EXEC file\n"); + goto err; + } + + // process core file segments + if (read_core_segments(ph, &core_ehdr) != true) { + goto err; + } - if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { - print_debug("executable file is not a valid ELF ET_EXEC file\n"); - goto err; - } + // process exec file segments + if (read_exec_segments(ph, &exec_ehdr) != true) { + goto err; + } - // process core file segments - if (read_core_segments(ph, &core_ehdr) != true) - goto err; - - // process exec file segments - if (read_exec_segments(ph, &exec_ehdr) != true) - goto err; + // exec file is also treated like a shared object for symbol search + if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, + (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) { + goto err; + } - // exec file is also treated like a shared object for symbol search - if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, - (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) - goto err; + // allocate and sort maps into map_array, we need to do this + // here because read_shared_lib_info needs to read from debuggee + // address space + if (sort_map_array(ph) != true) { + goto err; + } - // allocate and sort maps into map_array, we need to do this - // here because read_shared_lib_info needs to read from debuggee - // address space - if (sort_map_array(ph) != true) - goto err; + if (read_shared_lib_info(ph) != true) { + goto err; + } - if (read_shared_lib_info(ph) != true) - goto err; + // sort again because we have added more mappings from shared objects + if (sort_map_array(ph) != true) { + goto err; + } - // sort again because we have added more mappings from shared objects - if (sort_map_array(ph) != true) - goto err; + if (init_classsharing_workaround(ph) != true) { + goto err; + } - if (init_classsharing_workaround(ph) != true) - goto err; - - return ph; + return ph; err: - Prelease(ph); - return NULL; + Prelease(ph); + return NULL; } diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/linux/ps_proc.c Mon Oct 21 14:08:09 2013 +0100 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include "libproc_impl.h" diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/linux/salibelf.c --- a/agent/src/os/linux/salibelf.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/linux/salibelf.c Mon Oct 21 14:08:09 2013 +0100 @@ -25,6 +25,7 @@ #include "salibelf.h" #include #include +#include extern void print_debug(const char*,...); diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/os/linux/symtab.c --- a/agent/src/os/linux/symtab.c Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/os/linux/symtab.c Mon Oct 21 14:08:09 2013 +0100 @@ -305,7 +305,7 @@ unsigned char *bytes = (unsigned char*)(note+1) + note->n_namesz; - unsigned char *filename + char *filename = (build_id_to_debug_filename (note->n_descsz, bytes)); fd = pathmap_open(filename); diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/asm/Disassembler.java --- a/agent/src/share/classes/sun/jvm/hotspot/asm/Disassembler.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/asm/Disassembler.java Mon Oct 21 14:08:09 2013 +0100 @@ -67,6 +67,13 @@ String libname = "hsdis"; String arch = System.getProperty("os.arch"); if (os.lastIndexOf("Windows", 0) != -1) { + if (arch.equals("x86")) { + libname += "-i386"; + } else if (arch.equals("amd64")) { + libname += "-amd64"; + } else { + libname += "-" + arch; + } path.append(sep + "bin" + sep); libname += ".dll"; } else if (os.lastIndexOf("SunOS", 0) != -1) { diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class ProtectionDomainCacheEntry extends VMObject { + private static sun.jvm.hotspot.types.OopField protectionDomainField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("ProtectionDomainCacheEntry"); + protectionDomainField = type.getOopField("_literal"); + } + + public ProtectionDomainCacheEntry(Address addr) { + super(addr); + } + + public Oop protectionDomain() { + return VM.getVM().getObjectHeap().newOop(protectionDomainField.getValue(addr)); + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ public class ProtectionDomainEntry extends VMObject { private static AddressField nextField; - private static sun.jvm.hotspot.types.OopField protectionDomainField; + private static AddressField pdCacheField; static { VM.registerVMInitializedObserver(new Observer() { @@ -46,7 +46,7 @@ Type type = db.lookupType("ProtectionDomainEntry"); nextField = type.getAddressField("_next"); - protectionDomainField = type.getOopField("_protection_domain"); + pdCacheField = type.getAddressField("_pd_cache"); } public ProtectionDomainEntry(Address addr) { @@ -54,10 +54,12 @@ } public ProtectionDomainEntry next() { - return (ProtectionDomainEntry) VMObjectFactory.newObject(ProtectionDomainEntry.class, addr); + return (ProtectionDomainEntry) VMObjectFactory.newObject(ProtectionDomainEntry.class, nextField.getValue(addr)); } public Oop protectionDomain() { - return VM.getVM().getObjectHeap().newOop(protectionDomainField.getValue(addr)); + ProtectionDomainCacheEntry pd_cache = (ProtectionDomainCacheEntry) + VMObjectFactory.newObject(ProtectionDomainCacheEntry.class, pdCacheField.getValue(addr)); + return pd_cache.protectionDomain(); } } diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java Mon Oct 21 14:08:09 2013 +0100 @@ -44,12 +44,10 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("SymbolTable"); theTableField = type.getAddressField("_the_table"); - symbolTableSize = db.lookupIntConstant("SymbolTable::symbol_table_size").intValue(); } // Fields private static AddressField theTableField; - private static int symbolTableSize; // Accessors public static SymbolTable getTheTable() { @@ -57,10 +55,6 @@ return (SymbolTable) VMObjectFactory.newObject(SymbolTable.class, tmp); } - public static int getSymbolTableSize() { - return symbolTableSize; - } - public SymbolTable(Address addr) { super(addr); } diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Mon Oct 21 14:08:09 2013 +0100 @@ -134,15 +134,13 @@ private String type; private String name; private Address addr; - private String kind; - private int origin; + private int flags; - private Flag(String type, String name, Address addr, String kind, int origin) { + private Flag(String type, String name, Address addr, int flags) { this.type = type; this.name = name; this.addr = addr; - this.kind = kind; - this.origin = origin; + this.flags = flags; } public String getType() { @@ -157,12 +155,8 @@ return addr; } - public String getKind() { - return kind; - } - public int getOrigin() { - return origin; + return flags & 0xF; // XXX can we get the mask bits from somewhere? } public boolean isBool() { @@ -173,8 +167,7 @@ if (Assert.ASSERTS_ENABLED) { Assert.that(isBool(), "not a bool flag!"); } - return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) - != 0; + return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) != 0; } public boolean isIntx() { @@ -843,11 +836,10 @@ Address flagAddr = flagType.getAddressField("flags").getValue(); - AddressField typeFld = flagType.getAddressField("type"); - AddressField nameFld = flagType.getAddressField("name"); - AddressField addrFld = flagType.getAddressField("addr"); - AddressField kindFld = flagType.getAddressField("kind"); - CIntField originFld = new CIntField(flagType.getCIntegerField("origin"), 0); + AddressField typeFld = flagType.getAddressField("_type"); + AddressField nameFld = flagType.getAddressField("_name"); + AddressField addrFld = flagType.getAddressField("_addr"); + CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0); long flagSize = flagType.getSize(); // sizeof(Flag) @@ -856,9 +848,8 @@ String type = CStringUtilities.getString(typeFld.getValue(flagAddr)); String name = CStringUtilities.getString(nameFld.getValue(flagAddr)); Address addr = addrFld.getValue(flagAddr); - String kind = CStringUtilities.getString(kindFld.getValue(flagAddr)); - int origin = (int)originFld.getValue(flagAddr); - commandLineFlags[f] = new Flag(type, name, addr, kind, origin); + int flags = (int)flagsFld.getValue(flagAddr); + commandLineFlags[f] = new Flag(type, name, addr, flags); flagAddr = flagAddr.addOffsetTo(flagSize); } diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java Mon Oct 21 14:08:09 2013 +0100 @@ -59,6 +59,7 @@ public boolean doObj(Oop oop) { try { + writeHeapRecordPrologue(); if (oop instanceof TypeArray) { writePrimitiveArray((TypeArray)oop); } else if (oop instanceof ObjArray) { @@ -97,6 +98,7 @@ // not-a-Java-visible oop writeInternalObject(oop); } + writeHeapRecordEpilogue(); } catch (IOException exp) { throw new RuntimeException(exp); } @@ -416,6 +418,12 @@ protected void writeHeapFooter() throws IOException { } + protected void writeHeapRecordPrologue() throws IOException { + } + + protected void writeHeapRecordEpilogue() throws IOException { + } + // HeapVisitor, OopVisitor methods can't throw any non-runtime // exception. But, derived class write methods (which are called // from visitor callbacks) may throw IOException. Hence, we throw diff -r 6fa574bfd32a -r 6795fcebbf42 agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Thu Oct 03 19:13:12 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Mon Oct 21 14:08:09 2013 +0100 @@ -44,7 +44,7 @@ * WARNING: This format is still under development, and is subject to * change without notice. * - * header "JAVA PROFILE 1.0.1" (0-terminated) + * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated) * u4 size of identifiers. Identifiers are used to represent * UTF8 strings, objects, stack traces, etc. They usually * have the same size as host pointers. For example, on @@ -292,11 +292,34 @@ * 0x00000002: cpu sampling on/off * u2 stack trace depth * + * + * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally + * be generated as a sequence of heap dump segments. This sequence is + * terminated by an end record. The additional tags allowed by format + * "JAVA PROFILE 1.0.2" are: + * + * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment + * + * [heap dump sub-records]* + * The same sub-record types allowed by HPROF_HEAP_DUMP + * + * HPROF_HEAP_DUMP_END denotes the end of a heap dump + * */ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + + // The heap size threshold used to determine if segmented format + // ("JAVA PROFILE 1.0.2") should be used. + private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000; + + // The approximate size of a heap segment. Used to calculate when to create + // a new segment. + private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000; + // hprof binary file header - private static final String HPROF_HEADER = "JAVA PROFILE 1.0.1"; + private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1"; + private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2"; // constants in enum HprofTag private static final int HPROF_UTF8 = 0x01; @@ -312,6 +335,10 @@ private static final int HPROF_CPU_SAMPLES = 0x0D; private static final int HPROF_CONTROL_SETTINGS = 0x0E; + // 1.0.2 record types + private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C; + private static final int HPROF_HEAP_DUMP_END = 0x2C; + // Heap dump constants // constants in enum HprofGcTag private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF; @@ -352,11 +379,9 @@ private static final int JVM_SIGNATURE_ARRAY = '['; private static final int JVM_SIGNATURE_CLASS = 'L'; - public synchronized void write(String fileName) throws IOException { // open file stream and create buffered data output stream - FileOutputStream fos = new FileOutputStream(fileName); - FileChannel chn = fos.getChannel(); + fos = new FileOutputStream(fileName); out = new DataOutputStream(new BufferedOutputStream(fos)); VM vm = VM.getVM(); @@ -385,6 +410,9 @@ FLOAT_SIZE = objectHeap.getFloatSize(); DOUBLE_SIZE = objectHeap.getDoubleSize(); + // Check weather we should dump the heap as segments + useSegmentedHeapDump = vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD; + // hprof bin format header writeFileHeader(); @@ -394,38 +422,87 @@ // hprof UTF-8 symbols section writeSymbols(); + // HPROF_LOAD_CLASS records for all classes writeClasses(); - // write heap data now - out.writeByte((byte)HPROF_HEAP_DUMP); - out.writeInt(0); // relative timestamp - - // remember position of dump length, we will fixup - // length later - hprof format requires length. - out.flush(); - long dumpStart = chn.position(); - - // write dummy length of 0 and we'll fix it later. - out.writeInt(0); - // write CLASS_DUMP records writeClassDumpRecords(); // this will write heap data into the buffer stream super.write(); + // flush buffer stream. + out.flush(); + + // Fill in final length + fillInHeapRecordLength(); + + if (useSegmentedHeapDump) { + // Write heap segment-end record + out.writeByte((byte) HPROF_HEAP_DUMP_END); + out.writeInt(0); + out.writeInt(0); + } + // flush buffer stream and throw it. out.flush(); out = null; + // close the file stream + fos.close(); + } + + @Override + protected void writeHeapRecordPrologue() throws IOException { + if (currentSegmentStart == 0) { + // write heap data header, depending on heap size use segmented heap + // format + out.writeByte((byte) (useSegmentedHeapDump ? HPROF_HEAP_DUMP_SEGMENT + : HPROF_HEAP_DUMP)); + out.writeInt(0); + + // remember position of dump length, we will fixup + // length later - hprof format requires length. + out.flush(); + currentSegmentStart = fos.getChannel().position(); + + // write dummy length of 0 and we'll fix it later. + out.writeInt(0); + } + } + + @Override + protected void writeHeapRecordEpilogue() throws IOException { + if (useSegmentedHeapDump) { + out.flush(); + if ((fos.getChannel().position() - currentSegmentStart - 4) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) { + fillInHeapRecordLength(); + currentSegmentStart = 0; + } + } + } + + private void fillInHeapRecordLength() throws IOException { + // now get current position to calculate length - long dumpEnd = chn.position(); + long dumpEnd = fos.getChannel().position(); + // calculate length of heap data - int dumpLen = (int) (dumpEnd - dumpStart - 4); + long dumpLenLong = (dumpEnd - currentSegmentStart - 4L); + + // Check length boundary, overflow could happen but is _very_ unlikely + if(dumpLenLong >= (4L * 0x40000000)){ + throw new RuntimeException("Heap segment size overflow."); + } + + // Save the current position + long currentPosition = fos.getChannel().position(); // seek the position to write length - chn.position(dumpStart); + fos.getChannel().position(currentSegmentStart); + + int dumpLen = (int) dumpLenLong; // write length as integer fos.write((dumpLen >>> 24) & 0xFF); @@ -433,8 +510,8 @@ fos.write((dumpLen >>> 8) & 0xFF); fos.write((dumpLen >>> 0) & 0xFF); - // close the file stream - fos.close(); + //Reset to previous current position + fos.getChannel().position(currentPosition); } private void writeClassDumpRecords() throws IOException { @@ -443,7 +520,9 @@ sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { public void visit(Klass k) { try { + writeHeapRecordPrologue(); writeClassDumpRecord(k); + writeHeapRecordEpilogue(); } catch (IOException e) { throw new RuntimeException(e); } @@ -884,7 +963,12 @@ // writes hprof binary file header private void writeFileHeader() throws IOException { // version string - out.writeBytes(HPROF_HEADER); + if(useSegmentedHeapDump) { + out.writeBytes(HPROF_HEADER_1_0_2); + } + else { + out.writeBytes(HPROF_HEADER_1_0_1); + } out.writeByte((byte)'\0'); // write identifier size. we use pointers as identifiers. @@ -976,6 +1060,7 @@ private static final int EMPTY_FRAME_DEPTH = -1; private DataOutputStream out; + private FileOutputStream fos; private Debugger dbg; private ObjectHeap objectHeap; private SymbolTable symTbl; @@ -983,6 +1068,10 @@ // oopSize of the debuggee private int OBJ_ID_SIZE; + // Added for hprof file format 1.0.2 support + private boolean useSegmentedHeapDump; + private long currentSegmentStart; + private long BOOLEAN_BASE_OFFSET; private long BYTE_BASE_OFFSET; private long CHAR_BASE_OFFSET; @@ -1005,6 +1094,7 @@ private static class ClassData { int instSize; List fields; + ClassData(int instSize, List fields) { this.instSize = instSize; this.fields = fields; diff -r 6fa574bfd32a -r 6795fcebbf42 make/bsd/makefiles/fastdebug.make --- a/make/bsd/makefiles/fastdebug.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/bsd/makefiles/fastdebug.make Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -59,5 +59,5 @@ MAPFILE = $(GAMMADIR)/make/bsd/makefiles/mapfile-vers-debug VERSION = fastdebug -SYSDEFS += -DASSERT +SYSDEFS += -DASSERT -DCHECK_UNHANDLED_OOPS PICFLAGS = DEFAULT diff -r 6fa574bfd32a -r 6795fcebbf42 make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/bsd/makefiles/gcc.make Mon Oct 21 14:08:09 2013 +0100 @@ -247,7 +247,7 @@ ifeq ($(USE_CLANG), true) # However we need to clean the code up before we can unrestrictedly enable this option with Clang - WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-compare # Not yet supported by clang in Xcode 4.6.2 # WARNINGS_ARE_ERRORS += -Wno-tautological-constant-out-of-range-compare @@ -262,7 +262,7 @@ # conversions which might affect the values. Only enable it in earlier versions. WARNING_FLAGS = -Wunused-function ifeq ($(USE_CLANG),) - WARNINGS_FLAGS += -Wconversion + WARNING_FLAGS += -Wconversion endif endif diff -r 6fa574bfd32a -r 6795fcebbf42 make/hotspot_version --- a/make/hotspot_version Thu Oct 03 19:13:12 2013 +0100 +++ b/make/hotspot_version Mon Oct 21 14:08:09 2013 +0100 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=52 +HS_BUILD_NUMBER=54 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 6fa574bfd32a -r 6795fcebbf42 make/linux/makefiles/fastdebug.make --- a/make/linux/makefiles/fastdebug.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/linux/makefiles/fastdebug.make Mon Oct 21 14:08:09 2013 +0100 @@ -59,5 +59,5 @@ MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug VERSION = optimized -SYSDEFS += -DASSERT +SYSDEFS += -DASSERT -DCHECK_UNHANDLED_OOPS PICFLAGS = DEFAULT diff -r 6fa574bfd32a -r 6795fcebbf42 make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/linux/makefiles/gcc.make Mon Oct 21 14:08:09 2013 +0100 @@ -208,7 +208,7 @@ ifeq ($(USE_CLANG), true) # However we need to clean the code up before we can unrestrictedly enable this option with Clang - WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body diff -r 6fa574bfd32a -r 6795fcebbf42 make/windows/makefiles/compile.make --- a/make/windows/makefiles/compile.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/windows/makefiles/compile.make Mon Oct 21 14:08:09 2013 +0100 @@ -44,6 +44,7 @@ # /GS Inserts security stack checks in some functions (VS2005 default) # /Oi Use intrinsics (in /O2) # /Od Disable all optimizations +# /MP Use multiple cores for compilation # # NOTE: Normally following any of the above with a '-' will turn off that flag # @@ -208,6 +209,7 @@ DEBUG_OPT_OPTION = /Od GX_OPTION = /EHsc LD_FLAGS = /manifest $(LD_FLAGS) +MP_FLAG = /MP # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. !if "x$(MT)" == "x" @@ -222,6 +224,7 @@ DEBUG_OPT_OPTION = /Od GX_OPTION = /EHsc LD_FLAGS = /manifest $(LD_FLAGS) +MP_FLAG = /MP # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. !if "x$(MT)" == "x" @@ -238,6 +241,7 @@ DEBUG_OPT_OPTION = /Od GX_OPTION = /EHsc LD_FLAGS = /manifest $(LD_FLAGS) +MP_FLAG = /MP # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. !if "x$(MT)" == "x" @@ -250,6 +254,8 @@ LD_FLAGS = $(SAFESEH_FLAG) $(LD_FLAGS) !endif +CXX_FLAGS = $(CXX_FLAGS) $(MP_FLAG) + # If NO_OPTIMIZATIONS is defined in the environment, turn everything off !ifdef NO_OPTIMIZATIONS PRODUCT_OPT_OPTION = $(DEBUG_OPT_OPTION) diff -r 6fa574bfd32a -r 6795fcebbf42 make/windows/makefiles/fastdebug.make --- a/make/windows/makefiles/fastdebug.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/windows/makefiles/fastdebug.make Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff -r 6fa574bfd32a -r 6795fcebbf42 make/windows/makefiles/sa.make --- a/make/windows/makefiles/sa.make Thu Oct 03 19:13:12 2013 +0100 +++ b/make/windows/makefiles/sa.make Mon Oct 21 14:08:09 2013 +0100 @@ -102,7 +102,10 @@ !if "$(MT)" != "" SA_LD_FLAGS = -manifest $(SA_LD_FLAGS) !endif -SASRCFILE = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp + +SASRCFILES = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp \ + $(AGENT_DIR)/src/share/native/sadis.c + SA_LFLAGS = $(SA_LD_FLAGS) -nologo -subsystem:console -machine:$(MACHINE) !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" SA_LFLAGS = $(SA_LFLAGS) -map -debug @@ -111,22 +114,24 @@ SA_LFLAGS = $(SAFESEH_FLAG) $(SA_LFLAGS) !endif +SA_CFLAGS = $(SA_CFLAGS) $(MP_FLAG) + # Note that we do not keep sawindbj.obj around as it would then # get included in the dumpbin command in build_vm_def.sh # In VS2005 or VS2008 the link command creates a .manifest file that we want # to insert into the linked artifact so we do not need to track it separately. # Use ";#2" for .dll and ";#1" for .exe in the MT command below: -$(SAWINDBG): $(SASRCFILE) +$(SAWINDBG): $(SASRCFILES) set INCLUDE=$(SA_INCLUDE)$(INCLUDE) $(CXX) @<< -I"$(BootStrapDir)/include" -I"$(BootStrapDir)/include/win32" -I"$(GENERATED)" $(SA_CFLAGS) - $(SASRCFILE) + $(SASRCFILES) -out:$*.obj << set LIB=$(SA_LIB)$(LIB) - $(LD) -out:$@ -DLL $*.obj dbgeng.lib $(SA_LFLAGS) + $(LD) -out:$@ -DLL sawindbg.obj sadis.obj dbgeng.lib $(SA_LFLAGS) !if "$(MT)" != "" $(MT) -manifest $(@F).manifest -outputresource:$(@F);#2 !endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -37,6 +37,9 @@ #include "runtime/vframeArray.hpp" #include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#endif // Implementation of StubAssembler @@ -912,7 +915,7 @@ Register tmp2 = G3_scratch; jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base; - Label not_already_dirty, restart, refill; + Label not_already_dirty, restart, refill, young_card; #ifdef _LP64 __ srlx(addr, CardTableModRefBS::card_shift, addr); @@ -924,9 +927,15 @@ __ set(rs, cardtable); // cardtable := __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + __ cmp_and_br_short(tmp, G1SATBCardTableModRefBS::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); + __ bind(young_card); // We didn't take the branch, so we're already dirty: return. // Use return-from-leaf __ retl(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -764,7 +764,7 @@ #ifdef CC_INTERP *oop_result = istate->_oop_temp; #else - oop obj = (oop) at(interpreter_frame_oop_temp_offset); + oop obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); *oop_result = obj; #endif // CC_INTERP @@ -788,7 +788,7 @@ switch(type) { case T_OBJECT: case T_ARRAY: { - oop obj = (oop)*tos_addr; + oop obj = cast_to_oop(*tos_addr); assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); *oop_result = obj; break; diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -3752,7 +3752,7 @@ #define __ masm. address start = __ pc(); - Label not_already_dirty, restart, refill; + Label not_already_dirty, restart, refill, young_card; #ifdef _LP64 __ srlx(O0, CardTableModRefBS::card_shift, O0); @@ -3763,9 +3763,15 @@ __ set(addrlit, O1); // O1 := __ ldub(O0, O1, O2); // O2 := [O0 + O1] + __ cmp_and_br_short(O2, G1SATBCardTableModRefBS::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ ldub(O0, O1, O2); // O2 := [O0 + O1] + assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); + __ bind(young_card); // We didn't take the branch, so we're already dirty: return. // Use return-from-leaf __ retl(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,6 +121,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { + Label L_no_such_method; assert(method == G5_method, "interpreter calling convention"); assert_different_registers(method, target, temp); @@ -133,6 +134,9 @@ const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); __ ld(interp_only, temp); __ cmp_and_br_short(temp, 0, Assembler::zero, Assembler::pt, run_compiled_code); + // Null method test is replicated below in compiled case, + // it might be able to address across the verify_thread() + __ br_null_short(G5_method, Assembler::pn, L_no_such_method); __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target); __ jmp(target, 0); __ delayed()->nop(); @@ -141,11 +145,19 @@ // it doesn't matter, since this is interpreter code. } + // Compiled case, either static or fall-through from runtime conditional + __ br_null_short(G5_method, Assembler::pn, L_no_such_method); + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ld_ptr(G5_method, in_bytes(entry_offset), target); __ jmp(target, 0); __ delayed()->nop(); + + __ bind(L_no_such_method); + AddressLiteral ame(StubRoutines::throw_AbstractMethodError_entry()); + __ jump_to(ame, temp); + __ delayed()->nop(); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/nativeInst_sparc.cpp --- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -358,7 +358,7 @@ oop_Relocation *r = iter.oop_reloc(); if (oop_addr == NULL) { oop_addr = r->oop_addr(); - *oop_addr = (oop)x; + *oop_addr = cast_to_oop(x); } else { assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); } @@ -478,7 +478,7 @@ oop_Relocation *r = iter.oop_reloc(); if (oop_addr == NULL) { oop_addr = r->oop_addr(); - *oop_addr = (oop)x; + *oop_addr = cast_to_oop(x); } else { assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/sparc/vm/sparc.ad Mon Oct 21 14:08:09 2013 +0100 @@ -2018,6 +2018,15 @@ return L7_REGP_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return G1_REGI_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + + %} @@ -4245,12 +4254,16 @@ greater_equal(0xB); less_equal(0x2); greater(0xA); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, unsigned operand cmpOpU() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "u" %} interface(COND_INTER) %{ @@ -4260,12 +4273,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, pointer (same as unsigned) operand cmpOpP() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "p" %} interface(COND_INTER) %{ @@ -4275,12 +4292,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, branch-register encoding operand cmpOp_reg() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4290,12 +4311,16 @@ greater_equal(0x7); less_equal (0x2); greater (0x6); + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Comparison Code, floating, unordered same as less operand cmpOpF() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "fl" %} interface(COND_INTER) %{ @@ -4305,12 +4330,17 @@ greater_equal(0xB); less_equal(0xE); greater(0x6); + + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Used by long compare operand cmpOp_commute() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4320,6 +4350,8 @@ greater_equal(0x2); less_equal(0xB); greater(0x3); + overflow(0x7); + no_overflow(0xF); %} %} diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/assembler_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -4769,7 +4769,7 @@ } void Assembler::adcq(Register dst, Register src) { - (int) prefixq_and_encode(dst->encoding(), src->encoding()); + (void) prefixq_and_encode(dst->encoding(), src->encoding()); emit_arith(0x13, 0xC0, dst, src); } @@ -4824,7 +4824,7 @@ } void Assembler::andq(Register dst, Register src) { - (int) prefixq_and_encode(dst->encoding(), src->encoding()); + (void) prefixq_and_encode(dst->encoding(), src->encoding()); emit_arith(0x23, 0xC0, dst, src); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -38,6 +38,9 @@ #include "runtime/vframeArray.hpp" #include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#endif // Implementation of StubAssembler @@ -1753,13 +1756,17 @@ __ leal(card_addr, __ as_Address(ArrayAddress(cardtable, index))); #endif - __ cmpb(Address(card_addr, 0), 0); + __ cmpb(Address(card_addr, 0), (int)G1SATBCardTableModRefBS::g1_young_card_val()); + __ jcc(Assembler::equal, done); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ cmpb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); __ jcc(Assembler::equal, done); // storing region crossing non-NULL, card is clean. // dirty card and log. - __ movb(Address(card_addr, 0), 0); + __ movb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); __ cmpl(queue_index, 0); __ jcc(Assembler::equal, runtime); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/frame_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -639,7 +639,7 @@ #ifdef CC_INTERP obj = istate->_oop_temp; #else - obj = (oop) at(interpreter_frame_oop_temp_offset); + obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); #endif // CC_INTERP } else { oop* obj_p = (oop*)tos_addr; diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -3389,13 +3389,18 @@ const Register card_addr = tmp; lea(card_addr, as_Address(ArrayAddress(cardtable, index))); #endif - cmpb(Address(card_addr, 0), 0); + cmpb(Address(card_addr, 0), (int)G1SATBCardTableModRefBS::g1_young_card_val()); jcc(Assembler::equal, done); + membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + cmpb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); + jcc(Assembler::equal, done); + + // storing a region crossing, non-NULL oop, card is clean. // dirty card and log. - movb(Address(card_addr, 0), 0); + movb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); cmpl(queue_index, 0); jcc(Assembler::equal, runtime); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, bool for_compiler_entry) { assert(method == rbx, "interpreter calling convention"); + + Label L_no_such_method; + __ testptr(rbx, rbx); + __ jcc(Assembler::zero, L_no_such_method); + __ verify_method_ptr(method); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { @@ -138,6 +143,9 @@ const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ jmp(Address(method, entry_offset)); + + __ bind(L_no_such_method); + __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -475,7 +483,7 @@ const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx"; tty->print_cr("MH %s %s="PTR_FORMAT" sp="PTR_FORMAT, adaptername, mh_reg_name, - mh, entry_sp); + (void *)mh, entry_sp); if (Verbose) { tty->print_cr("Registers:"); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/x86_32.ad Mon Oct 21 14:08:09 2013 +0100 @@ -351,7 +351,7 @@ int format) { #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) { - assert(oop(d32)->is_oop() && (ScavengeRootsInCode || !oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); + assert(cast_to_oop(d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.insts_mark(), rspec, format); @@ -1534,6 +1534,14 @@ return EBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return EAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + // Returns true if the high 32 bits of the value is known to be zero. bool is_operand_hi32_zero(Node* n) { int opc = n->Opcode(); @@ -4922,6 +4930,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4939,6 +4949,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4957,6 +4969,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4974,6 +4988,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4981,6 +4997,8 @@ operand cmpOp_fcmov() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ equal (0x0C8); @@ -4989,6 +5007,8 @@ greater_equal(0x1C0); less_equal (0x0D0); greater (0x1D0); + overflow(0x0, "o"); // not really supported by the instruction + no_overflow(0x1, "no"); // not really supported by the instruction %} %} @@ -5004,6 +5024,8 @@ greater_equal(0xE, "le"); less_equal(0xD, "ge"); greater(0xC, "l"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -7496,6 +7518,31 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- + +instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + // Integer Addition Instructions instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 6fa574bfd32a -r 6795fcebbf42 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Thu Oct 03 19:13:12 2013 +0100 +++ b/src/cpu/x86/vm/x86_64.ad Mon Oct 21 14:08:09 2013 +0100 @@ -529,7 +529,7 @@ if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) { assert(Universe::heap()->is_in_reserved((address)(intptr_t)d32), "should be real oop"); - assert(oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); + assert(cast_to_oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.insts_mark(), rspec, format); @@ -556,7 +556,7 @@ if (rspec.reloc()->type() == relocInfo::oop_type && d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) { assert(Universe::heap()->is_in_reserved((address)d64), "should be real oop"); - assert(oop(d64)->is_oop() && (ScavengeRootsInCode || !oop(d64)->is_scavengable()), + assert(cast_to_oop(d64)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d64)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif @@ -1649,6 +1649,14 @@ return PTR_RBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return INT_RAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + %} //----------ENCODING BLOCK----------------------------------------------------- @@ -4133,6 +4141,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4151,6 +4161,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4170,6 +4182,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4187,6 +4201,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -6922,6 +6938,30 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- +instruct addExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 6fa574bfd32a -r 6795fcebbf42 src/os/bsd/vm/osThread_bsd.hpp --- a/src/os/bsd/vm/osThread_bsd.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os/bsd/vm/osThread_bsd.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -42,7 +42,7 @@ #ifdef __APPLE__ typedef thread_t thread_id_t; #else - typedef pthread_t thread_id_t; + typedef pid_t thread_id_t; #endif // _pthread_id is the pthread id, which is used by library calls diff -r 6fa574bfd32a -r 6795fcebbf42 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os/bsd/vm/os_bsd.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -100,6 +100,7 @@ # include # include # include +# include #if defined(__FreeBSD__) || defined(__NetBSD__) # include @@ -152,6 +153,7 @@ // utility functions static int SR_initialize(); +static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); julong os::available_memory() { return Bsd::available_memory(); @@ -247,7 +249,17 @@ * since it returns a 64 bit value) */ mib[0] = CTL_HW; + +#if defined (HW_MEMSIZE) // Apple mib[1] = HW_MEMSIZE; +#elif defined(HW_PHYSMEM) // Most of BSD + mib[1] = HW_PHYSMEM; +#elif defined(HW_REALMEM) // Old FreeBSD + mib[1] = HW_REALMEM; +#else + #error No ways to get physmem +#endif + len = sizeof(mem_val); if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1) { assert(len == sizeof(mem_val), "unexpected data size"); @@ -679,18 +691,12 @@ return NULL; } + osthread->set_thread_id(os::Bsd::gettid()); + #ifdef __APPLE__ - // thread_id is mach thread on macos, which pthreads graciously caches and provides for us - mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); - guarantee(thread_id != 0, "thread id missing from pthreads"); - osthread->set_thread_id(thread_id); - - uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id()); guarantee(unique_thread_id != 0, "unique thread id was not found"); osthread->set_unique_thread_id(unique_thread_id); -#else - // thread_id is pthread_id on BSD - osthread->set_thread_id(::pthread_self()); #endif // initialize signal mask for this thread os::Bsd::hotspot_sigmask(thread); @@ -847,18 +853,13 @@ return false; } + osthread->set_thread_id(os::Bsd::gettid()); + // Store pthread info into the OSThread #ifdef __APPLE__ - // thread_id is mach thread on macos, which pthreads graciously caches and provides for us - mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); - guarantee(thread_id != 0, "just checking"); - osthread->set_thread_id(thread_id); - - uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id()); guarantee(unique_thread_id != 0, "just checking"); osthread->set_unique_thread_id(unique_thread_id); -#else - osthread->set_thread_id(::pthread_self()); #endif osthread->set_pthread_id(::pthread_self()); @@ -1125,6 +1126,30 @@ return n; } +// Information of current thread in variety of formats +pid_t os::Bsd::gettid() { + int retval = -1; + +#ifdef __APPLE__ //XNU kernel + // despite the fact mach port is actually not a thread id use it + // instead of syscall(SYS_thread_selfid) as it certainly fits to u4 + retval = ::pthread_mach_thread_np(::pthread_self()); + guarantee(retval != 0, "just checking"); + return retval; + +#elif __FreeBSD__ + retval = syscall(SYS_thr_self); +#elif __OpenBSD__ + retval = syscall(SYS_getthrid); +#elif __NetBSD__ + retval = (pid_t) syscall(SYS__lwp_self); +#endif + + if (retval == -1) { + return getpid(); + } +} + intx os::current_thread_id() { #ifdef __APPLE__ return (intx)::pthread_mach_thread_np(::pthread_self()); @@ -1132,6 +1157,7 @@ return (intx)::pthread_self(); #endif } + int os::current_process_id() { // Under the old bsd thread library, bsd gives each thread @@ -1904,7 +1930,7 @@ bool timedwait(unsigned int sec, int nsec); private: jlong currenttime() const; - semaphore_t _semaphore; + os_semaphore_t _semaphore; }; Semaphore::Semaphore() : _semaphore(0) { @@ -1972,7 +1998,7 @@ bool Semaphore::timedwait(unsigned int sec, int nsec) { struct timespec ts; - jlong endtime = unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); while (1) { int result = sem_timedwait(&_semaphore, &ts); diff -r 6fa574bfd32a -r 6795fcebbf42 src/os/bsd/vm/os_bsd.hpp --- a/src/os/bsd/vm/os_bsd.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os/bsd/vm/os_bsd.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -84,6 +84,7 @@ static void hotspot_sigmask(Thread* thread); static bool is_initial_thread(void); + static pid_t gettid(); static int page_size(void) { return _page_size; } static void set_page_size(int val) { _page_size = val; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/os/linux/vm/globals_linux.hpp --- a/src/os/linux/vm/globals_linux.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os/linux/vm/globals_linux.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -53,7 +53,7 @@ // Defines Linux-specific default values. The flags are available on all // platforms, but they may have different default values on other platforms. // -define_pd_global(bool, UseLargePages, true); +define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; diff -r 6fa574bfd32a -r 6795fcebbf42 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os/linux/vm/os_linux.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -3361,13 +3361,15 @@ if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM) && FLAG_IS_DEFAULT(UseTransparentHugePages)) { - // If UseLargePages is specified on the command line try all methods, - // if it's default, then try only UseTransparentHugePages. - if (FLAG_IS_DEFAULT(UseLargePages)) { - UseTransparentHugePages = true; - } else { - UseHugeTLBFS = UseTransparentHugePages = UseSHM = true; - } + + // The type of large pages has not been specified by the user. + + // Try UseHugeTLBFS and then UseSHM. + UseHugeTLBFS = UseSHM = true; + + // Don't try UseTransparentHugePages since there are known + // performance issues with it turned on. This might change in the future. + UseTransparentHugePages = false; } if (UseTransparentHugePages) { @@ -3393,9 +3395,19 @@ } void os::large_page_init() { - if (!UseLargePages) { + if (!UseLargePages && + !UseTransparentHugePages && + !UseHugeTLBFS && + !UseSHM) { + // Not using large pages. + return; + } + + if (!FLAG_IS_DEFAULT(UseLargePages) && !UseLargePages) { + // The user explicitly turned off large pages. + // Ignore the rest of the large pages flags. + UseTransparentHugePages = false; UseHugeTLBFS = false; - UseTransparentHugePages = false; UseSHM = false; return; } @@ -4839,6 +4851,10 @@ Linux::capture_initial_stack(JavaThread::stack_size_at_create()); +#if defined(IA32) + workaround_expand_exec_shield_cs_limit(); +#endif + Linux::libpthread_init(); if (PrintMiscellaneous && (Verbose || WizardMode)) { tty->print_cr("[HotSpot is running with %s, %s(%s)]\n", diff -r 6fa574bfd32a -r 6795fcebbf42 src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -876,3 +876,46 @@ #endif } #endif + + +/* + * IA32 only: execute code at a high address in case buggy NX emulation is present. I.e. avoid CS limit + * updates (JDK-8023956). + */ +void os::workaround_expand_exec_shield_cs_limit() { +#if defined(IA32) + size_t page_size = os::vm_page_size(); + /* + * Take the highest VA the OS will give us and exec + * + * Although using -(pagesz) as mmap hint works on newer kernel as you would + * think, older variants affected by this work-around don't (search forward only). + * + * On the affected distributions, we understand the memory layout to be: + * + * TASK_LIMIT= 3G, main stack base close to TASK_LIMT. + * + * A few pages south main stack will do it. + * + * If we are embedded in an app other than launcher (initial != main stack), + * we don't have much control or understanding of the address space, just let it slide. + */ + char* hint = (char*) (Linux::initial_thread_stack_bottom() - + ((StackYellowPages + StackRedPages + 1) * page_size)); + char* codebuf = os::reserve_memory(page_size, hint); + if ( (codebuf == NULL) || (!os::commit_memory(codebuf, page_size, true)) ) { + return; // No matter, we tried, best effort. + } + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print_cr("[CS limit NX emulation work-around, exec code at: %p]", codebuf); + } + + // Some code to exec: the 'ret' instruction + codebuf[0] = 0xC3; + + // Call the code in the codebuf + __asm__ volatile("call *%0" : : "r"(codebuf)); + + // keep the page mapped so CS limit isn't reduced. +#endif +} diff -r 6fa574bfd32a -r 6795fcebbf42 src/os_cpu/linux_x86/vm/os_linux_x86.hpp --- a/src/os_cpu/linux_x86/vm/os_linux_x86.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -36,4 +36,17 @@ // Note: Currently only used in 64 bit Windows implementations static bool register_code_area(char *low, char *high) { return true; } + /* + * Work-around for broken NX emulation using CS limit, Red Hat patch "Exec-Shield" + * (IA32 only). + * + * Map and execute at a high VA to prevent CS lazy updates race with SMP MM + * invalidation.Further code generation by the JVM will no longer cause CS limit + * updates. + * + * Affects IA32: RHEL 5 & 6, Ubuntu 10.04 (LTS), 10.10, 11.04, 11.10, 12.04. + * @see JDK-8023956 + */ + static void workaround_expand_exec_shield_cs_limit(); + #endif // OS_CPU_LINUX_X86_VM_OS_LINUX_X86_HPP diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/adlc/adlparse.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -3395,12 +3395,16 @@ char *greater_equal; char *less_equal; char *greater; + char *overflow; + char *no_overflow; const char *equal_format = "eq"; const char *not_equal_format = "ne"; const char *less_format = "lt"; const char *greater_equal_format = "ge"; const char *less_equal_format = "le"; const char *greater_format = "gt"; + const char *overflow_format = "o"; + const char *no_overflow_format = "no"; if (_curchar != '%') { parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); @@ -3437,6 +3441,12 @@ else if ( strcmp(field,"greater") == 0 ) { greater = interface_field_parse(&greater_format); } + else if ( strcmp(field,"overflow") == 0 ) { + overflow = interface_field_parse(&overflow_format); + } + else if ( strcmp(field,"no_overflow") == 0 ) { + no_overflow = interface_field_parse(&no_overflow_format); + } else { parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; @@ -3455,7 +3465,9 @@ less, less_format, greater_equal, greater_equal_format, less_equal, less_equal_format, - greater, greater_format); + greater, greater_format, + overflow, overflow_format, + no_overflow, no_overflow_format); return inter; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/adlc/archDesc.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1192,6 +1192,8 @@ || strcmp(idealName,"CmpF") == 0 || strcmp(idealName,"FastLock") == 0 || strcmp(idealName,"FastUnlock") == 0 + || strcmp(idealName,"AddExactI") == 0 + || strcmp(idealName,"FlagsProj") == 0 || strcmp(idealName,"Bool") == 0 || strcmp(idealName,"Binary") == 0 ) { // Removed ConI from the must_clone list. CPUs that cannot use diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/adlc/formssel.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -2757,14 +2757,18 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format) + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format) : Interface("COND_INTER"), _equal(equal), _equal_format(equal_format), _not_equal(not_equal), _not_equal_format(not_equal_format), _less(less), _less_format(less_format), _greater_equal(greater_equal), _greater_equal_format(greater_equal_format), _less_equal(less_equal), _less_equal_format(less_equal_format), - _greater(greater), _greater_format(greater_format) { + _greater(greater), _greater_format(greater_format), + _overflow(overflow), _overflow_format(overflow_format), + _no_overflow(no_overflow), _no_overflow_format(no_overflow_format) { } CondInterface::~CondInterface() { // not owner of any character arrays @@ -2777,12 +2781,14 @@ // Write info to output files void CondInterface::output(FILE *fp) { Interface::output(fp); - if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); - if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); - if ( _less != NULL ) fprintf(fp," less == %s\n", _less); - if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); - if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); - if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); + if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); + if ( _less != NULL ) fprintf(fp," less == %s\n", _less); + if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); + if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); + if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _overflow != NULL ) fprintf(fp," overflow == %s\n", _overflow); + if ( _no_overflow != NULL ) fprintf(fp," no_overflow == %s\n", _no_overflow); // fprintf(fp,"\n"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/adlc/formssel.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -798,12 +798,16 @@ const char *_greater_equal; const char *_less_equal; const char *_greater; + const char *_overflow; + const char *_no_overflow; const char *_equal_format; const char *_not_equal_format; const char *_less_format; const char *_greater_equal_format; const char *_less_equal_format; const char *_greater_format; + const char *_overflow_format; + const char *_no_overflow_format; // Public Methods CondInterface(const char* equal, const char* equal_format, @@ -811,7 +815,9 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format); + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format); ~CondInterface(); void dump(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/adlc/output_h.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -388,6 +388,8 @@ fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print(\"%s\");\n",i,cond->_greater_equal_format); fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print(\"%s\");\n",i,cond->_less_format); fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print(\"%s\");\n",i,cond->_greater_format); + fprintf(fp, " else if( _c%d == BoolTest::overflow ) st->print(\"%s\");\n",i,cond->_overflow_format); + fprintf(fp, " else if( _c%d == BoolTest::no_overflow ) st->print(\"%s\");\n",i,cond->_no_overflow_format); } // Output code that dumps constant values, increment "i" if type is constant @@ -1208,6 +1210,8 @@ fprintf(fp," case BoolTest::ne : return not_equal();\n"); fprintf(fp," case BoolTest::le : return less_equal();\n"); fprintf(fp," case BoolTest::ge : return greater_equal();\n"); + fprintf(fp," case BoolTest::overflow : return overflow();\n"); + fprintf(fp," case BoolTest::no_overflow: return no_overflow();\n"); fprintf(fp," default : ShouldNotReachHere(); return 0;\n"); fprintf(fp," }\n"); fprintf(fp," };\n"); @@ -1373,6 +1377,14 @@ if( greater != NULL ) { define_oper_interface(fp, *oper, _globalNames, "greater", greater); } + const char *overflow = cInterface->_overflow; + if( overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "overflow", overflow); + } + const char *no_overflow = cInterface->_no_overflow; + if( no_overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "no_overflow", no_overflow); + } } // end Conditional Interface // Check if it is a Constant Interface else if (oper->_interface->is_ConstInterface() != NULL ) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/c1/c1_Runtime1.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1019,7 +1019,7 @@ n_copy->set_data((intx) (load_klass())); } else { assert(mirror() != NULL, "klass not set"); - n_copy->set_data((intx) (mirror())); + n_copy->set_data(cast_from_oop(mirror())); } if (TracePatching) { @@ -1031,7 +1031,7 @@ assert(n_copy->data() == 0 || n_copy->data() == (intptr_t)Universe::non_oop_word(), "illegal init value"); - n_copy->set_data((intx) (appendix())); + n_copy->set_data(cast_from_oop(appendix())); if (TracePatching) { Disassembler::decode(copy_buff, copy_buff + *byte_count, tty); @@ -1078,14 +1078,17 @@ // replace instructions // first replace the tail, then the call #ifdef ARM - if(load_klass_or_mirror_patch_id && !VM_Version::supports_movw()) { + if((load_klass_or_mirror_patch_id || + stub_id == Runtime1::load_appendix_patching_id) && + !VM_Version::supports_movw()) { nmethod* nm = CodeCache::find_nmethod(instr_pc); address addr = NULL; assert(nm != NULL, "invalid nmethod_pc"); RelocIterator mds(nm, copy_buff, copy_buff + 1); while (mds.next()) { if (mds.type() == relocInfo::oop_type) { - assert(stub_id == Runtime1::load_mirror_patching_id, "wrong stub id"); + assert(stub_id == Runtime1::load_mirror_patching_id || + stub_id == Runtime1::load_appendix_patching_id, "wrong stub id"); oop_Relocation* r = mds.oop_reloc(); addr = (address)r->oop_addr(); break; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1787,7 +1787,7 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_LambdaForm_Hidden; - case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code return _field_Stable; @@ -2545,7 +2545,9 @@ if (method->is_final()) { *has_final_method = true; } - if (is_interface && !method->is_abstract() && !method->is_static()) { + if (is_interface && !(*has_default_methods) + && !method->is_abstract() && !method->is_static() + && !method->is_private()) { // default method *has_default_methods = true; } @@ -4078,8 +4080,7 @@ // Generate any default methods - default methods are interface methods // that have a default implementation. This is new with Lambda project. - if (has_default_methods && !access_flags.is_interface() && - local_interfaces->length() > 0) { + if (has_default_methods && !access_flags.is_interface() ) { DefaultMethods::generate_default_methods( this_klass(), &all_mirandas, CHECK_(nullHandle)); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/classLoaderData.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -261,7 +261,7 @@ k, k->external_name(), k->class_loader_data(), - k->class_loader(), + (void *)k->class_loader(), loader_name()); } } @@ -297,7 +297,7 @@ if (TraceClassLoaderData) { ResourceMark rm; tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this); - tty->print(" for instance "PTR_FORMAT" of %s", class_loader(), + tty->print(" for instance "PTR_FORMAT" of %s", (void *)class_loader(), loader_name()); if (is_anonymous()) { tty->print(" for anonymous class "PTR_FORMAT " ", _klasses); @@ -458,7 +458,7 @@ void ClassLoaderData::dump(outputStream * const out) { ResourceMark rm; out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {", - this, class_loader(), + this, (void *)class_loader(), class_loader() != NULL ? class_loader()->klass() : NULL, loader_name()); if (claimed()) out->print(" claimed "); if (is_unloading()) out->print(" unloading "); @@ -553,7 +553,7 @@ ResourceMark rm; tty->print("[ClassLoaderData: "); tty->print("create class loader data "PTR_FORMAT, cld); - tty->print(" for instance "PTR_FORMAT" of %s", cld->class_loader(), + tty->print(" for instance "PTR_FORMAT" of %s", (void *)cld->class_loader(), cld->loader_name()); tty->print_cr("]"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/defaultMethods.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -325,6 +325,7 @@ Method* _selected_target; // Filled in later, if a unique target exists Symbol* _exception_message; // If no unique target is found + Symbol* _exception_name; // If no unique target is found bool contains_method(Method* method) { int* lookup = _member_index.get(method); @@ -344,13 +345,12 @@ } Symbol* generate_no_defaults_message(TRAPS) const; - Symbol* generate_abstract_method_message(Method* method, TRAPS) const; Symbol* generate_conflicts_message(GrowableArray* methods, TRAPS) const; public: MethodFamily() - : _selected_target(NULL), _exception_message(NULL) {} + : _selected_target(NULL), _exception_message(NULL), _exception_name(NULL) {} void set_target_if_empty(Method* m) { if (_selected_target == NULL && !m->is_overpass()) { @@ -383,6 +383,7 @@ Method* get_selected_target() { return _selected_target; } Symbol* get_exception_message() { return _exception_message; } + Symbol* get_exception_name() { return _exception_name; } // Either sets the target or the exception error message void determine_target(InstanceKlass* root, TRAPS) { @@ -400,19 +401,21 @@ if (qualified_methods.length() == 0) { _exception_message = generate_no_defaults_message(CHECK); + _exception_name = vmSymbols::java_lang_AbstractMethodError(); } else if (qualified_methods.length() == 1) { + // leave abstract methods alone, they will be found via normal search path Method* method = qualified_methods.at(0); - if (method->is_abstract()) { - _exception_message = generate_abstract_method_message(method, CHECK); - } else { + if (!method->is_abstract()) { _selected_target = qualified_methods.at(0); } } else { _exception_message = generate_conflicts_message(&qualified_methods,CHECK); + _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError(); + if (TraceDefaultMethods) { + _exception_message->print_value_on(tty); + tty->print_cr(""); + } } - - assert((has_target() ^ throws_exception()) == 1, - "One and only one must be true"); } bool contains_signature(Symbol* query) { @@ -459,8 +462,9 @@ void print_exception(outputStream* str, int indent) { assert(throws_exception(), "Should be called otherwise"); + assert(_exception_name != NULL, "exception_name should be set"); streamIndentor si(str, indent * 2); - str->indent().print_cr("%s", _exception_message->as_C_string()); + str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string()); } #endif // ndef PRODUCT }; @@ -469,20 +473,6 @@ return SymbolTable::new_symbol("No qualifying defaults found", CHECK_NULL); } -Symbol* MethodFamily::generate_abstract_method_message(Method* method, TRAPS) const { - Symbol* klass = method->klass_name(); - Symbol* name = method->name(); - Symbol* sig = method->signature(); - stringStream ss; - ss.print("Method "); - ss.write((const char*)klass->bytes(), klass->utf8_length()); - ss.print("."); - ss.write((const char*)name->bytes(), name->utf8_length()); - ss.write((const char*)sig->bytes(), sig->utf8_length()); - ss.print(" is abstract"); - return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL); -} - Symbol* MethodFamily::generate_conflicts_message(GrowableArray* methods, TRAPS) const { stringStream ss; ss.print("Conflicting default methods:"); @@ -589,6 +579,18 @@ #endif // ndef PRODUCT }; +static bool already_in_vtable_slots(GrowableArray* slots, Method* m) { + bool found = false; + for (int j = 0; j < slots->length(); ++j) { + if (slots->at(j)->name() == m->name() && + slots->at(j)->signature() == m->signature() ) { + found = true; + break; + } + } + return found; +} + static GrowableArray* find_empty_vtable_slots( InstanceKlass* klass, GrowableArray* mirandas, TRAPS) { @@ -598,8 +600,10 @@ // All miranda methods are obvious candidates for (int i = 0; i < mirandas->length(); ++i) { - EmptyVtableSlot* slot = new EmptyVtableSlot(mirandas->at(i)); - slots->append(slot); + Method* m = mirandas->at(i); + if (!already_in_vtable_slots(slots, m)) { + slots->append(new EmptyVtableSlot(m)); + } } // Also any overpasses in our superclasses, that we haven't implemented. @@ -615,7 +619,26 @@ // unless we have a real implementation of it in the current class. Method* impl = klass->lookup_method(m->name(), m->signature()); if (impl == NULL || impl->is_overpass()) { - slots->append(new EmptyVtableSlot(m)); + if (!already_in_vtable_slots(slots, m)) { + slots->append(new EmptyVtableSlot(m)); + } + } + } + } + + // also any default methods in our superclasses + if (super->default_methods() != NULL) { + for (int i = 0; i < super->default_methods()->length(); ++i) { + Method* m = super->default_methods()->at(i); + // m is a method that would have been a miranda if not for the + // default method processing that occurred on behalf of our superclass, + // so it's a method we want to re-examine in this new context. That is, + // unless we have a real implementation of it in the current class. + Method* impl = klass->lookup_method(m->name(), m->signature()); + if (impl == NULL || impl->is_overpass()) { + if (!already_in_vtable_slots(slots, m)) { + slots->append(new EmptyVtableSlot(m)); + } } } } @@ -670,7 +693,10 @@ InstanceKlass* iklass = current_class(); Method* m = iklass->find_method(_method_name, _method_signature); - if (m != NULL) { + // private interface methods are not candidates for default methods + // invokespecial to private interface methods doesn't use default method logic + // future: take access controls into account for superclass methods + if (m != NULL && !m->is_static() && (!iklass->is_interface() || m->is_public())) { if (_family == NULL) { _family = new StatefulMethodFamily(); } @@ -691,7 +717,7 @@ -static void create_overpasses( +static void create_defaults_and_exceptions( GrowableArray* slots, InstanceKlass* klass, TRAPS); static void generate_erased_defaults( @@ -712,6 +738,8 @@ static void merge_in_new_methods(InstanceKlass* klass, GrowableArray* new_methods, TRAPS); +static void create_default_methods( InstanceKlass* klass, + GrowableArray* new_methods, TRAPS); // This is the guts of the default methods implementation. This is called just // after the classfile has been parsed if some ancestor has default methods. @@ -773,7 +801,7 @@ } #endif // ndef PRODUCT - create_overpasses(empty_slots, klass, CHECK); + create_defaults_and_exceptions(empty_slots, klass, CHECK); #ifndef PRODUCT if (TraceDefaultMethods) { @@ -782,263 +810,9 @@ #endif // ndef PRODUCT } -/** - * Interface inheritance rules were used to find a unique default method - * candidate for the resolved class. This - * method is only viable if it would also be in the set of default method - * candidates if we ran a full analysis on the current class. - * - * The only reason that the method would not be in the set of candidates for - * the current class is if that there's another matching method - * which is "more specific" than the found method -- i.e., one could find a - * path in the interface hierarchy in which the matching method appears - * before we get to '_target'. - * - * In order to determine this, we examine all of the implemented - * interfaces. If we find path that leads to the '_target' interface, then - * we examine that path to see if there are any methods that would shadow - * the selected method along that path. - */ -class ShadowChecker : public HierarchyVisitor { - protected: - Thread* THREAD; - - InstanceKlass* _target; - - Symbol* _method_name; - InstanceKlass* _method_holder; - bool _found_shadow; - - - public: - - ShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder, - InstanceKlass* target) - : THREAD(thread), _method_name(name), _method_holder(holder), - _target(target), _found_shadow(false) {} - - void* new_node_data(InstanceKlass* cls) { return NULL; } - void free_node_data(void* data) { return; } - - bool visit() { - InstanceKlass* ik = current_class(); - if (ik == _target && current_depth() == 1) { - return false; // This was the specified super -- no need to search it - } - if (ik == _method_holder || ik == _target) { - // We found a path that should be examined to see if it shadows _method - if (path_has_shadow()) { - _found_shadow = true; - cancel_iteration(); - } - return false; // no need to continue up hierarchy - } - return true; - } - - virtual bool path_has_shadow() = 0; - bool found_shadow() { return _found_shadow; } -}; - -// Used for Invokespecial. -// Invokespecial is allowed to invoke a concrete interface method -// and can be used to disambuiguate among qualified candidates, -// which are methods in immediate superinterfaces, -// but may not be used to invoke a candidate that would be shadowed -// from the perspective of the caller. -// Invokespecial is also used in the overpass generation today -// We re-run the shadowchecker because we can't distinguish this case, -// but it should return the same answer, since the overpass target -// is now the invokespecial caller. -class ErasedShadowChecker : public ShadowChecker { - private: - bool path_has_shadow() { - - for (int i = current_depth() - 1; i > 0; --i) { - InstanceKlass* ik = class_at_depth(i); - - if (ik->is_interface()) { - int end; - int start = ik->find_method_by_name(_method_name, &end); - if (start != -1) { - return true; - } - } - } - return false; - } - public: - - ErasedShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder, - InstanceKlass* target) - : ShadowChecker(thread, name, holder, target) {} -}; - -// Find the unique qualified candidate from the perspective of the super_class -// which is the resolved_klass, which must be an immediate superinterface -// of klass -Method* find_erased_super_default(InstanceKlass* current_class, InstanceKlass* super_class, Symbol* method_name, Symbol* sig, TRAPS) { - - FindMethodsByErasedSig visitor(method_name, sig); - visitor.run(super_class); // find candidates from resolved_klass - - MethodFamily* family; - visitor.get_discovered_family(&family); - - if (family != NULL) { - family->determine_target(current_class, CHECK_NULL); // get target from current_class - - if (family->has_target()) { - Method* target = family->get_selected_target(); - InstanceKlass* holder = InstanceKlass::cast(target->method_holder()); - - // Verify that the identified method is valid from the context of - // the current class, which is the caller class for invokespecial - // link resolution, i.e. ensure there it is not shadowed. - // You can use invokespecial to disambiguate interface methods, but - // you can not use it to skip over an interface method that would shadow it. - ErasedShadowChecker checker(THREAD, target->name(), holder, super_class); - checker.run(current_class); +static int assemble_method_error( + BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) { - if (checker.found_shadow()) { -#ifndef PRODUCT - if (TraceDefaultMethods) { - tty->print_cr(" Only candidate found was shadowed."); - } -#endif // ndef PRODUCT - THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(), - "Accessible default method not found", NULL); - } else { -#ifndef PRODUCT - if (TraceDefaultMethods) { - family->print_sig_on(tty, target->signature(), 1); - } -#endif // ndef PRODUCT - return target; - } - } else { - assert(family->throws_exception(), "must have target or throw"); - THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(), - family->get_exception_message()->as_C_string(), NULL); - } - } else { - // no method found - ResourceMark rm(THREAD); - THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), - Method::name_and_sig_as_C_string(current_class, - method_name, sig), NULL); - } -} -// This is called during linktime when we find an invokespecial call that -// refers to a direct superinterface. It indicates that we should find the -// default method in the hierarchy of that superinterface, and if that method -// would have been a candidate from the point of view of 'this' class, then we -// return that method. -// This logic assumes that the super is a direct superclass of the caller -Method* DefaultMethods::find_super_default( - Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) { - - ResourceMark rm(THREAD); - - assert(cls != NULL && super != NULL, "Need real classes"); - - InstanceKlass* current_class = InstanceKlass::cast(cls); - InstanceKlass* super_class = InstanceKlass::cast(super); - - // Keep entire hierarchy alive for the duration of the computation - KeepAliveRegistrar keepAlive(THREAD); - KeepAliveVisitor loadKeepAlive(&keepAlive); - loadKeepAlive.run(current_class); // get hierarchy from current class - -#ifndef PRODUCT - if (TraceDefaultMethods) { - tty->print_cr("Finding super default method %s.%s%s from %s", - super_class->name()->as_C_string(), - method_name->as_C_string(), sig->as_C_string(), - current_class->name()->as_C_string()); - } -#endif // ndef PRODUCT - - assert(super_class->is_interface(), "only call for default methods"); - - Method* target = NULL; - target = find_erased_super_default(current_class, super_class, - method_name, sig, CHECK_NULL); - -#ifndef PRODUCT - if (target != NULL) { - if (TraceDefaultMethods) { - tty->print(" Returning "); - print_method(tty, target, true); - tty->print_cr(""); - } - } -#endif // ndef PRODUCT - return target; -} - -#ifndef PRODUCT -// Return true is broad type is a covariant return of narrow type -static bool covariant_return_type(BasicType narrow, BasicType broad) { - if (narrow == broad) { - return true; - } - if (broad == T_OBJECT) { - return true; - } - return false; -} -#endif // ndef PRODUCT - -static int assemble_redirect( - BytecodeConstantPool* cp, BytecodeBuffer* buffer, - Symbol* incoming, Method* target, TRAPS) { - - BytecodeAssembler assem(buffer, cp); - - SignatureStream in(incoming, true); - SignatureStream out(target->signature(), true); - u2 parameter_count = 0; - - assem.aload(parameter_count++); // load 'this' - - while (!in.at_return_type()) { - assert(!out.at_return_type(), "Parameter counts do not match"); - BasicType bt = in.type(); - assert(out.type() == bt, "Parameter types are not compatible"); - assem.load(bt, parameter_count); - if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) { - assem.checkcast(out.as_symbol(THREAD)); - } else if (bt == T_LONG || bt == T_DOUBLE) { - ++parameter_count; // longs and doubles use two slots - } - ++parameter_count; - in.next(); - out.next(); - } - assert(out.at_return_type(), "Parameter counts do not match"); - assert(covariant_return_type(out.type(), in.type()), "Return types are not compatible"); - - if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) { - ++parameter_count; // need room for return value - } - if (target->method_holder()->is_interface()) { - assem.invokespecial(target); - } else { - assem.invokevirtual(target); - } - - if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) { - assem.checkcast(in.as_symbol(THREAD)); - } - assem._return(in.type()); - return parameter_count; -} - -static int assemble_abstract_method_error( - BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* message, TRAPS) { - - Symbol* errorName = vmSymbols::java_lang_AbstractMethodError(); Symbol* init = vmSymbols::object_initializer_name(); Symbol* sig = vmSymbols::string_void_signature(); @@ -1109,18 +883,18 @@ } } -// A "bridge" is a method created by javac to bridge the gap between -// an implementation and a generically-compatible, but different, signature. -// Bridges have actual bytecode implementation in classfiles. -// An "overpass", on the other hand, performs the same function as a bridge -// but does not occur in a classfile; the VM creates overpass itself, -// when it needs a path to get from a call site to an default method, and -// a bridge doesn't exist. -static void create_overpasses( +// Create default_methods list for the current class. +// With the VM only processing erased signatures, the VM only +// creates an overpass in a conflict case or a case with no candidates. +// This allows virtual methods to override the overpass, but ensures +// that a local method search will find the exception rather than an abstract +// or default method that is not a valid candidate. +static void create_defaults_and_exceptions( GrowableArray* slots, InstanceKlass* klass, TRAPS) { GrowableArray overpasses; + GrowableArray defaults; BytecodeConstantPool bpool(klass->constants()); for (int i = 0; i < slots->length(); ++i) { @@ -1128,7 +902,6 @@ if (slot->is_bound()) { MethodFamily* method = slot->get_binding(); - int max_stack = 0; BytecodeBuffer buffer; #ifndef PRODUCT @@ -1138,27 +911,27 @@ tty->print_cr(""); if (method->has_target()) { method->print_selected(tty, 1); - } else { + } else if (method->throws_exception()) { method->print_exception(tty, 1); } } #endif // ndef PRODUCT + if (method->has_target()) { Method* selected = method->get_selected_target(); if (selected->method_holder()->is_interface()) { - max_stack = assemble_redirect( - &bpool, &buffer, slot->signature(), selected, CHECK); + defaults.push(selected); } } else if (method->throws_exception()) { - max_stack = assemble_abstract_method_error( - &bpool, &buffer, method->get_exception_message(), CHECK); - } - if (max_stack != 0) { + int max_stack = assemble_method_error(&bpool, &buffer, + method->get_exception_name(), method->get_exception_message(), CHECK); AccessFlags flags = accessFlags_from( JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE); - Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(), + Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(), flags, max_stack, slot->size_of_parameters(), ConstMethod::OVERPASS, CHECK); + // We push to the methods list: + // overpass methods which are exception throwing methods if (m != NULL) { overpasses.push(m); } @@ -1169,11 +942,31 @@ #ifndef PRODUCT if (TraceDefaultMethods) { tty->print_cr("Created %d overpass methods", overpasses.length()); + tty->print_cr("Created %d default methods", defaults.length()); } #endif // ndef PRODUCT - switchover_constant_pool(&bpool, klass, &overpasses, CHECK); - merge_in_new_methods(klass, &overpasses, CHECK); + if (overpasses.length() > 0) { + switchover_constant_pool(&bpool, klass, &overpasses, CHECK); + merge_in_new_methods(klass, &overpasses, CHECK); + } + if (defaults.length() > 0) { + create_default_methods(klass, &defaults, CHECK); + } +} + +static void create_default_methods( InstanceKlass* klass, + GrowableArray* new_methods, TRAPS) { + + int new_size = new_methods->length(); + Array* total_default_methods = MetadataFactory::new_array( + klass->class_loader_data(), new_size, NULL, CHECK); + for (int index = 0; index < new_size; index++ ) { + total_default_methods->at_put(index, new_methods->at(index)); + } + Method::sort_methods(total_default_methods, false, false); + + klass->set_default_methods(total_default_methods); } static void sort_methods(GrowableArray* methods) { @@ -1281,4 +1074,3 @@ MetadataFactory::free_array(cld, original_ordering); } } - diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/defaultMethods.hpp --- a/src/share/vm/classfile/defaultMethods.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/defaultMethods.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,15 +44,5 @@ // the class. static void generate_default_methods( InstanceKlass* klass, GrowableArray* mirandas, TRAPS); - - - // Called during linking when an invokespecial to an direct interface - // method is found. Selects and returns a method if there is a unique - // default method in the 'super_iface' part of the hierarchy which is - // also a candidate default for 'this_klass'. Otherwise throws an AME. - static Method* find_super_default( - Klass* this_klass, Klass* super_iface, - Symbol* method_name, Symbol* method_sig, TRAPS); }; - #endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/dictionary.cpp --- a/src/share/vm/classfile/dictionary.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/dictionary.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/dictionary.hpp" #include "classfile/systemDictionary.hpp" +#include "memory/iterator.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "utilities/hashtable.inline.hpp" @@ -38,17 +39,21 @@ : TwoOopHashtable(table_size, sizeof(DictionaryEntry)) { _current_class_index = 0; _current_class_entry = NULL; + _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize); }; - Dictionary::Dictionary(int table_size, HashtableBucket* t, int number_of_entries) : TwoOopHashtable(table_size, sizeof(DictionaryEntry), t, number_of_entries) { _current_class_index = 0; _current_class_entry = NULL; + _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize); }; +ProtectionDomainCacheEntry* Dictionary::cache_get(oop protection_domain) { + return _pd_cache_table->get(protection_domain); +} DictionaryEntry* Dictionary::new_entry(unsigned int hash, Klass* klass, ClassLoaderData* loader_data) { @@ -105,11 +110,12 @@ } -void DictionaryEntry::add_protection_domain(oop protection_domain) { +void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_domain) { assert_locked_or_safepoint(SystemDictionary_lock); if (!contains_protection_domain(protection_domain)) { + ProtectionDomainCacheEntry* entry = dict->cache_get(protection_domain); ProtectionDomainEntry* new_head = - new ProtectionDomainEntry(protection_domain, _pd_set); + new ProtectionDomainEntry(entry, _pd_set); // Warning: Preserve store ordering. The SystemDictionary is read // without locks. The new ProtectionDomainEntry must be // complete before other threads can be allowed to see it @@ -193,7 +199,10 @@ void Dictionary::always_strong_oops_do(OopClosure* blk) { - // Follow all system classes and temporary placeholders in dictionary + // Follow all system classes and temporary placeholders in dictionary; only + // protection domain oops contain references into the heap. In a first + // pass over the system dictionary determine which need to be treated as + // strongly reachable and mark them as such. for (int index = 0; index < table_size(); index++) { for (DictionaryEntry *probe = bucket(index); probe != NULL; @@ -201,10 +210,13 @@ Klass* e = probe->klass(); ClassLoaderData* loader_data = probe->loader_data(); if (is_strongly_reachable(loader_data, e)) { - probe->protection_domain_set_oops_do(blk); + probe->set_strongly_reachable(); } } } + // Then iterate over the protection domain cache to apply the closure on the + // previously marked ones. + _pd_cache_table->always_strong_oops_do(blk); } @@ -266,18 +278,12 @@ } } - void Dictionary::oops_do(OopClosure* f) { - for (int index = 0; index < table_size(); index++) { - for (DictionaryEntry* probe = bucket(index); - probe != NULL; - probe = probe->next()) { - probe->protection_domain_set_oops_do(f); - } - } + // Only the protection domain oops contain references into the heap. Iterate + // over all of them. + _pd_cache_table->oops_do(f); } - void Dictionary::methods_do(void f(Method*)) { for (int index = 0; index < table_size(); index++) { for (DictionaryEntry* probe = bucket(index); @@ -292,6 +298,11 @@ } } +void Dictionary::unlink(BoolObjectClosure* is_alive) { + // Only the protection domain cache table may contain references to the heap + // that need to be unlinked. + _pd_cache_table->unlink(is_alive); +} Klass* Dictionary::try_get_next_class() { while (true) { @@ -306,7 +317,6 @@ // never reached } - // Add a loaded class to the system dictionary. // Readers of the SystemDictionary aren't always locked, so _buckets // is volatile. The store of the next field in the constructor is @@ -396,7 +406,7 @@ assert(protection_domain() != NULL, "real protection domain should be present"); - entry->add_protection_domain(protection_domain()); + entry->add_protection_domain(this, protection_domain()); assert(entry->contains_protection_domain(protection_domain()), "now protection domain should be present"); @@ -446,6 +456,146 @@ } } +ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size) + : Hashtable(table_size, sizeof(ProtectionDomainCacheEntry)) +{ +} + +void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) { + assert(SafepointSynchronize::is_at_safepoint(), "must be"); + for (int i = 0; i < table_size(); ++i) { + ProtectionDomainCacheEntry** p = bucket_addr(i); + ProtectionDomainCacheEntry* entry = bucket(i); + while (entry != NULL) { + if (is_alive->do_object_b(entry->literal())) { + p = entry->next_addr(); + } else { + *p = entry->next(); + free_entry(entry); + } + entry = *p; + } + } +} + +void ProtectionDomainCacheTable::oops_do(OopClosure* f) { + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->oops_do(f); + } + } +} + +uint ProtectionDomainCacheTable::bucket_size() { + return sizeof(ProtectionDomainCacheEntry); +} + +#ifndef PRODUCT +void ProtectionDomainCacheTable::print() { + tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)", + table_size(), number_of_entries()); + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->print(); + } + } +} + +void ProtectionDomainCacheEntry::print() { + tty->print_cr("entry "PTR_FORMAT" value "PTR_FORMAT" strongly_reachable %d next "PTR_FORMAT, + this, (void*)literal(), _strongly_reachable, next()); +} +#endif + +void ProtectionDomainCacheTable::verify() { + int element_count = 0; + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of protection domain cache table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void ProtectionDomainCacheEntry::verify() { + guarantee(literal()->is_oop(), "must be an oop"); +} + +void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f) { + // the caller marked the protection domain cache entries that we need to apply + // the closure on. Only process them. + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + if (probe->is_strongly_reachable()) { + probe->reset_strongly_reachable(); + probe->oops_do(f); + } + } + } +} + +ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(oop protection_domain) { + unsigned int hash = compute_hash(protection_domain); + int index = hash_to_index(hash); + + ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain); + if (entry == NULL) { + entry = add_entry(index, hash, protection_domain); + } + return entry; +} + +ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, oop protection_domain) { + for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) { + if (e->protection_domain() == protection_domain) { + return e; + } + } + + return NULL; +} + +ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, oop protection_domain) { + assert_locked_or_safepoint(SystemDictionary_lock); + assert(index == index_for(protection_domain), "incorrect index?"); + assert(find_entry(index, protection_domain) == NULL, "no double entry"); + + ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain); + Hashtable::add_entry(index, p); + return p; +} + +void ProtectionDomainCacheTable::free(ProtectionDomainCacheEntry* to_delete) { + unsigned int hash = compute_hash(to_delete->protection_domain()); + int index = hash_to_index(hash); + + ProtectionDomainCacheEntry** p = bucket_addr(index); + ProtectionDomainCacheEntry* entry = bucket(index); + while (true) { + assert(entry != NULL, "sanity"); + + if (entry == to_delete) { + *p = entry->next(); + Hashtable::free_entry(entry); + break; + } else { + p = entry->next_addr(); + entry = *p; + } + } +} + SymbolPropertyTable::SymbolPropertyTable(int table_size) : Hashtable(table_size, sizeof(SymbolPropertyEntry)) { @@ -532,11 +682,13 @@ tty->cr(); } } + tty->cr(); + _pd_cache_table->print(); + tty->cr(); } #endif - void Dictionary::verify() { guarantee(number_of_entries() >= 0, "Verify of system dictionary failed"); @@ -563,5 +715,7 @@ guarantee(number_of_entries() == element_count, "Verify of system dictionary failed"); debug_only(verify_lookup_length((double)number_of_entries() / table_size())); + + _pd_cache_table->verify(); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/dictionary.hpp --- a/src/share/vm/classfile/dictionary.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/dictionary.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,14 @@ #include "classfile/systemDictionary.hpp" #include "oops/instanceKlass.hpp" -#include "oops/oop.hpp" +#include "oops/oop.inline.hpp" #include "utilities/hashtable.hpp" class DictionaryEntry; class PSPromotionManager; +class ProtectionDomainCacheTable; +class ProtectionDomainCacheEntry; +class BoolObjectClosure; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The data structure for the system dictionary (and the shared system @@ -45,6 +48,8 @@ // pointer to the current hash table entry. static DictionaryEntry* _current_class_entry; + ProtectionDomainCacheTable* _pd_cache_table; + DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data); @@ -93,6 +98,7 @@ void methods_do(void f(Method*)); + void unlink(BoolObjectClosure* is_alive); // Classes loaded by the bootstrap loader are always strongly reachable. // If we're not doing class unloading, all classes are strongly reachable. @@ -118,6 +124,7 @@ // Sharing support void reorder_dictionary(); + ProtectionDomainCacheEntry* cache_get(oop protection_domain); #ifndef PRODUCT void print(); @@ -126,21 +133,112 @@ }; // The following classes can be in dictionary.cpp, but we need these -// to be in header file so that SA's vmStructs can access. +// to be in header file so that SA's vmStructs can access them. +class ProtectionDomainCacheEntry : public HashtableEntry { + friend class VMStructs; + private: + // Flag indicating whether this protection domain entry is strongly reachable. + // Used during iterating over the system dictionary to remember oops that need + // to be updated. + bool _strongly_reachable; + public: + oop protection_domain() { return literal(); } + + void init() { + _strongly_reachable = false; + } + + ProtectionDomainCacheEntry* next() { + return (ProtectionDomainCacheEntry*)HashtableEntry::next(); + } + + ProtectionDomainCacheEntry** next_addr() { + return (ProtectionDomainCacheEntry**)HashtableEntry::next_addr(); + } + + void oops_do(OopClosure* f) { + f->do_oop(literal_addr()); + } + + void set_strongly_reachable() { _strongly_reachable = true; } + bool is_strongly_reachable() { return _strongly_reachable; } + void reset_strongly_reachable() { _strongly_reachable = false; } + + void print() PRODUCT_RETURN; + void verify(); +}; + +// The ProtectionDomainCacheTable contains all protection domain oops. The system +// dictionary entries reference its entries instead of having references to oops +// directly. +// This is used to speed up system dictionary iteration: the oops in the +// protection domain are the only ones referring the Java heap. So when there is +// need to update these, instead of going over every entry of the system dictionary, +// we only need to iterate over this set. +// The amount of different protection domains used is typically magnitudes smaller +// than the number of system dictionary entries (loaded classes). +class ProtectionDomainCacheTable : public Hashtable { + friend class VMStructs; +private: + ProtectionDomainCacheEntry* bucket(int i) { + return (ProtectionDomainCacheEntry*) Hashtable::bucket(i); + } + + // The following method is not MT-safe and must be done under lock. + ProtectionDomainCacheEntry** bucket_addr(int i) { + return (ProtectionDomainCacheEntry**) Hashtable::bucket_addr(i); + } + + ProtectionDomainCacheEntry* new_entry(unsigned int hash, oop protection_domain) { + ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable::new_entry(hash, protection_domain); + entry->init(); + return entry; + } + + static unsigned int compute_hash(oop protection_domain) { + return (unsigned int)(protection_domain->identity_hash()); + } + + int index_for(oop protection_domain) { + return hash_to_index(compute_hash(protection_domain)); + } + + ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, oop protection_domain); + ProtectionDomainCacheEntry* find_entry(int index, oop protection_domain); + +public: + + ProtectionDomainCacheTable(int table_size); + + ProtectionDomainCacheEntry* get(oop protection_domain); + void free(ProtectionDomainCacheEntry* entry); + + void unlink(BoolObjectClosure* cl); + + // GC support + void oops_do(OopClosure* f); + void always_strong_oops_do(OopClosure* f); + + static uint bucket_size(); + + void print() PRODUCT_RETURN; + void verify(); +}; + class ProtectionDomainEntry :public CHeapObj { friend class VMStructs; public: ProtectionDomainEntry* _next; - oop _protection_domain; + ProtectionDomainCacheEntry* _pd_cache; - ProtectionDomainEntry(oop protection_domain, ProtectionDomainEntry* next) { - _protection_domain = protection_domain; - _next = next; + ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) { + _pd_cache = pd_cache; + _next = next; } ProtectionDomainEntry* next() { return _next; } - oop protection_domain() { return _protection_domain; } + oop protection_domain() { return _pd_cache->protection_domain(); } }; // An entry in the system dictionary, this describes a class as @@ -151,6 +249,24 @@ private: // Contains the set of approved protection domains that can access // this system dictionary entry. + // + // This protection domain set is a set of tuples: + // + // (InstanceKlass C, initiating class loader ICL, Protection Domain PD) + // + // [Note that C.protection_domain(), which is stored in the java.lang.Class + // mirror of C, is NOT the same as PD] + // + // If such an entry (C, ICL, PD) exists in the table, it means that + // it is okay for a class Foo to reference C, where + // + // Foo.protection_domain() == PD, and + // Foo's defining class loader == ICL + // + // The usage of the PD set can be seen in SystemDictionary::validate_protection_domain() + // It is essentially a cache to avoid repeated Java up-calls to + // ClassLoader.checkPackageAccess(). + // ProtectionDomainEntry* _pd_set; ClassLoaderData* _loader_data; @@ -158,7 +274,7 @@ // Tells whether a protection is in the approved set. bool contains_protection_domain(oop protection_domain) const; // Adds a protection domain to the approved set. - void add_protection_domain(oop protection_domain); + void add_protection_domain(Dictionary* dict, oop protection_domain); Klass* klass() const { return (Klass*)literal(); } Klass** klass_addr() { return (Klass**)literal_addr(); } @@ -189,12 +305,11 @@ : contains_protection_domain(protection_domain()); } - - void protection_domain_set_oops_do(OopClosure* f) { + void set_strongly_reachable() { for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { - f->do_oop(&(current->_protection_domain)); + current->_pd_cache->set_strongly_reachable(); } } @@ -202,7 +317,7 @@ for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { - current->_protection_domain->verify(); + current->_pd_cache->protection_domain()->verify(); } } @@ -264,7 +379,7 @@ } if (method_type() != NULL) { if (printed) st->print(" and "); - st->print(INTPTR_FORMAT, method_type()); + st->print(INTPTR_FORMAT, (void *)method_type()); printed = true; } st->print_cr(printed ? "" : "(empty)"); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/javaClasses.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1376,8 +1376,15 @@ const char* klass_name = holder->external_name(); int buf_len = (int)strlen(klass_name); - // pushing to the stack trace added one. + // The method id may point to an obsolete method, can't get more stack information Method* method = holder->method_with_idnum(method_id); + if (method == NULL) { + char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); + // This is what the java code prints in this case - added Redefined + sprintf(buf, "\tat %s.null (Redefined)", klass_name); + return buf; + } + char* method_name = method->name()->as_C_string(); buf_len += (int)strlen(method_name); @@ -1773,7 +1780,8 @@ return element; } -oop java_lang_StackTraceElement::create(Handle mirror, int method_id, int version, int bci, TRAPS) { +oop java_lang_StackTraceElement::create(Handle mirror, int method_id, + int version, int bci, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -1790,8 +1798,16 @@ oop classname = StringTable::intern((char*) str, CHECK_0); java_lang_StackTraceElement::set_declaringClass(element(), classname); + Method* method = holder->method_with_idnum(method_id); + // Method on stack may be obsolete because it was redefined so cannot be + // found by idnum. + if (method == NULL) { + // leave name and fileName null + java_lang_StackTraceElement::set_lineNumber(element(), -1); + return element(); + } + // Fill in method name - Method* method = holder->method_with_idnum(method_id); oop methodname = StringTable::intern(method->name(), CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/symbolTable.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -840,7 +840,7 @@ if (str1 == str2) { tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") " "in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]", - str1, bkt1, e_cnt1, bkt2, e_cnt2); + (void *)str1, bkt1, e_cnt1, bkt2, e_cnt2); return _verify_fail_continue; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/symbolTable.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -107,18 +107,13 @@ add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); } - // Table size - enum { - symbol_table_size = 20011 - }; - Symbol* lookup(int index, const char* name, int len, unsigned int hash); SymbolTable() - : Hashtable(symbol_table_size, sizeof (HashtableEntry)) {} + : Hashtable(SymbolTableSize, sizeof (HashtableEntry)) {} SymbolTable(HashtableBucket* t, int number_of_entries) - : Hashtable(symbol_table_size, sizeof (HashtableEntry), t, + : Hashtable(SymbolTableSize, sizeof (HashtableEntry), t, number_of_entries) {} // Arena for permanent symbols (null class loader) that are never unloaded @@ -136,6 +131,9 @@ // The symbol table static SymbolTable* the_table() { return _the_table; } + // Size of one bucket in the string table. Used when checking for rollover. + static uint bucket_size() { return sizeof(HashtableBucket); } + static void create_table() { assert(_the_table == NULL, "One symbol table allowed."); _the_table = new SymbolTable(); @@ -145,8 +143,11 @@ static void create_table(HashtableBucket* t, int length, int number_of_entries) { assert(_the_table == NULL, "One symbol table allowed."); - assert(length == symbol_table_size * sizeof(HashtableBucket), - "bad shared symbol size."); + + // If CDS archive used a different symbol table size, use that size instead + // which is better than giving an error. + SymbolTableSize = length/bucket_size(); + _the_table = new SymbolTable(t, number_of_entries); // if CDS give symbol table a default arena size since most symbols // are already allocated in the shared misc section. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/systemDictionary.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1697,6 +1697,24 @@ return newsize; } +#ifdef ASSERT +class VerifySDReachableAndLiveClosure : public OopClosure { +private: + BoolObjectClosure* _is_alive; + + template void do_oop_work(T* p) { + oop obj = oopDesc::load_decode_heap_oop(p); + guarantee(_is_alive->do_object_b(obj), "Oop in system dictionary must be live"); + } + +public: + VerifySDReachableAndLiveClosure(BoolObjectClosure* is_alive) : OopClosure(), _is_alive(is_alive) { } + + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } +}; +#endif + // Assumes classes in the SystemDictionary are only unloaded at a safepoint // Note: anonymous classes are not in the SD. bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { @@ -1707,7 +1725,15 @@ unloading_occurred = dictionary()->do_unloading(); constraints()->purge_loader_constraints(); resolution_errors()->purge_resolution_errors(); -} + } + // Oops referenced by the system dictionary may get unreachable independently + // of the class loader (eg. cached protection domain oops). So we need to + // explicitly unlink them here instead of in Dictionary::do_unloading. + dictionary()->unlink(is_alive); +#ifdef ASSERT + VerifySDReachableAndLiveClosure cl(is_alive); + dictionary()->oops_do(&cl); +#endif return unloading_occurred; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/verifier.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -2439,8 +2439,14 @@ && !ref_class_type.equals(current_type()) && !ref_class_type.equals(VerificationType::reference_type( current_class()->super()->name()))) { - bool subtype = ref_class_type.is_assignable_from( - current_type(), this, CHECK_VERIFY(this)); + bool subtype = false; + if (!current_class()->is_anonymous()) { + subtype = ref_class_type.is_assignable_from( + current_type(), this, CHECK_VERIFY(this)); + } else { + subtype = ref_class_type.is_assignable_from(VerificationType::reference_type( + current_class()->host_klass()->name()), this, CHECK_VERIFY(this)); + } if (!subtype) { verify_error(ErrorContext::bad_code(bci), "Bad invokespecial instruction: " @@ -2461,7 +2467,24 @@ } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) { - current_frame->pop_stack(current_type(), CHECK_VERIFY(this)); + if (!current_class()->is_anonymous()) { + current_frame->pop_stack(current_type(), CHECK_VERIFY(this)); + } else { + // anonymous class invokespecial calls: check if the + // objectref is a subtype of the host_klass of the current class + // to allow an anonymous class to reference methods in the host_klass + VerificationType top = current_frame->pop_stack(CHECK_VERIFY(this)); + VerificationType hosttype = + VerificationType::reference_type(current_class()->host_klass()->name()); + bool subtype = hosttype.is_assignable_from(top, this, CHECK_VERIFY(this)); + if (!subtype) { + verify_error( ErrorContext::bad_type(current_frame->offset(), + current_frame->stack_top_ctx(), + TypeOrigin::implicit(top)), + "Bad type on operand stack"); + return; + } + } } else if (opcode == Bytecodes::_invokevirtual) { VerificationType stack_object_type = current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this)); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -270,7 +270,7 @@ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ - template(sun_invoke_Stable_signature, "Lsun/invoke/Stable;") \ + template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ template(java_lang_invoke_MagicLambdaImpl, "java/lang/invoke/MagicLambdaImpl") \ @@ -631,6 +631,10 @@ do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ \ + do_name(addExact_name,"addExact") \ + do_name(subtractExact_name,"subtractExact") \ + do_name(multiplyExact_name,"multiplyExact") \ + \ do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \ do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \ do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \ @@ -643,6 +647,7 @@ do_intrinsic(_dexp, java_lang_Math, exp_name, double_double_signature, F_S) \ do_intrinsic(_min, java_lang_Math, min_name, int2_int_signature, F_S) \ do_intrinsic(_max, java_lang_Math, max_name, int2_int_signature, F_S) \ + do_intrinsic(_addExact, java_lang_Math, addExact_name, int2_int_signature, F_S) \ \ do_intrinsic(_floatToRawIntBits, java_lang_Float, floatToRawIntBits_name, float_int_signature, F_S) \ do_name( floatToRawIntBits_name, "floatToRawIntBits") \ diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/code/codeCache.cpp --- a/src/share/vm/code/codeCache.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/code/codeCache.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -124,7 +124,6 @@ int CodeCache::_number_of_nmethods_with_dependencies = 0; bool CodeCache::_needs_cache_clean = false; nmethod* CodeCache::_scavenge_root_nmethods = NULL; -nmethod* CodeCache::_saved_nmethods = NULL; int CodeCache::_codemem_full_count = 0; @@ -464,96 +463,11 @@ } #endif //PRODUCT -/** - * Remove and return nmethod from the saved code list in order to reanimate it. - */ -nmethod* CodeCache::reanimate_saved_code(Method* m) { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - nmethod* saved = _saved_nmethods; - nmethod* prev = NULL; - while (saved != NULL) { - if (saved->is_in_use() && saved->method() == m) { - if (prev != NULL) { - prev->set_saved_nmethod_link(saved->saved_nmethod_link()); - } else { - _saved_nmethods = saved->saved_nmethod_link(); - } - assert(saved->is_speculatively_disconnected(), "shouldn't call for other nmethods"); - saved->set_speculatively_disconnected(false); - saved->set_saved_nmethod_link(NULL); - if (PrintMethodFlushing) { - saved->print_on(tty, " ### nmethod is reconnected"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_reconnected compile_id='%3d'", saved->compile_id()); - xtty->method(m); - xtty->stamp(); - xtty->end_elem(); - } - return saved; - } - prev = saved; - saved = saved->saved_nmethod_link(); - } - return NULL; -} - -/** - * Remove nmethod from the saved code list in order to discard it permanently - */ -void CodeCache::remove_saved_code(nmethod* nm) { - // For conc swpr this will be called with CodeCache_lock taken by caller - assert_locked_or_safepoint(CodeCache_lock); - assert(nm->is_speculatively_disconnected(), "shouldn't call for other nmethods"); - nmethod* saved = _saved_nmethods; - nmethod* prev = NULL; - while (saved != NULL) { - if (saved == nm) { - if (prev != NULL) { - prev->set_saved_nmethod_link(saved->saved_nmethod_link()); - } else { - _saved_nmethods = saved->saved_nmethod_link(); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_removed compile_id='%3d'", nm->compile_id()); - xtty->stamp(); - xtty->end_elem(); - } - return; - } - prev = saved; - saved = saved->saved_nmethod_link(); - } - ShouldNotReachHere(); -} - -void CodeCache::speculatively_disconnect(nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); - assert(nm->is_in_use() && !nm->is_speculatively_disconnected(), "should only disconnect live nmethods"); - nm->set_saved_nmethod_link(_saved_nmethods); - _saved_nmethods = nm; - if (PrintMethodFlushing) { - nm->print_on(tty, " ### nmethod is speculatively disconnected"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_disconnected compile_id='%3d'", nm->compile_id()); - xtty->method(nm->method()); - xtty->stamp(); - xtty->end_elem(); - } - nm->method()->clear_code(); - nm->set_speculatively_disconnected(true); -} - void CodeCache::gc_prologue() { assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called"); } - void CodeCache::gc_epilogue() { assert_locked_or_safepoint(CodeCache_lock); FOR_ALL_ALIVE_BLOBS(cb) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/code/codeCache.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -57,7 +57,6 @@ static int _number_of_nmethods_with_dependencies; static bool _needs_cache_clean; static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() - static nmethod* _saved_nmethods; // Linked list of speculatively disconnected nmethods. static void verify_if_often() PRODUCT_RETURN; @@ -167,17 +166,12 @@ static size_t capacity() { return _heap->capacity(); } static size_t max_capacity() { return _heap->max_capacity(); } static size_t unallocated_capacity() { return _heap->unallocated_capacity(); } - static bool needs_flushing() { return unallocated_capacity() < CodeCacheFlushingMinimumFreeSpace; } static double reverse_free_ratio(); static bool needs_cache_clean() { return _needs_cache_clean; } static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } static void clear_inline_caches(); // clear all inline caches - static nmethod* reanimate_saved_code(Method* m); - static void remove_saved_code(nmethod* nm); - static void speculatively_disconnect(nmethod* nm); - // Deoptimization static int mark_for_deoptimization(DepChange& changes); #ifdef HOTSWAP diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/code/dependencies.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -812,8 +812,8 @@ Klass* k = ctxk; Method* lm = k->lookup_method(m->name(), m->signature()); if (lm == NULL && k->oop_is_instance()) { - // It might be an abstract interface method, devoid of mirandas. - lm = ((InstanceKlass*)k)->lookup_method_in_all_interfaces(m->name(), + // It might be an interface method + lm = ((InstanceKlass*)k)->lookup_method_in_ordered_interfaces(m->name(), m->signature()); } if (lm == m) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/code/nmethod.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -462,7 +462,6 @@ _state = alive; _marked_for_reclamation = 0; _has_flushed_dependencies = 0; - _speculatively_disconnected = 0; _has_unsafe_access = 0; _has_method_handle_invokes = 0; _lazy_critical_native = 0; @@ -481,7 +480,6 @@ _osr_link = NULL; _scavenge_root_link = NULL; _scavenge_root_state = 0; - _saved_nmethod_link = NULL; _compiler = NULL; #ifdef HAVE_DTRACE_H @@ -686,6 +684,7 @@ _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); code_buffer->copy_values_to(this); if (ScavengeRootsInCode && detect_scavenge_root_oops()) { @@ -770,6 +769,7 @@ _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); code_buffer->copy_values_to(this); debug_only(verify_scavenge_root_oops()); @@ -842,6 +842,7 @@ _comp_level = comp_level; _compiler = compiler; _orig_pc_offset = orig_pc_offset; + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); // Section offsets _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); @@ -1176,7 +1177,7 @@ // This is a private interface with the sweeper. void nmethod::mark_as_seen_on_stack() { - assert(is_not_entrant(), "must be a non-entrant method"); + assert(is_alive(), "Must be an alive method"); // Set the traversal mark to ensure that the sweeper does 2 // cleaning passes before moving to zombie. set_stack_traversal_mark(NMethodSweeper::traversal_count()); @@ -1261,7 +1262,7 @@ set_osr_link(NULL); //set_scavenge_root_link(NULL); // done by prune_scavenge_root_nmethods - NMethodSweeper::notify(this); + NMethodSweeper::notify(); } void nmethod::invalidate_osr_method() { @@ -1351,6 +1352,15 @@ nmethod_needs_unregister = true; } + // Must happen before state change. Otherwise we have a race condition in + // nmethod::can_not_entrant_be_converted(). I.e., a method can immediately + // transition its state from 'not_entrant' to 'zombie' without having to wait + // for stack scanning. + if (state == not_entrant) { + mark_as_seen_on_stack(); + OrderAccess::storestore(); + } + // Change state _state = state; @@ -1369,11 +1379,6 @@ HandleMark hm; method()->clear_code(); } - - if (state == not_entrant) { - mark_as_seen_on_stack(); - } - } // leave critical region under Patching_lock // When the nmethod becomes zombie it is no longer alive so the @@ -1416,7 +1421,7 @@ } // Make sweeper aware that there is a zombie method that needs to be removed - NMethodSweeper::notify(this); + NMethodSweeper::notify(); return true; } @@ -1451,10 +1456,6 @@ CodeCache::drop_scavenge_root_nmethod(this); } - if (is_speculatively_disconnected()) { - CodeCache::remove_saved_code(this); - } - #ifdef SHARK ((SharkCompiler *) compiler())->free_compiled_method(insts_begin()); #endif // SHARK @@ -1965,7 +1966,7 @@ if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root"); tty->print_cr(""PTR_FORMAT"[offset=%d] detected scavengable oop "PTR_FORMAT" (found at "PTR_FORMAT")", _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm), - (intptr_t)(*p), (intptr_t)p); + (void *)(*p), (intptr_t)p); (*p)->print(); } #endif //PRODUCT @@ -2345,7 +2346,7 @@ _ok = false; } tty->print_cr("*** non-oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", - (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } }; @@ -2466,7 +2467,7 @@ _ok = false; } tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", - (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); (*p)->print(); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/code/nmethod.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -119,7 +119,6 @@ // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods - nmethod* _saved_nmethod_link; // from CodeCache::speculatively_disconnect static nmethod* volatile _oops_do_mark_nmethods; nmethod* volatile _oops_do_mark_link; @@ -165,7 +164,6 @@ // protected by CodeCache_lock bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) - bool _speculatively_disconnected; // Marked for potential unload bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) bool _marked_for_deoptimization; // Used for stack deoptimization @@ -180,7 +178,7 @@ unsigned int _has_wide_vectors:1; // Preserve wide vectors at safepoints // Protected by Patching_lock - unsigned char _state; // {alive, not_entrant, zombie, unloaded} + volatile unsigned char _state; // {alive, not_entrant, zombie, unloaded} #ifdef ASSERT bool _oops_are_stale; // indicates that it's no longer safe to access oops section @@ -202,11 +200,18 @@ // not_entrant method removal. Each mark_sweep pass will update // this mark to current sweep invocation count if it is seen on the - // stack. An not_entrant method can be removed when there is no + // stack. An not_entrant method can be removed when there are no // more activations, i.e., when the _stack_traversal_mark is less than // current sweep traversal index. long _stack_traversal_mark; + // The _hotness_counter indicates the hotness of a method. The higher + // the value the hotter the method. The hotness counter of a nmethod is + // set to [(ReservedCodeCacheSize / (1024 * 1024)) * 2] each time the method + // is active while stack scanning (mark_active_nmethods()). The hotness + // counter is decreased (by 1) while sweeping. + int _hotness_counter; + ExceptionCache *_exception_cache; PcDescCache _pc_desc_cache; @@ -382,6 +387,10 @@ int total_size () const; + void dec_hotness_counter() { _hotness_counter--; } + void set_hotness_counter(int val) { _hotness_counter = val; } + int hotness_counter() const { return _hotness_counter; } + // Containment bool consts_contains (address addr) const { return consts_begin () <= addr && addr < consts_end (); } bool insts_contains (address addr) const { return insts_begin () <= addr && addr < insts_end (); } @@ -408,8 +417,8 @@ // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } - bool make_zombie() { return make_not_entrant_or_zombie(zombie); } + bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } + bool make_zombie() { return make_not_entrant_or_zombie(zombie); } // used by jvmti to track if the unload event has been reported bool unload_reported() { return _unload_reported; } @@ -437,9 +446,6 @@ bool has_method_handle_invokes() const { return _has_method_handle_invokes; } void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool is_speculatively_disconnected() const { return _speculatively_disconnected; } - void set_speculatively_disconnected(bool z) { _speculatively_disconnected = z; } - bool is_lazy_critical_native() const { return _lazy_critical_native; } void set_lazy_critical_native(bool z) { _lazy_critical_native = z; } @@ -499,9 +505,6 @@ nmethod* scavenge_root_link() const { return _scavenge_root_link; } void set_scavenge_root_link(nmethod *n) { _scavenge_root_link = n; } - nmethod* saved_nmethod_link() const { return _saved_nmethod_link; } - void set_saved_nmethod_link(nmethod *n) { _saved_nmethod_link = n; } - public: // Sweeper support diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -634,19 +634,36 @@ NMethodSweeper::possibly_sweep(); MutexLocker locker(lock()); - // Wait for an available CompileTask. + // If _first is NULL we have no more compile jobs. There are two reasons for + // having no compile jobs: First, we compiled everything we wanted. Second, + // we ran out of code cache so compilation has been disabled. In the latter + // case we perform code cache sweeps to free memory such that we can re-enable + // compilation. while (_first == NULL) { - // There is no work to be done right now. Wait. - if (UseCodeCacheFlushing && (!CompileBroker::should_compile_new_jobs() || CodeCache::needs_flushing())) { - // During the emergency sweeping periods, wake up and sweep occasionally - bool timedout = lock()->wait(!Mutex::_no_safepoint_check_flag, NmethodSweepCheckInterval*1000); - if (timedout) { + if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs()) { + // Wait a certain amount of time to possibly do another sweep. + // We must wait until stack scanning has happened so that we can + // transition a method's state from 'not_entrant' to 'zombie'. + long wait_time = NmethodSweepCheckInterval * 1000; + if (FLAG_IS_DEFAULT(NmethodSweepCheckInterval)) { + // Only one thread at a time can do sweeping. Scale the + // wait time according to the number of compiler threads. + // As a result, the next sweep is likely to happen every 100ms + // with an arbitrary number of threads that do sweeping. + wait_time = 100 * CICompilerCount; + } + bool timeout = lock()->wait(!Mutex::_no_safepoint_check_flag, wait_time); + if (timeout) { MutexUnlocker ul(lock()); - // When otherwise not busy, run nmethod sweeping NMethodSweeper::possibly_sweep(); } } else { - // During normal operation no need to wake up on timer + // If there are no compilation tasks and we can compile new jobs + // (i.e., there is enough free space in the code cache) there is + // no need to invoke the sweeper. As a result, the hotness of methods + // remains unchanged. This behavior is desired, since we want to keep + // the stable state, i.e., we do not want to evict methods from the + // code cache if it is unnecessary. lock()->wait(); } } @@ -1227,16 +1244,9 @@ return method_code; } } - if (method->is_not_compilable(comp_level)) return NULL; - - if (UseCodeCacheFlushing) { - nmethod* saved = CodeCache::reanimate_saved_code(method()); - if (saved != NULL) { - method->set_code(method, saved); - return saved; - } + if (method->is_not_compilable(comp_level)) { + return NULL; } - } else { // osr compilation #ifndef TIERED @@ -1585,9 +1595,6 @@ if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) { // the code cache is really full handle_full_code_cache(); - } else if (UseCodeCacheFlushing && CodeCache::needs_flushing()) { - // Attempt to start cleaning the code cache while there is still a little headroom - NMethodSweeper::handle_full_code_cache(false); } CompileTask* task = queue->get(); @@ -1943,7 +1950,11 @@ } #endif if (UseCodeCacheFlushing) { - NMethodSweeper::handle_full_code_cache(true); + // Since code cache is full, immediately stop new compiles + if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { + NMethodSweeper::log_sweep("disable_compiler"); + NMethodSweeper::possibly_sweep(); + } } else { UseCompiler = false; AlwaysCompileLoopMethods = false; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/compiler/oopMap.cpp --- a/src/share/vm/compiler/oopMap.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/compiler/oopMap.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -628,7 +628,7 @@ // Returns value of location as an int -intptr_t value_of_loc(oop *pointer) { return (intptr_t)(*pointer); } +intptr_t value_of_loc(oop *pointer) { return cast_from_oop((*pointer)); } void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -9065,7 +9065,7 @@ return !stack->isEmpty(); } -#define BUSY (oop(0x1aff1aff)) +#define BUSY (cast_to_oop(0x1aff1aff)) // (MT-safe) Get a prefix of at most "num" from the list. // The overflow list is chained through the mark word of // each object in the list. We fetch the entire list, @@ -9098,7 +9098,7 @@ return false; } // Grab the entire list; we'll put back a suffix - oop prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); + oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); Thread* tid = Thread::current(); // Before "no_of_gc_threads" was introduced CMSOverflowSpinCount was // set to ParallelGCThreads. @@ -9113,7 +9113,7 @@ return false; } else if (_overflow_list != BUSY) { // Try and grab the prefix - prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); + prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); } } // If the list was found to be empty, or we spun long diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -2694,7 +2694,7 @@ if (print_it) { _out->print_cr(" "PTR_FORMAT"%s", - o, (over_tams) ? " >" : (marked) ? " M" : ""); + (void *)o, (over_tams) ? " >" : (marked) ? " M" : ""); PrintReachableOopClosure oopCl(_out, _vo, _all); o->oop_iterate_no_header(&oopCl); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -81,7 +81,7 @@ size_t* marked_bytes_array, BitMap* task_card_bm) { G1CollectedHeap* g1h = _g1h; - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); + CardTableModRefBS* ct_bs = g1h->g1_barrier_set(); HeapWord* start = mr.start(); HeapWord* end = mr.end(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1CardCounts.cpp --- a/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -65,9 +65,7 @@ // threshold limit is no more than this. guarantee(G1ConcRSHotCardLimit <= max_jubyte, "sanity"); - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ct_bs = (CardTableModRefBS*)bs; + _ct_bs = _g1h->g1_barrier_set(); _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start()); // Allocate/Reserve the counts table diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -125,10 +125,8 @@ int _histo[256]; public: ClearLoggedCardTableEntryClosure() : - _calls(0) + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); for (int i = 0; i < 256; i++) _histo[i] = 0; } bool do_card_ptr(jbyte* card_ptr, int worker_i) { @@ -158,11 +156,8 @@ CardTableModRefBS* _ctbs; public: RedirtyLoggedCardTableEntryClosure() : - _calls(0) - { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); - } + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) {} + bool do_card_ptr(jbyte* card_ptr, int worker_i) { if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) { _calls++; @@ -478,7 +473,7 @@ void G1CollectedHeap::check_ct_logs_at_safepoint() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + CardTableModRefBS* ct_bs = g1_barrier_set(); // Count the dirty cards at the start. CountNonCleanMemRegionClosure count1(this); @@ -1205,7 +1200,7 @@ }; void G1CollectedHeap::clear_rsets_post_compaction() { - PostMCRemSetClearClosure rs_clear(this, mr_bs()); + PostMCRemSetClearClosure rs_clear(this, g1_barrier_set()); heap_region_iterate(&rs_clear); } @@ -1777,7 +1772,6 @@ } bool G1CollectedHeap::expand(size_t expand_bytes) { - size_t old_mem_size = _g1_storage.committed_size(); size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_size_up(aligned_expand_bytes, HeapRegion::GrainBytes); @@ -1787,6 +1781,13 @@ ergo_format_byte("attempted expansion amount"), expand_bytes, aligned_expand_bytes); + if (_g1_storage.uncommitted_size() == 0) { + ergo_verbose0(ErgoHeapSizing, + "did not expand the heap", + ergo_format_reason("heap already fully expanded")); + return false; + } + // First commit the memory. HeapWord* old_end = (HeapWord*) _g1_storage.high(); bool successful = _g1_storage.expand_by(aligned_expand_bytes); @@ -1845,7 +1846,6 @@ } void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { - size_t old_mem_size = _g1_storage.committed_size(); size_t aligned_shrink_bytes = ReservedSpace::page_align_size_down(shrink_bytes); aligned_shrink_bytes = align_size_down(aligned_shrink_bytes, @@ -2045,20 +2045,13 @@ // Create the gen rem set (and barrier set) for the entire reserved region. _rem_set = collector_policy()->create_rem_set(_reserved, 2); set_barrier_set(rem_set()->bs()); - if (barrier_set()->is_a(BarrierSet::ModRef)) { - _mr_bs = (ModRefBarrierSet*)_barrier_set; - } else { - vm_exit_during_initialization("G1 requires a mod ref bs."); + if (!barrier_set()->is_a(BarrierSet::G1SATBCTLogging)) { + vm_exit_during_initialization("G1 requires a G1SATBLoggingCardTableModRefBS"); return JNI_ENOMEM; } // Also create a G1 rem set. - if (mr_bs()->is_a(BarrierSet::CardTableModRef)) { - _g1_rem_set = new G1RemSet(this, (CardTableModRefBS*)mr_bs()); - } else { - vm_exit_during_initialization("G1 requires a cardtable mod ref bs."); - return JNI_ENOMEM; - } + _g1_rem_set = new G1RemSet(this, g1_barrier_set()); // Carve out the G1 part of the heap. @@ -3681,6 +3674,11 @@ assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); // Fill TLAB's and such ensure_parsability(true); + + if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && + (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { + g1_rem_set()->print_periodic_summary_info("Before GC RS summary"); + } } void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { @@ -3689,7 +3687,7 @@ (G1SummarizeRSetStatsPeriod > 0) && // we are at the end of the GC. Total collections has already been increased. ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_periodic_summary_info(); + g1_rem_set()->print_periodic_summary_info("After GC RS summary"); } // FIXME: what is this about? @@ -4550,7 +4548,7 @@ : _g1h(g1h), _refs(g1h->task_queue(queue_num)), _dcq(&g1h->dirty_card_queue_set()), - _ct_bs((CardTableModRefBS*)_g1h->barrier_set()), + _ct_bs(g1h->g1_barrier_set()), _g1_rem(g1h->g1_rem_set()), _hash_seed(17), _queue_num(queue_num), _term_attempts(0), @@ -4617,7 +4615,7 @@ assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, ref)); oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p))); + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, (void *)p)); return true; } @@ -4627,11 +4625,11 @@ // Must be in the collection set--it's already been copied. oop p = clear_partial_array_mask(ref); assert(_g1h->obj_in_cs(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p))); + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, (void *)p)); } else { oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p))); + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, (void *)p)); } return true; } @@ -5979,11 +5977,11 @@ } class G1ParCleanupCTTask : public AbstractGangTask { - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; HeapRegion* volatile _su_head; public: - G1ParCleanupCTTask(CardTableModRefBS* ct_bs, + G1ParCleanupCTTask(G1SATBCardTableModRefBS* ct_bs, G1CollectedHeap* g1h) : AbstractGangTask("G1 Par Cleanup CT Task"), _ct_bs(ct_bs), _g1h(g1h) { } @@ -6006,9 +6004,9 @@ #ifndef PRODUCT class G1VerifyCardTableCleanup: public HeapRegionClosure { G1CollectedHeap* _g1h; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: - G1VerifyCardTableCleanup(G1CollectedHeap* g1h, CardTableModRefBS* ct_bs) + G1VerifyCardTableCleanup(G1CollectedHeap* g1h, G1SATBCardTableModRefBS* ct_bs) : _g1h(g1h), _ct_bs(ct_bs) { } virtual bool doHeapRegion(HeapRegion* r) { if (r->is_survivor()) { @@ -6022,7 +6020,7 @@ void G1CollectedHeap::verify_not_dirty_region(HeapRegion* hr) { // All of the region should be clean. - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->end()); ct_bs->verify_not_dirty_region(mr); } @@ -6035,13 +6033,17 @@ // not dirty that area (one less thing to have to do while holding // a lock). So we can only verify that [bottom(),pre_dummy_top()] // is dirty. - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->pre_dummy_top()); - ct_bs->verify_dirty_region(mr); + if (hr->is_young()) { + ct_bs->verify_g1_young_region(mr); + } else { + ct_bs->verify_dirty_region(mr); + } } void G1CollectedHeap::verify_dirty_young_list(HeapRegion* head) { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); for (HeapRegion* hr = head; hr != NULL; hr = hr->get_next_young_region()) { verify_dirty_region(hr); } @@ -6053,7 +6055,7 @@ #endif void G1CollectedHeap::cleanUpCardTable() { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (barrier_set()); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); double start = os::elapsedTime(); { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -31,6 +31,7 @@ #include "gc_implementation/g1/g1HRPrinter.hpp" #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" #include "gc_implementation/g1/heapRegionSets.hpp" @@ -703,7 +704,7 @@ if (_g1_committed.contains((HeapWord*) obj)) { // no need to subtract the bottom of the heap from obj, // _in_cset_fast_test is biased - uintx index = (uintx) obj >> HeapRegion::LogOfHRGrainBytes; + uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; bool ret = _in_cset_fast_test[index]; // let's make sure the result is consistent with what the slower // test returns @@ -791,8 +792,6 @@ // The g1 remembered set of the heap. G1RemSet* _g1_rem_set; - // And it's mod ref barrier set, used to track updates for the above. - ModRefBarrierSet* _mr_bs; // A set of cards that cover the objects for which the Rsets should be updated // concurrently after the collection. @@ -1127,7 +1126,6 @@ // The rem set and barrier set. G1RemSet* g1_rem_set() const { return _g1_rem_set; } - ModRefBarrierSet* mr_bs() const { return _mr_bs; } unsigned get_gc_time_stamp() { return _gc_time_stamp; @@ -1346,6 +1344,10 @@ virtual bool is_in_closed_subset(const void* p) const; + G1SATBCardTableModRefBS* g1_barrier_set() { + return (G1SATBCardTableModRefBS*) barrier_set(); + } + // This resets the card table to all zeros. It is used after // a collection pause which used the card table to claim cards. void cleanUpCardTable(); @@ -1875,7 +1877,7 @@ G1CollectedHeap* _g1h; RefToScanQueue* _refs; DirtyCardQueue _dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; G1ParGCAllocBufferContainer _surviving_alloc_buffer; @@ -1914,7 +1916,7 @@ void add_to_undo_waste(size_t waste) { _undo_waste += waste; } DirtyCardQueue& dirty_card_queue() { return _dcq; } - CardTableModRefBS* ctbs() { return _ct_bs; } + G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } template void immediate_rs_update(HeapRegion* from, T* p, int tid) { if (!from->is_survivor()) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -29,6 +29,7 @@ #include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1AllocRegion.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "utilities/taskqueue.hpp" @@ -134,7 +135,7 @@ assert(containing_hr->is_in(end - 1), "it should also contain end - 1"); MemRegion mr(start, end); - ((CardTableModRefBS*)_g1h->barrier_set())->dirty(mr); + g1_barrier_set()->g1_mark_as_young(mr); } inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -319,10 +319,10 @@ } void G1CollectorPolicy::initialize_flags() { - set_min_alignment(HeapRegion::GrainBytes); + _min_alignment = HeapRegion::GrainBytes; size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name()); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - set_max_alignment(MAX3(card_table_alignment, min_alignment(), page_size)); + _max_alignment = MAX3(card_table_alignment, _min_alignment, page_size); if (SurvivorRatio < 1) { vm_exit_during_initialization("Invalid survivor ratio specified"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1EvacFailure.hpp --- a/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -41,11 +41,11 @@ private: G1CollectedHeap* _g1; DirtyCardQueue *_dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} + _g1(g1), _ct_bs(_g1->g1_barrier_set()), _dcq(dcq) {} virtual void do_oop(narrowOop* p) { do_oop_work(p); } virtual void do_oop( oop* p) { do_oop_work(p); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -220,7 +220,7 @@ public: G1PrepareCompactClosure(CompactibleSpace* cs) : _g1h(G1CollectedHeap::heap()), - _mrbs(G1CollectedHeap::heap()->mr_bs()), + _mrbs(_g1h->g1_barrier_set()), _cp(NULL, cs, cs->initialize_threshold()), _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1OopClosures.hpp --- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,12 +91,12 @@ } template inline T* set_partial_array_mask(T obj) { - assert(((uintptr_t)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); - return (T*) ((uintptr_t)obj | G1_PARTIAL_ARRAY_MASK); + assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); + return (T*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); } template inline oop clear_partial_array_mask(T* ref) { - return oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); + return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); } class G1ParScanPartialArrayClosure : public G1ParClosureSuper { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -83,7 +83,9 @@ for (uint i = 0; i < n_workers(); i++) { _cset_rs_update_cl[i] = NULL; } - _prev_period_summary.initialize(this, n_workers()); + if (G1SummarizeRSetStats) { + _prev_period_summary.initialize(this); + } } G1RemSet::~G1RemSet() { @@ -109,7 +111,7 @@ CodeBlobToOopClosure* _code_root_cl; G1BlockOffsetSharedArray* _bot_shared; - CardTableModRefBS *_ct_bs; + G1SATBCardTableModRefBS *_ct_bs; double _strong_code_root_scan_time_sec; int _worker_i; @@ -130,7 +132,7 @@ { _g1h = G1CollectedHeap::heap(); _bot_shared = _g1h->bot_shared(); - _ct_bs = (CardTableModRefBS*) (_g1h->barrier_set()); + _ct_bs = _g1h->g1_barrier_set(); _block_size = MAX2(G1RSetScanBlockSize, 1); } @@ -505,12 +507,7 @@ ScrubRSClosure(BitMap* region_bm, BitMap* card_bm) : _g1h(G1CollectedHeap::heap()), _region_bm(region_bm), _card_bm(card_bm), - _ctbs(NULL) - { - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ctbs = (CardTableModRefBS*)bs; - } + _ctbs(_g1h->g1_barrier_set()) {} bool doHeapRegion(HeapRegion* r) { if (!r->continuesHumongous()) { @@ -731,19 +728,19 @@ return has_refs_into_cset; } -void G1RemSet::print_periodic_summary_info() { +void G1RemSet::print_periodic_summary_info(const char* header) { G1RemSetSummary current; - current.initialize(this, n_workers()); + current.initialize(this); _prev_period_summary.subtract_from(¤t); - print_summary_info(&_prev_period_summary); + print_summary_info(&_prev_period_summary, header); _prev_period_summary.set(¤t); } void G1RemSet::print_summary_info() { G1RemSetSummary current; - current.initialize(this, n_workers()); + current.initialize(this); print_summary_info(¤t, " Cumulative RS summary"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1RemSet.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -145,7 +145,7 @@ virtual void print_summary_info(); // Print accumulated summary info from the last time called. - virtual void print_periodic_summary_info(); + virtual void print_periodic_summary_info(const char* header); // Prepare remembered set for verification. virtual void prepare_for_verify(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -77,12 +77,12 @@ return _rs_threads_vtimes[thread]; } -void G1RemSetSummary::initialize(G1RemSet* remset, uint num_workers) { +void G1RemSetSummary::initialize(G1RemSet* remset) { assert(_rs_threads_vtimes == NULL, "just checking"); assert(remset != NULL, "just checking"); _remset = remset; - _num_vtimes = num_workers; + _num_vtimes = ConcurrentG1Refine::thread_num(); _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC); memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); @@ -125,25 +125,115 @@ _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; } +static double percent_of(size_t numerator, size_t denominator) { + if (denominator != 0) { + return (double)numerator / denominator * 100.0f; + } else { + return 0.0f; + } +} + +static size_t round_to_K(size_t value) { + return value / K; +} + +class RegionTypeCounter VALUE_OBJ_CLASS_SPEC { +private: + const char* _name; + + size_t _rs_mem_size; + size_t _cards_occupied; + size_t _amount; + + size_t _code_root_mem_size; + size_t _code_root_elems; + + double rs_mem_size_percent_of(size_t total) { + return percent_of(_rs_mem_size, total); + } + + double cards_occupied_percent_of(size_t total) { + return percent_of(_cards_occupied, total); + } + + double code_root_mem_size_percent_of(size_t total) { + return percent_of(_code_root_mem_size, total); + } + + double code_root_elems_percent_of(size_t total) { + return percent_of(_code_root_elems, total); + } + + size_t amount() const { return _amount; } + +public: + + RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0), + _amount(0), _code_root_mem_size(0), _code_root_elems(0) { } + + void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size, + size_t code_root_elems) { + _rs_mem_size += rs_mem_size; + _cards_occupied += cards_occupied; + _code_root_mem_size += code_root_mem_size; + _code_root_elems += code_root_elems; + _amount++; + } + + size_t rs_mem_size() const { return _rs_mem_size; } + size_t cards_occupied() const { return _cards_occupied; } + + size_t code_root_mem_size() const { return _code_root_mem_size; } + size_t code_root_elems() const { return _code_root_elems; } + + void print_rs_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name); + } + + void print_cards_occupied_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) entries by %zd %s regions", cards_occupied(), cards_occupied_percent_of(total), amount(), _name); + } + + void print_code_root_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name); + } + + void print_code_root_elems_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) elements by %zd %s regions", code_root_elems(), code_root_elems_percent_of(total), amount(), _name); + } +}; + + class HRRSStatsIter: public HeapRegionClosure { - size_t _occupied; +private: + RegionTypeCounter _young; + RegionTypeCounter _humonguous; + RegionTypeCounter _free; + RegionTypeCounter _old; + RegionTypeCounter _all; - size_t _total_rs_mem_sz; size_t _max_rs_mem_sz; HeapRegion* _max_rs_mem_sz_region; - size_t _total_code_root_mem_sz; + size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } + size_t total_cards_occupied() const { return _all.cards_occupied(); } + + size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } + HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } + size_t _max_code_root_mem_sz; HeapRegion* _max_code_root_mem_sz_region; + + size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } + size_t total_code_root_elems() const { return _all.code_root_elems(); } + + size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } + HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } + public: - HRRSStatsIter() : - _occupied(0), - _total_rs_mem_sz(0), - _max_rs_mem_sz(0), - _max_rs_mem_sz_region(NULL), - _total_code_root_mem_sz(0), - _max_code_root_mem_sz(0), - _max_code_root_mem_sz_region(NULL) + HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"), + _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL), + _max_rs_mem_sz(0), _max_code_root_mem_sz(0) {} bool doHeapRegion(HeapRegion* r) { @@ -156,46 +246,95 @@ _max_rs_mem_sz = rs_mem_sz; _max_rs_mem_sz_region = r; } - _total_rs_mem_sz += rs_mem_sz; - + size_t occupied_cards = hrrs->occupied(); size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); - if (code_root_mem_sz > _max_code_root_mem_sz) { - _max_code_root_mem_sz = code_root_mem_sz; + if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz_region = r; } - _total_code_root_mem_sz += code_root_mem_sz; + size_t code_root_elems = hrrs->strong_code_roots_list_length(); - size_t occ = hrrs->occupied(); - _occupied += occ; + RegionTypeCounter* current = NULL; + if (r->is_young()) { + current = &_young; + } else if (r->isHumongous()) { + current = &_humonguous; + } else if (r->is_empty()) { + current = &_free; + } else { + current = &_old; + } + current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); + _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); + return false; } - size_t total_rs_mem_sz() { return _total_rs_mem_sz; } - size_t max_rs_mem_sz() { return _max_rs_mem_sz; } - HeapRegion* max_rs_mem_sz_region() { return _max_rs_mem_sz_region; } - size_t total_code_root_mem_sz() { return _total_code_root_mem_sz; } - size_t max_code_root_mem_sz() { return _max_code_root_mem_sz; } - HeapRegion* max_code_root_mem_sz_region() { return _max_code_root_mem_sz_region; } - size_t occupied() { return _occupied; } + + void print_summary_on(outputStream* out) { + RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL }; + + out->print_cr("\n Current rem set statistics"); + out->print_cr(" Total per region rem sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_rs_mem_info_on(out, total_rs_mem_sz()); + } + + out->print_cr(" Static structures = "SIZE_FORMAT"K," + " free_lists = "SIZE_FORMAT"K.", + round_to_K(HeapRegionRemSet::static_mem_size()), + round_to_K(HeapRegionRemSet::fl_mem_size())); + + out->print_cr(" "SIZE_FORMAT" occupied cards represented.", + total_cards_occupied()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_cards_occupied_info_on(out, total_cards_occupied()); + } + + // Largest sized rem set region statistics + HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); + out->print_cr(" Region with largest rem set = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", + HR_FORMAT_PARAMS(max_rs_mem_sz_region()), + round_to_K(rem_set->mem_size()), + round_to_K(rem_set->occupied())); + + // Strong code root statistics + HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); + out->print_cr(" Total heap region code root sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_code_root_mem_sz()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); + } + + out->print_cr(" "SIZE_FORMAT" code roots represented.", + total_code_root_elems()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_elems_info_on(out, total_code_root_elems()); + } + + out->print_cr(" Region with largest amount of code roots = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", + HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()), + round_to_K(max_code_root_rem_set->strong_code_roots_list_length())); + } }; -double calc_percentage(size_t numerator, size_t denominator) { - if (denominator != 0) { - return (double)numerator / denominator * 100.0; - } else { - return 0.0f; - } -} - void G1RemSetSummary::print_on(outputStream* out) { - out->print_cr("\n Concurrent RS processed "SIZE_FORMAT" cards", + out->print_cr("\n Recent concurrent refinement statistics"); + out->print_cr(" Processed "SIZE_FORMAT" cards", num_concurrent_refined_cards()); out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", num_processed_buf_total(), - calc_percentage(num_processed_buf_rs_threads(), num_processed_buf_total())); + percent_of(num_processed_buf_rs_threads(), num_processed_buf_total())); out->print_cr(" %8d (%5.1f%%) by mutator threads.", num_processed_buf_mutator(), - calc_percentage(num_processed_buf_mutator(), num_processed_buf_total())); + percent_of(num_processed_buf_mutator(), num_processed_buf_total())); + out->print_cr(" Did %d coarsenings.", num_coarsenings()); out->print_cr(" Concurrent RS threads times (s)"); out->print(" "); for (uint i = 0; i < _num_vtimes; i++) { @@ -207,33 +346,5 @@ HRRSStatsIter blk; G1CollectedHeap::heap()->heap_region_iterate(&blk); - // RemSet stats - out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_rs_mem_sz()/K, blk.max_rs_mem_sz()/K); - out->print_cr(" Static structures = "SIZE_FORMAT"K," - " free_lists = "SIZE_FORMAT"K.", - HeapRegionRemSet::static_mem_size() / K, - HeapRegionRemSet::fl_mem_size() / K); - out->print_cr(" "SIZE_FORMAT" occupied cards represented.", - blk.occupied()); - HeapRegion* max_rs_mem_sz_region = blk.max_rs_mem_sz_region(); - HeapRegionRemSet* max_rs_rem_set = max_rs_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", - HR_FORMAT_PARAMS(max_rs_mem_sz_region), - (max_rs_rem_set->mem_size() + K - 1)/K, - (max_rs_rem_set->occupied() + K - 1)/K); - out->print_cr(" Did %d coarsenings.", num_coarsenings()); - // Strong code root stats - out->print_cr(" Total heap region code-root set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_code_root_mem_sz()/K, blk.max_code_root_mem_sz()/K); - HeapRegion* max_code_root_mem_sz_region = blk.max_code_root_mem_sz_region(); - HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", - HR_FORMAT_PARAMS(max_code_root_mem_sz_region), - (max_code_root_rem_set->strong_code_roots_mem_size() + K - 1)/K, - (max_code_root_rem_set->strong_code_roots_list_length())); + blk.print_summary_on(out); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -84,7 +84,7 @@ void subtract_from(G1RemSetSummary* other); // initialize and get the first sampling - void initialize(G1RemSet* remset, uint num_workers); + void initialize(G1RemSet* remset); void print_on(outputStream* out); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,46 @@ } } +bool G1SATBCardTableModRefBS::mark_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + // It's already processed + if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { + return false; + } + + if (val == g1_young_gen) { + // the card is for a young gen region. We don't need to keep track of all pointers into young + return false; + } + + // Cached bit can be installed either on a clean card or on a claimed card. + jbyte new_val = val; + if (val == clean_card_val()) { + new_val = (jbyte)deferred_card_val(); + } else { + if (val & claimed_card_val()) { + new_val = val | (jbyte)deferred_card_val(); + } + } + if (new_val != val) { + Atomic::cmpxchg(new_val, &_byte_map[card_index], val); + } + return true; +} + +void G1SATBCardTableModRefBS::g1_mark_as_young(const MemRegion& mr) { + jbyte *const first = byte_for(mr.start()); + jbyte *const last = byte_after(mr.last()); + + memset(first, g1_young_gen, last - first); +} + +#ifndef PRODUCT +void G1SATBCardTableModRefBS::verify_g1_young_region(MemRegion mr) { + verify_region(mr, g1_young_gen, true); +} +#endif + G1SATBCardTableLoggingModRefBS:: G1SATBCardTableLoggingModRefBS(MemRegion whole_heap, int max_covered_regions) : @@ -76,7 +116,11 @@ void G1SATBCardTableLoggingModRefBS::write_ref_field_work(void* field, oop new_val) { - jbyte* byte = byte_for(field); + volatile jbyte* byte = byte_for(field); + if (*byte == g1_young_gen) { + return; + } + OrderAccess::storeload(); if (*byte != dirty_card) { *byte = dirty_card; Thread* thr = Thread::current(); @@ -95,7 +139,7 @@ G1SATBCardTableLoggingModRefBS::write_ref_field_static(void* field, oop new_val) { uintptr_t field_uint = (uintptr_t)field; - uintptr_t new_val_uint = (uintptr_t)new_val; + uintptr_t new_val_uint = cast_from_oop(new_val); uintptr_t comb = field_uint ^ new_val_uint; comb = comb >> HeapRegion::LogOfHRGrainBytes; if (comb == 0) return; @@ -108,7 +152,7 @@ void G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) { - jbyte* byte = byte_for(mr.start()); + volatile jbyte* byte = byte_for(mr.start()); jbyte* last_byte = byte_for(mr.last()); Thread* thr = Thread::current(); if (whole_heap) { @@ -117,25 +161,35 @@ byte++; } } else { - // Enqueue if necessary. - if (thr->is_Java_thread()) { - JavaThread* jt = (JavaThread*)thr; - while (byte <= last_byte) { - if (*byte != dirty_card) { - *byte = dirty_card; - jt->dirty_card_queue().enqueue(byte); + // skip all consecutive young cards + for (; byte <= last_byte && *byte == g1_young_gen; byte++); + + if (byte <= last_byte) { + OrderAccess::storeload(); + // Enqueue if necessary. + if (thr->is_Java_thread()) { + JavaThread* jt = (JavaThread*)thr; + for (; byte <= last_byte; byte++) { + if (*byte == g1_young_gen) { + continue; + } + if (*byte != dirty_card) { + *byte = dirty_card; + jt->dirty_card_queue().enqueue(byte); + } } - byte++; - } - } else { - MutexLockerEx x(Shared_DirtyCardQ_lock, - Mutex::_no_safepoint_check_flag); - while (byte <= last_byte) { - if (*byte != dirty_card) { - *byte = dirty_card; - _dcqs.shared_dirty_card_queue()->enqueue(byte); + } else { + MutexLockerEx x(Shared_DirtyCardQ_lock, + Mutex::_no_safepoint_check_flag); + for (; byte <= last_byte; byte++) { + if (*byte == g1_young_gen) { + continue; + } + if (*byte != dirty_card) { + *byte = dirty_card; + _dcqs.shared_dirty_card_queue()->enqueue(byte); + } } - byte++; } } } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -38,7 +38,14 @@ // snapshot-at-the-beginning marking. class G1SATBCardTableModRefBS: public CardTableModRefBSForCTRS { +protected: + enum G1CardValues { + g1_young_gen = CT_MR_BS_last_reserved << 1 + }; + public: + static int g1_young_card_val() { return g1_young_gen; } + // Add "pre_val" to a set of objects that may have been disconnected from the // pre-marking object graph. static void enqueue(oop pre_val); @@ -89,6 +96,45 @@ write_ref_array_pre_work(dst, count); } } + +/* + Claimed and deferred bits are used together in G1 during the evacuation + pause. These bits can have the following state transitions: + 1. The claimed bit can be put over any other card state. Except that + the "dirty -> dirty and claimed" transition is checked for in + G1 code and is not used. + 2. Deferred bit can be set only if the previous state of the card + was either clean or claimed. mark_card_deferred() is wait-free. + We do not care if the operation is be successful because if + it does not it will only result in duplicate entry in the update + buffer because of the "cache-miss". So it's not worth spinning. + */ + + bool is_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); + } + + void set_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + if (val == clean_card_val()) { + val = (jbyte)claimed_card_val(); + } else { + val |= (jbyte)claimed_card_val(); + } + _byte_map[card_index] = val; + } + + void verify_g1_young_region(MemRegion mr) PRODUCT_RETURN; + void g1_mark_as_young(const MemRegion& mr); + + bool mark_card_deferred(size_t card_index); + + bool is_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); + } + }; // Adds card-table logging to the post-barrier. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -637,7 +637,7 @@ gclog_or_tty->print_cr("Object "PTR_FORMAT" in region " "["PTR_FORMAT", "PTR_FORMAT") is above " "top "PTR_FORMAT, - obj, _hr->bottom(), _hr->end(), _hr->top()); + (void *)obj, _hr->bottom(), _hr->end(), _hr->top()); _failures = true; return; } @@ -951,12 +951,12 @@ Klass* klass = obj->klass(); if (!klass->is_metaspace_object()) { gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " - "not metadata", klass, obj); + "not metadata", klass, (void *)obj); *failures = true; return; } else if (!klass->is_klass()) { gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " - "not a klass", klass, obj); + "not a klass", klass, (void *)obj); *failures = true; return; } else { @@ -971,7 +971,7 @@ } } } else { - gclog_or_tty->print_cr(PTR_FORMAT" no an oop", obj); + gclog_or_tty->print_cr(PTR_FORMAT" no an oop", (void *)obj); *failures = true; return; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -91,8 +91,8 @@ gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").", from, UseCompressedOops - ? oopDesc::load_decode_heap_oop((narrowOop*)from) - : oopDesc::load_decode_heap_oop((oop*)from)); + ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from) + : (void *)oopDesc::load_decode_heap_oop((oop*)from)); } HeapRegion* loc_hr = hr(); @@ -403,8 +403,8 @@ gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").", from, UseCompressedOops - ? oopDesc::load_decode_heap_oop((narrowOop*)from) - : oopDesc::load_decode_heap_oop((oop*)from)); + ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from) + : (void *)oopDesc::load_decode_heap_oop((oop*)from)); } int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/g1/ptrQueue.hpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -80,6 +80,10 @@ void reset() { if (_buf != NULL) _index = _sz; } + void enqueue(volatile void* ptr) { + enqueue((void*)(ptr)); + } + // Enqueues the given "obj". void enqueue(void* ptr) { if (!_active) return; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1103,7 +1103,7 @@ } } -static const oop ClaimedForwardPtr = oop(0x4); +static const oop ClaimedForwardPtr = cast_to_oop(0x4); // Because of concurrency, there are times where an object for which // "is_forwarded()" is true contains an "interim" forwarding pointer @@ -1226,7 +1226,7 @@ if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", is_in_reserved(new_obj) ? "copying" : "tenuring", - new_obj->klass()->internal_name(), old, new_obj, new_obj->size()); + new_obj->klass()->internal_name(), (void *)old, (void *)new_obj, new_obj->size()); } #endif @@ -1347,7 +1347,7 @@ if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", is_in_reserved(new_obj) ? "copying" : "tenuring", - new_obj->klass()->internal_name(), old, new_obj, new_obj->size()); + new_obj->klass()->internal_name(), (void *)old, (void *)new_obj, new_obj->size()); } #endif @@ -1436,7 +1436,7 @@ // (although some performance comparisons would be useful since // single global lists have their own performance disadvantages // as we were made painfully aware not long ago, see 6786503). -#define BUSY (oop(0x1aff1aff)) +#define BUSY (cast_to_oop(0x1aff1aff)) void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) { assert(is_in_reserved(from_space_obj), "Should be from this generation"); if (ParGCUseLocalOverflow) { @@ -1512,7 +1512,7 @@ if (_overflow_list == NULL) return false; // Otherwise, there was something there; try claiming the list. - oop prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); + oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); // Trim off a prefix of at most objsFromOverflow items Thread* tid = Thread::current(); size_t spin_count = (size_t)ParallelGCThreads; @@ -1526,7 +1526,7 @@ return false; } else if (_overflow_list != BUSY) { // try and grab the prefix - prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); + prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); } } if (prefix == NULL || prefix == BUSY) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp --- a/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ Space* sp = gch->space_containing(p); oop obj = oop(sp->block_start(p)); assert((HeapWord*)obj < (HeapWord*)p, "Error"); - tty->print_cr("Object: " PTR_FORMAT, obj); + tty->print_cr("Object: " PTR_FORMAT, (void *)obj); tty->print_cr("-------"); obj->print(); tty->print_cr("-----"); @@ -110,7 +110,7 @@ if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", "forwarded ", - new_obj->klass()->internal_name(), p, obj, new_obj, new_obj->size()); + new_obj->klass()->internal_name(), p, (void *)obj, (void *)new_obj, new_obj->size()); } #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -40,10 +40,8 @@ void initialize_flags() { // Do basic sizing work - this->TwoGenerationCollectorPolicy::initialize_flags(); + TwoGenerationCollectorPolicy::initialize_flags(); - // If the user hasn't explicitly set the number of worker - // threads, set the count. assert(UseSerialGC || !FLAG_IS_DEFAULT(ParallelGCThreads) || (ParallelGCThreads > 0), diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -53,7 +53,6 @@ // Forward decls class elapsedTimer; -class GenerationSizer; class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { friend class PSGCAdaptivePolicyCounters; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -26,7 +26,6 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -27,7 +27,6 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/parallelScavenge/pcTasks.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -333,7 +333,7 @@ gclog_or_tty->print_cr("{%s %s 0x%x (%d)}", "promotion-failure", obj->klass()->internal_name(), - obj, obj->size()); + (void *)obj, obj->size()); } #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -126,7 +126,7 @@ oop* mask_chunked_array_oop(oop obj) { assert(!is_oop_masked((oop*) obj), "invariant"); - oop* ret = (oop*) ((uintptr_t)obj | PS_CHUNKED_ARRAY_OOP_MASK); + oop* ret = (oop*) (cast_from_oop(obj) | PS_CHUNKED_ARRAY_OOP_MASK); assert(is_oop_masked(ret), "invariant"); return ret; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -225,7 +225,7 @@ if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", PSScavenge::should_scavenge(&new_obj) ? "copying" : "tenuring", - new_obj->klass()->internal_name(), o, new_obj, new_obj->size()); + new_obj->klass()->internal_name(), (void *)o, (void *)new_obj, new_obj->size()); } #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -27,7 +27,6 @@ #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ if (TraceScavenge && o->is_forwarded()) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", "forwarding", - new_obj->klass()->internal_name(), o, new_obj, new_obj->size()); + new_obj->klass()->internal_name(), (void *)o, (void *)new_obj, new_obj->size()); } #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -214,9 +214,6 @@ : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true), _loader_data(loader_data), _size(size), _mdtype(mdtype), _result(NULL) { } - ~VM_CollectForMetadataAllocation() { - MetaspaceGC::set_expand_after_GC(false); - } virtual VMOp_Type type() const { return VMOp_CollectForMetadataAllocation; } virtual void doit(); MetaWord* result() const { return _result; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_interface/collectedHeap.cpp --- a/src/share/vm/gc_interface/collectedHeap.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -202,12 +202,6 @@ ShouldNotReachHere(); // Unexpected use of this function } } -MetaWord* CollectedHeap::satisfy_failed_metadata_allocation( - ClassLoaderData* loader_data, - size_t size, Metaspace::MetadataType mdtype) { - return collector_policy()->satisfy_failed_metadata_allocation(loader_data, size, mdtype); -} - void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -475,11 +475,6 @@ // the context of the vm thread. virtual void collect_as_vm_thread(GCCause::Cause cause); - // Callback from VM_CollectForMetadataAllocation operation. - MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, - size_t size, - Metaspace::MetadataType mdtype); - // Returns the barrier set for this heap BarrierSet* barrier_set() { return _barrier_set; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/interpreter/bytecodeTracer.cpp --- a/src/share/vm/interpreter/bytecodeTracer.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/interpreter/bytecodeTracer.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -215,7 +215,7 @@ st->print_cr(" %s", buf); } } else { - st->print_cr(" " PTR_FORMAT, (intptr_t) value); + st->print_cr(" " PTR_FORMAT, (void *)value); } } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/interpreter/linkResolver.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -222,8 +222,17 @@ // // According to JVM spec. $5.4.3c & $5.4.3d +// Look up method in klasses, including static methods +// Then look up local default methods void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { Method* result_oop = klass->uncached_lookup_method(name, signature); + if (result_oop == NULL) { + Array* default_methods = InstanceKlass::cast(klass())->default_methods(); + if (default_methods != NULL) { + result_oop = InstanceKlass::find_method(default_methods, name, signature); + } + } + if (EnableInvokeDynamic && result_oop != NULL) { vmIntrinsics::ID iid = result_oop->intrinsic_id(); if (MethodHandles::is_signature_polymorphic(iid)) { @@ -235,6 +244,7 @@ } // returns first instance method +// Looks up method in classes, then looks up local default methods void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { Method* result_oop = klass->uncached_lookup_method(name, signature); result = methodHandle(THREAD, result_oop); @@ -242,13 +252,38 @@ klass = KlassHandle(THREAD, result->method_holder()->super()); result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature)); } + + if (result.is_null()) { + Array* default_methods = InstanceKlass::cast(klass())->default_methods(); + if (default_methods != NULL) { + result = methodHandle(InstanceKlass::find_method(default_methods, name, signature)); + assert(result.is_null() || !result->is_static(), "static defaults not allowed"); + } + } } +int LinkResolver::vtable_index_of_interface_method(KlassHandle klass, + methodHandle resolved_method, TRAPS) { -int LinkResolver::vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { - ResourceMark rm(THREAD); - klassVtable *vt = InstanceKlass::cast(klass())->vtable(); - return vt->index_of_miranda(name, signature); + int vtable_index = Method::invalid_vtable_index; + Symbol* name = resolved_method->name(); + Symbol* signature = resolved_method->signature(); + + // First check in default method array + if (!resolved_method->is_abstract() && + (InstanceKlass::cast(klass())->default_methods() != NULL)) { + int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature); + if (index >= 0 ) { + vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index); + } + } + if (vtable_index == Method::invalid_vtable_index) { + // get vtable_index for miranda methods + ResourceMark rm(THREAD); + klassVtable *vt = InstanceKlass::cast(klass())->vtable(); + vtable_index = vt->index_of_miranda(name, signature); + } + return vtable_index; } void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { @@ -573,6 +608,16 @@ } if (check_access) { + // JDK8 adds non-public interface methods, and accessability check requirement + assert(current_klass.not_null() , "current_klass should not be null"); + + // check if method can be accessed by the referring class + check_method_accessability(current_klass, + resolved_klass, + KlassHandle(THREAD, resolved_method->method_holder()), + resolved_method, + CHECK); + HandleMark hm(THREAD); Handle loader (THREAD, InstanceKlass::cast(current_klass())->class_loader()); Handle class_loader (THREAD, resolved_method->method_holder()->class_loader()); @@ -604,6 +649,26 @@ } } } + + if (TraceItables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokeinterface resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", + (current_klass.is_null() ? "" : current_klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + resolved_method->method_holder()->internal_name() + ); + resolved_method->access_flags().print_on(tty); + if (resolved_method->is_default_method()) { + tty->print("default"); + } + if (resolved_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } } //------------------------------------------------------------------------------------------------------------------------ @@ -795,26 +860,12 @@ Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { - if (resolved_klass->is_interface() && current_klass() != NULL) { - // If the target class is a direct interface, treat this as a "super" - // default call. - // - // If the current method is an overpass that happens to call a direct - // super-interface's method, then we'll end up rerunning the default method - // analysis even though we don't need to, but that's ok since it will end - // up with the same answer. - InstanceKlass* ik = InstanceKlass::cast(current_klass()); - Array* interfaces = ik->local_interfaces(); - int num_interfaces = interfaces->length(); - for (int index = 0; index < num_interfaces; index++) { - if (interfaces->at(index) == resolved_klass()) { - Method* method = DefaultMethods::find_super_default(current_klass(), - resolved_klass(), method_name, method_signature, CHECK); - resolved_method = methodHandle(THREAD, method); - return; - } - } - } + // Invokespecial is called for multiple special reasons: + // + // local private method invocation, for classes and interfaces + // superclass.method, which can also resolve to a default method + // and the selected method is recalculated relative to the direct superclass + // superinterface.method, which explicitly does not check shadowing resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); @@ -844,6 +895,26 @@ resolved_method->signature())); THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + + if (TraceItables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", + (current_klass.is_null() ? "" : current_klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + resolved_method->method_holder()->internal_name() + ); + resolved_method->access_flags().print_on(tty); + if (resolved_method->is_default_method()) { + tty->print("default"); + } + if (resolved_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } } // throws runtime exceptions @@ -851,23 +922,24 @@ KlassHandle current_klass, bool check_access, TRAPS) { // resolved method is selected method unless we have an old-style lookup + // for a superclass method + // Invokespecial for a superinterface, resolved method is selected method, + // no checks for shadowing methodHandle sel_method(THREAD, resolved_method()); // check if this is an old-style super call and do a new lookup if so { KlassHandle method_klass = KlassHandle(THREAD, resolved_method->method_holder()); - const bool direct_calling_default_method = - resolved_klass() != NULL && resolved_method() != NULL && - resolved_klass->is_interface() && !resolved_method->is_abstract(); - - if (!direct_calling_default_method && - check_access && + if (check_access && // a) check if ACC_SUPER flag is set for the current class (current_klass->is_super() || !AllowNonVirtualCalls) && - // b) check if the method class is a superclass of the current class (superclass relation is not reflexive!) - current_klass->is_subtype_of(method_klass()) && - current_klass() != method_klass() && + // b) check if the class of the resolved_klass is a superclass + // (not supertype in order to exclude interface classes) of the current class. + // This check is not performed for super.invoke for interface methods + // in super interfaces. + current_klass->is_subclass_of(resolved_klass()) && + current_klass() != resolved_klass() && // c) check if the method is not resolved_method->name() != vmSymbols::object_initializer_name()) { // Lookup super method @@ -905,6 +977,25 @@ sel_method->signature())); } + if (TraceItables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokespecial selected method: resolved-class:%s, method:%s, method_holder:%s, access_flags: ", + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + sel_method->name(), + sel_method->signature()), + sel_method->method_holder()->internal_name() + ); + sel_method->access_flags().print_on(tty); + if (sel_method->is_default_method()) { + tty->print("default"); + } + if (sel_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } + // setup result result.set_static(resolved_klass, sel_method, CHECK); } @@ -927,6 +1018,18 @@ assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier"); assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier"); + // check if private interface method + if (resolved_klass->is_interface() && resolved_method->is_private()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s", + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + (current_klass.is_null() ? "" : current_klass->internal_name())); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + // check if not static if (resolved_method->is_static()) { ResourceMark rm(THREAD); @@ -936,6 +1039,26 @@ resolved_method->signature())); THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + + if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", + (current_klass.is_null() ? "" : current_klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + resolved_method->method_holder()->internal_name() + ); + resolved_method->access_flags().print_on(tty); + if (resolved_method->is_default_method()) { + tty->print("default"); + } + if (resolved_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } } // throws runtime exceptions @@ -965,10 +1088,8 @@ // do lookup based on receiver klass using the vtable index if (resolved_method->method_holder()->is_interface()) { // miranda method - vtable_index = vtable_index_of_miranda_method(resolved_klass, - resolved_method->name(), - resolved_method->signature(), CHECK); - + vtable_index = vtable_index_of_interface_method(resolved_klass, + resolved_method, CHECK); assert(vtable_index >= 0 , "we should have valid vtable index at this point"); InstanceKlass* inst = InstanceKlass::cast(recv_klass()); @@ -1012,6 +1133,26 @@ selected_method->signature())); } + if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokevirtual selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, vtable_index:%d, access_flags: ", + (recv_klass.is_null() ? "" : recv_klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + selected_method->method_holder()->internal_name(), + vtable_index + ); + selected_method->access_flags().print_on(tty); + if (selected_method->is_default_method()) { + tty->print("default"); + } + if (selected_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } // setup result result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK); } @@ -1042,6 +1183,17 @@ THROW(vmSymbols::java_lang_NullPointerException()); } + // check if private interface method + if (resolved_klass->is_interface() && resolved_method->is_private()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokeinterface: method %s", + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature())); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + // check if receiver klass implements the resolved interface if (!recv_klass->is_subtype_of(resolved_klass())) { ResourceMark rm(THREAD); @@ -1071,27 +1223,13 @@ resolved_method->signature())); } // check access - if (sel_method->method_holder()->is_interface()) { - // Method holder is an interface. Throw Illegal Access Error if sel_method - // is neither public nor private. - if (!(sel_method->is_public() || sel_method->is_private())) { - ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), - Method::name_and_sig_as_C_string(recv_klass(), - sel_method->name(), - sel_method->signature())); - } - } - else { - // Method holder is a class. Throw Illegal Access Error if sel_method - // is not public. - if (!sel_method->is_public()) { - ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), - Method::name_and_sig_as_C_string(recv_klass(), - sel_method->name(), - sel_method->signature())); - } + // Throw Illegal Access Error if sel_method is not public. + if (!sel_method->is_public()) { + ResourceMark rm(THREAD); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), + Method::name_and_sig_as_C_string(recv_klass(), + sel_method->name(), + sel_method->signature())); } // check if abstract if (check_null_and_abstract && sel_method->is_abstract()) { @@ -1109,6 +1247,26 @@ return; } int itable_index = resolved_method()->itable_index(); + + if (TraceItables && Verbose) { + ResourceMark rm(THREAD); + tty->print("invokeinterface selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, access_flags: ", + (recv_klass.is_null() ? "" : recv_klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), + resolved_method->signature()), + sel_method->method_holder()->internal_name() + ); + sel_method->access_flags().print_on(tty); + if (sel_method->is_default_method()) { + tty->print("default"); + } + if (sel_method->is_overpass()) { + tty->print("overpass"); + } + tty->cr(); + } result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK); } @@ -1384,7 +1542,7 @@ THREAD); if (HAS_PENDING_EXCEPTION) { if (TraceMethodHandles) { - tty->print_cr("invokedynamic throws BSME for "INTPTR_FORMAT, PENDING_EXCEPTION); + tty->print_cr("invokedynamic throws BSME for "INTPTR_FORMAT, (void *)PENDING_EXCEPTION); PENDING_EXCEPTION->print(); } if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/interpreter/linkResolver.hpp --- a/src/share/vm/interpreter/linkResolver.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/interpreter/linkResolver.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -130,8 +130,7 @@ static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); - static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); - + static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method, TRAPS); static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -423,60 +423,6 @@ inline_write_ref_field(field, newVal); } -/* - Claimed and deferred bits are used together in G1 during the evacuation - pause. These bits can have the following state transitions: - 1. The claimed bit can be put over any other card state. Except that - the "dirty -> dirty and claimed" transition is checked for in - G1 code and is not used. - 2. Deferred bit can be set only if the previous state of the card - was either clean or claimed. mark_card_deferred() is wait-free. - We do not care if the operation is be successful because if - it does not it will only result in duplicate entry in the update - buffer because of the "cache-miss". So it's not worth spinning. - */ - - -bool CardTableModRefBS::claim_card(size_t card_index) { - jbyte val = _byte_map[card_index]; - assert(val != dirty_card_val(), "Shouldn't claim a dirty card"); - while (val == clean_card_val() || - (val & (clean_card_mask_val() | claimed_card_val())) != claimed_card_val()) { - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)claimed_card_val(); - } else { - new_val = val | (jbyte)claimed_card_val(); - } - jbyte res = Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - if (res == val) { - return true; - } - val = res; - } - return false; -} - -bool CardTableModRefBS::mark_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - // It's already processed - if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { - return false; - } - // Cached bit can be installed either on a clean card or on a claimed card. - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)deferred_card_val(); - } else { - if (val & claimed_card_val()) { - new_val = val | (jbyte)deferred_card_val(); - } - } - if (new_val != val) { - Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - } - return true; -} void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr, diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/cardTableModRefBS.hpp --- a/src/share/vm/memory/cardTableModRefBS.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/cardTableModRefBS.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -339,34 +339,10 @@ _byte_map[card_index] = dirty_card_val(); } - bool is_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); - } - - void set_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - if (val == clean_card_val()) { - val = (jbyte)claimed_card_val(); - } else { - val |= (jbyte)claimed_card_val(); - } - _byte_map[card_index] = val; - } - - bool claim_card(size_t card_index); - bool is_card_clean(size_t card_index) { return _byte_map[card_index] == clean_card_val(); } - bool is_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); - } - - bool mark_card_deferred(size_t card_index); - // Card marking array base (adjusted for heap low boundary) // This would be the 0th element of _byte_map, if the heap started at 0x0. // But since the heap starts at some higher address, this points to somewhere diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/collectorPolicy.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -47,83 +47,53 @@ // CollectorPolicy methods. -// Align down. If the aligning result in 0, return 'alignment'. -static size_t restricted_align_down(size_t size, size_t alignment) { - return MAX2(alignment, align_size_down_(size, alignment)); -} - void CollectorPolicy::initialize_flags() { - assert(max_alignment() >= min_alignment(), - err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT, - max_alignment(), min_alignment())); - assert(max_alignment() % min_alignment() == 0, - err_msg("max_alignment: " SIZE_FORMAT " not aligned by min_alignment: " SIZE_FORMAT, - max_alignment(), min_alignment())); + assert(_max_alignment >= _min_alignment, + err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT, + _max_alignment, _min_alignment)); + assert(_max_alignment % _min_alignment == 0, + err_msg("max_alignment: " SIZE_FORMAT " not aligned by min_alignment: " SIZE_FORMAT, + _max_alignment, _min_alignment)); if (MaxHeapSize < InitialHeapSize) { vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); } - if (!is_size_aligned(MaxMetaspaceSize, max_alignment())) { - FLAG_SET_ERGO(uintx, MaxMetaspaceSize, - restricted_align_down(MaxMetaspaceSize, max_alignment())); - } - - if (MetaspaceSize > MaxMetaspaceSize) { - FLAG_SET_ERGO(uintx, MetaspaceSize, MaxMetaspaceSize); - } - - if (!is_size_aligned(MetaspaceSize, min_alignment())) { - FLAG_SET_ERGO(uintx, MetaspaceSize, - restricted_align_down(MetaspaceSize, min_alignment())); - } - - assert(MetaspaceSize <= MaxMetaspaceSize, "Must be"); - - MinMetaspaceExpansion = restricted_align_down(MinMetaspaceExpansion, min_alignment()); - MaxMetaspaceExpansion = restricted_align_down(MaxMetaspaceExpansion, min_alignment()); - - MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, min_alignment()); - - assert(MetaspaceSize % min_alignment() == 0, "metapace alignment"); - assert(MaxMetaspaceSize % max_alignment() == 0, "maximum metaspace alignment"); - if (MetaspaceSize < 256*K) { - vm_exit_during_initialization("Too small initial Metaspace size"); - } + MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, _min_alignment); } void CollectorPolicy::initialize_size_info() { // User inputs from -mx and ms must be aligned - set_min_heap_byte_size(align_size_up(Arguments::min_heap_size(), min_alignment())); - set_initial_heap_byte_size(align_size_up(InitialHeapSize, min_alignment())); - set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment())); + _min_heap_byte_size = align_size_up(Arguments::min_heap_size(), _min_alignment); + _initial_heap_byte_size = align_size_up(InitialHeapSize, _min_alignment); + _max_heap_byte_size = align_size_up(MaxHeapSize, _max_alignment); // Check heap parameter properties - if (initial_heap_byte_size() < M) { + if (_initial_heap_byte_size < M) { vm_exit_during_initialization("Too small initial heap"); } // Check heap parameter properties - if (min_heap_byte_size() < M) { + if (_min_heap_byte_size < M) { vm_exit_during_initialization("Too small minimum heap"); } - if (initial_heap_byte_size() <= NewSize) { + if (_initial_heap_byte_size <= NewSize) { // make sure there is at least some room in old space vm_exit_during_initialization("Too small initial heap for new size specified"); } - if (max_heap_byte_size() < min_heap_byte_size()) { + if (_max_heap_byte_size < _min_heap_byte_size) { vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); } - if (initial_heap_byte_size() < min_heap_byte_size()) { + if (_initial_heap_byte_size < _min_heap_byte_size) { vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); } - if (max_heap_byte_size() < initial_heap_byte_size()) { + if (_max_heap_byte_size < _initial_heap_byte_size) { vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); } if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " SIZE_FORMAT " Maximum heap " SIZE_FORMAT, - min_heap_byte_size(), initial_heap_byte_size(), max_heap_byte_size()); + _min_heap_byte_size, _initial_heap_byte_size, _max_heap_byte_size); } } @@ -135,15 +105,8 @@ GenRemSet* CollectorPolicy::create_rem_set(MemRegion whole_heap, int max_covered_regions) { - switch (rem_set_name()) { - case GenRemSet::CardTable: { - CardTableRS* res = new CardTableRS(whole_heap, max_covered_regions); - return res; - } - default: - guarantee(false, "unrecognized GenRemSet::Name"); - return NULL; - } + assert(rem_set_name() == GenRemSet::CardTable, "unrecognized GenRemSet::Name"); + return new CardTableRS(whole_heap, max_covered_regions); } void CollectorPolicy::cleared_all_soft_refs() { @@ -185,15 +148,15 @@ size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { size_t x = base_size / (NewRatio+1); - size_t new_gen_size = x > min_alignment() ? - align_size_down(x, min_alignment()) : - min_alignment(); + size_t new_gen_size = x > _min_alignment ? + align_size_down(x, _min_alignment) : + _min_alignment; return new_gen_size; } size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, size_t maximum_size) { - size_t alignment = min_alignment(); + size_t alignment = _min_alignment; size_t max_minus = maximum_size - alignment; return desired_size < max_minus ? desired_size : max_minus; } @@ -212,8 +175,8 @@ void GenCollectorPolicy::initialize_flags() { // All sizes must be multiples of the generation granularity. - set_min_alignment((uintx) Generation::GenGrain); - set_max_alignment(compute_max_alignment()); + _min_alignment = (uintx) Generation::GenGrain; + _max_alignment = compute_max_alignment(); CollectorPolicy::initialize_flags(); @@ -223,26 +186,26 @@ if (NewSize > MaxNewSize) { MaxNewSize = NewSize; } - NewSize = align_size_down(NewSize, min_alignment()); - MaxNewSize = align_size_down(MaxNewSize, min_alignment()); + NewSize = align_size_down(NewSize, _min_alignment); + MaxNewSize = align_size_down(MaxNewSize, _min_alignment); // Check validity of heap flags - assert(NewSize % min_alignment() == 0, "eden space alignment"); - assert(MaxNewSize % min_alignment() == 0, "survivor space alignment"); + assert(NewSize % _min_alignment == 0, "eden space alignment"); + assert(MaxNewSize % _min_alignment == 0, "survivor space alignment"); - if (NewSize < 3*min_alignment()) { + if (NewSize < 3 * _min_alignment) { // make sure there room for eden and two survivor spaces vm_exit_during_initialization("Too small new size specified"); } if (SurvivorRatio < 1 || NewRatio < 1) { - vm_exit_during_initialization("Invalid heap ratio specified"); + vm_exit_during_initialization("Invalid young gen ratio specified"); } } void TwoGenerationCollectorPolicy::initialize_flags() { GenCollectorPolicy::initialize_flags(); - OldSize = align_size_down(OldSize, min_alignment()); + OldSize = align_size_down(OldSize, _min_alignment); if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) { // NewRatio will be used later to set the young generation size so we use @@ -251,11 +214,11 @@ assert(NewRatio > 0, "NewRatio should have been set up earlier"); size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); - calculated_heapsize = align_size_up(calculated_heapsize, max_alignment()); + calculated_heapsize = align_size_up(calculated_heapsize, _max_alignment); MaxHeapSize = calculated_heapsize; InitialHeapSize = calculated_heapsize; } - MaxHeapSize = align_size_up(MaxHeapSize, max_alignment()); + MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); // adjust max heap size if necessary if (NewSize + OldSize > MaxHeapSize) { @@ -265,18 +228,18 @@ uintx calculated_size = NewSize + OldSize; double shrink_factor = (double) MaxHeapSize / calculated_size; // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), min_alignment()); + NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); // OldSize is already aligned because above we aligned MaxHeapSize to - // max_alignment(), and we just made sure that NewSize is aligned to - // min_alignment(). In initialize_flags() we verified that max_alignment() - // is a multiple of min_alignment(). + // _max_alignment, and we just made sure that NewSize is aligned to + // _min_alignment. In initialize_flags() we verified that _max_alignment + // is a multiple of _min_alignment. OldSize = MaxHeapSize - NewSize; } else { MaxHeapSize = NewSize + OldSize; } } // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, max_alignment()); + MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); // adjust max heap size if necessary if (NewSize + OldSize > MaxHeapSize) { @@ -286,24 +249,24 @@ uintx calculated_size = NewSize + OldSize; double shrink_factor = (double) MaxHeapSize / calculated_size; // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), min_alignment()); + NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); // OldSize is already aligned because above we aligned MaxHeapSize to - // max_alignment(), and we just made sure that NewSize is aligned to - // min_alignment(). In initialize_flags() we verified that max_alignment() - // is a multiple of min_alignment(). + // _max_alignment, and we just made sure that NewSize is aligned to + // _min_alignment. In initialize_flags() we verified that _max_alignment + // is a multiple of _min_alignment. OldSize = MaxHeapSize - NewSize; } else { MaxHeapSize = NewSize + OldSize; } } // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, max_alignment()); + MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); always_do_update_barrier = UseConcMarkSweepGC; // Check validity of heap flags - assert(OldSize % min_alignment() == 0, "old space alignment"); - assert(MaxHeapSize % max_alignment() == 0, "maximum heap alignment"); + assert(OldSize % _min_alignment == 0, "old space alignment"); + assert(MaxHeapSize % _max_alignment == 0, "maximum heap alignment"); } // Values set on the command line win over any ergonomically @@ -318,7 +281,7 @@ void GenCollectorPolicy::initialize_size_info() { CollectorPolicy::initialize_size_info(); - // min_alignment() is used for alignment within a generation. + // _min_alignment is used for alignment within a generation. // There is additional alignment done down stream for some // collectors that sometimes causes unwanted rounding up of // generations sizes. @@ -327,18 +290,18 @@ size_t max_new_size = 0; if (FLAG_IS_CMDLINE(MaxNewSize) || FLAG_IS_ERGO(MaxNewSize)) { - if (MaxNewSize < min_alignment()) { - max_new_size = min_alignment(); + if (MaxNewSize < _min_alignment) { + max_new_size = _min_alignment; } - if (MaxNewSize >= max_heap_byte_size()) { - max_new_size = align_size_down(max_heap_byte_size() - min_alignment(), - min_alignment()); + if (MaxNewSize >= _max_heap_byte_size) { + max_new_size = align_size_down(_max_heap_byte_size - _min_alignment, + _min_alignment); warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or " "greater than the entire heap (" SIZE_FORMAT "k). A " "new generation size of " SIZE_FORMAT "k will be used.", - MaxNewSize/K, max_heap_byte_size()/K, max_new_size/K); + MaxNewSize/K, _max_heap_byte_size/K, max_new_size/K); } else { - max_new_size = align_size_down(MaxNewSize, min_alignment()); + max_new_size = align_size_down(MaxNewSize, _min_alignment); } // The case for FLAG_IS_ERGO(MaxNewSize) could be treated @@ -356,7 +319,7 @@ // just accept those choices. The choices currently made are // not always "wise". } else { - max_new_size = scale_by_NewRatio_aligned(max_heap_byte_size()); + max_new_size = scale_by_NewRatio_aligned(_max_heap_byte_size); // Bound the maximum size by NewSize below (since it historically // would have been NewSize and because the NewRatio calculation could // yield a size that is too small) and bound it by MaxNewSize above. @@ -369,13 +332,13 @@ // Given the maximum gen0 size, determine the initial and // minimum gen0 sizes. - if (max_heap_byte_size() == min_heap_byte_size()) { + if (_max_heap_byte_size == _min_heap_byte_size) { // The maximum and minimum heap sizes are the same so // the generations minimum and initial must be the // same as its maximum. - set_min_gen0_size(max_new_size); - set_initial_gen0_size(max_new_size); - set_max_gen0_size(max_new_size); + _min_gen0_size = max_new_size; + _initial_gen0_size = max_new_size; + _max_gen0_size = max_new_size; } else { size_t desired_new_size = 0; if (!FLAG_IS_DEFAULT(NewSize)) { @@ -396,43 +359,37 @@ // Use the default NewSize as the floor for these values. If // NewRatio is overly large, the resulting sizes can be too // small. - _min_gen0_size = MAX2(scale_by_NewRatio_aligned(min_heap_byte_size()), - NewSize); + _min_gen0_size = MAX2(scale_by_NewRatio_aligned(_min_heap_byte_size), NewSize); desired_new_size = - MAX2(scale_by_NewRatio_aligned(initial_heap_byte_size()), - NewSize); + MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize); } assert(_min_gen0_size > 0, "Sanity check"); - set_initial_gen0_size(desired_new_size); - set_max_gen0_size(max_new_size); + _initial_gen0_size = desired_new_size; + _max_gen0_size = max_new_size; // At this point the desirable initial and minimum sizes have been // determined without regard to the maximum sizes. // Bound the sizes by the corresponding overall heap sizes. - set_min_gen0_size( - bound_minus_alignment(_min_gen0_size, min_heap_byte_size())); - set_initial_gen0_size( - bound_minus_alignment(_initial_gen0_size, initial_heap_byte_size())); - set_max_gen0_size( - bound_minus_alignment(_max_gen0_size, max_heap_byte_size())); + _min_gen0_size = bound_minus_alignment(_min_gen0_size, _min_heap_byte_size); + _initial_gen0_size = bound_minus_alignment(_initial_gen0_size, _initial_heap_byte_size); + _max_gen0_size = bound_minus_alignment(_max_gen0_size, _max_heap_byte_size); // At this point all three sizes have been checked against the // maximum sizes but have not been checked for consistency // among the three. // Final check min <= initial <= max - set_min_gen0_size(MIN2(_min_gen0_size, _max_gen0_size)); - set_initial_gen0_size( - MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size)); - set_min_gen0_size(MIN2(_min_gen0_size, _initial_gen0_size)); + _min_gen0_size = MIN2(_min_gen0_size, _max_gen0_size); + _initial_gen0_size = MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size); + _min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size); } if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("1: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, - min_gen0_size(), initial_gen0_size(), max_gen0_size()); + _min_gen0_size, _initial_gen0_size, _max_gen0_size); } } @@ -452,19 +409,17 @@ if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && - (heap_size >= min_gen1_size + min_alignment())) { + (heap_size >= min_gen1_size + _min_alignment)) { // Adjust gen0 down to accommodate min_gen1_size *gen0_size_ptr = heap_size - min_gen1_size; *gen0_size_ptr = - MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()), - min_alignment()); + MAX2((uintx)align_size_down(*gen0_size_ptr, _min_alignment), _min_alignment); assert(*gen0_size_ptr > 0, "Min gen0 is too large"); result = true; } else { *gen1_size_ptr = heap_size - *gen0_size_ptr; *gen1_size_ptr = - MAX2((uintx)align_size_down(*gen1_size_ptr, min_alignment()), - min_alignment()); + MAX2((uintx)align_size_down(*gen1_size_ptr, _min_alignment), _min_alignment); } } return result; @@ -485,10 +440,9 @@ // The maximum gen1 size can be determined from the maximum gen0 // and maximum heap size since no explicit flags exits // for setting the gen1 maximum. - _max_gen1_size = max_heap_byte_size() - _max_gen0_size; + _max_gen1_size = _max_heap_byte_size - _max_gen0_size; _max_gen1_size = - MAX2((uintx)align_size_down(_max_gen1_size, min_alignment()), - min_alignment()); + MAX2((uintx)align_size_down(_max_gen1_size, _min_alignment), _min_alignment); // If no explicit command line flag has been set for the // gen1 size, use what is left for gen1. if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) { @@ -497,70 +451,66 @@ // with the overall heap size). In either case make // the minimum, maximum and initial sizes consistent // with the gen0 sizes and the overall heap sizes. - assert(min_heap_byte_size() > _min_gen0_size, + assert(_min_heap_byte_size > _min_gen0_size, "gen0 has an unexpected minimum size"); - set_min_gen1_size(min_heap_byte_size() - min_gen0_size()); - set_min_gen1_size( - MAX2((uintx)align_size_down(_min_gen1_size, min_alignment()), - min_alignment())); - set_initial_gen1_size(initial_heap_byte_size() - initial_gen0_size()); - set_initial_gen1_size( - MAX2((uintx)align_size_down(_initial_gen1_size, min_alignment()), - min_alignment())); - + _min_gen1_size = _min_heap_byte_size - _min_gen0_size; + _min_gen1_size = + MAX2((uintx)align_size_down(_min_gen1_size, _min_alignment), _min_alignment); + _initial_gen1_size = _initial_heap_byte_size - _initial_gen0_size; + _initial_gen1_size = + MAX2((uintx)align_size_down(_initial_gen1_size, _min_alignment), _min_alignment); } else { // It's been explicitly set on the command line. Use the // OldSize and then determine the consequences. - set_min_gen1_size(OldSize); - set_initial_gen1_size(OldSize); + _min_gen1_size = OldSize; + _initial_gen1_size = OldSize; // If the user has explicitly set an OldSize that is inconsistent // with other command line flags, issue a warning. // The generation minimums and the overall heap mimimum should // be within one heap alignment. - if ((_min_gen1_size + _min_gen0_size + min_alignment()) < - min_heap_byte_size()) { + if ((_min_gen1_size + _min_gen0_size + _min_alignment) < _min_heap_byte_size) { warning("Inconsistency between minimum heap size and minimum " - "generation sizes: using minimum heap = " SIZE_FORMAT, - min_heap_byte_size()); + "generation sizes: using minimum heap = " SIZE_FORMAT, + _min_heap_byte_size); } if ((OldSize > _max_gen1_size)) { warning("Inconsistency between maximum heap size and maximum " - "generation sizes: using maximum heap = " SIZE_FORMAT - " -XX:OldSize flag is being ignored", - max_heap_byte_size()); + "generation sizes: using maximum heap = " SIZE_FORMAT + " -XX:OldSize flag is being ignored", + _max_heap_byte_size); } // If there is an inconsistency between the OldSize and the minimum and/or // initial size of gen0, since OldSize was explicitly set, OldSize wins. if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, - min_heap_byte_size(), OldSize)) { + _min_heap_byte_size, OldSize)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, - min_gen0_size(), initial_gen0_size(), max_gen0_size()); + _min_gen0_size, _initial_gen0_size, _max_gen0_size); } } // Initial size if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size, - initial_heap_byte_size(), OldSize)) { + _initial_heap_byte_size, OldSize)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, - min_gen0_size(), initial_gen0_size(), max_gen0_size()); + _min_gen0_size, _initial_gen0_size, _max_gen0_size); } } } // Enforce the maximum gen1 size. - set_min_gen1_size(MIN2(_min_gen1_size, _max_gen1_size)); + _min_gen1_size = MIN2(_min_gen1_size, _max_gen1_size); // Check that min gen1 <= initial gen1 <= max gen1 - set_initial_gen1_size(MAX2(_initial_gen1_size, _min_gen1_size)); - set_initial_gen1_size(MIN2(_initial_gen1_size, _max_gen1_size)); + _initial_gen1_size = MAX2(_initial_gen1_size, _min_gen1_size); + _initial_gen1_size = MIN2(_initial_gen1_size, _max_gen1_size); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT " Initial gen1 " SIZE_FORMAT " Maximum gen1 " SIZE_FORMAT, - min_gen1_size(), initial_gen1_size(), max_gen1_size()); + _min_gen1_size, _initial_gen1_size, _max_gen1_size); } } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/collectorPolicy.hpp --- a/src/share/vm/memory/collectorPolicy.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/collectorPolicy.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -101,17 +101,12 @@ // Return maximum heap alignment that may be imposed by the policy static size_t compute_max_alignment(); - void set_min_alignment(size_t align) { _min_alignment = align; } size_t min_alignment() { return _min_alignment; } - void set_max_alignment(size_t align) { _max_alignment = align; } size_t max_alignment() { return _max_alignment; } size_t initial_heap_byte_size() { return _initial_heap_byte_size; } - void set_initial_heap_byte_size(size_t v) { _initial_heap_byte_size = v; } size_t max_heap_byte_size() { return _max_heap_byte_size; } - void set_max_heap_byte_size(size_t v) { _max_heap_byte_size = v; } size_t min_heap_byte_size() { return _min_heap_byte_size; } - void set_min_heap_byte_size(size_t v) { _min_heap_byte_size = v; } enum Name { CollectorPolicyKind, @@ -248,12 +243,9 @@ public: // Accessors - size_t min_gen0_size() { return _min_gen0_size; } - void set_min_gen0_size(size_t v) { _min_gen0_size = v; } + size_t min_gen0_size() { return _min_gen0_size; } size_t initial_gen0_size() { return _initial_gen0_size; } - void set_initial_gen0_size(size_t v) { _initial_gen0_size = v; } - size_t max_gen0_size() { return _max_gen0_size; } - void set_max_gen0_size(size_t v) { _max_gen0_size = v; } + size_t max_gen0_size() { return _max_gen0_size; } virtual int number_of_generations() = 0; @@ -302,12 +294,9 @@ public: // Accessors - size_t min_gen1_size() { return _min_gen1_size; } - void set_min_gen1_size(size_t v) { _min_gen1_size = v; } + size_t min_gen1_size() { return _min_gen1_size; } size_t initial_gen1_size() { return _initial_gen1_size; } - void set_initial_gen1_size(size_t v) { _initial_gen1_size = v; } - size_t max_gen1_size() { return _max_gen1_size; } - void set_max_gen1_size(size_t v) { _max_gen1_size = v; } + size_t max_gen1_size() { return _max_gen1_size; } // Inherited methods TwoGenerationCollectorPolicy* as_two_generation_policy() { return this; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/filemap.hpp --- a/src/share/vm/memory/filemap.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/filemap.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_FILEMAP_HPP #include "memory/metaspaceShared.hpp" +#include "memory/metaspace.hpp" // Layout of the file: // header: dump of archive instance plus versioning info, datestamp, etc. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/genRemSet.cpp --- a/src/share/vm/memory/genRemSet.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/genRemSet.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -32,13 +32,8 @@ // enumeration.) uintx GenRemSet::max_alignment_constraint(Name nm) { - switch (nm) { - case GenRemSet::CardTable: - return CardTableRS::ct_max_alignment_constraint(); - default: - guarantee(false, "Unrecognized GenRemSet type."); - return (0); // Make Windows compiler happy - } + assert(nm == GenRemSet::CardTable, "Unrecognized GenRemSet type."); + return CardTableRS::ct_max_alignment_constraint(); } class HasAccumulatedModifiedOopsClosure : public KlassClosure { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/heapInspection.hpp --- a/src/share/vm/memory/heapInspection.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/heapInspection.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -73,6 +73,10 @@ "Number of bytes used by the InstanceKlass::methods() array") \ f(method_ordering_bytes, IK_method_ordering, \ "Number of bytes used by the InstanceKlass::method_ordering() array") \ + f(default_methods_array_bytes, IK_default_methods, \ + "Number of bytes used by the InstanceKlass::default_methods() array") \ + f(default_vtable_indices_bytes, IK_default_vtable_indices, \ + "Number of bytes used by the InstanceKlass::default_vtable_indices() array") \ f(local_interfaces_bytes, IK_local_interfaces, \ "Number of bytes used by the InstanceKlass::local_interfaces() array") \ f(transitive_interfaces_bytes, IK_transitive_interfaces, \ @@ -150,11 +154,11 @@ HEAP_INSPECTION_COLUMNS_DO(DECLARE_KLASS_SIZE_STATS_FIELD) static int count(oop x) { - return (HeapWordSize * ((x) ? (x)->size() : 0)); + return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0)); } static int count_array(objArrayOop x) { - return (HeapWordSize * ((x) ? (x)->size() : 0)); + return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0)); } template static int count(T* x) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/metaspace.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -29,17 +29,21 @@ #include "memory/collectorPolicy.hpp" #include "memory/filemap.hpp" #include "memory/freeList.hpp" +#include "memory/gcLocker.hpp" #include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "memory/metaspace.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/globals.hpp" +#include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "services/memTracker.hpp" +#include "services/memoryService.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" @@ -84,13 +88,7 @@ return (ChunkIndex) (i+1); } -// Originally _capacity_until_GC was set to MetaspaceSize here but -// the default MetaspaceSize before argument processing was being -// used which was not the desired value. See the code -// in should_expand() to see how the initialization is handled -// now. -size_t MetaspaceGC::_capacity_until_GC = 0; -bool MetaspaceGC::_expand_after_GC = false; +volatile intptr_t MetaspaceGC::_capacity_until_GC = 0; uint MetaspaceGC::_shrink_factor = 0; bool MetaspaceGC::_should_concurrent_collect = false; @@ -293,9 +291,10 @@ MetaWord* end() const { return (MetaWord*) _virtual_space.high(); } size_t reserved_words() const { return _virtual_space.reserved_size() / BytesPerWord; } - size_t expanded_words() const { return _virtual_space.committed_size() / BytesPerWord; } size_t committed_words() const { return _virtual_space.actual_committed_size() / BytesPerWord; } + bool is_pre_committed() const { return _virtual_space.special(); } + // address of next available space in _virtual_space; // Accessors VirtualSpaceNode* next() { return _next; } @@ -337,7 +336,7 @@ // Expands/shrinks the committed space in a virtual space. Delegates // to Virtualspace - bool expand_by(size_t words, bool pre_touch = false); + bool expand_by(size_t min_words, size_t preferred_words); // In preparation for deleting this node, remove all the chunks // in the node from any freelist. @@ -351,29 +350,64 @@ void print_on(outputStream* st) const; }; +#define assert_is_ptr_aligned(ptr, alignment) \ + assert(is_ptr_aligned(ptr, alignment), \ + err_msg(PTR_FORMAT " is not aligned to " \ + SIZE_FORMAT, ptr, alignment)) + +#define assert_is_size_aligned(size, alignment) \ + assert(is_size_aligned(size, alignment), \ + err_msg(SIZE_FORMAT " is not aligned to " \ + SIZE_FORMAT, size, alignment)) + + +// Decide if large pages should be committed when the memory is reserved. +static bool should_commit_large_pages_when_reserving(size_t bytes) { + if (UseLargePages && UseLargePagesInMetaspace && !os::can_commit_large_page_memory()) { + size_t words = bytes / BytesPerWord; + bool is_class = false; // We never reserve large pages for the class space. + if (MetaspaceGC::can_expand(words, is_class) && + MetaspaceGC::allowed_expansion() >= words) { + return true; + } + } + + return false; +} + // byte_size is the size of the associated virtualspace. -VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(), _container_count(0) { - // align up to vm allocation granularity - byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); +VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(), _container_count(0) { + assert_is_size_aligned(bytes, Metaspace::reserve_alignment()); // This allocates memory with mmap. For DumpSharedspaces, try to reserve // configurable address, generally at the top of the Java heap so other // memory addresses don't conflict. if (DumpSharedSpaces) { - char* shared_base = (char*)SharedBaseAddress; - _rs = ReservedSpace(byte_size, 0, false, shared_base, 0); + bool large_pages = false; // No large pages when dumping the CDS archive. + char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, Metaspace::reserve_alignment()); + + _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base, 0); if (_rs.is_reserved()) { assert(shared_base == 0 || _rs.base() == shared_base, "should match"); } else { // Get a mmap region anywhere if the SharedBaseAddress fails. - _rs = ReservedSpace(byte_size); + _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); } MetaspaceShared::set_shared_rs(&_rs); } else { - _rs = ReservedSpace(byte_size); + bool large_pages = should_commit_large_pages_when_reserving(bytes); + + _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); } - MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass); + if (_rs.is_reserved()) { + assert(_rs.base() != NULL, "Catch if we get a NULL address"); + assert(_rs.size() != 0, "Catch if we get a 0 size"); + assert_is_ptr_aligned(_rs.base(), Metaspace::reserve_alignment()); + assert_is_size_aligned(_rs.size(), Metaspace::reserve_alignment()); + + MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass); + } } void VirtualSpaceNode::purge(ChunkManager* chunk_manager) { @@ -410,8 +444,6 @@ #endif // List of VirtualSpaces for metadata allocation. -// It has a _next link for singly linked list and a MemRegion -// for total space in the VirtualSpace. class VirtualSpaceList : public CHeapObj { friend class VirtualSpaceNode; @@ -419,16 +451,13 @@ VirtualSpaceSize = 256 * K }; - // Global list of virtual spaces // Head of the list VirtualSpaceNode* _virtual_space_list; // virtual space currently being used for allocations VirtualSpaceNode* _current_virtual_space; - // Can this virtual list allocate >1 spaces? Also, used to determine - // whether to allocate unlimited small chunks in this virtual space + // Is this VirtualSpaceList used for the compressed class space bool _is_class; - bool can_grow() const { return !is_class() || !UseCompressedClassPointers; } // Sum of reserved and committed memory in the virtual spaces size_t _reserved_words; @@ -453,7 +482,7 @@ // Get another virtual space and add it to the list. This // is typically prompted by a failed attempt to allocate a chunk // and is typically followed by the allocation of a chunk. - bool grow_vs(size_t vs_word_size); + bool create_new_virtual_space(size_t vs_word_size); public: VirtualSpaceList(size_t word_size); @@ -465,12 +494,12 @@ size_t grow_chunks_by_words, size_t medium_chunk_bunch); - bool expand_by(VirtualSpaceNode* node, size_t word_size, bool pre_touch = false); - - // Get the first chunk for a Metaspace. Used for - // special cases such as the boot class loader, reflection - // class loader and anonymous class loader. - Metachunk* get_initialization_chunk(size_t word_size, size_t chunk_bunch); + bool expand_node_by(VirtualSpaceNode* node, + size_t min_words, + size_t preferred_words); + + bool expand_by(size_t min_words, + size_t preferred_words); VirtualSpaceNode* current_virtual_space() { return _current_virtual_space; @@ -478,8 +507,7 @@ bool is_class() const { return _is_class; } - // Allocate the first virtualspace. - void initialize(size_t word_size); + bool initialization_succeeded() { return _virtual_space_list != NULL; } size_t reserved_words() { return _reserved_words; } size_t reserved_bytes() { return reserved_words() * BytesPerWord; } @@ -708,6 +736,9 @@ // and allocates from that chunk. MetaWord* grow_and_allocate(size_t word_size); + // Notify memory usage to MemoryService. + void track_metaspace_memory_usage(); + // debugging support. void dump(outputStream* const out) const; @@ -869,6 +900,12 @@ MetaWord* chunk_limit = top(); assert(chunk_limit != NULL, "Not safe to call this method"); + // The virtual spaces are always expanded by the + // commit granularity to enforce the following condition. + // Without this the is_available check will not work correctly. + assert(_virtual_space.committed_size() == _virtual_space.actual_committed_size(), + "The committed memory doesn't match the expanded memory."); + if (!is_available(chunk_word_size)) { if (TraceMetadataChunkAllocation) { gclog_or_tty->print("VirtualSpaceNode::take_from_committed() not available %d words ", chunk_word_size); @@ -888,14 +925,21 @@ // Expand the virtual space (commit more of the reserved space) -bool VirtualSpaceNode::expand_by(size_t words, bool pre_touch) { - size_t bytes = words * BytesPerWord; - bool result = virtual_space()->expand_by(bytes, pre_touch); - if (TraceMetavirtualspaceAllocation && !result) { - gclog_or_tty->print_cr("VirtualSpaceNode::expand_by() failed " - "for byte size " SIZE_FORMAT, bytes); - virtual_space()->print_on(gclog_or_tty); +bool VirtualSpaceNode::expand_by(size_t min_words, size_t preferred_words) { + size_t min_bytes = min_words * BytesPerWord; + size_t preferred_bytes = preferred_words * BytesPerWord; + + size_t uncommitted = virtual_space()->reserved_size() - virtual_space()->actual_committed_size(); + + if (uncommitted < min_bytes) { + return false; } + + size_t commit = MIN2(preferred_bytes, uncommitted); + bool result = virtual_space()->expand_by(commit, false); + + assert(result, "Failed to commit memory"); + return result; } @@ -914,12 +958,23 @@ return false; } - // An allocation out of this Virtualspace that is larger - // than an initial commit size can waste that initial committed - // space. - size_t committed_byte_size = 0; - bool result = virtual_space()->initialize(_rs, committed_byte_size); + // These are necessary restriction to make sure that the virtual space always + // grows in steps of Metaspace::commit_alignment(). If both base and size are + // aligned only the middle alignment of the VirtualSpace is used. + assert_is_ptr_aligned(_rs.base(), Metaspace::commit_alignment()); + assert_is_size_aligned(_rs.size(), Metaspace::commit_alignment()); + + // ReservedSpaces marked as special will have the entire memory + // pre-committed. Setting a committed size will make sure that + // committed_size and actual_committed_size agrees. + size_t pre_committed_size = _rs.special() ? _rs.size() : 0; + + bool result = virtual_space()->initialize_with_granularity(_rs, pre_committed_size, + Metaspace::commit_alignment()); if (result) { + assert(virtual_space()->committed_size() == virtual_space()->actual_committed_size(), + "Checking that the pre-committed memory was registered by the VirtualSpace"); + set_top((MetaWord*)virtual_space()->low()); set_reserved(MemRegion((HeapWord*)_rs.base(), (HeapWord*)(_rs.base() + _rs.size()))); @@ -976,13 +1031,23 @@ _reserved_words = _reserved_words - v; } +#define assert_committed_below_limit() \ + assert(MetaspaceAux::committed_bytes() <= MaxMetaspaceSize, \ + err_msg("Too much committed memory. Committed: " SIZE_FORMAT \ + " limit (MaxMetaspaceSize): " SIZE_FORMAT, \ + MetaspaceAux::committed_bytes(), MaxMetaspaceSize)); + void VirtualSpaceList::inc_committed_words(size_t v) { assert_lock_strong(SpaceManager::expand_lock()); _committed_words = _committed_words + v; + + assert_committed_below_limit(); } void VirtualSpaceList::dec_committed_words(size_t v) { assert_lock_strong(SpaceManager::expand_lock()); _committed_words = _committed_words - v; + + assert_committed_below_limit(); } void VirtualSpaceList::inc_virtual_space_count() { @@ -1025,8 +1090,8 @@ if (vsl->container_count() == 0 && vsl != current_virtual_space()) { // Unlink it from the list if (prev_vsl == vsl) { - // This is the case of the current note being the first note. - assert(vsl == virtual_space_list(), "Expected to be the first note"); + // This is the case of the current node being the first node. + assert(vsl == virtual_space_list(), "Expected to be the first node"); set_virtual_space_list(vsl->next()); } else { prev_vsl->set_next(vsl->next()); @@ -1054,7 +1119,7 @@ #endif } -VirtualSpaceList::VirtualSpaceList(size_t word_size ) : +VirtualSpaceList::VirtualSpaceList(size_t word_size) : _is_class(false), _virtual_space_list(NULL), _current_virtual_space(NULL), @@ -1063,9 +1128,7 @@ _virtual_space_count(0) { MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); - bool initialization_succeeded = grow_vs(word_size); - assert(initialization_succeeded, - " VirtualSpaceList initialization should not fail"); + create_new_virtual_space(word_size); } VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : @@ -1079,8 +1142,9 @@ Mutex::_no_safepoint_check_flag); VirtualSpaceNode* class_entry = new VirtualSpaceNode(rs); bool succeeded = class_entry->initialize(); - assert(succeeded, " VirtualSpaceList initialization should not fail"); - link_vs(class_entry); + if (succeeded) { + link_vs(class_entry); + } } size_t VirtualSpaceList::free_bytes() { @@ -1088,14 +1152,24 @@ } // Allocate another meta virtual space and add it to the list. -bool VirtualSpaceList::grow_vs(size_t vs_word_size) { +bool VirtualSpaceList::create_new_virtual_space(size_t vs_word_size) { assert_lock_strong(SpaceManager::expand_lock()); - if (vs_word_size == 0) { + + if (is_class()) { + assert(false, "We currently don't support more than one VirtualSpace for" + " the compressed class space. The initialization of the" + " CCS uses another code path and should not hit this path."); return false; } + + if (vs_word_size == 0) { + assert(false, "vs_word_size should always be at least _reserve_alignment large."); + return false; + } + // Reserve the space size_t vs_byte_size = vs_word_size * BytesPerWord; - assert(vs_byte_size % os::vm_allocation_granularity() == 0, "Not aligned"); + assert_is_size_aligned(vs_byte_size, Metaspace::reserve_alignment()); // Allocate the meta virtual space and initialize it. VirtualSpaceNode* new_entry = new VirtualSpaceNode(vs_byte_size); @@ -1103,7 +1177,8 @@ delete new_entry; return false; } else { - assert(new_entry->reserved_words() == vs_word_size, "Must be"); + assert(new_entry->reserved_words() == vs_word_size, + "Reserved memory size differs from requested memory size"); // ensure lock-free iteration sees fully initialized node OrderAccess::storestore(); link_vs(new_entry); @@ -1130,20 +1205,67 @@ } } -bool VirtualSpaceList::expand_by(VirtualSpaceNode* node, size_t word_size, bool pre_touch) { +bool VirtualSpaceList::expand_node_by(VirtualSpaceNode* node, + size_t min_words, + size_t preferred_words) { size_t before = node->committed_words(); - bool result = node->expand_by(word_size, pre_touch); + bool result = node->expand_by(min_words, preferred_words); size_t after = node->committed_words(); // after and before can be the same if the memory was pre-committed. - assert(after >= before, "Must be"); + assert(after >= before, "Inconsistency"); inc_committed_words(after - before); return result; } +bool VirtualSpaceList::expand_by(size_t min_words, size_t preferred_words) { + assert_is_size_aligned(min_words, Metaspace::commit_alignment_words()); + assert_is_size_aligned(preferred_words, Metaspace::commit_alignment_words()); + assert(min_words <= preferred_words, "Invalid arguments"); + + if (!MetaspaceGC::can_expand(min_words, this->is_class())) { + return false; + } + + size_t allowed_expansion_words = MetaspaceGC::allowed_expansion(); + if (allowed_expansion_words < min_words) { + return false; + } + + size_t max_expansion_words = MIN2(preferred_words, allowed_expansion_words); + + // Commit more memory from the the current virtual space. + bool vs_expanded = expand_node_by(current_virtual_space(), + min_words, + max_expansion_words); + if (vs_expanded) { + return true; + } + + // Get another virtual space. + size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words); + grow_vs_words = align_size_up(grow_vs_words, Metaspace::reserve_alignment_words()); + + if (create_new_virtual_space(grow_vs_words)) { + if (current_virtual_space()->is_pre_committed()) { + // The memory was pre-committed, so we are done here. + assert(min_words <= current_virtual_space()->committed_words(), + "The new VirtualSpace was pre-committed, so it" + "should be large enough to fit the alloc request."); + return true; + } + + return expand_node_by(current_virtual_space(), + min_words, + max_expansion_words); + } + + return false; +} + Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, size_t grow_chunks_by_words, size_t medium_chunk_bunch) { @@ -1151,63 +1273,27 @@ // Allocate a chunk out of the current virtual space. Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); - if (next == NULL) { - // Not enough room in current virtual space. Try to commit - // more space. - size_t expand_vs_by_words = MAX2(medium_chunk_bunch, - grow_chunks_by_words); - size_t page_size_words = os::vm_page_size() / BytesPerWord; - size_t aligned_expand_vs_by_words = align_size_up(expand_vs_by_words, - page_size_words); - bool vs_expanded = - expand_by(current_virtual_space(), aligned_expand_vs_by_words); - if (!vs_expanded) { - // Should the capacity of the metaspaces be expanded for - // this allocation? If it's the virtual space for classes and is - // being used for CompressedHeaders, don't allocate a new virtualspace. - if (can_grow() && MetaspaceGC::should_expand(this, word_size)) { - // Get another virtual space. - size_t allocation_aligned_expand_words = - align_size_up(aligned_expand_vs_by_words, os::vm_allocation_granularity() / BytesPerWord); - size_t grow_vs_words = - MAX2((size_t)VirtualSpaceSize, allocation_aligned_expand_words); - if (grow_vs(grow_vs_words)) { - // Got it. It's on the list now. Get a chunk from it. - assert(current_virtual_space()->expanded_words() == 0, - "New virtual space nodes should not have expanded"); - - size_t grow_chunks_by_words_aligned = align_size_up(grow_chunks_by_words, - page_size_words); - // We probably want to expand by aligned_expand_vs_by_words here. - expand_by(current_virtual_space(), grow_chunks_by_words_aligned); - next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); - } - } else { - // Allocation will fail and induce a GC - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("VirtualSpaceList::get_new_chunk():" - " Fail instead of expand the metaspace"); - } - } - } else { - // The virtual space expanded, get a new chunk - next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); - assert(next != NULL, "Just expanded, should succeed"); - } + if (next != NULL) { + return next; } - assert(next == NULL || (next->next() == NULL && next->prev() == NULL), - "New chunk is still on some list"); - return next; -} - -Metachunk* VirtualSpaceList::get_initialization_chunk(size_t chunk_word_size, - size_t chunk_bunch) { - // Get a chunk from the chunk freelist - Metachunk* new_chunk = get_new_chunk(chunk_word_size, - chunk_word_size, - chunk_bunch); - return new_chunk; + // The expand amount is currently only determined by the requested sizes + // and not how much committed memory is left in the current virtual space. + + size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words()); + size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words()); + if (min_word_size >= preferred_word_size) { + // Can happen when humongous chunks are allocated. + preferred_word_size = min_word_size; + } + + bool expanded = expand_by(min_word_size, preferred_word_size); + if (expanded) { + next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); + assert(next != NULL, "The allocation was expected to succeed after the expansion"); + } + + return next; } void VirtualSpaceList::print_on(outputStream* st) const { @@ -1256,96 +1342,96 @@ // Calculate the amount to increase the high water mark (HWM). // Increase by a minimum amount (MinMetaspaceExpansion) so that // another expansion is not requested too soon. If that is not -// enough to satisfy the allocation (i.e. big enough for a word_size -// allocation), increase by MaxMetaspaceExpansion. If that is still -// not enough, expand by the size of the allocation (word_size) plus -// some. -size_t MetaspaceGC::delta_capacity_until_GC(size_t word_size) { - size_t before_inc = MetaspaceGC::capacity_until_GC(); - size_t min_delta_words = MinMetaspaceExpansion / BytesPerWord; - size_t max_delta_words = MaxMetaspaceExpansion / BytesPerWord; - size_t page_size_words = os::vm_page_size() / BytesPerWord; - size_t size_delta_words = align_size_up(word_size, page_size_words); - size_t delta_words = MAX2(size_delta_words, min_delta_words); - if (delta_words > min_delta_words) { +// enough to satisfy the allocation, increase by MaxMetaspaceExpansion. +// If that is still not enough, expand by the size of the allocation +// plus some. +size_t MetaspaceGC::delta_capacity_until_GC(size_t bytes) { + size_t min_delta = MinMetaspaceExpansion; + size_t max_delta = MaxMetaspaceExpansion; + size_t delta = align_size_up(bytes, Metaspace::commit_alignment()); + + if (delta <= min_delta) { + delta = min_delta; + } else if (delta <= max_delta) { // Don't want to hit the high water mark on the next // allocation so make the delta greater than just enough // for this allocation. - delta_words = MAX2(delta_words, max_delta_words); - if (delta_words > max_delta_words) { - // This allocation is large but the next ones are probably not - // so increase by the minimum. - delta_words = delta_words + min_delta_words; - } + delta = max_delta; + } else { + // This allocation is large but the next ones are probably not + // so increase by the minimum. + delta = delta + min_delta; } - return delta_words; + + assert_is_size_aligned(delta, Metaspace::commit_alignment()); + + return delta; +} + +size_t MetaspaceGC::capacity_until_GC() { + size_t value = (size_t)OrderAccess::load_ptr_acquire(&_capacity_until_GC); + assert(value >= MetaspaceSize, "Not initialied properly?"); + return value; } -bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) { - - // If the user wants a limit, impose one. - // The reason for someone using this flag is to limit reserved space. So - // for non-class virtual space, compare against virtual spaces that are reserved. - // For class virtual space, we only compare against the committed space, not - // reserved space, because this is a larger space prereserved for compressed - // class pointers. - if (!FLAG_IS_DEFAULT(MaxMetaspaceSize)) { - size_t nonclass_allocated = MetaspaceAux::reserved_bytes(Metaspace::NonClassType); - size_t class_allocated = MetaspaceAux::allocated_capacity_bytes(Metaspace::ClassType); - size_t real_allocated = nonclass_allocated + class_allocated; - if (real_allocated >= MaxMetaspaceSize) { +size_t MetaspaceGC::inc_capacity_until_GC(size_t v) { + assert_is_size_aligned(v, Metaspace::commit_alignment()); + + return (size_t)Atomic::add_ptr(v, &_capacity_until_GC); +} + +size_t MetaspaceGC::dec_capacity_until_GC(size_t v) { + assert_is_size_aligned(v, Metaspace::commit_alignment()); + + return (size_t)Atomic::add_ptr(-(intptr_t)v, &_capacity_until_GC); +} + +bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { + // Check if the compressed class space is full. + if (is_class && Metaspace::using_class_space()) { + size_t class_committed = MetaspaceAux::committed_bytes(Metaspace::ClassType); + if (class_committed + word_size * BytesPerWord > CompressedClassSpaceSize) { return false; } } - // Class virtual space should always be expanded. Call GC for the other - // metadata virtual space. - if (Metaspace::using_class_space() && - (vsl == Metaspace::class_space_list())) return true; - - // If this is part of an allocation after a GC, expand - // unconditionally. - if (MetaspaceGC::expand_after_GC()) { - return true; + // Check if the user has imposed a limit on the metaspace memory. + size_t committed_bytes = MetaspaceAux::committed_bytes(); + if (committed_bytes + word_size * BytesPerWord > MaxMetaspaceSize) { + return false; } - - // If the capacity is below the minimum capacity, allow the - // expansion. Also set the high-water-mark (capacity_until_GC) - // to that minimum capacity so that a GC will not be induced - // until that minimum capacity is exceeded. - size_t committed_capacity_bytes = MetaspaceAux::allocated_capacity_bytes(); - size_t metaspace_size_bytes = MetaspaceSize; - if (committed_capacity_bytes < metaspace_size_bytes || - capacity_until_GC() == 0) { - set_capacity_until_GC(metaspace_size_bytes); - return true; - } else { - if (committed_capacity_bytes < capacity_until_GC()) { - return true; - } else { - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr(" allocation request size " SIZE_FORMAT - " capacity_until_GC " SIZE_FORMAT - " allocated_capacity_bytes " SIZE_FORMAT, - word_size, - capacity_until_GC(), - MetaspaceAux::allocated_capacity_bytes()); - } - return false; - } + return true; +} + +size_t MetaspaceGC::allowed_expansion() { + size_t committed_bytes = MetaspaceAux::committed_bytes(); + + size_t left_until_max = MaxMetaspaceSize - committed_bytes; + + // Always grant expansion if we are initiating the JVM, + // or if the GC_locker is preventing GCs. + if (!is_init_completed() || GC_locker::is_active_and_needs_gc()) { + return left_until_max / BytesPerWord; } + + size_t capacity_until_gc = capacity_until_GC(); + + if (capacity_until_gc <= committed_bytes) { + return 0; + } + + size_t left_until_GC = capacity_until_gc - committed_bytes; + size_t left_to_commit = MIN2(left_until_GC, left_until_max); + + return left_to_commit / BytesPerWord; } - - void MetaspaceGC::compute_new_size() { assert(_shrink_factor <= 100, "invalid shrink factor"); uint current_shrink_factor = _shrink_factor; _shrink_factor = 0; - // Until a faster way of calculating the "used" quantity is implemented, - // use "capacity". const size_t used_after_gc = MetaspaceAux::allocated_capacity_bytes(); const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC(); @@ -1377,9 +1463,10 @@ // If we have less capacity below the metaspace HWM, then // increment the HWM. size_t expand_bytes = minimum_desired_capacity - capacity_until_GC; + expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment()); // Don't expand unless it's significant if (expand_bytes >= MinMetaspaceExpansion) { - MetaspaceGC::set_capacity_until_GC(capacity_until_GC + expand_bytes); + MetaspaceGC::inc_capacity_until_GC(expand_bytes); } if (PrintGCDetails && Verbose) { size_t new_capacity_until_GC = capacity_until_GC; @@ -1436,6 +1523,9 @@ // on the third call, and 100% by the fourth call. But if we recompute // size without shrinking, it goes back to 0%. shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + + shrink_bytes = align_size_down(shrink_bytes, Metaspace::commit_alignment()); + assert(shrink_bytes <= max_shrink_bytes, err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, shrink_bytes, max_shrink_bytes)); @@ -1467,7 +1557,7 @@ // Don't shrink unless it's significant if (shrink_bytes >= MinMetaspaceExpansion && ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) { - MetaspaceGC::set_capacity_until_GC(capacity_until_GC - shrink_bytes); + MetaspaceGC::dec_capacity_until_GC(shrink_bytes); } } @@ -1700,7 +1790,6 @@ assert(free_list != NULL, "Sanity check"); chunk = free_list->head(); - debug_only(Metachunk* debug_head = chunk;) if (chunk == NULL) { return NULL; @@ -1709,9 +1798,6 @@ // Remove the chunk as the head of the list. free_list->remove_chunk(chunk); - // Chunk is being removed from the chunks free list. - dec_free_chunks_total(chunk->capacity_word_size()); - if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print_cr("ChunkManager::free_chunks_get: free_list " PTR_FORMAT " head " PTR_FORMAT " size " SIZE_FORMAT, @@ -1722,21 +1808,22 @@ word_size, FreeBlockDictionary::atLeast); - if (chunk != NULL) { - if (TraceMetadataHumongousAllocation) { - size_t waste = chunk->word_size() - word_size; - gclog_or_tty->print_cr("Free list allocate humongous chunk size " - SIZE_FORMAT " for requested size " SIZE_FORMAT - " waste " SIZE_FORMAT, - chunk->word_size(), word_size, waste); - } - // Chunk is being removed from the chunks free list. - dec_free_chunks_total(chunk->capacity_word_size()); - } else { + if (chunk == NULL) { return NULL; } + + if (TraceMetadataHumongousAllocation) { + size_t waste = chunk->word_size() - word_size; + gclog_or_tty->print_cr("Free list allocate humongous chunk size " + SIZE_FORMAT " for requested size " SIZE_FORMAT + " waste " SIZE_FORMAT, + chunk->word_size(), word_size, waste); + } } + // Chunk is being removed from the chunks free list. + dec_free_chunks_total(chunk->capacity_word_size()); + // Remove it from the links to this freelist chunk->set_next(NULL); chunk->set_prev(NULL); @@ -1977,6 +2064,15 @@ return chunk_word_size; } +void SpaceManager::track_metaspace_memory_usage() { + if (is_init_completed()) { + if (is_class()) { + MemoryService::track_compressed_class_memory_usage(); + } + MemoryService::track_metaspace_memory_usage(); + } +} + MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { assert(vs_list()->current_virtual_space() != NULL, "Should have been set"); @@ -2002,15 +2098,24 @@ size_t grow_chunks_by_words = calc_chunk_size(word_size); Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); + if (next != NULL) { + Metadebug::deallocate_chunk_a_lot(this, grow_chunks_by_words); + } + + MetaWord* mem = NULL; + // If a chunk was available, add it to the in-use chunk list // and do an allocation from it. if (next != NULL) { - Metadebug::deallocate_chunk_a_lot(this, grow_chunks_by_words); // Add to this manager's list of chunks in use. add_chunk(next, false); - return next->allocate(word_size); + mem = next->allocate(word_size); } - return NULL; + + // Track metaspace memory usage statistic. + track_metaspace_memory_usage(); + + return mem; } void SpaceManager::print_on(outputStream* st) const { @@ -2366,6 +2471,7 @@ inc_used_metrics(word_size); return current_chunk()->allocate(word_size); // caller handles null result } + if (current_chunk() != NULL) { result = current_chunk()->allocate(word_size); } @@ -2373,7 +2479,8 @@ if (result == NULL) { result = grow_and_allocate(word_size); } - if (result != 0) { + + if (result != NULL) { inc_used_metrics(word_size); assert(result != (MetaWord*) chunks_in_use(MediumIndex), "Head of the list is being allocated"); @@ -2639,24 +2746,26 @@ void MetaspaceAux::print_on(outputStream* out) { Metaspace::MetadataType nct = Metaspace::NonClassType; - out->print_cr(" Metaspace total " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", - allocated_capacity_bytes()/K, allocated_used_bytes()/K, reserved_bytes()/K); - - out->print_cr(" data space " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", - allocated_capacity_bytes(nct)/K, - allocated_used_bytes(nct)/K, - reserved_bytes(nct)/K); + out->print_cr(" Metaspace " + "used " SIZE_FORMAT "K, " + "capacity " SIZE_FORMAT "K, " + "committed " SIZE_FORMAT "K, " + "reserved " SIZE_FORMAT "K", + allocated_used_bytes()/K, + allocated_capacity_bytes()/K, + committed_bytes()/K, + reserved_bytes()/K); + if (Metaspace::using_class_space()) { Metaspace::MetadataType ct = Metaspace::ClassType; out->print_cr(" class space " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", + "used " SIZE_FORMAT "K, " + "capacity " SIZE_FORMAT "K, " + "committed " SIZE_FORMAT "K, " + "reserved " SIZE_FORMAT "K", + allocated_used_bytes(ct)/K, allocated_capacity_bytes(ct)/K, - allocated_used_bytes(ct)/K, + committed_bytes(ct)/K, reserved_bytes(ct)/K); } } @@ -2808,6 +2917,9 @@ size_t Metaspace::_first_chunk_word_size = 0; size_t Metaspace::_first_class_chunk_word_size = 0; +size_t Metaspace::_commit_alignment = 0; +size_t Metaspace::_reserve_alignment = 0; + Metaspace::Metaspace(Mutex* lock, MetaspaceType type) { initialize(lock, type); } @@ -2869,21 +2981,30 @@ assert(UseCompressedClassPointers, "Only use with CompressedKlassPtrs"); assert(class_metaspace_size() < KlassEncodingMetaspaceMax, "Metaspace size is too big"); + assert_is_ptr_aligned(requested_addr, _reserve_alignment); + assert_is_ptr_aligned(cds_base, _reserve_alignment); + assert_is_size_aligned(class_metaspace_size(), _reserve_alignment); + + // Don't use large pages for the class space. + bool large_pages = false; ReservedSpace metaspace_rs = ReservedSpace(class_metaspace_size(), - os::vm_allocation_granularity(), - false, requested_addr, 0); + _reserve_alignment, + large_pages, + requested_addr, 0); if (!metaspace_rs.is_reserved()) { if (UseSharedSpaces) { + size_t increment = align_size_up(1*G, _reserve_alignment); + // Keep trying to allocate the metaspace, increasing the requested_addr // by 1GB each time, until we reach an address that will no longer allow // use of CDS with compressed klass pointers. char *addr = requested_addr; - while (!metaspace_rs.is_reserved() && (addr + 1*G > addr) && - can_use_cds_with_metaspace_addr(addr + 1*G, cds_base)) { - addr = addr + 1*G; + while (!metaspace_rs.is_reserved() && (addr + increment > addr) && + can_use_cds_with_metaspace_addr(addr + increment, cds_base)) { + addr = addr + increment; metaspace_rs = ReservedSpace(class_metaspace_size(), - os::vm_allocation_granularity(), false, addr, 0); + _reserve_alignment, large_pages, addr, 0); } } @@ -2894,7 +3015,7 @@ // So, UseCompressedClassPointers cannot be turned off at this point. if (!metaspace_rs.is_reserved()) { metaspace_rs = ReservedSpace(class_metaspace_size(), - os::vm_allocation_granularity(), false); + _reserve_alignment, large_pages); if (!metaspace_rs.is_reserved()) { vm_exit_during_initialization(err_msg("Could not allocate metaspace: %d bytes", class_metaspace_size())); @@ -2933,34 +3054,96 @@ assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); + + if (!_class_space_list->initialization_succeeded()) { + vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); + } } #endif +// Align down. If the aligning result in 0, return 'alignment'. +static size_t restricted_align_down(size_t size, size_t alignment) { + return MAX2(alignment, align_size_down_(size, alignment)); +} + +void Metaspace::ergo_initialize() { + if (DumpSharedSpaces) { + // Using large pages when dumping the shared archive is currently not implemented. + FLAG_SET_ERGO(bool, UseLargePagesInMetaspace, false); + } + + size_t page_size = os::vm_page_size(); + if (UseLargePages && UseLargePagesInMetaspace) { + page_size = os::large_page_size(); + } + + _commit_alignment = page_size; + _reserve_alignment = MAX2(page_size, (size_t)os::vm_allocation_granularity()); + + // Do not use FLAG_SET_ERGO to update MaxMetaspaceSize, since this will + // override if MaxMetaspaceSize was set on the command line or not. + // This information is needed later to conform to the specification of the + // java.lang.management.MemoryUsage API. + // + // Ideally, we would be able to set the default value of MaxMetaspaceSize in + // globals.hpp to the aligned value, but this is not possible, since the + // alignment depends on other flags being parsed. + MaxMetaspaceSize = restricted_align_down(MaxMetaspaceSize, _reserve_alignment); + + if (MetaspaceSize > MaxMetaspaceSize) { + MetaspaceSize = MaxMetaspaceSize; + } + + MetaspaceSize = restricted_align_down(MetaspaceSize, _commit_alignment); + + assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize"); + + if (MetaspaceSize < 256*K) { + vm_exit_during_initialization("Too small initial Metaspace size"); + } + + MinMetaspaceExpansion = restricted_align_down(MinMetaspaceExpansion, _commit_alignment); + MaxMetaspaceExpansion = restricted_align_down(MaxMetaspaceExpansion, _commit_alignment); + + CompressedClassSpaceSize = restricted_align_down(CompressedClassSpaceSize, _reserve_alignment); + set_class_metaspace_size(CompressedClassSpaceSize); +} + void Metaspace::global_initialize() { // Initialize the alignment for shared spaces. int max_alignment = os::vm_page_size(); size_t cds_total = 0; - set_class_metaspace_size(align_size_up(CompressedClassSpaceSize, - os::vm_allocation_granularity())); - MetaspaceShared::set_max_alignment(max_alignment); if (DumpSharedSpaces) { - SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment); + SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment); SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment); - SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment); - SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment); + SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment); + SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment); // Initialize with the sum of the shared space sizes. The read-only // and read write metaspace chunks will be allocated out of this and the // remainder is the misc code and data chunks. cds_total = FileMapInfo::shared_spaces_size(); + cds_total = align_size_up(cds_total, _reserve_alignment); _space_list = new VirtualSpaceList(cds_total/wordSize); _chunk_manager_metadata = new ChunkManager(SpecializedChunk, SmallChunk, MediumChunk); + if (!_space_list->initialization_succeeded()) { + vm_exit_during_initialization("Unable to dump shared archive.", NULL); + } + #ifdef _LP64 + if (cds_total + class_metaspace_size() > (uint64_t)max_juint) { + vm_exit_during_initialization("Unable to dump shared archive.", + err_msg("Size of archive (" SIZE_FORMAT ") + compressed class space (" + SIZE_FORMAT ") == total (" SIZE_FORMAT ") is larger than compressed " + "klass limit: " SIZE_FORMAT, cds_total, class_metaspace_size(), + cds_total + class_metaspace_size(), (size_t)max_juint)); + } + // Set the compressed klass pointer base so that decoding of these pointers works // properly when creating the shared archive. assert(UseCompressedOops && UseCompressedClassPointers, @@ -2971,9 +3154,6 @@ _space_list->current_virtual_space()->bottom()); } - // Set the shift to zero. - assert(class_metaspace_size() < (uint64_t)(max_juint) - cds_total, - "CDS region is too large"); Universe::set_narrow_klass_shift(0); #endif @@ -2992,12 +3172,12 @@ // Map in spaces now also if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { FileMapInfo::set_current_info(mapinfo); + cds_total = FileMapInfo::shared_spaces_size(); + cds_address = (address)mapinfo->region_base(0); } else { assert(!mapinfo->is_open() && !UseSharedSpaces, "archive file not closed or shared spaces not disabled."); } - cds_total = FileMapInfo::shared_spaces_size(); - cds_address = (address)mapinfo->region_base(0); } #ifdef _LP64 @@ -3005,7 +3185,9 @@ // above the heap and above the CDS area (if it exists). if (using_class_space()) { if (UseSharedSpaces) { - allocate_metaspace_compressed_klass_ptrs((char *)(cds_address + cds_total), cds_address); + char* cds_end = (char*)(cds_address + cds_total); + cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment); + allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); } else { allocate_metaspace_compressed_klass_ptrs((char *)CompressedKlassPointersBase, 0); } @@ -3023,11 +3205,19 @@ _first_class_chunk_word_size = align_word_size_up(_first_class_chunk_word_size); // Arbitrarily set the initial virtual space to a multiple // of the boot class loader size. - size_t word_size = VIRTUALSPACEMULTIPLIER * first_chunk_word_size(); + size_t word_size = VIRTUALSPACEMULTIPLIER * _first_chunk_word_size; + word_size = align_size_up(word_size, Metaspace::reserve_alignment_words()); + // Initialize the list of virtual spaces. _space_list = new VirtualSpaceList(word_size); _chunk_manager_metadata = new ChunkManager(SpecializedChunk, SmallChunk, MediumChunk); + + if (!_space_list->initialization_succeeded()) { + vm_exit_during_initialization("Unable to setup metadata virtual space list.", NULL); + } } + + MetaspaceGC::initialize(); } Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, @@ -3039,7 +3229,7 @@ return chunk; } - return get_space_list(mdtype)->get_initialization_chunk(chunk_word_size, chunk_bunch); + return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch); } void Metaspace::initialize(Mutex* lock, MetaspaceType type) { @@ -3104,7 +3294,7 @@ MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) { // DumpSharedSpaces doesn't use class metadata area (yet) // Also, don't use class_vsm() unless UseCompressedClassPointers is true. - if (mdtype == ClassType && using_class_space()) { + if (is_class_space_allocation(mdtype)) { return class_vsm()->allocate(word_size); } else { return vsm()->allocate(word_size); @@ -3112,19 +3302,18 @@ } MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) { - MetaWord* result; - MetaspaceGC::set_expand_after_GC(true); - size_t before_inc = MetaspaceGC::capacity_until_GC(); - size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size) * BytesPerWord; - MetaspaceGC::inc_capacity_until_GC(delta_bytes); + size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord); + assert(delta_bytes > 0, "Must be"); + + size_t after_inc = MetaspaceGC::inc_capacity_until_GC(delta_bytes); + size_t before_inc = after_inc - delta_bytes; + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT - " to " SIZE_FORMAT, before_inc, MetaspaceGC::capacity_until_GC()); + " to " SIZE_FORMAT, before_inc, after_inc); } - result = allocate(word_size, mdtype); - - return result; + return allocate(word_size, mdtype); } // Space allocated in the Metaspace. This may @@ -3206,6 +3395,7 @@ } } + Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, bool read_only, MetaspaceObj::Type type, TRAPS) { if (HAS_PENDING_EXCEPTION) { @@ -3213,20 +3403,16 @@ return NULL; // caller does a CHECK_NULL too } - MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; - - // SSS: Should we align the allocations and make sure the sizes are aligned. - MetaWord* result = NULL; - assert(loader_data != NULL, "Should never pass around a NULL loader_data. " "ClassLoaderData::the_null_class_loader_data() should have been used."); + // Allocate in metaspaces without taking out a lock, because it deadlocks // with the SymbolTable_lock. Dumping is single threaded for now. We'll have // to revisit this for application class data sharing. if (DumpSharedSpaces) { assert(type > MetaspaceObj::UnknownType && type < MetaspaceObj::_number_of_types, "sanity"); Metaspace* space = read_only ? loader_data->ro_metaspace() : loader_data->rw_metaspace(); - result = space->allocate(word_size, NonClassType); + MetaWord* result = space->allocate(word_size, NonClassType); if (result == NULL) { report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite); } else { @@ -3235,40 +3421,62 @@ return Metablock::initialize(result, word_size); } - result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); + MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; + + // Try to allocate metadata. + MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); + + if (result == NULL) { + // Allocation failed. + if (is_init_completed()) { + // Only start a GC if the bootstrapping has completed. + + // Try to clean out some memory and retry. + result = Universe::heap()->collector_policy()->satisfy_failed_metadata_allocation( + loader_data, word_size, mdtype); + } + } if (result == NULL) { - // Try to clean out some memory and retry. - result = - Universe::heap()->collector_policy()->satisfy_failed_metadata_allocation( - loader_data, word_size, mdtype); - - // If result is still null, we are out of memory. - if (result == NULL) { - if (Verbose && TraceMetadataChunkAllocation) { - gclog_or_tty->print_cr("Metaspace allocation failed for size " - SIZE_FORMAT, word_size); - if (loader_data->metaspace_or_null() != NULL) loader_data->dump(gclog_or_tty); - MetaspaceAux::dump(gclog_or_tty); - } - // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support - const char* space_string = (mdtype == ClassType) ? "Compressed class space" : - "Metadata space"; - report_java_out_of_memory(space_string); - - if (JvmtiExport::should_post_resource_exhausted()) { - JvmtiExport::post_resource_exhausted( - JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR, - space_string); - } - if (mdtype == ClassType) { - THROW_OOP_0(Universe::out_of_memory_error_class_metaspace()); - } else { - THROW_OOP_0(Universe::out_of_memory_error_metaspace()); - } + report_metadata_oome(loader_data, word_size, mdtype, THREAD); + // Will not reach here. + return NULL; + } + + return Metablock::initialize(result, word_size); +} + +void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) { + // If result is still null, we are out of memory. + if (Verbose && TraceMetadataChunkAllocation) { + gclog_or_tty->print_cr("Metaspace allocation failed for size " + SIZE_FORMAT, word_size); + if (loader_data->metaspace_or_null() != NULL) { + loader_data->dump(gclog_or_tty); } + MetaspaceAux::dump(gclog_or_tty); } - return Metablock::initialize(result, word_size); + + // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support + const char* space_string = is_class_space_allocation(mdtype) ? "Compressed class space" : + "Metadata space"; + report_java_out_of_memory(space_string); + + if (JvmtiExport::should_post_resource_exhausted()) { + JvmtiExport::post_resource_exhausted( + JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR, + space_string); + } + + if (!is_init_completed()) { + vm_exit_during_initialization("OutOfMemoryError", space_string); + } + + if (is_class_space_allocation(mdtype)) { + THROW_OOP(Universe::out_of_memory_error_class_metaspace()); + } else { + THROW_OOP(Universe::out_of_memory_error_metaspace()); + } } void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/metaspace.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -87,9 +87,10 @@ friend class MetaspaceAux; public: - enum MetadataType {ClassType = 0, - NonClassType = ClassType + 1, - MetadataTypeCount = ClassType + 2 + enum MetadataType { + ClassType, + NonClassType, + MetadataTypeCount }; enum MetaspaceType { StandardMetaspaceType, @@ -103,6 +104,9 @@ private: void initialize(Mutex* lock, MetaspaceType type); + // Get the first chunk for a Metaspace. Used for + // special cases such as the boot class loader, reflection + // class loader and anonymous class loader. Metachunk* get_initialization_chunk(MetadataType mdtype, size_t chunk_word_size, size_t chunk_bunch); @@ -123,6 +127,9 @@ static size_t _first_chunk_word_size; static size_t _first_class_chunk_word_size; + static size_t _commit_alignment; + static size_t _reserve_alignment; + SpaceManager* _vsm; SpaceManager* vsm() const { return _vsm; } @@ -191,12 +198,17 @@ Metaspace(Mutex* lock, MetaspaceType type); ~Metaspace(); - // Initialize globals for Metaspace + static void ergo_initialize(); static void global_initialize(); static size_t first_chunk_word_size() { return _first_chunk_word_size; } static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; } + static size_t reserve_alignment() { return _reserve_alignment; } + static size_t reserve_alignment_words() { return _reserve_alignment / BytesPerWord; } + static size_t commit_alignment() { return _commit_alignment; } + static size_t commit_alignment_words() { return _commit_alignment / BytesPerWord; } + char* bottom() const; size_t used_words_slow(MetadataType mdtype) const; size_t free_words_slow(MetadataType mdtype) const; @@ -219,6 +231,9 @@ static void purge(MetadataType mdtype); static void purge(); + static void report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, + MetadataType mdtype, TRAPS); + void print_on(outputStream* st) const; // Debugging support void verify(); @@ -235,6 +250,9 @@ return NOT_LP64(false) LP64_ONLY(UseCompressedClassPointers && !DumpSharedSpaces); } + static bool is_class_space_allocation(MetadataType mdType) { + return mdType == ClassType && using_class_space(); + } }; class MetaspaceAux : AllStatic { @@ -349,17 +367,10 @@ class MetaspaceGC : AllStatic { - // The current high-water-mark for inducing a GC. When - // the capacity of all space in the virtual lists reaches this value, - // a GC is induced and the value is increased. This should be changed - // to the space actually used for allocations to avoid affects of - // fragmentation losses to partially used chunks. Size is in words. - static size_t _capacity_until_GC; - - // After a GC is done any allocation that fails should try to expand - // the capacity of the Metaspaces. This flag is set during attempts - // to allocate in the VMGCOperation that does the GC. - static bool _expand_after_GC; + // The current high-water-mark for inducing a GC. + // When committed memory of all metaspaces reaches this value, + // a GC is induced and the value is increased. Size is in bytes. + static volatile intptr_t _capacity_until_GC; // For a CMS collection, signal that a concurrent collection should // be started. @@ -367,20 +378,16 @@ static uint _shrink_factor; - static void set_capacity_until_GC(size_t v) { _capacity_until_GC = v; } - static size_t shrink_factor() { return _shrink_factor; } void set_shrink_factor(uint v) { _shrink_factor = v; } public: - static size_t capacity_until_GC() { return _capacity_until_GC; } - static void inc_capacity_until_GC(size_t v) { _capacity_until_GC += v; } - static void dec_capacity_until_GC(size_t v) { - _capacity_until_GC = _capacity_until_GC > v ? _capacity_until_GC - v : 0; - } - static bool expand_after_GC() { return _expand_after_GC; } - static void set_expand_after_GC(bool v) { _expand_after_GC = v; } + static void initialize() { _capacity_until_GC = MetaspaceSize; } + + static size_t capacity_until_GC(); + static size_t inc_capacity_until_GC(size_t v); + static size_t dec_capacity_until_GC(size_t v); static bool should_concurrent_collect() { return _should_concurrent_collect; } static void set_should_concurrent_collect(bool v) { @@ -388,11 +395,14 @@ } // The amount to increase the high-water-mark (_capacity_until_GC) - static size_t delta_capacity_until_GC(size_t word_size); + static size_t delta_capacity_until_GC(size_t bytes); - // It is expected that this will be called when the current capacity - // has been used and a GC should be considered. - static bool should_expand(VirtualSpaceList* vsl, size_t word_size); + // Tells if we have can expand metaspace without hitting set limits. + static bool can_expand(size_t words, bool is_class); + + // Returns amount that we can expand without hitting a GC, + // measured in words. + static size_t allowed_expansion(); // Calculate the new high-water mark at which to induce // a GC. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/memory/referenceProcessor.cpp --- a/src/share/vm/memory/referenceProcessor.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/memory/referenceProcessor.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -367,7 +367,7 @@ next_d = java_lang_ref_Reference::discovered(obj); if (TraceReferenceGC && PrintGCDetails) { gclog_or_tty->print_cr(" obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT, - obj, next_d); + (void *)obj, (void *)next_d); } assert(java_lang_ref_Reference::next(obj) == NULL, "Reference not active; should not be discovered"); @@ -392,7 +392,7 @@ next_d = java_lang_ref_Reference::discovered(obj); if (TraceReferenceGC && PrintGCDetails) { gclog_or_tty->print_cr(" obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT, - obj, next_d); + (void *)obj, (void *)next_d); } assert(java_lang_ref_Reference::next(obj) == NULL, "The reference should not be enqueued"); @@ -562,7 +562,7 @@ !policy->should_clear_reference(iter.obj(), _soft_ref_timestamp_clock)) { if (TraceReferenceGC) { gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", - iter.obj(), iter.obj()->klass()->internal_name()); + (void *)iter.obj(), iter.obj()->klass()->internal_name()); } // Remove Reference object from list iter.remove(); @@ -601,7 +601,7 @@ if (iter.is_referent_alive()) { if (TraceReferenceGC) { gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", - iter.obj(), iter.obj()->klass()->internal_name()); + (void *)iter.obj(), iter.obj()->klass()->internal_name()); } // The referent is reachable after all. // Remove Reference object from list. @@ -687,7 +687,7 @@ if (TraceReferenceGC) { gclog_or_tty->print_cr("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", clear_referent ? "cleared " : "", - iter.obj(), iter.obj()->klass()->internal_name()); + (void *)iter.obj(), iter.obj()->klass()->internal_name()); } assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference"); iter.next(); @@ -1003,7 +1003,7 @@ gclog_or_tty->print_cr("clean_up_discovered_list: Dropping Reference: " INTPTR_FORMAT " with next field: " INTPTR_FORMAT " and referent: " INTPTR_FORMAT, - iter.obj(), next, iter.referent()); + (void *)iter.obj(), (void *)next, (void *)iter.referent()); } ) // Remove Reference object from list @@ -1103,14 +1103,14 @@ if (TraceReferenceGC) { gclog_or_tty->print_cr("Discovered reference (mt) (" INTPTR_FORMAT ": %s)", - obj, obj->klass()->internal_name()); + (void *)obj, obj->klass()->internal_name()); } } else { // If retest was non NULL, another thread beat us to it: // The reference has already been discovered... if (TraceReferenceGC) { gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)", - obj, obj->klass()->internal_name()); + (void *)obj, obj->klass()->internal_name()); } } } @@ -1125,7 +1125,7 @@ assert(da ? referent->is_oop() : referent->is_oop_or_null(), err_msg("Bad referent " INTPTR_FORMAT " found in Reference " INTPTR_FORMAT " during %satomic discovery ", - (intptr_t)referent, (intptr_t)obj, da ? "" : "non-")); + (void *)referent, (void *)obj, da ? "" : "non-")); } #endif @@ -1205,7 +1205,7 @@ // The reference has already been discovered... if (TraceReferenceGC) { gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)", - obj, obj->klass()->internal_name()); + (void *)obj, obj->klass()->internal_name()); } if (RefDiscoveryPolicy == ReferentBasedDiscovery) { // assumes that an object is not processed twice; @@ -1273,7 +1273,7 @@ if (TraceReferenceGC) { gclog_or_tty->print_cr("Discovered reference (" INTPTR_FORMAT ": %s)", - obj, obj->klass()->internal_name()); + (void *)obj, obj->klass()->internal_name()); } } assert(obj->is_oop(), "Discovered a bad reference"); @@ -1372,7 +1372,7 @@ // active; we need to trace and mark its cohort. if (TraceReferenceGC) { gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)", - iter.obj(), iter.obj()->klass()->internal_name()); + (void *)iter.obj(), iter.obj()->klass()->internal_name()); } // Remove Reference object from list iter.remove(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/constantPool.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1918,7 +1918,7 @@ st->print_cr(" - holder: " INTPTR_FORMAT, pool_holder()); } st->print_cr(" - cache: " INTPTR_FORMAT, cache()); - st->print_cr(" - resolved_references: " INTPTR_FORMAT, resolved_references()); + st->print_cr(" - resolved_references: " INTPTR_FORMAT, (void *)resolved_references()); st->print_cr(" - reference_map: " INTPTR_FORMAT, reference_map()); for (int index = 1; index < length(); index++) { // Index 0 is unused diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/cpCache.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -306,8 +306,8 @@ if (TraceInvokeDynamic) { tty->print_cr("set_method_handle bc=%d appendix="PTR_FORMAT"%s method_type="PTR_FORMAT"%s method="PTR_FORMAT" ", invoke_code, - (intptr_t)appendix(), (has_appendix ? "" : " (unused)"), - (intptr_t)method_type(), (has_method_type ? "" : " (unused)"), + (void *)appendix(), (has_appendix ? "" : " (unused)"), + (void *)method_type(), (has_method_type ? "" : " (unused)"), (intptr_t)adapter()); adapter->print(); if (has_appendix) appendix()->print(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -106,7 +106,7 @@ len = name->utf8_length(); \ } \ HS_DTRACE_PROBE4(hotspot, class__initialization__##type, \ - data, len, (clss)->class_loader(), thread_type); \ + data, len, SOLARIS_ONLY((void *))(clss)->class_loader(), thread_type); \ } #define DTRACE_CLASSINIT_PROBE_WAIT(type, clss, thread_type, wait) \ @@ -119,7 +119,7 @@ len = name->utf8_length(); \ } \ HS_DTRACE_PROBE5(hotspot, class__initialization__##type, \ - data, len, (clss)->class_loader(), thread_type, wait); \ + data, len, SOLARIS_ONLY((void *))(clss)->class_loader(), thread_type, wait); \ } #else /* USDT2 */ @@ -238,6 +238,13 @@ } } +// create a new array of vtable_indices for default methods +Array* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) { + Array* vtable_indices = MetadataFactory::new_array(class_loader_data(), len, CHECK_NULL); + assert(default_vtable_indices() == NULL, "only create once"); + set_default_vtable_indices(vtable_indices); + return vtable_indices; +} InstanceKlass::InstanceKlass(int vtable_len, int itable_len, @@ -263,6 +270,8 @@ set_array_klasses(NULL); set_methods(NULL); set_method_ordering(NULL); + set_default_methods(NULL); + set_default_vtable_indices(NULL); set_local_interfaces(NULL); set_transitive_interfaces(NULL); init_implementor(); @@ -376,6 +385,21 @@ } set_method_ordering(NULL); + // default methods can be empty + if (default_methods() != NULL && + default_methods() != Universe::the_empty_method_array()) { + MetadataFactory::free_array(loader_data, default_methods()); + } + // Do NOT deallocate the default methods, they are owned by superinterfaces. + set_default_methods(NULL); + + // default methods vtable indices can be empty + if (default_vtable_indices() != NULL) { + MetadataFactory::free_array(loader_data, default_vtable_indices()); + } + set_default_vtable_indices(NULL); + + // This array is in Klass, but remove it with the InstanceKlass since // this place would be the only caller and it can share memory with transitive // interfaces. @@ -456,14 +480,14 @@ return java_lang_Class::signers(java_mirror()); } -volatile oop InstanceKlass::init_lock() const { +oop InstanceKlass::init_lock() const { // return the init lock from the mirror return java_lang_Class::init_lock(java_mirror()); } void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { EXCEPTION_MARK; - volatile oop init_lock = this_oop->init_lock(); + oop init_lock = this_oop->init_lock(); ObjectLocker ol(init_lock, THREAD); // abort if someone beat us to the initialization @@ -608,7 +632,7 @@ // verification & rewriting { - volatile oop init_lock = this_oop->init_lock(); + oop init_lock = this_oop->init_lock(); ObjectLocker ol(init_lock, THREAD); // rewritten will have been set if loader constraint error found // on an earlier link attempt @@ -731,7 +755,7 @@ // refer to the JVM book page 47 for description of steps // Step 1 { - volatile oop init_lock = this_oop->init_lock(); + oop init_lock = this_oop->init_lock(); ObjectLocker ol(init_lock, THREAD); Thread *self = THREAD; // it's passed the current thread @@ -879,7 +903,7 @@ } void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) { - volatile oop init_lock = this_oop->init_lock(); + oop init_lock = this_oop->init_lock(); ObjectLocker ol(init_lock, THREAD); this_oop->set_init_state(state); ol.notify_all(CHECK); @@ -1354,32 +1378,44 @@ return -1; } +// find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const { return InstanceKlass::find_method(methods(), name, signature); } +// find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method( Array* methods, Symbol* name, Symbol* signature) { + int hit = find_method_index(methods, name, signature); + return hit >= 0 ? methods->at(hit): NULL; +} + +// Used directly for default_methods to find the index into the +// default_vtable_indices, and indirectly by find_method +// find_method_index looks in the local methods array to return the index +// of the matching name/signature +int InstanceKlass::find_method_index( + Array* methods, Symbol* name, Symbol* signature) { int hit = binary_search(methods, name); if (hit != -1) { Method* m = methods->at(hit); // Do linear search to find matching signature. First, quick check // for common case - if (m->signature() == signature) return m; + if (m->signature() == signature) return hit; // search downwards through overloaded methods int i; for (i = hit - 1; i >= 0; --i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (m->signature() == signature) return m; + if (m->signature() == signature) return i; } // search upwards for (i = hit + 1; i < methods->length(); ++i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (m->signature() == signature) return m; + if (m->signature() == signature) return i; } // not found #ifdef ASSERT @@ -1387,9 +1423,8 @@ assert(index == -1, err_msg("binary search should have found entry %d", index)); #endif } - return NULL; + return -1; } - int InstanceKlass::find_method_by_name(Symbol* name, int* end) { return find_method_by_name(methods(), name, end); } @@ -1408,6 +1443,7 @@ return -1; } +// lookup_method searches both the local methods array and all superclasses methods arrays Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const { Klass* klass = const_cast(this); while (klass != NULL) { @@ -1418,7 +1454,24 @@ return NULL; } +// lookup a method in the default methods list then in all transitive interfaces +// Do NOT return private or static methods +Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name, + Symbol* signature) const { + Method* m = NULL; + if (default_methods() != NULL) { + m = find_method(default_methods(), name, signature); + } + // Look up interfaces + if (m == NULL) { + m = lookup_method_in_all_interfaces(name, signature); + } + return m; +} + // lookup a method in all the interfaces that this class implements +// Do NOT return private or static methods, new in JDK8 which are not externally visible +// They should only be found in the initial InterfaceMethodRef Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, Symbol* signature) const { Array* all_ifs = transitive_interfaces(); @@ -1427,7 +1480,7 @@ for (int i = 0; i < num_ifs; i++) { ik = InstanceKlass::cast(all_ifs->at(i)); Method* m = ik->lookup_method(name, signature); - if (m != NULL) { + if (m != NULL && m->is_public() && !m->is_static()) { return m; } } @@ -2303,7 +2356,7 @@ } address InstanceKlass::static_field_addr(int offset) { - return (address)(offset + InstanceMirrorKlass::offset_of_static_fields() + (intptr_t)java_mirror()); + return (address)(offset + InstanceMirrorKlass::offset_of_static_fields() + cast_from_oop(java_mirror())); } @@ -2546,6 +2599,42 @@ return m; } + +#if INCLUDE_JVMTI +// update default_methods for redefineclasses for methods that are +// not yet in the vtable due to concurrent subclass define and superinterface +// redefinition +// Note: those in the vtable, should have been updated via adjust_method_entries +void InstanceKlass::adjust_default_methods(Method** old_methods, Method** new_methods, + int methods_length, bool* trace_name_printed) { + // search the default_methods for uses of either obsolete or EMCP methods + if (default_methods() != NULL) { + for (int j = 0; j < methods_length; j++) { + Method* old_method = old_methods[j]; + Method* new_method = new_methods[j]; + + for (int index = 0; index < default_methods()->length(); index ++) { + if (default_methods()->at(index) == old_method) { + default_methods()->at_put(index, new_method); + if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { + if (!(*trace_name_printed)) { + // RC_TRACE_MESG macro has an embedded ResourceMark + RC_TRACE_MESG(("adjust: klassname=%s default methods from name=%s", + external_name(), + old_method->method_holder()->external_name())); + *trace_name_printed = true; + } + RC_TRACE(0x00100000, ("default method update: %s(%s) ", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string())); + } + } + } + } + } +} +#endif // INCLUDE_JVMTI + // On-stack replacement stuff void InstanceKlass::add_osr_nmethod(nmethod* n) { // only one compilation can be active @@ -2740,11 +2829,21 @@ st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr(); if (Verbose || WizardMode) { Array* method_array = methods(); - for(int i = 0; i < method_array->length(); i++) { + for (int i = 0; i < method_array->length(); i++) { st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); } } - st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); + st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); + st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); + if (Verbose && default_methods() != NULL) { + Array* method_array = default_methods(); + for (int i = 0; i < method_array->length(); i++) { + st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + } + } + if (default_vtable_indices() != NULL) { + st->print(BULLET"default vtable indices: "); default_vtable_indices()->print_value_on(st); st->cr(); + } st->print(BULLET"local interfaces: "); local_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"constants: "); constants()->print_value_on(st); st->cr(); @@ -3097,6 +3196,19 @@ } } + // Verify default methods + if (default_methods() != NULL) { + Array* methods = this->default_methods(); + for (int j = 0; j < methods->length(); j++) { + guarantee(methods->at(j)->is_method(), "non-method in methods array"); + } + for (int j = 0; j < methods->length() - 1; j++) { + Method* m1 = methods->at(j); + Method* m2 = methods->at(j + 1); + guarantee(m1->name()->fast_compare(m2->name()) <= 0, "methods not sorted correctly"); + } + } + // Verify JNI static field identifiers if (jni_ids() != NULL) { jni_ids()->verify(this); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -269,12 +269,18 @@ // Method array. Array* _methods; + // Default Method Array, concrete methods inherited from interfaces + Array* _default_methods; // Interface (Klass*s) this class declares locally to implement. Array* _local_interfaces; // Interface (Klass*s) this class implements transitively. Array* _transitive_interfaces; // Int array containing the original order of method in the class file (for JVMTI). Array* _method_ordering; + // Int array containing the vtable_indices for default_methods + // offset matches _default_methods offset + Array* _default_vtable_indices; + // Instance and static variable information, starts with 6-tuples of shorts // [access, name index, sig index, initval index, low_offset, high_offset] // for all fields, followed by the generic signature data at the end of @@ -356,6 +362,15 @@ void set_method_ordering(Array* m) { _method_ordering = m; } void copy_method_ordering(intArray* m, TRAPS); + // default_methods + Array* default_methods() const { return _default_methods; } + void set_default_methods(Array* a) { _default_methods = a; } + + // default method vtable_indices + Array* default_vtable_indices() const { return _default_vtable_indices; } + void set_default_vtable_indices(Array* v) { _default_vtable_indices = v; } + Array* create_new_default_vtable_indices(int len, TRAPS); + // interfaces Array* local_interfaces() const { return _local_interfaces; } void set_local_interfaces(Array* a) { @@ -501,12 +516,18 @@ Method* find_method(Symbol* name, Symbol* signature) const; static Method* find_method(Array* methods, Symbol* name, Symbol* signature); + // find a local method index in default_methods (returns -1 if not found) + static int find_method_index(Array* methods, Symbol* name, Symbol* signature); + // lookup operation (returns NULL if not found) Method* uncached_lookup_method(Symbol* name, Symbol* signature) const; // lookup a method in all the interfaces that this class implements // (returns NULL if not found) Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature) const; + // lookup a method in local defaults then in all interfaces + // (returns NULL if not found) + Method* lookup_method_in_ordered_interfaces(Symbol* name, Symbol* signature) const; // Find method indices by name. If a method with the specified name is // found the index to the first method is returned, and 'end' is filled in @@ -910,6 +931,11 @@ klassItable* itable() const; // return new klassItable wrapper Method* method_at_itable(Klass* holder, int index, TRAPS); +#if INCLUDE_JVMTI + void adjust_default_methods(Method** old_methods, Method** new_methods, + int methods_length, bool* trace_name_printed); +#endif // INCLUDE_JVMTI + // Garbage collection void oop_follow_contents(oop obj); int oop_adjust_pointers(oop obj); @@ -995,7 +1021,7 @@ // Must be one per class and it has to be a VM internal object so java code // cannot lock it (like the mirror). // It has to be an object not a Mutex because it's held through java calls. - volatile oop init_lock() const; + oop init_lock() const; private: // Static methods that are used to implement member methods where an exposed this pointer diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/instanceMirrorKlass.hpp --- a/src/share/vm/oops/instanceMirrorKlass.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/instanceMirrorKlass.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ // Static field offset is an offset into the Heap, should be converted by // based on UseCompressedOop for traversal static HeapWord* start_of_static_fields(oop obj) { - return (HeapWord*)((intptr_t)obj + offset_of_static_fields()); + return (HeapWord*)(cast_from_oop(obj) + offset_of_static_fields()); } static void init_offset_of_static_fields() { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/instanceRefKlass.cpp --- a/src/share/vm/oops/instanceRefKlass.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/instanceRefKlass.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ T heap_oop = oopDesc::load_heap_oop(referent_addr); debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); } ) if (!oopDesc::is_null(heap_oop)) { @@ -62,7 +62,7 @@ ref->InstanceKlass::oop_follow_contents(obj); debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); } ) return; @@ -70,7 +70,7 @@ // treat referent as normal oop debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); } ) MarkSweep::mark_and_push(referent_addr); @@ -130,7 +130,7 @@ T heap_oop = oopDesc::load_heap_oop(referent_addr); debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); } ) if (!oopDesc::is_null(heap_oop)) { @@ -142,7 +142,7 @@ ref->InstanceKlass::oop_follow_contents(cm, obj); debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); } ) return; @@ -150,7 +150,7 @@ // treat referent as normal oop debug_only( if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, obj); + gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); } ) PSParallelCompact::mark_and_push(cm, referent_addr); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/klassVtable.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -83,7 +83,7 @@ GrowableArray new_mirandas(20); // compute the number of mirandas methods that must be added to the end - get_mirandas(&new_mirandas, all_mirandas, super, methods, local_interfaces); + get_mirandas(&new_mirandas, all_mirandas, super, methods, NULL, local_interfaces); *num_new_mirandas = new_mirandas.length(); vtable_length += *num_new_mirandas * vtableEntry::size(); @@ -186,7 +186,7 @@ assert(methods->at(i)->is_method(), "must be a Method*"); methodHandle mh(THREAD, methods->at(i)); - bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); + bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, -1, checkconstraints, CHECK); if (needs_new_entry) { put_method_at(mh(), initialized); @@ -195,7 +195,35 @@ } } - // add miranda methods to end of vtable. + // update vtable with default_methods + Array* default_methods = ik()->default_methods(); + if (default_methods != NULL) { + len = default_methods->length(); + if (len > 0) { + Array* def_vtable_indices = NULL; + if ((def_vtable_indices = ik()->default_vtable_indices()) == NULL) { + def_vtable_indices = ik()->create_new_default_vtable_indices(len, CHECK); + } else { + assert(def_vtable_indices->length() == len, "reinit vtable len?"); + } + for (int i = 0; i < len; i++) { + HandleMark hm(THREAD); + assert(default_methods->at(i)->is_method(), "must be a Method*"); + methodHandle mh(THREAD, default_methods->at(i)); + + bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, i, checkconstraints, CHECK); + + // needs new entry + if (needs_new_entry) { + put_method_at(mh(), initialized); + def_vtable_indices->at_put(i, initialized); //set vtable index + initialized++; + } + } + } + } + + // add miranda methods; it will also return the updated initialized initialized = fill_in_mirandas(initialized); // In class hierarchies where the accessibility is not increasing (i.e., going from private -> @@ -230,14 +258,19 @@ #ifndef PRODUCT if (PrintVtables && Verbose) { ResourceMark rm(THREAD); + char* sig = target_method()->name_and_sig_as_C_string(); tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", supersuperklass->internal_name(), - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", vtable_index); + _klass->internal_name(), sig, vtable_index); super_method->access_flags().print_on(tty); + if (super_method->is_default_method()) { + tty->print("default"); + } tty->print("overriders flags: "); target_method->access_flags().print_on(tty); - tty->cr(); + if (target_method->is_default_method()) { + tty->print("default"); + } } #endif /*PRODUCT*/ break; // return found superk @@ -258,16 +291,31 @@ // OR return true if a new vtable entry is required. // Only called for InstanceKlass's, i.e. not for arrays // If that changed, could not use _klass as handle for klass -bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, - bool checkconstraints, TRAPS) { +bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, + int super_vtable_len, int default_index, + bool checkconstraints, TRAPS) { ResourceMark rm; bool allocate_new = true; assert(klass->oop_is_instance(), "must be InstanceKlass"); - assert(klass == target_method()->method_holder(), "caller resp."); - // Initialize the method's vtable index to "nonvirtual". - // If we allocate a vtable entry, we will update it to a non-negative number. - target_method()->set_vtable_index(Method::nonvirtual_vtable_index); + Array* def_vtable_indices = NULL; + bool is_default = false; + // default methods are concrete methods in superinterfaces which are added to the vtable + // with their real method_holder + // Since vtable and itable indices share the same storage, don't touch + // the default method's real vtable/itable index + // default_vtable_indices stores the vtable value relative to this inheritor + if (default_index >= 0 ) { + is_default = true; + def_vtable_indices = klass->default_vtable_indices(); + assert(def_vtable_indices != NULL, "def vtable alloc?"); + assert(default_index <= def_vtable_indices->length(), "def vtable len?"); + } else { + assert(klass == target_method()->method_holder(), "caller resp."); + // Initialize the method's vtable index to "nonvirtual". + // If we allocate a vtable entry, we will update it to a non-negative number. + target_method()->set_vtable_index(Method::nonvirtual_vtable_index); + } // Static and methods are never in if (target_method()->is_static() || target_method()->name() == vmSymbols::object_initializer_name()) { @@ -284,6 +332,8 @@ // An interface never allocates new vtable slots, only inherits old ones. // This method will either be assigned its own itable index later, // or be assigned an inherited vtable index in the loop below. + // default methods store their vtable indices in the inheritors default_vtable_indices + assert (default_index == -1, "interfaces don't store resolved default methods"); target_method()->set_vtable_index(Method::pending_itable_index); } @@ -292,9 +342,10 @@ return allocate_new; } - // private methods always have a new entry in the vtable + // private methods in classes always have a new entry in the vtable // specification interpretation since classic has // private methods not overriding + // JDK8 adds private methods in interfaces which require invokespecial if (target_method()->is_private()) { return allocate_new; } @@ -306,8 +357,15 @@ Symbol* name = target_method()->name(); Symbol* signature = target_method()->signature(); - Handle target_loader(THREAD, _klass()->class_loader()); - Symbol* target_classname = _klass->name(); + + KlassHandle target_klass(THREAD, target_method()->method_holder()); + if (target_klass == NULL) { + target_klass = _klass; + } + + Handle target_loader(THREAD, target_klass->class_loader()); + + Symbol* target_classname = target_klass->name(); for(int i = 0; i < super_vtable_len; i++) { Method* super_method = method_at(i); // Check if method name matches @@ -316,10 +374,14 @@ // get super_klass for method_holder for the found method InstanceKlass* super_klass = super_method->method_holder(); - if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) || - ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) - && ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader, - target_classname, THREAD)) != (InstanceKlass*)NULL))) { + if (is_default + || ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) + || ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) + && ((super_klass = find_transitive_override(super_klass, + target_method, i, target_loader, + target_classname, THREAD)) + != (InstanceKlass*)NULL)))) + { // overriding, so no new entry allocate_new = false; @@ -346,7 +408,7 @@ "%s used in the signature"; char* sig = target_method()->name_and_sig_as_C_string(); const char* loader1 = SystemDictionary::loader_name(target_loader()); - char* current = _klass->name()->as_C_string(); + char* current = target_klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(super_loader()); char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + @@ -359,16 +421,39 @@ } } - put_method_at(target_method(), i); - target_method()->set_vtable_index(i); + put_method_at(target_method(), i); + if (!is_default) { + target_method()->set_vtable_index(i); + } else { + if (def_vtable_indices != NULL) { + def_vtable_indices->at_put(default_index, i); + } + assert(super_method->is_default_method() || super_method->is_overpass() + || super_method->is_abstract(), "default override error"); + } + + #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + char* sig = target_method()->name_and_sig_as_C_string(); tty->print("overriding with %s::%s index %d, original flags: ", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i); + target_klass->internal_name(), sig, i); super_method->access_flags().print_on(tty); + if (super_method->is_default_method()) { + tty->print("default"); + } + if (super_method->is_overpass()) { + tty->print("overpass"); + } tty->print("overriders flags: "); target_method->access_flags().print_on(tty); + if (target_method->is_default_method()) { + tty->print("default"); + } + if (target_method->is_overpass()) { + tty->print("overpass"); + } tty->cr(); } #endif /*PRODUCT*/ @@ -377,12 +462,25 @@ // but not override another. Once we override one, not need new #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + char* sig = target_method()->name_and_sig_as_C_string(); tty->print("NOT overriding with %s::%s index %d, original flags: ", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i); + target_klass->internal_name(), sig,i); super_method->access_flags().print_on(tty); + if (super_method->is_default_method()) { + tty->print("default"); + } + if (super_method->is_overpass()) { + tty->print("overpass"); + } tty->print("overriders flags: "); target_method->access_flags().print_on(tty); + if (target_method->is_default_method()) { + tty->print("default"); + } + if (target_method->is_overpass()) { + tty->print("overpass"); + } tty->cr(); } #endif /*PRODUCT*/ @@ -437,14 +535,23 @@ return false; } + // Concrete interface methods do not need new entries, they override + // abstract method entries using default inheritance rules + if (target_method()->method_holder() != NULL && + target_method()->method_holder()->is_interface() && + !target_method()->is_abstract() ) { + return false; + } + // we need a new entry if there is no superclass if (super == NULL) { return true; } - // private methods always have a new entry in the vtable + // private methods in classes always have a new entry in the vtable // specification interpretation since classic has // private methods not overriding + // JDK8 adds private methods in interfaces which require invokespecial if (target_method()->is_private()) { return true; } @@ -520,37 +627,44 @@ Klass* method_holder = m->method_holder(); InstanceKlass *mhk = InstanceKlass::cast(method_holder); - // miranda methods are interface methods in a class's vtable + // miranda methods are public abstract instance interface methods in a class's vtable if (mhk->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(method_holder) , "this class should implement the interface"); - assert(is_miranda(m, ik()->methods(), ik()->super()), "should be a miranda_method"); + assert(is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super()), "should be a miranda_method"); return true; } return false; } -// check if a method is a miranda method, given a class's methods table and its super -// "miranda" means not static, not defined by this class, and not defined -// in super unless it is private and therefore inaccessible to this class. +// check if a method is a miranda method, given a class's methods table, +// its default_method table and its super +// "miranda" means not static, not defined by this class. +// private methods in interfaces do not belong in the miranda list. // the caller must make sure that the method belongs to an interface implemented by the class -bool klassVtable::is_miranda(Method* m, Array* class_methods, Klass* super) { - if (m->is_static()) { +// Miranda methods only include public interface instance methods +// Not private methods, not static methods, not default == concrete abstract +bool klassVtable::is_miranda(Method* m, Array* class_methods, + Array* default_methods, Klass* super) { + if (m->is_static() || m->is_private()) { return false; } Symbol* name = m->name(); Symbol* signature = m->signature(); if (InstanceKlass::find_method(class_methods, name, signature) == NULL) { // did not find it in the method table of the current class - if (super == NULL) { - // super doesn't exist - return true; - } + if ((default_methods == NULL) || + InstanceKlass::find_method(default_methods, name, signature) == NULL) { + if (super == NULL) { + // super doesn't exist + return true; + } - Method* mo = InstanceKlass::cast(super)->lookup_method(name, signature); - if (mo == NULL || mo->access_flags().is_private() ) { - // super class hierarchy does not implement it or protection is different - return true; + Method* mo = InstanceKlass::cast(super)->lookup_method(name, signature); + if (mo == NULL || mo->access_flags().is_private() ) { + // super class hierarchy does not implement it or protection is different + return true; + } } } @@ -558,7 +672,7 @@ } // Scans current_interface_methods for miranda methods that do not -// already appear in new_mirandas and are also not defined-and-non-private +// already appear in new_mirandas, or default methods, and are also not defined-and-non-private // in super (superclass). These mirandas are added to all_mirandas if it is // not null; in addition, those that are not duplicates of miranda methods // inherited by super from its interfaces are added to new_mirandas. @@ -568,7 +682,8 @@ void klassVtable::add_new_mirandas_to_lists( GrowableArray* new_mirandas, GrowableArray* all_mirandas, Array* current_interface_methods, Array* class_methods, - Klass* super) { + Array* default_methods, Klass* super) { + // iterate thru the current interface's method to see if it a miranda int num_methods = current_interface_methods->length(); for (int i = 0; i < num_methods; i++) { @@ -586,7 +701,7 @@ } if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable - if (is_miranda(im, class_methods, super)) { // is it a miranda at all? + if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all? InstanceKlass *sk = InstanceKlass::cast(super); // check if it is a duplicate of a super's miranda if (sk->lookup_method_in_all_interfaces(im->name(), im->signature()) == NULL) { @@ -603,6 +718,7 @@ void klassVtable::get_mirandas(GrowableArray* new_mirandas, GrowableArray* all_mirandas, Klass* super, Array* class_methods, + Array* default_methods, Array* local_interfaces) { assert((new_mirandas->length() == 0) , "current mirandas must be 0"); @@ -611,14 +727,16 @@ for (int i = 0; i < num_local_ifs; i++) { InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i)); add_new_mirandas_to_lists(new_mirandas, all_mirandas, - ik->methods(), class_methods, super); + ik->methods(), class_methods, + default_methods, super); // iterate thru each local's super interfaces Array* super_ifs = ik->transitive_interfaces(); int num_super_ifs = super_ifs->length(); for (int j = 0; j < num_super_ifs; j++) { InstanceKlass *sik = InstanceKlass::cast(super_ifs->at(j)); add_new_mirandas_to_lists(new_mirandas, all_mirandas, - sik->methods(), class_methods, super); + sik->methods(), class_methods, + default_methods, super); } } } @@ -629,8 +747,22 @@ int klassVtable::fill_in_mirandas(int initialized) { GrowableArray mirandas(20); get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(), - ik()->local_interfaces()); + ik()->default_methods(), ik()->local_interfaces()); for (int i = 0; i < mirandas.length(); i++) { + if (PrintVtables && Verbose) { + Method* meth = mirandas.at(i); + ResourceMark rm(Thread::current()); + if (meth != NULL) { + char* sig = meth->name_and_sig_as_C_string(); + tty->print("fill in mirandas with %s index %d, flags: ", + sig, initialized); + meth->access_flags().print_on(tty); + if (meth->is_default_method()) { + tty->print("default"); + } + tty->cr(); + } + } put_method_at(mirandas.at(i), initialized); ++initialized; } @@ -644,6 +776,26 @@ } #if INCLUDE_JVMTI +bool klassVtable::adjust_default_method(int vtable_index, Method* old_method, Method* new_method) { + // If old_method is default, find this vtable index in default_vtable_indices + // and replace that method in the _default_methods list + bool updated = false; + + Array* default_methods = ik()->default_methods(); + if (default_methods != NULL) { + int len = default_methods->length(); + for (int idx = 0; idx < len; idx++) { + if (vtable_index == ik()->default_vtable_indices()->at(idx)) { + if (default_methods->at(idx) == old_method) { + default_methods->at_put(idx, new_method); + updated = true; + } + break; + } + } + } + return updated; +} void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed) { // search the vtable for uses of either obsolete or EMCP methods @@ -659,18 +811,26 @@ for (int index = 0; index < length(); index++) { if (unchecked_method_at(index) == old_method) { put_method_at(new_method, index); + // For default methods, need to update the _default_methods array + // which can only have one method entry for a given signature + bool updated_default = false; + if (old_method->is_default_method()) { + updated_default = adjust_default_method(index, old_method, new_method); + } if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { if (!(*trace_name_printed)) { // RC_TRACE_MESG macro has an embedded ResourceMark - RC_TRACE_MESG(("adjust: name=%s", + RC_TRACE_MESG(("adjust: klassname=%s for methods from name=%s", + klass()->external_name(), old_method->method_holder()->external_name())); *trace_name_printed = true; } // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00100000, ("vtable method update: %s(%s)", + RC_TRACE(0x00100000, ("vtable method update: %s(%s), updated default = %s", new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); + new_method->signature()->as_C_string(), + updated_default ? "true" : "false")); } // cannot 'break' here; see for-loop comment above. } @@ -697,6 +857,12 @@ if (m != NULL) { tty->print(" (%5d) ", i); m->access_flags().print_on(tty); + if (m->is_default_method()) { + tty->print("default"); + } + if (m->is_overpass()) { + tty->print("overpass"); + } tty->print(" -- "); m->print_name(tty); tty->cr(); @@ -753,9 +919,9 @@ // Initialization void klassItable::initialize_itable(bool checkconstraints, TRAPS) { if (_klass->is_interface()) { - // This needs to go after vtable indexes are assigned but - // before implementors need to know the number of itable indexes. - assign_itable_indexes_for_interface(_klass()); + // This needs to go after vtable indices are assigned but + // before implementors need to know the number of itable indices. + assign_itable_indices_for_interface(_klass()); } // Cannot be setup doing bootstrapping, interfaces don't have @@ -799,7 +965,7 @@ return true; } -int klassItable::assign_itable_indexes_for_interface(Klass* klass) { +int klassItable::assign_itable_indices_for_interface(Klass* klass) { // an interface does not have an itable, but its methods need to be numbered if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count, klass->name()->as_C_string()); @@ -842,7 +1008,7 @@ } nof_methods -= 1; } - // no methods have itable indexes + // no methods have itable indices return 0; } @@ -903,6 +1069,21 @@ int ime_num = m->itable_index(); assert(ime_num < ime_count, "oob"); itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target()); + if (TraceItables && Verbose) { + ResourceMark rm(THREAD); + if (target() != NULL) { + char* sig = target()->name_and_sig_as_C_string(); + tty->print("interface: %s, ime_num: %d, target: %s, method_holder: %s ", + interf_h()->internal_name(), ime_num, sig, + target()->method_holder()->internal_name()); + tty->print("target_method flags: "); + target()->access_flags().print_on(tty); + if (target()->is_default_method()) { + tty->print("default"); + } + tty->cr(); + } + } } } } @@ -976,6 +1157,9 @@ if (m != NULL) { tty->print(" (%5d) ", i); m->access_flags().print_on(tty); + if (m->is_default_method()) { + tty->print("default"); + } tty->print(" -- "); m->print_name(tty); tty->cr(); @@ -1112,7 +1296,7 @@ Array* methods = InstanceKlass::cast(intf)->methods(); if (itable_index < 0 || itable_index >= method_count_for_interface(intf)) - return NULL; // help caller defend against bad indexes + return NULL; // help caller defend against bad indices int index = itable_index; Method* m = methods->at(index); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/klassVtable.hpp --- a/src/share/vm/oops/klassVtable.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/klassVtable.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -97,6 +97,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. + bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method); void adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed); bool check_no_old_or_obsolete_entries(); @@ -118,24 +119,28 @@ void put_method_at(Method* m, int index); static bool needs_new_vtable_entry(methodHandle m, Klass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, TRAPS); - bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); + bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, int default_index, bool checkconstraints, TRAPS); InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, methodHandle target_method, int vtable_index, Handle target_loader, Symbol* target_classname, Thread* THREAD); // support for miranda methods bool is_miranda_entry_at(int i); int fill_in_mirandas(int initialized); - static bool is_miranda(Method* m, Array* class_methods, Klass* super); + static bool is_miranda(Method* m, Array* class_methods, + Array* default_methods, Klass* super); static void add_new_mirandas_to_lists( GrowableArray* new_mirandas, GrowableArray* all_mirandas, - Array* current_interface_methods, Array* class_methods, + Array* current_interface_methods, + Array* class_methods, + Array* default_methods, Klass* super); static void get_mirandas( GrowableArray* new_mirandas, GrowableArray* all_mirandas, Klass* super, - Array* class_methods, Array* local_interfaces); - + Array* class_methods, + Array* default_methods, + Array* local_interfaces); void verify_against(outputStream* st, klassVtable* vt, int index); inline InstanceKlass* ik() const; }; @@ -290,7 +295,7 @@ #endif // INCLUDE_JVMTI // Setup of itable - static int assign_itable_indexes_for_interface(Klass* klass); + static int assign_itable_indices_for_interface(Klass* klass); static int method_count_for_interface(Klass* klass); static int compute_itable_size(Array* transitive_interfaces); static void setup_itable_offset_table(instanceKlassHandle klass); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/method.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -511,9 +511,9 @@ bool Method::is_final_method(AccessFlags class_access_flags) const { // or "does_not_require_vtable_entry" - // overpass can occur, is not final (reuses vtable entry) + // default method or overpass can occur, is not final (reuses vtable entry) // private methods get vtable entries for backward class compatibility. - if (is_overpass()) return false; + if (is_overpass() || is_default_method()) return false; return is_final() || class_access_flags.is_final(); } @@ -521,11 +521,24 @@ return is_final_method(method_holder()->access_flags()); } +bool Method::is_default_method() const { + if (method_holder() != NULL && + method_holder()->is_interface() && + !is_abstract()) { + return true; + } else { + return false; + } +} + bool Method::can_be_statically_bound(AccessFlags class_access_flags) const { if (is_final_method(class_access_flags)) return true; #ifdef ASSERT + ResourceMark rm; bool is_nonv = (vtable_index() == nonvirtual_vtable_index); - if (class_access_flags.is_interface()) assert(is_nonv == is_static(), err_msg("is_nonv=%s", is_nonv)); + if (class_access_flags.is_interface()) { + assert(is_nonv == is_static(), err_msg("is_nonv=%s", name_and_sig_as_C_string())); + } #endif assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question"); return vtable_index() == nonvirtual_vtable_index; @@ -901,16 +914,6 @@ // This function must not hit a safepoint! address Method::verified_code_entry() { debug_only(No_Safepoint_Verifier nsv;) - nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code); - if (code == NULL && UseCodeCacheFlushing) { - nmethod *saved_code = CodeCache::reanimate_saved_code(this); - if (saved_code != NULL) { - methodHandle method(this); - assert( ! saved_code->is_osr_method(), "should not get here for osr" ); - set_code( method, saved_code ); - } - } - assert(_from_compiled_entry != NULL, "must be set"); return _from_compiled_entry; } @@ -1381,7 +1384,8 @@ } // This is only done during class loading, so it is OK to assume method_idnum matches the methods() array -void Method::sort_methods(Array* methods, bool idempotent) { +// default_methods also uses this without the ordering for fast find_method +void Method::sort_methods(Array* methods, bool idempotent, bool set_idnums) { int length = methods->length(); if (length > 1) { { @@ -1389,14 +1393,15 @@ QuickSort::sort(methods->data(), length, method_comparator, idempotent); } // Reset method ordering - for (int i = 0; i < length; i++) { - Method* m = methods->at(i); - m->set_method_idnum(i); + if (set_idnums) { + for (int i = 0; i < length; i++) { + Method* m = methods->at(i); + m->set_method_idnum(i); + } } } } - //----------------------------------------------------------------------------------- // Non-product code unless JVM/TI needs it diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/method.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -567,6 +567,7 @@ // checks method and its method holder bool is_final_method() const; bool is_final_method(AccessFlags class_access_flags) const; + bool is_default_method() const; // true if method needs no dynamic dispatch (final and/or no vtable entry) bool can_be_statically_bound() const; @@ -846,7 +847,7 @@ #endif // Helper routine used for method sorting - static void sort_methods(Array* methods, bool idempotent = false); + static void sort_methods(Array* methods, bool idempotent = false, bool set_idnums = true); // Deallocation function for redefine classes or if an error occurs void deallocate_contents(ClassLoaderData* loader_data); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/methodData.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -333,10 +333,10 @@ return (int)data()->cell_at(index); } void set_oop_at(int index, oop value) { - set_intptr_at(index, (intptr_t) value); + set_intptr_at(index, cast_from_oop(value)); } oop oop_at(int index) { - return (oop)intptr_at(index); + return cast_to_oop(intptr_at(index)); } void set_flag_at(int flag_number) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/oop.inline.hpp --- a/src/share/vm/oops/oop.inline.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/oop.inline.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -183,7 +183,7 @@ // in inner GC loops so these are separated. inline bool check_obj_alignment(oop obj) { - return (intptr_t)obj % MinObjAlignmentInBytes == 0; + return cast_from_oop(obj) % MinObjAlignmentInBytes == 0; } inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/oops/oopsHierarchy.hpp --- a/src/share/vm/oops/oopsHierarchy.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/oops/oopsHierarchy.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -55,11 +55,16 @@ // to and from the underlying oopDesc pointer type. // // Because oop and its subclasses Oop are class types, arbitrary -// conversions are not accepted by the compiler, and you may get a message -// about overloading ambiguity (between long and int is common when converting -// from a constant in 64 bit mode), or unable to convert from type to 'oop'. -// Applying a cast to one of these conversion operators first will get to the -// underlying oopDesc* type if appropriate. +// conversions are not accepted by the compiler. Applying a cast to +// an oop will cause the best matched conversion operator to be +// invoked returning the underlying oopDesc* type if appropriate. +// No copy constructors, explicit user conversions or operators of +// numerical type should be defined within the oop class. Most C++ +// compilers will issue a compile time error concerning the overloading +// ambiguity between operators of numerical and pointer types. If +// a conversion to or from an oop to a numerical type is needed, +// use the inline template methods, cast_*_oop, defined below. +// // Converting NULL to oop to Handle implicit is no longer accepted by the // compiler because there are too many steps in the conversion. Use Handle() // instead, which generates less code anyway. @@ -83,12 +88,9 @@ void raw_set_obj(const void* p) { _o = (oopDesc*)p; } oop() { set_obj(NULL); } + oop(const oop& o) { set_obj(o.obj()); } oop(const volatile oop& o) { set_obj(o.obj()); } oop(const void* p) { set_obj(p); } - oop(intptr_t i) { set_obj((void *)i); } -#ifdef _LP64 - oop(int i) { set_obj((void *)i); } -#endif ~oop() { if (CheckUnhandledOops) unregister_oop(); } @@ -101,8 +103,6 @@ bool operator==(void *p) const { return obj() == p; } bool operator!=(const volatile oop o) const { return obj() != o.obj(); } bool operator!=(void *p) const { return obj() != p; } - bool operator==(intptr_t p) const { return obj() == (oopDesc*)p; } - bool operator!=(intptr_t p) const { return obj() != (oopDesc*)p; } bool operator<(oop o) const { return obj() < o.obj(); } bool operator>(oop o) const { return obj() > o.obj(); } @@ -110,8 +110,18 @@ bool operator>=(oop o) const { return obj() >= o.obj(); } bool operator!() const { return !obj(); } - // Cast + // Assignment + oop& operator=(const oop& o) { _o = o.obj(); return *this; } +#ifndef SOLARIS + volatile oop& operator=(const oop& o) volatile { _o = o.obj(); return *this; } +#endif + volatile oop& operator=(const volatile oop& o) volatile { _o = o.obj(); return *this; } + + // Explict user conversions operator void* () const { return (void *)obj(); } +#ifndef SOLARIS + operator void* () const volatile { return (void *)obj(); } +#endif operator HeapWord* () const { return (HeapWord*)obj(); } operator oopDesc* () const { return obj(); } operator intptr_t* () const { return (intptr_t*)obj(); } @@ -119,7 +129,6 @@ operator markOop () const { return markOop(obj()); } operator address () const { return (address)obj(); } - operator intptr_t () const volatile { return (intptr_t)obj(); } // from javaCalls.cpp operator jobject () const { return (jobject)obj(); } @@ -141,12 +150,26 @@ class type##Oop : public oop { \ public: \ type##Oop() : oop() {} \ + type##Oop(const oop& o) : oop(o) {} \ type##Oop(const volatile oop& o) : oop(o) {} \ type##Oop(const void* p) : oop(p) {} \ operator type##OopDesc* () const { return (type##OopDesc*)obj(); } \ type##OopDesc* operator->() const { \ return (type##OopDesc*)obj(); \ } \ + type##Oop& operator=(const type##Oop& o) { \ + oop::operator=(o); \ + return *this; \ + } \ + NOT_SOLARIS( \ + volatile type##Oop& operator=(const type##Oop& o) volatile { \ + (void)const_cast(oop::operator=(o)); \ + return *this; \ + }) \ + volatile type##Oop& operator=(const volatile type##Oop& o) volatile {\ + (void)const_cast(oop::operator=(o)); \ + return *this; \ + } \ }; DEF_OOP(instance); @@ -156,6 +179,16 @@ #endif // CHECK_UNHANDLED_OOPS +// For CHECK_UNHANDLED_OOPS, it is ambiguous C++ behavior to have the oop +// structure contain explicit user defined conversions of both numerical +// and pointer type. Define inline methods to provide the numerical conversions. +template inline oop cast_to_oop(T value) { + return (oop)(CHECK_UNHANDLED_OOPS_ONLY((void *))(value)); +} +template inline T cast_from_oop(oop o) { + return (T)(CHECK_UNHANDLED_OOPS_ONLY((void*))o); +} + // The metadata hierarchy is separate from the oop hierarchy // class MetaspaceObj diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/c2_globals.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -636,7 +636,9 @@ \ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ - + \ + product(bool, UseMathExactIntrinsics, true, \ + "Enables intrinsification of various java.lang.Math funcitons") C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/callGenerator.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -65,6 +65,8 @@ virtual bool is_predicted() const { return false; } // is_trap: Does not return to the caller. (E.g., uncommon trap.) virtual bool is_trap() const { return false; } + // does_virtual_dispatch: Should try inlining as normal method first. + virtual bool does_virtual_dispatch() const { return false; } // is_late_inline: supports conversion of call into an inline virtual bool is_late_inline() const { return false; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/classes.cpp --- a/src/share/vm/opto/classes.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/classes.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -32,6 +32,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/multnode.hpp" #include "opto/node.hpp" diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/classes.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -29,6 +29,7 @@ macro(AbsF) macro(AbsI) macro(AddD) +macro(AddExactI) macro(AddF) macro(AddI) macro(AddL) @@ -133,6 +134,7 @@ macro(ExpD) macro(FastLock) macro(FastUnlock) +macro(FlagsProj) macro(Goto) macro(Halt) macro(If) @@ -167,6 +169,7 @@ macro(LoopLimit) macro(Mach) macro(MachProj) +macro(MathExact) macro(MaxI) macro(MemBarAcquire) macro(MemBarAcquireLock) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/doCall.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -110,6 +110,7 @@ // then we return it as the inlined version of the call. // We do this before the strict f.p. check below because the // intrinsics handle strict f.p. correctly. + CallGenerator* cg_intrinsic = NULL; if (allow_inline && allow_intrinsics) { CallGenerator* cg = find_intrinsic(callee, call_does_dispatch); if (cg != NULL) { @@ -121,7 +122,16 @@ cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); } } - return cg; + + // If intrinsic does the virtual dispatch, we try to use the type profile + // first, and hopefully inline it as the regular virtual call below. + // We will retry the intrinsic if nothing had claimed it afterwards. + if (cg->does_virtual_dispatch()) { + cg_intrinsic = cg; + cg = NULL; + } else { + return cg; + } } } @@ -266,6 +276,13 @@ } } + // Nothing claimed the intrinsic, we go with straight-forward inlining + // for already discovered intrinsic. + if (allow_inline && allow_intrinsics && cg_intrinsic != NULL) { + assert(cg_intrinsic->does_virtual_dispatch(), "sanity"); + return cg_intrinsic; + } + // There was no special inlining tactic, or it bailed out. // Use a more generic tactic, like a simple call. if (call_does_dispatch) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/graphKit.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -3713,7 +3713,8 @@ Node* no_base = __ top(); float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); - Node* zero = __ ConI(0); + Node* young_card = __ ConI((jint)G1SATBCardTableModRefBS::g1_young_card_val()); + Node* dirty_card = __ ConI((jint)CardTableModRefBS::dirty_card_val()); Node* zeroX = __ ConX(0); // Get the alias_index for raw card-mark memory @@ -3769,8 +3770,16 @@ // load the original value of the card Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val, BoolTest::ne, zero); { - g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); + __ if_then(card_val, BoolTest::ne, young_card); { + sync_kit(ideal); + // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. + insert_mem_bar(Op_MemBarVolatile, oop_store); + __ sync_kit(this); + + Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); + __ if_then(card_val_reload, BoolTest::ne, dirty_card); { + g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); + } __ end_if(); } __ end_if(); } __ end_if(); } __ end_if(); @@ -3849,9 +3858,9 @@ const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* value_field_type = string_type->add_offset(value_offset); - int value_field_idx = C->get_alias_index(value_field_type); - store_to_memory(ctrl, basic_plus_adr(str, value_offset), - value, T_OBJECT, value_field_idx); + + store_oop_to_object(ctrl, str, basic_plus_adr(str, value_offset), value_field_type, + value, TypeAryPtr::CHARS, T_OBJECT); } void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/ifnode.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -76,6 +76,7 @@ if( !i1->is_Bool() ) return NULL; BoolNode *b = i1->as_Bool(); Node *cmp = b->in(1); + if( cmp->is_FlagsProj() ) return NULL; if( !cmp->is_Cmp() ) return NULL; i1 = cmp->in(1); if( i1 == NULL || !i1->is_Phi() ) return NULL; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/lcm.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -472,6 +472,13 @@ break; } + // For nodes that produce a FlagsProj, make the node adjacent to the + // use of the FlagsProj + if (use->is_FlagsProj() && get_block_for_node(use) == block) { + found_machif = true; + break; + } + // More than this instruction pending for successor to be ready, // don't choose this if other opportunities are ready if (ready_cnt.at(use->_idx) > 1) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/library_call.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -32,6 +32,7 @@ #include "opto/callGenerator.hpp" #include "opto/cfgnode.hpp" #include "opto/idealKit.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" @@ -46,19 +47,22 @@ private: bool _is_virtual; bool _is_predicted; + bool _does_virtual_dispatch; vmIntrinsics::ID _intrinsic_id; public: - LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, vmIntrinsics::ID id) + LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, bool does_virtual_dispatch, vmIntrinsics::ID id) : InlineCallGenerator(m), _is_virtual(is_virtual), _is_predicted(is_predicted), + _does_virtual_dispatch(does_virtual_dispatch), _intrinsic_id(id) { } virtual bool is_intrinsic() const { return true; } virtual bool is_virtual() const { return _is_virtual; } virtual bool is_predicted() const { return _is_predicted; } + virtual bool does_virtual_dispatch() const { return _does_virtual_dispatch; } virtual JVMState* generate(JVMState* jvms); virtual Node* generate_predicate(JVMState* jvms); vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } @@ -199,6 +203,8 @@ bool inline_math_native(vmIntrinsics::ID id); bool inline_trig(vmIntrinsics::ID id); bool inline_math(vmIntrinsics::ID id); + bool inline_math_mathExact(Node* math); + bool inline_math_addExact(); bool inline_exp(); bool inline_pow(); void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); @@ -352,6 +358,7 @@ } bool is_predicted = false; + bool does_virtual_dispatch = false; switch (id) { case vmIntrinsics::_compareTo: @@ -378,8 +385,10 @@ break; case vmIntrinsics::_hashCode: if (!InlineObjectHash) return NULL; + does_virtual_dispatch = true; break; case vmIntrinsics::_clone: + does_virtual_dispatch = true; case vmIntrinsics::_copyOf: case vmIntrinsics::_copyOfRange: if (!InlineObjectCopy) return NULL; @@ -498,6 +507,15 @@ if (!UseCRC32Intrinsics) return NULL; break; + case vmIntrinsics::_addExact: + if (!Matcher::match_rule_supported(Op_AddExactI)) { + return NULL; + } + if (!UseMathExactIntrinsics) { + return NULL; + } + break; + default: assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); @@ -529,7 +547,7 @@ if (!InlineUnsafeOps) return NULL; } - return new LibraryIntrinsic(m, is_virtual, is_predicted, (vmIntrinsics::ID) id); + return new LibraryIntrinsic(m, is_virtual, is_predicted, does_virtual_dispatch, (vmIntrinsics::ID) id); } //----------------------register_library_intrinsics----------------------- @@ -668,6 +686,8 @@ case vmIntrinsics::_min: case vmIntrinsics::_max: return inline_min_max(intrinsic_id()); + case vmIntrinsics::_addExact: return inline_math_addExact(); + case vmIntrinsics::_arraycopy: return inline_arraycopy(); case vmIntrinsics::_compareTo: return inline_string_compareTo(); @@ -1911,6 +1931,45 @@ return true; } +bool LibraryCallKit::inline_math_mathExact(Node* math) { + Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node)); + Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node)); + + Node* bol = _gvn.transform( new (C) BoolNode(flags, BoolTest::overflow) ); + IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); + Node* fast_path = _gvn.transform( new (C) IfFalseNode(check)); + Node* slow_path = _gvn.transform( new (C) IfTrueNode(check) ); + + { + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + } + + set_control(fast_path); + set_result(result); + return true; +} + +bool LibraryCallKit::inline_math_addExact() { + Node* arg1 = argument(0); + Node* arg2 = argument(1); + + Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) ); + if (add->Opcode() == Op_AddExactI) { + return inline_math_mathExact(add); + } else { + set_result(add); + } + return true; +} + Node* LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) { // These are the candidate return value: diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/loopTransform.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -776,6 +776,9 @@ continue; // not RC Node *cmp = bol->in(1); + if (cmp->is_FlagsProj()) { + continue; + } Node *rc_exp = cmp->in(1); Node *limit = cmp->in(2); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/loopopts.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -2355,7 +2355,8 @@ opc == Op_Catch || opc == Op_CatchProj || opc == Op_Jump || - opc == Op_JumpProj) { + opc == Op_JumpProj || + opc == Op_FlagsProj) { #if !defined(PRODUCT) if (TracePartialPeeling) { tty->print_cr("\nExit control too complex: lp: %d", head->_idx); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/machnode.cpp --- a/src/share/vm/opto/machnode.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/machnode.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -341,7 +341,7 @@ return TypePtr::BOTTOM; } // %%% make offset be intptr_t - assert(!Universe::heap()->is_in_reserved((oop)offset), "must be a raw ptr"); + assert(!Universe::heap()->is_in_reserved(cast_to_oop(offset)), "must be a raw ptr"); return TypeRawPtr::BOTTOM; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/matcher.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1964,6 +1964,7 @@ case Op_Catch: case Op_CatchProj: case Op_CProj: + case Op_FlagsProj: case Op_JumpProj: case Op_JProj: case Op_NeverBranch: diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/matcher.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -337,6 +337,9 @@ // Register for MODL projection of divmodL static RegMask modL_proj_mask(); + static const RegMask mathExactI_result_proj_mask(); + static const RegMask mathExactI_flags_proj_mask(); + // Use hardware DIV instruction when it is faster than // a code which use multiply for division by constant. static bool use_asm_for_ldiv_by_con( jlong divisor ); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/mathexactnode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.inline.hpp" +#include "opto/addnode.hpp" +#include "opto/machnode.hpp" +#include "opto/mathexactnode.hpp" +#include "opto/matcher.hpp" +#include "opto/subnode.hpp" + +MathExactNode::MathExactNode(Node* ctrl, Node* n1, Node* n2) : MultiNode(3) { + init_req(0, ctrl); + init_req(1, n1); + init_req(2, n2); +} + +Node* AddExactINode::match(const ProjNode* proj, const Matcher* m) { + uint ideal_reg = proj->ideal_reg(); + RegMask rm; + if (proj->_con == result_proj_node) { + rm = m->mathExactI_result_proj_mask(); + } else { + assert(proj->_con == flags_proj_node, "must be result or flags"); + assert(ideal_reg == Op_RegFlags, "sanity"); + rm = m->mathExactI_flags_proj_mask(); + } + return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg); +} + +// If the MathExactNode won't overflow we have to replace the +// FlagsProjNode and ProjNode that is generated by the MathExactNode +Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) { + PhaseIterGVN *igvn = phase->is_IterGVN(); + if (igvn) { + ProjNode* result = result_node(); + ProjNode* flags = flags_node(); + + if (result != NULL) { + igvn->replace_node(result, new_result); + } + + if (flags != NULL) { + BoolNode* bolnode = (BoolNode *) flags->unique_out(); + switch (bolnode->_test._test) { + case BoolTest::overflow: + // if the check is for overflow - never taken + igvn->replace_node(bolnode, phase->intcon(0)); + break; + case BoolTest::no_overflow: + // if the check is for no overflow - always taken + igvn->replace_node(bolnode, phase->intcon(1)); + break; + default: + fatal("Unexpected value of BoolTest"); + break; + } + flags->del_req(0); + } + } + return new_result; +} + +Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node *arg1 = in(1); + Node *arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jint val1 = arg1->get_int(); + jint val2 = arg2->get_int(); + jint result = val1 + val2; + // Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result + if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) { + Node* con_result = ConINode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeInt::ZERO) { // (Add 0 x) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2 == TypeInt::ZERO) { // (Add x 0) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2->singleton()) { + return NULL; // no change - keep constant on the right + } + + if (type1->singleton()) { + // Make it x + Constant - move constant to the right + swap_edges(1, 2); + return this; + } + + if (arg2->is_Load()) { + return NULL; // no change - keep load on the right + } + + if (arg1->is_Load()) { + // Make it x + Load - move load to the right + swap_edges(1, 2); + return this; + } + + if (arg1->_idx > arg2->_idx) { + // Sort the edges + swap_edges(1, 2); + return this; + } + + return NULL; +} + diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/mathexactnode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OPTO_MATHEXACTNODE_HPP +#define SHARE_VM_OPTO_MATHEXACTNODE_HPP + +#include "opto/multnode.hpp" +#include "opto/node.hpp" +#include "opto/type.hpp" + +class Node; + +class PhaseGVN; +class PhaseTransform; + +class MathExactNode : public MultiNode { +public: + MathExactNode(Node* ctrl, Node* in1, Node* in2); + enum { + result_proj_node = 0, + flags_proj_node = 1 + }; + virtual int Opcode() const; + virtual Node* Identity(PhaseTransform* phase) { return this; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) { return NULL; } + virtual const Type* Value(PhaseTransform* phase) const { return bottom_type(); } + virtual uint hash() const { return Node::hash(); } + virtual bool is_CFG() const { return false; } + virtual uint ideal_reg() const { return NotAMachineReg; } + + ProjNode* result_node() { return proj_out(result_proj_node); } + ProjNode* flags_node() { return proj_out(flags_proj_node); } +protected: + Node* no_overflow(PhaseGVN *phase, Node* new_result); +}; + +class AddExactINode : public MathExactNode { +public: + AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; } + virtual Node* match(const ProjNode* proj, const Matcher* m); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +class FlagsProjNode : public ProjNode { +public: + FlagsProjNode(Node* src, uint con) : ProjNode(src, con) { + init_class_id(Class_FlagsProj); + } + + virtual int Opcode() const; + virtual bool is_CFG() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::CC; } + virtual uint ideal_reg() const { return Op_RegFlags; } +}; + + +#endif + diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/multnode.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "opto/callnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/multnode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" @@ -46,15 +47,21 @@ assert(Opcode() != Op_If || outcnt() == 2, "bad if #1"); for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) { Node *p = fast_out(i); - if( !p->is_Proj() ) { + if (p->is_Proj()) { + ProjNode *proj = p->as_Proj(); + if (proj->_con == which_proj) { + assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); + return proj; + } + } else if (p->is_FlagsProj()) { + FlagsProjNode *proj = p->as_FlagsProj(); + if (proj->_con == which_proj) { + return proj; + } + } else { assert(p == this && this->is_Start(), "else must be proj"); continue; } - ProjNode *proj = p->as_Proj(); - if( proj->_con == which_proj ) { - assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); - return proj; - } } return NULL; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/node.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -69,6 +69,7 @@ class EncodePKlassNode; class FastLockNode; class FastUnlockNode; +class FlagsProjNode; class IfNode; class IfFalseNode; class IfTrueNode; @@ -623,6 +624,7 @@ DEFINE_CLASS_ID(Cmp, Sub, 0) DEFINE_CLASS_ID(FastLock, Cmp, 0) DEFINE_CLASS_ID(FastUnlock, Cmp, 1) + DEFINE_CLASS_ID(FlagsProj, Cmp, 2) DEFINE_CLASS_ID(MergeMem, Node, 7) DEFINE_CLASS_ID(Bool, Node, 8) @@ -726,6 +728,7 @@ DEFINE_CLASS_QUERY(EncodePKlass) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) + DEFINE_CLASS_QUERY(FlagsProj) DEFINE_CLASS_QUERY(If) DEFINE_CLASS_QUERY(IfFalse) DEFINE_CLASS_QUERY(IfTrue) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/subnode.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1064,7 +1064,7 @@ // Print special per-node info #ifndef PRODUCT void BoolTest::dump_on(outputStream *st) const { - const char *msg[] = {"eq","gt","??","lt","ne","le","??","ge"}; + const char *msg[] = {"eq","gt","of","lt","ne","le","nof","ge"}; st->print(msg[_test]); } #endif @@ -1126,7 +1126,7 @@ Node *cmp = in(1); if( !cmp->is_Sub() ) return NULL; int cop = cmp->Opcode(); - if( cop == Op_FastLock || cop == Op_FastUnlock ) return NULL; + if( cop == Op_FastLock || cop == Op_FastUnlock || cop == Op_FlagsProj) return NULL; Node *cmp1 = cmp->in(1); Node *cmp2 = cmp->in(2); if( !cmp1 ) return NULL; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/subnode.hpp --- a/src/share/vm/opto/subnode.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/subnode.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -263,16 +263,16 @@ // We pick the values as 3 bits; the low order 2 bits we compare against the // condition codes, the high bit flips the sense of the result. struct BoolTest VALUE_OBJ_CLASS_SPEC { - enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, illegal = 8 }; + enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, overflow = 2, no_overflow = 6, illegal = 8 }; mask _test; BoolTest( mask btm ) : _test(btm) {} const Type *cc2logical( const Type *CC ) const; // Commute the test. I use a small table lookup. The table is created as // a simple char array where each element is the ASCII version of a 'mask' // enum from above. - mask commute( ) const { return mask("038147858"[_test]-'0'); } + mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } - bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le); } + bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } #ifndef PRODUCT void dump_on(outputStream *st) const; #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/type.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -430,6 +430,11 @@ longpair[1] = TypeLong::LONG; TypeTuple::LONG_PAIR = TypeTuple::make(2, longpair); + const Type **intccpair = TypeTuple::fields(2); + intccpair[0] = TypeInt::INT; + intccpair[1] = TypeInt::CC; + TypeTuple::INT_CC_PAIR = TypeTuple::make(2, intccpair); + _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; _const_basic_type[T_NARROWKLASS] = Type::BOTTOM; _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; @@ -1646,6 +1651,7 @@ const TypeTuple *TypeTuple::START_I2C; const TypeTuple *TypeTuple::INT_PAIR; const TypeTuple *TypeTuple::LONG_PAIR; +const TypeTuple *TypeTuple::INT_CC_PAIR; //------------------------------make------------------------------------------- diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/opto/type.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -584,6 +584,7 @@ static const TypeTuple *START_I2C; static const TypeTuple *INT_PAIR; static const TypeTuple *LONG_PAIR; + static const TypeTuple *INT_CC_PAIR; #ifndef PRODUCT virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jni.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1591,10 +1591,8 @@ } } else { m = klass->lookup_method(name, signature); - // Look up interfaces - if (m == NULL && klass->oop_is_instance()) { - m = InstanceKlass::cast(klass())->lookup_method_in_all_interfaces(name, - signature); + if (m == NULL && klass->oop_is_instance()) { + m = InstanceKlass::cast(klass())->lookup_method_in_ordered_interfaces(name, signature); } } if (m == NULL || (m->is_static() != is_static)) { @@ -3210,7 +3208,11 @@ HOTSPOT_JNI_GETSTRINGLENGTH_ENTRY( env, string); #endif /* USDT2 */ - jsize ret = java_lang_String::length(JNIHandles::resolve_non_null(string)); + jsize ret = 0; + oop s = JNIHandles::resolve_non_null(string); + if (java_lang_String::value(s) != NULL) { + ret = java_lang_String::length(s); + } #ifndef USDT2 DTRACE_PROBE1(hotspot_jni, GetStringLength__return, ret); #else /* USDT2 */ @@ -3230,20 +3232,23 @@ HOTSPOT_JNI_GETSTRINGCHARS_ENTRY( env, string, (uintptr_t *) isCopy); #endif /* USDT2 */ + jchar* buf = NULL; oop s = JNIHandles::resolve_non_null(string); - int s_len = java_lang_String::length(s); typeArrayOop s_value = java_lang_String::value(s); - int s_offset = java_lang_String::offset(s); - jchar* buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination - /* JNI Specification states return NULL on OOM */ - if (buf != NULL) { - if (s_len > 0) { - memcpy(buf, s_value->char_at_addr(s_offset), sizeof(jchar)*s_len); - } - buf[s_len] = 0; - //%note jni_5 - if (isCopy != NULL) { - *isCopy = JNI_TRUE; + if (s_value != NULL) { + int s_len = java_lang_String::length(s); + int s_offset = java_lang_String::offset(s); + buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination + /* JNI Specification states return NULL on OOM */ + if (buf != NULL) { + if (s_len > 0) { + memcpy(buf, s_value->char_at_addr(s_offset), sizeof(jchar)*s_len); + } + buf[s_len] = 0; + //%note jni_5 + if (isCopy != NULL) { + *isCopy = JNI_TRUE; + } } } #ifndef USDT2 @@ -3313,7 +3318,11 @@ HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY( env, string); #endif /* USDT2 */ - jsize ret = java_lang_String::utf8_length(JNIHandles::resolve_non_null(string)); + jsize ret = 0; + oop java_string = JNIHandles::resolve_non_null(string); + if (java_lang_String::value(java_string) != NULL) { + ret = java_lang_String::utf8_length(java_string); + } #ifndef USDT2 DTRACE_PROBE1(hotspot_jni, GetStringUTFLength__return, ret); #else /* USDT2 */ @@ -3332,14 +3341,17 @@ HOTSPOT_JNI_GETSTRINGUTFCHARS_ENTRY( env, string, (uintptr_t *) isCopy); #endif /* USDT2 */ + char* result = NULL; oop java_string = JNIHandles::resolve_non_null(string); - size_t length = java_lang_String::utf8_length(java_string); - /* JNI Specification states return NULL on OOM */ - char* result = AllocateHeap(length + 1, mtInternal, 0, AllocFailStrategy::RETURN_NULL); - if (result != NULL) { - java_lang_String::as_utf8_string(java_string, result, (int) length + 1); - if (isCopy != NULL) { - *isCopy = JNI_TRUE; + if (java_lang_String::value(java_string) != NULL) { + size_t length = java_lang_String::utf8_length(java_string); + /* JNI Specification states return NULL on OOM */ + result = AllocateHeap(length + 1, mtInternal, 0, AllocFailStrategy::RETURN_NULL); + if (result != NULL) { + java_lang_String::as_utf8_string(java_string, result, (int) length + 1); + if (isCopy != NULL) { + *isCopy = JNI_TRUE; + } } } #ifndef USDT2 diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jniCheck.cpp --- a/src/share/vm/prims/jniCheck.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jniCheck.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1324,18 +1324,19 @@ IN_VM( checkString(thr, str); ) + jchar* newResult = NULL; const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy); assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringChars didn't return a copy as expected"); - - size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination - jint* tagLocation = (jint*) AllocateHeap(len * sizeof(jchar) + sizeof(jint), mtInternal); - *tagLocation = STRING_TAG; - jchar* newResult = (jchar*) (tagLocation + 1); - memcpy(newResult, result, len * sizeof(jchar)); - // Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes - // Note that the dtrace arguments for the allocated memory will not match up with this solution. - FreeHeap((char*)result); - + if (result != NULL) { + size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination + jint* tagLocation = (jint*) AllocateHeap(len * sizeof(jchar) + sizeof(jint), mtInternal); + *tagLocation = STRING_TAG; + newResult = (jchar*) (tagLocation + 1); + memcpy(newResult, result, len * sizeof(jchar)); + // Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes + // Note that the dtrace arguments for the allocated memory will not match up with this solution. + FreeHeap((char*)result); + } functionExit(env); return newResult; JNI_END @@ -1394,18 +1395,19 @@ IN_VM( checkString(thr, str); ) + char* newResult = NULL; const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy); assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected"); - - size_t len = strlen(result) + 1; // + 1 for NULL termination - jint* tagLocation = (jint*) AllocateHeap(len + sizeof(jint), mtInternal); - *tagLocation = STRING_UTF_TAG; - char* newResult = (char*) (tagLocation + 1); - strcpy(newResult, result); - // Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes - // Note that the dtrace arguments for the allocated memory will not match up with this solution. - FreeHeap((char*)result, mtInternal); - + if (result != NULL) { + size_t len = strlen(result) + 1; // + 1 for NULL termination + jint* tagLocation = (jint*) AllocateHeap(len + sizeof(jint), mtInternal); + *tagLocation = STRING_UTF_TAG; + newResult = (char*) (tagLocation + 1); + strcpy(newResult, result); + // Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes + // Note that the dtrace arguments for the allocated memory will not match up with this solution. + FreeHeap((char*)result, mtInternal); + } functionExit(env); return newResult; JNI_END diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jvm.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -668,13 +668,12 @@ JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth)) JVMWrapper("JVM_GetCallerClass"); - // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation. - if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) { + // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation; or + // sun.reflect.Reflection.getCallerClass with a depth parameter is provided + // temporarily for existing code to use until a replacement API is defined. + if (SystemDictionary::reflect_CallerSensitive_klass() == NULL || depth != JVM_CALLER_DEPTH) { Klass* k = thread->security_get_caller_class(depth); return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror()); - } else { - // Basic handshaking with Java_sun_reflect_Reflection_getCallerClass - assert(depth == -1, "wrong handshake depth"); } // Getting the class of the caller frame. @@ -3954,248 +3953,6 @@ } -// Serialization -JVM_ENTRY(void, JVM_SetPrimitiveFieldValues(JNIEnv *env, jclass cb, jobject obj, - jlongArray fieldIDs, jcharArray typecodes, jbyteArray data)) - assert(!JDK_Version::is_gte_jdk14x_version(), "should only be used in 1.3.1 and earlier"); - - typeArrayOop tcodes = typeArrayOop(JNIHandles::resolve(typecodes)); - typeArrayOop dbuf = typeArrayOop(JNIHandles::resolve(data)); - typeArrayOop fids = typeArrayOop(JNIHandles::resolve(fieldIDs)); - oop o = JNIHandles::resolve(obj); - - if (o == NULL || fids == NULL || dbuf == NULL || tcodes == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - - jsize nfids = fids->length(); - if (nfids == 0) return; - - if (tcodes->length() < nfids) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); - } - - jsize off = 0; - /* loop through fields, setting values */ - for (jsize i = 0; i < nfids; i++) { - jfieldID fid = (jfieldID)(intptr_t) fids->long_at(i); - int field_offset; - if (fid != NULL) { - // NULL is a legal value for fid, but retrieving the field offset - // trigger assertion in that case - field_offset = jfieldIDWorkaround::from_instance_jfieldID(o->klass(), fid); - } - - switch (tcodes->char_at(i)) { - case 'Z': - if (fid != NULL) { - jboolean val = (dbuf->byte_at(off) != 0) ? JNI_TRUE : JNI_FALSE; - o->bool_field_put(field_offset, val); - } - off++; - break; - - case 'B': - if (fid != NULL) { - o->byte_field_put(field_offset, dbuf->byte_at(off)); - } - off++; - break; - - case 'C': - if (fid != NULL) { - jchar val = ((dbuf->byte_at(off + 0) & 0xFF) << 8) - + ((dbuf->byte_at(off + 1) & 0xFF) << 0); - o->char_field_put(field_offset, val); - } - off += 2; - break; - - case 'S': - if (fid != NULL) { - jshort val = ((dbuf->byte_at(off + 0) & 0xFF) << 8) - + ((dbuf->byte_at(off + 1) & 0xFF) << 0); - o->short_field_put(field_offset, val); - } - off += 2; - break; - - case 'I': - if (fid != NULL) { - jint ival = ((dbuf->byte_at(off + 0) & 0xFF) << 24) - + ((dbuf->byte_at(off + 1) & 0xFF) << 16) - + ((dbuf->byte_at(off + 2) & 0xFF) << 8) - + ((dbuf->byte_at(off + 3) & 0xFF) << 0); - o->int_field_put(field_offset, ival); - } - off += 4; - break; - - case 'F': - if (fid != NULL) { - jint ival = ((dbuf->byte_at(off + 0) & 0xFF) << 24) - + ((dbuf->byte_at(off + 1) & 0xFF) << 16) - + ((dbuf->byte_at(off + 2) & 0xFF) << 8) - + ((dbuf->byte_at(off + 3) & 0xFF) << 0); - jfloat fval = (*int_bits_to_float_fn)(env, NULL, ival); - o->float_field_put(field_offset, fval); - } - off += 4; - break; - - case 'J': - if (fid != NULL) { - jlong lval = (((jlong) dbuf->byte_at(off + 0) & 0xFF) << 56) - + (((jlong) dbuf->byte_at(off + 1) & 0xFF) << 48) - + (((jlong) dbuf->byte_at(off + 2) & 0xFF) << 40) - + (((jlong) dbuf->byte_at(off + 3) & 0xFF) << 32) - + (((jlong) dbuf->byte_at(off + 4) & 0xFF) << 24) - + (((jlong) dbuf->byte_at(off + 5) & 0xFF) << 16) - + (((jlong) dbuf->byte_at(off + 6) & 0xFF) << 8) - + (((jlong) dbuf->byte_at(off + 7) & 0xFF) << 0); - o->long_field_put(field_offset, lval); - } - off += 8; - break; - - case 'D': - if (fid != NULL) { - jlong lval = (((jlong) dbuf->byte_at(off + 0) & 0xFF) << 56) - + (((jlong) dbuf->byte_at(off + 1) & 0xFF) << 48) - + (((jlong) dbuf->byte_at(off + 2) & 0xFF) << 40) - + (((jlong) dbuf->byte_at(off + 3) & 0xFF) << 32) - + (((jlong) dbuf->byte_at(off + 4) & 0xFF) << 24) - + (((jlong) dbuf->byte_at(off + 5) & 0xFF) << 16) - + (((jlong) dbuf->byte_at(off + 6) & 0xFF) << 8) - + (((jlong) dbuf->byte_at(off + 7) & 0xFF) << 0); - jdouble dval = (*long_bits_to_double_fn)(env, NULL, lval); - o->double_field_put(field_offset, dval); - } - off += 8; - break; - - default: - // Illegal typecode - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "illegal typecode"); - } - } -JVM_END - - -JVM_ENTRY(void, JVM_GetPrimitiveFieldValues(JNIEnv *env, jclass cb, jobject obj, - jlongArray fieldIDs, jcharArray typecodes, jbyteArray data)) - assert(!JDK_Version::is_gte_jdk14x_version(), "should only be used in 1.3.1 and earlier"); - - typeArrayOop tcodes = typeArrayOop(JNIHandles::resolve(typecodes)); - typeArrayOop dbuf = typeArrayOop(JNIHandles::resolve(data)); - typeArrayOop fids = typeArrayOop(JNIHandles::resolve(fieldIDs)); - oop o = JNIHandles::resolve(obj); - - if (o == NULL || fids == NULL || dbuf == NULL || tcodes == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - - jsize nfids = fids->length(); - if (nfids == 0) return; - - if (tcodes->length() < nfids) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); - } - - /* loop through fields, fetching values */ - jsize off = 0; - for (jsize i = 0; i < nfids; i++) { - jfieldID fid = (jfieldID)(intptr_t) fids->long_at(i); - if (fid == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - int field_offset = jfieldIDWorkaround::from_instance_jfieldID(o->klass(), fid); - - switch (tcodes->char_at(i)) { - case 'Z': - { - jboolean val = o->bool_field(field_offset); - dbuf->byte_at_put(off++, (val != 0) ? 1 : 0); - } - break; - - case 'B': - dbuf->byte_at_put(off++, o->byte_field(field_offset)); - break; - - case 'C': - { - jchar val = o->char_field(field_offset); - dbuf->byte_at_put(off++, (val >> 8) & 0xFF); - dbuf->byte_at_put(off++, (val >> 0) & 0xFF); - } - break; - - case 'S': - { - jshort val = o->short_field(field_offset); - dbuf->byte_at_put(off++, (val >> 8) & 0xFF); - dbuf->byte_at_put(off++, (val >> 0) & 0xFF); - } - break; - - case 'I': - { - jint val = o->int_field(field_offset); - dbuf->byte_at_put(off++, (val >> 24) & 0xFF); - dbuf->byte_at_put(off++, (val >> 16) & 0xFF); - dbuf->byte_at_put(off++, (val >> 8) & 0xFF); - dbuf->byte_at_put(off++, (val >> 0) & 0xFF); - } - break; - - case 'F': - { - jfloat fval = o->float_field(field_offset); - jint ival = (*float_to_int_bits_fn)(env, NULL, fval); - dbuf->byte_at_put(off++, (ival >> 24) & 0xFF); - dbuf->byte_at_put(off++, (ival >> 16) & 0xFF); - dbuf->byte_at_put(off++, (ival >> 8) & 0xFF); - dbuf->byte_at_put(off++, (ival >> 0) & 0xFF); - } - break; - - case 'J': - { - jlong val = o->long_field(field_offset); - dbuf->byte_at_put(off++, (val >> 56) & 0xFF); - dbuf->byte_at_put(off++, (val >> 48) & 0xFF); - dbuf->byte_at_put(off++, (val >> 40) & 0xFF); - dbuf->byte_at_put(off++, (val >> 32) & 0xFF); - dbuf->byte_at_put(off++, (val >> 24) & 0xFF); - dbuf->byte_at_put(off++, (val >> 16) & 0xFF); - dbuf->byte_at_put(off++, (val >> 8) & 0xFF); - dbuf->byte_at_put(off++, (val >> 0) & 0xFF); - } - break; - - case 'D': - { - jdouble dval = o->double_field(field_offset); - jlong lval = (*double_to_long_bits_fn)(env, NULL, dval); - dbuf->byte_at_put(off++, (lval >> 56) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 48) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 40) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 32) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 24) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 16) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 8) & 0xFF); - dbuf->byte_at_put(off++, (lval >> 0) & 0xFF); - } - break; - - default: - // Illegal typecode - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "illegal typecode"); - } - } -JVM_END - // Shared JNI/JVM entry points ////////////////////////////////////////////////////////////// @@ -4226,13 +3983,13 @@ JVM_LEAF(jboolean, JVM_AccessVMBooleanFlag(const char* name, jboolean* value, jboolean is_get)) JVMWrapper("JVM_AccessBoolVMFlag"); - return is_get ? CommandLineFlags::boolAt((char*) name, (bool*) value) : CommandLineFlags::boolAtPut((char*) name, (bool*) value, INTERNAL); + return is_get ? CommandLineFlags::boolAt((char*) name, (bool*) value) : CommandLineFlags::boolAtPut((char*) name, (bool*) value, Flag::INTERNAL); JVM_END JVM_LEAF(jboolean, JVM_AccessVMIntFlag(const char* name, jint* value, jboolean is_get)) JVMWrapper("JVM_AccessVMIntFlag"); intx v; - jboolean result = is_get ? CommandLineFlags::intxAt((char*) name, &v) : CommandLineFlags::intxAtPut((char*) name, &v, INTERNAL); + jboolean result = is_get ? CommandLineFlags::intxAt((char*) name, &v) : CommandLineFlags::intxAtPut((char*) name, &v, Flag::INTERNAL); *value = (jint)v; return result; JVM_END diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jvm.h Mon Oct 21 14:08:09 2013 +0100 @@ -374,6 +374,9 @@ /* * java.lang.Class and java.lang.ClassLoader */ + +#define JVM_CALLER_DEPTH -1 + /* * Returns the class in which the code invoking the native method * belongs. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jvm_misc.hpp --- a/src/share/vm/prims/jvm_misc.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jvm_misc.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -36,22 +36,6 @@ void trace_class_resolution(Klass* to_class); /* - * Support for Serialization and RMI. Currently used by HotSpot only. - */ - -extern "C" { - -void JNICALL -JVM_SetPrimitiveFieldValues(JNIEnv *env, jclass cb, jobject obj, - jlongArray fieldIDs, jcharArray typecodes, jbyteArray data); - -void JNICALL -JVM_GetPrimitiveFieldValues(JNIEnv *env, jclass cb, jobject obj, - jlongArray fieldIDs, jcharArray typecodes, jbyteArray data); - -} - -/* * Support for -Xcheck:jni */ diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -2755,13 +2755,26 @@ // InstanceKlass around to hold obsolete methods so we don't have // any other InstanceKlass embedded vtables to update. The vtable // holds the Method*s for virtual (but not final) methods. - if (ik->vtable_length() > 0 && ik->is_subtype_of(_the_class_oop)) { + // Default methods, or concrete methods in interfaces are stored + // in the vtable, so if an interface changes we need to check + // adjust_method_entries() for every InstanceKlass, which will also + // adjust the default method vtable indices. + // We also need to adjust any default method entries that are + // not yet in the vtable, because the vtable setup is in progress. + // This must be done after we adjust the default_methods and + // default_vtable_indices for methods already in the vtable. + if (ik->vtable_length() > 0 && (_the_class_oop->is_interface() + || ik->is_subtype_of(_the_class_oop))) { // ik->vtable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); ik->vtable()->adjust_method_entries(_matching_old_methods, _matching_new_methods, _matching_methods_length, &trace_name_printed); + ik->adjust_default_methods(_matching_old_methods, + _matching_new_methods, + _matching_methods_length, + &trace_name_printed); } // If the current class has an itable and we are either redefining an @@ -2931,7 +2944,8 @@ old_method->set_is_obsolete(); obsolete_count++; - // obsolete methods need a unique idnum + // obsolete methods need a unique idnum so they become new entries in + // the jmethodID cache in InstanceKlass u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum(); if (num != ConstMethod::UNSET_IDNUM) { old_method->set_method_idnum(num); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -165,7 +165,7 @@ static unsigned int hash(oop key, int size) { // shift right to get better distribution (as these bits will be zero // with aligned addresses) - unsigned int addr = (unsigned int)((intptr_t)key); + unsigned int addr = (unsigned int)(cast_from_oop(key)); #ifdef _LP64 return (addr >> 3) % size; #else diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/methodHandles.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -187,12 +187,34 @@ receiver_limit = m->method_holder(); assert(receiver_limit->verify_itable_index(vmindex), ""); flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT); + if (TraceInvokeDynamic) { + ResourceMark rm; + tty->print_cr("memberName: invokeinterface method_holder::method: %s, receiver: %s, itableindex: %d, access_flags:", + Method::name_and_sig_as_C_string(receiver_limit(), m->name(), m->signature()), + receiver_limit()->internal_name(), vmindex); + m->access_flags().print_on(tty); + if (!m->is_abstract()) { + tty->print("default"); + } + tty->cr(); + } break; case CallInfo::vtable_call: vmindex = info.vtable_index(); flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT); assert(receiver_limit->is_subtype_of(m->method_holder()), "virtual call must be type-safe"); + if (TraceInvokeDynamic) { + ResourceMark rm; + tty->print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:", + Method::name_and_sig_as_C_string(receiver_limit(), m->name(), m->signature()), + receiver_limit()->internal_name(), vmindex); + m->access_flags().print_on(tty); + if (m->is_default_method()) { + tty->print("default"); + } + tty->cr(); + } break; case CallInfo::direct_call: diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/nativeLookup.cpp --- a/src/share/vm/prims/nativeLookup.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/nativeLookup.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -129,10 +129,6 @@ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) static JNINativeMethod lookup_special_native_methods[] = { - // Next two functions only exist for compatibility with 1.3.1 and earlier. - { CC"Java_java_io_ObjectOutputStream_getPrimitiveFieldValues", NULL, FN_PTR(JVM_GetPrimitiveFieldValues) }, // intercept ObjectOutputStream getPrimitiveFieldValues for faster serialization - { CC"Java_java_io_ObjectInputStream_setPrimitiveFieldValues", NULL, FN_PTR(JVM_SetPrimitiveFieldValues) }, // intercept ObjectInputStream setPrimitiveFieldValues for faster serialization - { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, @@ -140,9 +136,8 @@ }; static address lookup_special_native(char* jni_name) { - int i = !JDK_Version::is_gte_jdk14x_version() ? 0 : 2; // see comment in lookup_special_native_methods int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); - for (; i < count; i++) { + for (int i = 0; i < count; i++) { // NB: To ignore the jni prefix and jni postfix strstr is used matching. if (strstr(jni_name, lookup_special_native_methods[i].name) != NULL) { return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/unsafe.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -292,9 +292,9 @@ volatile oop v; if (UseCompressedOops) { volatile narrowOop n = *(volatile narrowOop*) addr; - v = oopDesc::decode_heap_oop(n); + (void)const_cast(v = oopDesc::decode_heap_oop(n)); } else { - v = *(volatile oop*) addr; + (void)const_cast(v = *(volatile oop*) addr); } OrderAccess::acquire(); return JNIHandles::make_local(env, v); @@ -1222,9 +1222,9 @@ #endif /* USDT2 */ if (event.should_commit()) { oop obj = thread->current_park_blocker(); - event.set_klass(obj ? obj->klass() : NULL); + event.set_klass((obj != NULL) ? obj->klass() : NULL); event.set_timeout(time); - event.set_address(obj ? (TYPE_ADDRESS) (uintptr_t) obj : 0); + event.set_address((obj != NULL) ? (TYPE_ADDRESS) cast_from_oop(obj) : 0); event.commit(); } UNSAFE_END diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/prims/wbtestmethods/parserTests.cpp --- a/src/share/vm/prims/wbtestmethods/parserTests.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/prims/wbtestmethods/parserTests.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,11 +117,12 @@ const char* c_cmdline = java_lang_String::as_utf8_string(JNIHandles::resolve(j_cmdline)); objArrayOop argumentArray = objArrayOop(JNIHandles::resolve_non_null(arguments)); + objArrayHandle argumentArray_ah(THREAD, argumentArray); - int length = argumentArray->length(); + int length = argumentArray_ah->length(); for (int i = 0; i < length; i++) { - oop argument_oop = argumentArray->obj_at(i); + oop argument_oop = argumentArray_ah->obj_at(i); fill_in_parser(&parser, argument_oop); } @@ -130,19 +131,20 @@ Klass* k = SystemDictionary::Object_klass(); objArrayOop returnvalue_array = oopFactory::new_objArray(k, parser.num_arguments() * 2, CHECK_NULL); + objArrayHandle returnvalue_array_ah(THREAD, returnvalue_array); GrowableArray*parsedArgNames = parser.argument_name_array(); for (int i = 0; i < parser.num_arguments(); i++) { oop parsedName = java_lang_String::create_oop_from_str(parsedArgNames->at(i), CHECK_NULL); - returnvalue_array->obj_at_put(i*2, parsedName); + returnvalue_array_ah->obj_at_put(i*2, parsedName); GenDCmdArgument* arg = parser.lookup_dcmd_option(parsedArgNames->at(i), strlen(parsedArgNames->at(i))); char buf[VALUE_MAXLEN]; arg->value_as_str(buf, sizeof(buf)); oop parsedValue = java_lang_String::create_oop_from_str(buf, CHECK_NULL); - returnvalue_array->obj_at_put(i*2+1, parsedValue); + returnvalue_array_ah->obj_at_put(i*2+1, parsedValue); } - return (jobjectArray) JNIHandles::make_local(returnvalue_array); + return (jobjectArray) JNIHandles::make_local(returnvalue_array_ah()); WB_END diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/arguments.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -625,11 +625,11 @@ } } -static bool set_bool_flag(char* name, bool value, FlagValueOrigin origin) { +static bool set_bool_flag(char* name, bool value, Flag::Flags origin) { return CommandLineFlags::boolAtPut(name, &value, origin); } -static bool set_fp_numeric_flag(char* name, char* value, FlagValueOrigin origin) { +static bool set_fp_numeric_flag(char* name, char* value, Flag::Flags origin) { double v; if (sscanf(value, "%lf", &v) != 1) { return false; @@ -641,7 +641,7 @@ return false; } -static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { +static bool set_numeric_flag(char* name, char* value, Flag::Flags origin) { julong v; intx intx_v; bool is_neg = false; @@ -674,14 +674,14 @@ return false; } -static bool set_string_flag(char* name, const char* value, FlagValueOrigin origin) { +static bool set_string_flag(char* name, const char* value, Flag::Flags origin) { if (!CommandLineFlags::ccstrAtPut(name, &value, origin)) return false; // Contract: CommandLineFlags always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value, mtInternal); return true; } -static bool append_to_string_flag(char* name, const char* new_value, FlagValueOrigin origin) { +static bool append_to_string_flag(char* name, const char* new_value, Flag::Flags origin) { const char* old_value = ""; if (!CommandLineFlags::ccstrAt(name, &old_value)) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; @@ -709,7 +709,7 @@ return true; } -bool Arguments::parse_argument(const char* arg, FlagValueOrigin origin) { +bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -850,7 +850,7 @@ } bool Arguments::process_argument(const char* arg, - jboolean ignore_unrecognized, FlagValueOrigin origin) { + jboolean ignore_unrecognized, Flag::Flags origin) { JDK_Version since = JDK_Version(); @@ -904,7 +904,7 @@ jio_fprintf(defaultStream::error_stream(), "Did you mean '%s%s%s'?\n", (fuzzy_matched->is_bool()) ? "(+/-)" : "", - fuzzy_matched->name, + fuzzy_matched->_name, (fuzzy_matched->is_bool()) ? "" : "="); } } @@ -952,7 +952,7 @@ // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -970,7 +970,7 @@ } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1132,6 +1132,9 @@ Tier3InvokeNotifyFreqLog = 0; Tier4InvocationThreshold = 0; } + if (FLAG_IS_DEFAULT(NmethodSweepFraction)) { + FLAG_SET_DEFAULT(NmethodSweepFraction, 1 + ReservedCodeCacheSize / (16 * M)); + } } #if INCLUDE_ALL_GCS @@ -2042,6 +2045,9 @@ status = status && verify_interval(StringTableSize, minimumStringTableSize, (max_uintx / StringTable::bucket_size()), "StringTable size"); + status = status && verify_interval(SymbolTableSize, minimumSymbolTableSize, + (max_uintx / SymbolTable::bucket_size()), "SymbolTable size"); + if (MinHeapFreeRatio > MaxHeapFreeRatio) { jio_fprintf(defaultStream::error_stream(), "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " @@ -2337,6 +2343,10 @@ (2*G)/M); status = false; } + + status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction"); + status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity"); + return status; } @@ -2438,7 +2448,7 @@ } // Parse JavaVMInitArgs structure passed in - result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, COMMAND_LINE); + result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, Flag::COMMAND_LINE); if (result != JNI_OK) { return result; } @@ -2510,7 +2520,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, - FlagValueOrigin origin) { + Flag::Flags origin) { // Remaining part of option string const char* tail; @@ -2647,16 +2657,16 @@ FLAG_SET_CMDLINE(bool, BackgroundCompilation, false); // -Xmn for compatibility with other JVM vendors } else if (match_option(option, "-Xmn", &tail)) { - julong long_initial_eden_size = 0; - ArgsRange errcode = parse_memory_size(tail, &long_initial_eden_size, 1); + julong long_initial_young_size = 0; + ArgsRange errcode = parse_memory_size(tail, &long_initial_young_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), - "Invalid initial eden size: %s\n", option->optionString); + "Invalid initial young generation size: %s\n", option->optionString); describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, MaxNewSize, (uintx)long_initial_eden_size); - FLAG_SET_CMDLINE(uintx, NewSize, (uintx)long_initial_eden_size); + FLAG_SET_CMDLINE(uintx, MaxNewSize, (uintx)long_initial_young_size); + FLAG_SET_CMDLINE(uintx, NewSize, (uintx)long_initial_young_size); // -Xms } else if (match_option(option, "-Xms", &tail)) { julong long_initial_heap_size = 0; @@ -3333,7 +3343,7 @@ } } - return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, ENVIRON_VAR)); + return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, Flag::ENVIRON_VAR)); } return JNI_OK; } @@ -3656,6 +3666,9 @@ assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS + // Initialize Metaspace flags and alignments. + Metaspace::ergo_initialize(); + // Set bytecode rewriting flags set_bytecode_flags(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/arguments.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -360,15 +360,15 @@ // Argument parsing static void do_pd_flag_adjustments(); - static bool parse_argument(const char* arg, FlagValueOrigin origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, FlagValueOrigin origin); + static bool parse_argument(const char* arg, Flag::Flags origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(char* arg); static jint parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_vm_init_args(const JavaVMInitArgs* args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, FlagValueOrigin origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, Flag::Flags origin); static jint finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/biasedLocking.cpp --- a/src/share/vm/runtime/biasedLocking.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/biasedLocking.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,7 +161,7 @@ if (TraceBiasedLocking && (Verbose || !is_bulk)) { ResourceMark rm; tty->print_cr("Revoking bias of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT " , allow rebias %d , requesting thread " INTPTR_FORMAT, - (intptr_t) obj, (intptr_t) mark, obj->klass()->external_name(), (intptr_t) obj->klass()->prototype_header(), (allow_rebias ? 1 : 0), (intptr_t) requesting_thread); + (void *)obj, (intptr_t) mark, obj->klass()->external_name(), (intptr_t) obj->klass()->prototype_header(), (allow_rebias ? 1 : 0), (intptr_t) requesting_thread); } JavaThread* biased_thread = mark->biased_locker(); @@ -214,8 +214,8 @@ if (mon_info->owner() == obj) { if (TraceBiasedLocking && Verbose) { tty->print_cr(" mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")", - (intptr_t) mon_info->owner(), - (intptr_t) obj); + (void *) mon_info->owner(), + (void *) obj); } // Assume recursive case and fix up highest lock later markOop mark = markOopDesc::encode((BasicLock*) NULL); @@ -224,8 +224,8 @@ } else { if (TraceBiasedLocking && Verbose) { tty->print_cr(" mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")", - (intptr_t) mon_info->owner(), - (intptr_t) obj); + (void *) mon_info->owner(), + (void *) obj); } } } @@ -326,7 +326,7 @@ tty->print_cr("* Beginning bulk revocation (kind == %s) because of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", (bulk_rebias ? "rebias" : "revoke"), - (intptr_t) o, (intptr_t) o->mark(), o->klass()->external_name()); + (void *) o, (intptr_t) o->mark(), o->klass()->external_name()); } jlong cur_time = os::javaTimeMillis(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -234,7 +234,7 @@ assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, result, thread); + tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread); } } bool reallocated = false; @@ -278,7 +278,7 @@ first = false; tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); } - tty->print_cr(" object <" INTPTR_FORMAT "> locked", mi->owner()); + tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner()); } } } @@ -977,7 +977,7 @@ KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); - tty->print(" object <" INTPTR_FORMAT "> of type ", sv->value()()); + tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()()); k->print_value(); tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize); tty->cr(); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/frame.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1097,7 +1097,7 @@ return NULL; } oop r = *oop_adr; - assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (intptr_t) r, (intptr_t) r)); + assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (void *) r, (void *) r)); return r; } @@ -1228,9 +1228,7 @@ void frame::ZapDeadClosure::do_oop(oop* p) { if (TraceZapDeadLocals) tty->print_cr("zapping @ " INTPTR_FORMAT " containing " INTPTR_FORMAT, p, (address)*p); - // Need cast because on _LP64 the conversion to oop is ambiguous. Constant - // can be either long or int. - *p = (oop)(int)0xbabebabe; + *p = cast_to_oop(0xbabebabe); } frame::ZapDeadClosure frame::_zap_dead; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/globals.cpp --- a/src/share/vm/runtime/globals.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/globals.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -62,26 +62,174 @@ MATERIALIZE_FLAGS_EXT +void Flag::check_writable() { + if (is_constant_in_binary()) { + fatal(err_msg("flag is constant: %s", _name)); + } +} + +bool Flag::is_bool() const { + return strcmp(_type, "bool") == 0; +} + +bool Flag::get_bool() const { + return *((bool*) _addr); +} + +void Flag::set_bool(bool value) { + check_writable(); + *((bool*) _addr) = value; +} + +bool Flag::is_intx() const { + return strcmp(_type, "intx") == 0; +} + +intx Flag::get_intx() const { + return *((intx*) _addr); +} + +void Flag::set_intx(intx value) { + check_writable(); + *((intx*) _addr) = value; +} + +bool Flag::is_uintx() const { + return strcmp(_type, "uintx") == 0; +} + +uintx Flag::get_uintx() const { + return *((uintx*) _addr); +} + +void Flag::set_uintx(uintx value) { + check_writable(); + *((uintx*) _addr) = value; +} + +bool Flag::is_uint64_t() const { + return strcmp(_type, "uint64_t") == 0; +} + +uint64_t Flag::get_uint64_t() const { + return *((uint64_t*) _addr); +} + +void Flag::set_uint64_t(uint64_t value) { + check_writable(); + *((uint64_t*) _addr) = value; +} + +bool Flag::is_double() const { + return strcmp(_type, "double") == 0; +} + +double Flag::get_double() const { + return *((double*) _addr); +} + +void Flag::set_double(double value) { + check_writable(); + *((double*) _addr) = value; +} + +bool Flag::is_ccstr() const { + return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; +} + +bool Flag::ccstr_accumulates() const { + return strcmp(_type, "ccstrlist") == 0; +} + +ccstr Flag::get_ccstr() const { + return *((ccstr*) _addr); +} + +void Flag::set_ccstr(ccstr value) { + check_writable(); + *((ccstr*) _addr) = value; +} + + +Flag::Flags Flag::get_origin() { + return Flags(_flags & VALUE_ORIGIN_MASK); +} + +void Flag::set_origin(Flags origin) { + assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | origin); +} + +bool Flag::is_default() { + return (get_origin() == DEFAULT); +} + +bool Flag::is_ergonomic() { + return (get_origin() == ERGONOMIC); +} + +bool Flag::is_command_line() { + return (get_origin() == COMMAND_LINE); +} + +bool Flag::is_product() const { + return (_flags & KIND_PRODUCT) != 0; +} + +bool Flag::is_manageable() const { + return (_flags & KIND_MANAGEABLE) != 0; +} + +bool Flag::is_diagnostic() const { + return (_flags & KIND_DIAGNOSTIC) != 0; +} + +bool Flag::is_experimental() const { + return (_flags & KIND_EXPERIMENTAL) != 0; +} + +bool Flag::is_notproduct() const { + return (_flags & KIND_NOT_PRODUCT) != 0; +} + +bool Flag::is_develop() const { + return (_flags & KIND_DEVELOP) != 0; +} + +bool Flag::is_read_write() const { + return (_flags & KIND_READ_WRITE) != 0; +} + +bool Flag::is_commercial() const { + return (_flags & KIND_COMMERCIAL) != 0; +} + +/** + * Returns if this flag is a constant in the binary. Right now this is + * true for notproduct and develop flags in product builds. + */ +bool Flag::is_constant_in_binary() const { +#ifdef PRODUCT + return is_notproduct() || is_develop(); +#else + return false; +#endif +} + bool Flag::is_unlocker() const { - return strcmp(name, "UnlockDiagnosticVMOptions") == 0 || - strcmp(name, "UnlockExperimentalVMOptions") == 0 || + return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || + strcmp(_name, "UnlockExperimentalVMOptions") == 0 || is_unlocker_ext(); } bool Flag::is_unlocked() const { - if (strcmp(kind, "{diagnostic}") == 0 || - strcmp(kind, "{C2 diagnostic}") == 0 || - strcmp(kind, "{ARCH diagnostic}") == 0 || - strcmp(kind, "{Shark diagnostic}") == 0) { + if (is_diagnostic()) { return UnlockDiagnosticVMOptions; - } else if (strcmp(kind, "{experimental}") == 0 || - strcmp(kind, "{C2 experimental}") == 0 || - strcmp(kind, "{ARCH experimental}") == 0 || - strcmp(kind, "{Shark experimental}") == 0) { + } + if (is_experimental()) { return UnlockExperimentalVMOptions; - } else { - return is_unlocked_ext(); } + return is_unlocked_ext(); } // Get custom message for this locked flag, or return NULL if @@ -91,16 +239,14 @@ } bool Flag::is_writeable() const { - return strcmp(kind, "{manageable}") == 0 || - strcmp(kind, "{product rw}") == 0 || - is_writeable_ext(); + return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); } // All flags except "manageable" are assumed to be internal flags. // Long term, we need to define a mechanism to specify which flags // are external/stable and change this function accordingly. bool Flag::is_external() const { - return strcmp(kind, "{manageable}") == 0 || is_external_ext(); + return is_manageable() || is_external_ext(); } @@ -108,53 +254,113 @@ #define FORMAT_BUFFER_LEN 16 void Flag::print_on(outputStream* st, bool withComments) { - st->print("%9s %-40s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); - if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); - if (is_intx()) st->print("%-16ld", get_intx()); - if (is_uintx()) st->print("%-16lu", get_uintx()); - if (is_uint64_t()) st->print("%-16lu", get_uint64_t()); - if (is_double()) st->print("%-16f", get_double()); + // Don't print notproduct and develop flags in a product build. + if (is_constant_in_binary()) { + return; + } + + st->print("%9s %-40s %c= ", _type, _name, (!is_default() ? ':' : ' ')); + if (is_bool()) { + st->print("%-16s", get_bool() ? "true" : "false"); + } + if (is_intx()) { + st->print("%-16ld", get_intx()); + } + if (is_uintx()) { + st->print("%-16lu", get_uintx()); + } + if (is_uint64_t()) { + st->print("%-16lu", get_uint64_t()); + } + if (is_double()) { + st->print("%-16f", get_double()); + } if (is_ccstr()) { - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - char format_buffer[FORMAT_BUFFER_LEN]; - size_t llen = pointer_delta(eol, cp, sizeof(char)); - jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, - "%%." SIZE_FORMAT "s", llen); - st->print(format_buffer, cp); - st->cr(); - cp = eol+1; - st->print("%5s %-35s += ", "", name); - } - st->print("%-16s", cp); - } - else st->print("%-16s", ""); + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + char format_buffer[FORMAT_BUFFER_LEN]; + size_t llen = pointer_delta(eol, cp, sizeof(char)); + jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, + "%%." SIZE_FORMAT "s", llen); + st->print(format_buffer, cp); + st->cr(); + cp = eol+1; + st->print("%5s %-35s += ", "", _name); + } + st->print("%-16s", cp); + } + else st->print("%-16s", ""); } - st->print("%-20s", kind); + + st->print("%-20"); + print_kind(st); + if (withComments) { #ifndef PRODUCT - st->print("%s", doc ); + st->print("%s", _doc); #endif } st->cr(); } +void Flag::print_kind(outputStream* st) { + struct Data { + int flag; + const char* name; + }; + + Data data[] = { + { KIND_C1, "C1" }, + { KIND_C2, "C2" }, + { KIND_ARCH, "ARCH" }, + { KIND_SHARK, "SHARK" }, + { KIND_PLATFORM_DEPENDENT, "pd" }, + { KIND_PRODUCT, "product" }, + { KIND_MANAGEABLE, "manageable" }, + { KIND_DIAGNOSTIC, "diagnostic" }, + { KIND_NOT_PRODUCT, "notproduct" }, + { KIND_DEVELOP, "develop" }, + { KIND_LP64_PRODUCT, "lp64_product" }, + { KIND_READ_WRITE, "rw" }, + { -1, "" } + }; + + if ((_flags & KIND_MASK) != 0) { + st->print("{"); + bool is_first = true; + + for (int i = 0; data[i].flag != -1; i++) { + Data d = data[i]; + if ((_flags & d.flag) != 0) { + if (is_first) { + is_first = false; + } else { + st->print(" "); + } + st->print(d.name); + } + } + + st->print("}"); + } +} + void Flag::print_as_flag(outputStream* st) { if (is_bool()) { - st->print("-XX:%s%s", get_bool() ? "+" : "-", name); + st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); } else if (is_intx()) { - st->print("-XX:%s=" INTX_FORMAT, name, get_intx()); + st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); } else if (is_uintx()) { - st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx()); + st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); } else if (is_uint64_t()) { - st->print("-XX:%s=" UINT64_FORMAT, name, get_uint64_t()); + st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); } else if (is_double()) { - st->print("-XX:%s=%f", name, get_double()); + st->print("-XX:%s=%f", _name, get_double()); } else if (is_ccstr()) { - st->print("-XX:%s=", name); + st->print("-XX:%s=", _name); const char* cp = get_ccstr(); if (cp != NULL) { // Need to turn embedded '\n's back into separate arguments @@ -167,7 +373,7 @@ st->print("%c", *cp); break; case '\n': - st->print(" -XX:%s=", name); + st->print(" -XX:%s=", _name); break; } } @@ -180,79 +386,51 @@ // 4991491 do not "optimize out" the was_set false values: omitting them // tickles a Microsoft compiler bug causing flagTable to be malformed -#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product}", DEFAULT }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{pd product}", DEFAULT }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{diagnostic}", DEFAULT }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{experimental}", DEFAULT }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{manageable}", DEFAULT }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product rw}", DEFAULT }, +#define NAME(name) NOT_PRODUCT(&name) PRODUCT_ONLY(&CONST_##name) -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "", DEFAULT }, - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{pd}", DEFAULT }, - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{notproduct}", DEFAULT }, -#endif +#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT) }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC) }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_EXPERIMENTAL) }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_MANAGEABLE) }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_READ_WRITE) }, +#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, +#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, #ifdef _LP64 - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{lp64_product}", DEFAULT }, +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, #else - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 product}", DEFAULT }, -#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 pd product}", DEFAULT }, -#define C1_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 diagnostic}", DEFAULT }, -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1}", DEFAULT }, - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C1 pd}", DEFAULT }, - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1 notproduct}", DEFAULT }, -#endif +#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT) }, +#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC) }, +#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP) }, +#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, -#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 product}", DEFAULT }, -#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 pd product}", DEFAULT }, -#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 diagnostic}", DEFAULT }, -#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 experimental}", DEFAULT }, -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2}", DEFAULT }, - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C2 pd}", DEFAULT }, - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2 notproduct}", DEFAULT }, -#endif +#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT) }, +#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC) }, +#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_EXPERIMENTAL) }, +#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP) }, +#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_NOT_PRODUCT) }, -#define ARCH_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH product}", DEFAULT }, -#define ARCH_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH diagnostic}", DEFAULT }, -#define ARCH_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH experimental}", DEFAULT }, -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{ARCH}", DEFAULT }, - #define ARCH_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{ARCH notproduct}", DEFAULT }, -#endif +#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_PRODUCT) }, +#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DIAGNOSTIC) }, +#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_EXPERIMENTAL) }, +#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, +#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, -#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark product}", DEFAULT }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark pd product}", DEFAULT }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark diagnostic}", DEFAULT }, -#ifdef PRODUCT - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark}", DEFAULT }, - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{Shark pd}", DEFAULT }, - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark notproduct}", DEFAULT }, -#endif +#define SHARK_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT) }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC) }, +#define SHARK_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP) }, +#define SHARK_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) }, static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT) @@ -285,9 +463,14 @@ // Search the flag table for a named flag Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) { - for (Flag* current = &flagTable[0]; current->name != NULL; current++) { - if (str_equal(current->name, name, length)) { - // Found a matching entry. Report locked flags only if allowed. + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + if (str_equal(current->_name, name, length)) { + // Found a matching entry. + // Don't report notproduct and develop flags in product builds. + if (current->is_constant_in_binary()) { + return NULL; + } + // Report locked flags only if allowed. if (!(current->is_unlocked() || current->is_unlocker())) { if (!allow_locked) { // disable use of locked flags, e.g. diagnostic, experimental, @@ -327,8 +510,8 @@ float score; float max_score = -1; - for (Flag* current = &flagTable[0]; current->name != NULL; current++) { - score = str_similar(current->name, name, length); + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + score = str_similar(current->_name, name, length); if (score > max_score) { max_score = score; match = current; @@ -357,25 +540,25 @@ bool CommandLineFlagsEx::is_default(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == DEFAULT); + return f->is_default(); } bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == ERGONOMIC); + return f->is_ergonomic(); } bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == COMMAND_LINE); + return f->is_command_line(); } bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { Flag* result = Flag::find_flag((char*)name, strlen(name)); if (result == NULL) return false; - *value = (result->origin == COMMAND_LINE); + *value = result->is_command_line(); return true; } @@ -387,22 +570,22 @@ return true; } -bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, FlagValueOrigin origin) { +bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_bool()) return false; bool old_value = result->get_bool(); result->set_bool(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin) { +void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); faddr->set_bool(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::intxAt(char* name, size_t len, intx* value) { @@ -413,22 +596,22 @@ return true; } -bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, FlagValueOrigin origin) { +bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_intx()) return false; intx old_value = result->get_intx(); result->set_intx(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin) { +void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); faddr->set_intx(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::uintxAt(char* name, size_t len, uintx* value) { @@ -439,22 +622,22 @@ return true; } -bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin) { +bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_uintx()) return false; uintx old_value = result->get_uintx(); result->set_uintx(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin) { +void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); faddr->set_uintx(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::uint64_tAt(char* name, size_t len, uint64_t* value) { @@ -465,22 +648,22 @@ return true; } -bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin) { +bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_uint64_t()) return false; uint64_t old_value = result->get_uint64_t(); result->set_uint64_t(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin) { +void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); faddr->set_uint64_t(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::doubleAt(char* name, size_t len, double* value) { @@ -491,22 +674,22 @@ return true; } -bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin) { +bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_double()) return false; double old_value = result->get_double(); result->set_double(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin) { +void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); faddr->set_double(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::ccstrAt(char* name, size_t len, ccstr* value) { @@ -519,7 +702,7 @@ // Contract: Flag will make private copy of the incoming value. // Outgoing value is always malloc-ed, and caller MUST call free. -bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, FlagValueOrigin origin) { +bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_ccstr()) return false; @@ -530,35 +713,35 @@ strcpy(new_value, *value); } result->set_ccstr(new_value); - if (result->origin == DEFAULT && old_value != NULL) { + if (result->is_default() && old_value != NULL) { // Prior value is NOT heap allocated, but was a literal constant. char* old_value_to_free = NEW_C_HEAP_ARRAY(char, strlen(old_value)+1, mtInternal); strcpy(old_value_to_free, old_value); old_value = old_value_to_free; } *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } // Contract: Flag will make private copy of the incoming value. -void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin) { +void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); ccstr old_value = faddr->get_ccstr(); char* new_value = NEW_C_HEAP_ARRAY(char, strlen(value)+1, mtInternal); strcpy(new_value, value); faddr->set_ccstr(new_value); - if (faddr->origin != DEFAULT && old_value != NULL) { + if (!faddr->is_default() && old_value != NULL) { // Prior value is heap allocated so free it. FREE_C_HEAP_ARRAY(char, old_value, mtInternal); } - faddr->origin = origin; + faddr->set_origin(origin); } extern "C" { static int compare_flags(const void* void_a, const void* void_b) { - return strcmp((*((Flag**) void_a))->name, (*((Flag**) void_b))->name); + return strcmp((*((Flag**) void_a))->_name, (*((Flag**) void_b))->_name); } } @@ -567,20 +750,19 @@ // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. - // Compute size - int length= 0; - while (flagTable[length].name != NULL) length++; + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; // Sort Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); - for (int index = 0; index < length; index++) { - array[index] = &flagTable[index]; + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; } qsort(array, length, sizeof(Flag*), compare_flags); // Print - for (int i = 0; i < length; i++) { - if (array[i]->origin /* naked field! */) { + for (size_t i = 0; i < length; i++) { + if (array[i]->get_origin() /* naked field! */) { array[i]->print_as_flag(out); out->print(" "); } @@ -603,20 +785,19 @@ // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. - // Compute size - int length= 0; - while (flagTable[length].name != NULL) length++; + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; // Sort Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); - for (int index = 0; index < length; index++) { - array[index] = &flagTable[index]; + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; } qsort(array, length, sizeof(Flag*), compare_flags); // Print out->print_cr("[Global flags]"); - for (int i = 0; i < length; i++) { + for (size_t i = 0; i < length; i++) { if (array[i]->is_unlocked()) { array[i]->print_on(out, withComments); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/globals.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -194,29 +194,49 @@ typedef const char* ccstr; typedef const char* ccstrlist; // represents string arguments which accumulate -enum FlagValueOrigin { - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 99 -}; +struct Flag { + enum Flags { + // value origin + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + + LAST_VALUE_ORIGIN = INTERNAL, + VALUE_ORIGIN_BITS = 4, + VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), -struct Flag { - const char *type; - const char *name; - void* addr; + // flag kind + KIND_PRODUCT = 1 << 4, + KIND_MANAGEABLE = 1 << 5, + KIND_DIAGNOSTIC = 1 << 6, + KIND_EXPERIMENTAL = 1 << 7, + KIND_NOT_PRODUCT = 1 << 8, + KIND_DEVELOP = 1 << 9, + KIND_PLATFORM_DEPENDENT = 1 << 10, + KIND_READ_WRITE = 1 << 11, + KIND_C1 = 1 << 12, + KIND_C2 = 1 << 13, + KIND_ARCH = 1 << 14, + KIND_SHARK = 1 << 15, + KIND_LP64_PRODUCT = 1 << 16, + KIND_COMMERCIAL = 1 << 17, - NOT_PRODUCT(const char *doc;) + KIND_MASK = ~VALUE_ORIGIN_MASK + }; - const char *kind; - FlagValueOrigin origin; + const char* _type; + const char* _name; + void* _addr; + NOT_PRODUCT(const char* _doc;) + Flags _flags; // points to all Flags static array - static Flag *flags; + static Flag* flags; // number of flags static size_t numFlags; @@ -224,30 +244,50 @@ static Flag* find_flag(const char* name, size_t length, bool allow_locked = false); static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); - bool is_bool() const { return strcmp(type, "bool") == 0; } - bool get_bool() const { return *((bool*) addr); } - void set_bool(bool value) { *((bool*) addr) = value; } + void check_writable(); + + bool is_bool() const; + bool get_bool() const; + void set_bool(bool value); + + bool is_intx() const; + intx get_intx() const; + void set_intx(intx value); - bool is_intx() const { return strcmp(type, "intx") == 0; } - intx get_intx() const { return *((intx*) addr); } - void set_intx(intx value) { *((intx*) addr) = value; } + bool is_uintx() const; + uintx get_uintx() const; + void set_uintx(uintx value); - bool is_uintx() const { return strcmp(type, "uintx") == 0; } - uintx get_uintx() const { return *((uintx*) addr); } - void set_uintx(uintx value) { *((uintx*) addr) = value; } + bool is_uint64_t() const; + uint64_t get_uint64_t() const; + void set_uint64_t(uint64_t value); + + bool is_double() const; + double get_double() const; + void set_double(double value); - bool is_uint64_t() const { return strcmp(type, "uint64_t") == 0; } - uint64_t get_uint64_t() const { return *((uint64_t*) addr); } - void set_uint64_t(uint64_t value) { *((uint64_t*) addr) = value; } + bool is_ccstr() const; + bool ccstr_accumulates() const; + ccstr get_ccstr() const; + void set_ccstr(ccstr value); + + Flags get_origin(); + void set_origin(Flags origin); - bool is_double() const { return strcmp(type, "double") == 0; } - double get_double() const { return *((double*) addr); } - void set_double(double value) { *((double*) addr) = value; } + bool is_default(); + bool is_ergonomic(); + bool is_command_line(); - bool is_ccstr() const { return strcmp(type, "ccstr") == 0 || strcmp(type, "ccstrlist") == 0; } - bool ccstr_accumulates() const { return strcmp(type, "ccstrlist") == 0; } - ccstr get_ccstr() const { return *((ccstr*) addr); } - void set_ccstr(ccstr value) { *((ccstr*) addr) = value; } + bool is_product() const; + bool is_manageable() const; + bool is_diagnostic() const; + bool is_experimental() const; + bool is_notproduct() const; + bool is_develop() const; + bool is_read_write() const; + bool is_commercial() const; + + bool is_constant_in_binary() const; bool is_unlocker() const; bool is_unlocked() const; @@ -263,6 +303,7 @@ void get_locked_message_ext(char*, int) const; void print_on(outputStream* st, bool withComments = false ); + void print_kind(outputStream* st); void print_as_flag(outputStream* st); }; @@ -310,33 +351,33 @@ public: static bool boolAt(char* name, size_t len, bool* value); static bool boolAt(char* name, bool* value) { return boolAt(name, strlen(name), value); } - static bool boolAtPut(char* name, size_t len, bool* value, FlagValueOrigin origin); - static bool boolAtPut(char* name, bool* value, FlagValueOrigin origin) { return boolAtPut(name, strlen(name), value, origin); } + static bool boolAtPut(char* name, size_t len, bool* value, Flag::Flags origin); + static bool boolAtPut(char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } static bool intxAt(char* name, size_t len, intx* value); static bool intxAt(char* name, intx* value) { return intxAt(name, strlen(name), value); } - static bool intxAtPut(char* name, size_t len, intx* value, FlagValueOrigin origin); - static bool intxAtPut(char* name, intx* value, FlagValueOrigin origin) { return intxAtPut(name, strlen(name), value, origin); } + static bool intxAtPut(char* name, size_t len, intx* value, Flag::Flags origin); + static bool intxAtPut(char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } static bool uintxAt(char* name, size_t len, uintx* value); static bool uintxAt(char* name, uintx* value) { return uintxAt(name, strlen(name), value); } - static bool uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin); - static bool uintxAtPut(char* name, uintx* value, FlagValueOrigin origin) { return uintxAtPut(name, strlen(name), value, origin); } + static bool uintxAtPut(char* name, size_t len, uintx* value, Flag::Flags origin); + static bool uintxAtPut(char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } static bool uint64_tAt(char* name, size_t len, uint64_t* value); static bool uint64_tAt(char* name, uint64_t* value) { return uint64_tAt(name, strlen(name), value); } - static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin); - static bool uint64_tAtPut(char* name, uint64_t* value, FlagValueOrigin origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, Flag::Flags origin); + static bool uint64_tAtPut(char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } static bool doubleAt(char* name, size_t len, double* value); static bool doubleAt(char* name, double* value) { return doubleAt(name, strlen(name), value); } - static bool doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin); - static bool doubleAtPut(char* name, double* value, FlagValueOrigin origin) { return doubleAtPut(name, strlen(name), value, origin); } + static bool doubleAtPut(char* name, size_t len, double* value, Flag::Flags origin); + static bool doubleAtPut(char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } static bool ccstrAt(char* name, size_t len, ccstr* value); static bool ccstrAt(char* name, ccstr* value) { return ccstrAt(name, strlen(name), value); } - static bool ccstrAtPut(char* name, size_t len, ccstr* value, FlagValueOrigin origin); - static bool ccstrAtPut(char* name, ccstr* value, FlagValueOrigin origin) { return ccstrAtPut(name, strlen(name), value, origin); } + static bool ccstrAtPut(char* name, size_t len, ccstr* value, Flag::Flags origin); + static bool ccstrAtPut(char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } // Returns false if name is not a command line flag. static bool wasSetOnCmdline(const char* name, bool* value); @@ -440,21 +481,21 @@ #define RUNTIME_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, lp64_product) \ \ lp64_product(bool, UseCompressedOops, false, \ - "Use 32-bit object references in 64-bit VM " \ - "lp64_product means flag is always constant in 32 bit VM") \ + "Use 32-bit object references in 64-bit VM. " \ + "lp64_product means flag is always constant in 32 bit VM") \ \ lp64_product(bool, UseCompressedClassPointers, false, \ - "Use 32-bit class pointers in 64-bit VM " \ - "lp64_product means flag is always constant in 32 bit VM") \ + "Use 32-bit class pointers in 64-bit VM. " \ + "lp64_product means flag is always constant in 32 bit VM") \ \ notproduct(bool, CheckCompressedOops, true, \ - "generate checks in encoding/decoding code in debug VM") \ + "Generate checks in encoding/decoding code in debug VM") \ \ product_pd(uintx, HeapBaseMinAddress, \ - "OS specific low limit for heap base address") \ + "OS specific low limit for heap base address") \ \ diagnostic(bool, PrintCompressedOopsMode, false, \ - "Print compressed oops base address and encoding mode") \ + "Print compressed oops base address and encoding mode") \ \ lp64_product(intx, ObjectAlignmentInBytes, 8, \ "Default object alignment in bytes, 8 is minimum") \ @@ -476,7 +517,7 @@ "Use lwsync instruction if true, else use slower sync") \ \ develop(bool, CleanChunkPoolAsync, falseInEmbedded, \ - "Whether to clean the chunk pool asynchronously") \ + "Clean the chunk pool asynchronously") \ \ /* Temporary: See 6948537 */ \ experimental(bool, UseMemSetInBOT, true, \ @@ -486,10 +527,12 @@ "Enable normal processing of flags relating to field diagnostics")\ \ experimental(bool, UnlockExperimentalVMOptions, false, \ - "Enable normal processing of flags relating to experimental features")\ + "Enable normal processing of flags relating to experimental " \ + "features") \ \ product(bool, JavaMonitorsInStackTrace, true, \ - "Print info. about Java monitor locks when the stacks are dumped")\ + "Print information about Java monitor locks when the stacks are" \ + "dumped") \ \ product_pd(bool, UseLargePages, \ "Use large page memory") \ @@ -500,8 +543,12 @@ develop(bool, LargePagesIndividualAllocationInjectError, false, \ "Fail large pages individual allocation") \ \ + product(bool, UseLargePagesInMetaspace, false, \ + "Use large page memory in metaspace. " \ + "Only used if UseLargePages is enabled.") \ + \ develop(bool, TracePageSizes, false, \ - "Trace page size selection and usage.") \ + "Trace page size selection and usage") \ \ product(bool, UseNUMA, false, \ "Use NUMA if available") \ @@ -516,12 +563,12 @@ "Force NUMA optimizations on single-node/UMA systems") \ \ product(uintx, NUMAChunkResizeWeight, 20, \ - "Percentage (0-100) used to weigh the current sample when " \ + "Percentage (0-100) used to weigh the current sample when " \ "computing exponentially decaying average for " \ "AdaptiveNUMAChunkSizing") \ \ product(uintx, NUMASpaceResizeRate, 1*G, \ - "Do not reallocate more that this amount per collection") \ + "Do not reallocate more than this amount per collection") \ \ product(bool, UseAdaptiveNUMAChunkSizing, true, \ "Enable adaptive chunk sizing for NUMA") \ @@ -538,17 +585,17 @@ product(intx, UseSSE, 99, \ "Highest supported SSE instructions set on x86/x64") \ \ - product(bool, UseAES, false, \ + product(bool, UseAES, false, \ "Control whether AES instructions can be used on x86/x64") \ \ product(uintx, LargePageSizeInBytes, 0, \ - "Large page size (0 to let VM choose the page size") \ + "Large page size (0 to let VM choose the page size)") \ \ product(uintx, LargePageHeapSizeThreshold, 128*M, \ - "Use large pages if max heap is at least this big") \ + "Use large pages if maximum heap is at least this big") \ \ product(bool, ForceTimeHighResolution, false, \ - "Using high time resolution(For Win32 only)") \ + "Using high time resolution (for Win32 only)") \ \ develop(bool, TraceItables, false, \ "Trace initialization and use of itables") \ @@ -564,10 +611,10 @@ \ develop(bool, TraceLongCompiles, false, \ "Print out every time compilation is longer than " \ - "a given threashold") \ + "a given threshold") \ \ develop(bool, SafepointALot, false, \ - "Generates a lot of safepoints. Works with " \ + "Generate a lot of safepoints. This works with " \ "GuaranteedSafepointInterval") \ \ product_pd(bool, BackgroundCompilation, \ @@ -575,13 +622,13 @@ "compilation") \ \ product(bool, PrintVMQWaitTime, false, \ - "Prints out the waiting time in VM operation queue") \ + "Print out the waiting time in VM operation queue") \ \ develop(bool, NoYieldsInMicrolock, false, \ "Disable yields in microlock") \ \ develop(bool, TraceOopMapGeneration, false, \ - "Shows oopmap generation") \ + "Show OopMapGeneration") \ \ product(bool, MethodFlushing, true, \ "Reclamation of zombie and not-entrant methods") \ @@ -590,10 +637,11 @@ "Verify stack of each thread when it is entering a runtime call") \ \ diagnostic(bool, ForceUnreachable, false, \ - "Make all non code cache addresses to be unreachable with forcing use of 64bit literal fixups") \ + "Make all non code cache addresses to be unreachable by " \ + "forcing use of 64bit literal fixups") \ \ notproduct(bool, StressDerivedPointers, false, \ - "Force scavenge when a derived pointers is detected on stack " \ + "Force scavenge when a derived pointer is detected on stack " \ "after rtm call") \ \ develop(bool, TraceDerivedPointers, false, \ @@ -612,86 +660,86 @@ "Use Inline Caches for virtual calls ") \ \ develop(bool, InlineArrayCopy, true, \ - "inline arraycopy native that is known to be part of " \ + "Inline arraycopy native that is known to be part of " \ "base library DLL") \ \ develop(bool, InlineObjectHash, true, \ - "inline Object::hashCode() native that is known to be part " \ + "Inline Object::hashCode() native that is known to be part " \ "of base library DLL") \ \ develop(bool, InlineNatives, true, \ - "inline natives that are known to be part of base library DLL") \ + "Inline natives that are known to be part of base library DLL") \ \ develop(bool, InlineMathNatives, true, \ - "inline SinD, CosD, etc.") \ + "Inline SinD, CosD, etc.") \ \ develop(bool, InlineClassNatives, true, \ - "inline Class.isInstance, etc") \ + "Inline Class.isInstance, etc") \ \ develop(bool, InlineThreadNatives, true, \ - "inline Thread.currentThread, etc") \ + "Inline Thread.currentThread, etc") \ \ develop(bool, InlineUnsafeOps, true, \ - "inline memory ops (native methods) from sun.misc.Unsafe") \ + "Inline memory ops (native methods) from sun.misc.Unsafe") \ \ product(bool, CriticalJNINatives, true, \ - "check for critical JNI entry points") \ + "Check for critical JNI entry points") \ \ notproduct(bool, StressCriticalJNINatives, false, \ - "Exercise register saving code in critical natives") \ + "Exercise register saving code in critical natives") \ \ product(bool, UseSSE42Intrinsics, false, \ "SSE4.2 versions of intrinsics") \ \ product(bool, UseAESIntrinsics, false, \ - "use intrinsics for AES versions of crypto") \ + "Use intrinsics for AES versions of crypto") \ \ product(bool, UseCRC32Intrinsics, false, \ "use intrinsics for java.util.zip.CRC32") \ \ develop(bool, TraceCallFixup, false, \ - "traces all call fixups") \ + "Trace all call fixups") \ \ develop(bool, DeoptimizeALot, false, \ - "deoptimize at every exit from the runtime system") \ + "Deoptimize at every exit from the runtime system") \ \ notproduct(ccstrlist, DeoptimizeOnlyAt, "", \ - "a comma separated list of bcis to deoptimize at") \ + "A comma separated list of bcis to deoptimize at") \ \ product(bool, DeoptimizeRandom, false, \ - "deoptimize random frames on random exit from the runtime system")\ + "Deoptimize random frames on random exit from the runtime system")\ \ notproduct(bool, ZombieALot, false, \ - "creates zombies (non-entrant) at exit from the runt. system") \ + "Create zombies (non-entrant) at exit from the runtime system") \ \ product(bool, UnlinkSymbolsALot, false, \ - "unlink unreferenced symbols from the symbol table at safepoints")\ + "Unlink unreferenced symbols from the symbol table at safepoints")\ \ notproduct(bool, WalkStackALot, false, \ - "trace stack (no print) at every exit from the runtime system") \ + "Trace stack (no print) at every exit from the runtime system") \ \ product(bool, Debugging, false, \ - "set when executing debug methods in debug.ccp " \ + "Set when executing debug methods in debug.cpp " \ "(to prevent triggering assertions)") \ \ notproduct(bool, StrictSafepointChecks, trueInDebug, \ "Enable strict checks that safepoints cannot happen for threads " \ - "that used No_Safepoint_Verifier") \ + "that use No_Safepoint_Verifier") \ \ notproduct(bool, VerifyLastFrame, false, \ "Verify oops on last frame on entry to VM") \ \ develop(bool, TraceHandleAllocation, false, \ - "Prints out warnings when suspicious many handles are allocated") \ + "Print out warnings when suspiciously many handles are allocated")\ \ product(bool, UseCompilerSafepoints, true, \ "Stop at safepoints in compiled code") \ \ product(bool, FailOverToOldVerifier, true, \ - "fail over to old verifier when split verifier fails") \ + "Fail over to old verifier when split verifier fails") \ \ develop(bool, ShowSafepointMsgs, false, \ - "Show msg. about safepoint synch.") \ + "Show message about safepoint synchronization") \ \ product(bool, SafepointTimeout, false, \ "Time out and warn or fail after SafepointTimeoutDelay " \ @@ -715,19 +763,19 @@ "Trace external suspend wait failures") \ \ product(bool, MaxFDLimit, true, \ - "Bump the number of file descriptors to max in solaris.") \ + "Bump the number of file descriptors to maximum in Solaris") \ \ diagnostic(bool, LogEvents, true, \ - "Enable the various ring buffer event logs") \ + "Enable the various ring buffer event logs") \ \ diagnostic(uintx, LogEventsBufferEntries, 10, \ - "Enable the various ring buffer event logs") \ + "Number of ring buffer event logs") \ \ product(bool, BytecodeVerificationRemote, true, \ - "Enables the Java bytecode verifier for remote classes") \ + "Enable the Java bytecode verifier for remote classes") \ \ product(bool, BytecodeVerificationLocal, false, \ - "Enables the Java bytecode verifier for local classes") \ + "Enable the Java bytecode verifier for local classes") \ \ develop(bool, ForceFloatExceptions, trueInDebug, \ "Force exceptions on FP stack under/overflow") \ @@ -739,7 +787,7 @@ "Trace java language assertions") \ \ notproduct(bool, CheckAssertionStatusDirectives, false, \ - "temporary - see javaClasses.cpp") \ + "Temporary - see javaClasses.cpp") \ \ notproduct(bool, PrintMallocFree, false, \ "Trace calls to C heap malloc/free allocation") \ @@ -758,16 +806,16 @@ "entering the VM") \ \ notproduct(bool, CheckOopishValues, false, \ - "Warn if value contains oop ( requires ZapDeadLocals)") \ + "Warn if value contains oop (requires ZapDeadLocals)") \ \ develop(bool, UseMallocOnly, false, \ - "use only malloc/free for allocation (no resource area/arena)") \ + "Use only malloc/free for allocation (no resource area/arena)") \ \ develop(bool, PrintMalloc, false, \ - "print all malloc/free calls") \ + "Print all malloc/free calls") \ \ develop(bool, PrintMallocStatistics, false, \ - "print malloc/free statistics") \ + "Print malloc/free statistics") \ \ develop(bool, ZapResourceArea, trueInDebug, \ "Zap freed resource/arena space with 0xABABABAB") \ @@ -779,7 +827,7 @@ "Zap freed JNI handle space with 0xFEFEFEFE") \ \ notproduct(bool, ZapStackSegments, trueInDebug, \ - "Zap allocated/freed Stack segments with 0xFADFADED") \ + "Zap allocated/freed stack segments with 0xFADFADED") \ \ develop(bool, ZapUnusedHeapArea, trueInDebug, \ "Zap unused heap space with 0xBAADBABE") \ @@ -794,7 +842,7 @@ "Zap filler objects with 0xDEAFBABE") \ \ develop(bool, PrintVMMessages, true, \ - "Print vm messages on console") \ + "Print VM messages on console") \ \ product(bool, PrintGCApplicationConcurrentTime, false, \ "Print the time the application has been running") \ @@ -803,21 +851,21 @@ "Print the time the application has been stopped") \ \ diagnostic(bool, VerboseVerification, false, \ - "Display detailed verification details") \ + "Display detailed verification details") \ \ notproduct(uintx, ErrorHandlerTest, 0, \ - "If > 0, provokes an error after VM initialization; the value" \ - "determines which error to provoke. See test_error_handler()" \ + "If > 0, provokes an error after VM initialization; the value " \ + "determines which error to provoke. See test_error_handler() " \ "in debug.cpp.") \ \ develop(bool, Verbose, false, \ - "Prints additional debugging information from other modes") \ + "Print additional debugging information from other modes") \ \ develop(bool, PrintMiscellaneous, false, \ - "Prints uncategorized debugging information (requires +Verbose)") \ + "Print uncategorized debugging information (requires +Verbose)") \ \ develop(bool, WizardMode, false, \ - "Prints much more debugging information") \ + "Print much more debugging information") \ \ product(bool, ShowMessageBoxOnError, false, \ "Keep process alive on VM fatal error") \ @@ -829,7 +877,7 @@ "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ \ product(bool, SuppressFatalErrorMessage, false, \ - "Do NO Fatal Error report [Avoid deadlock]") \ + "Report NO fatal error message (avoid deadlock)") \ \ product(ccstrlist, OnError, "", \ "Run user-defined commands on fatal error; see VMError.cpp " \ @@ -839,17 +887,17 @@ "Run user-defined commands on first java.lang.OutOfMemoryError") \ \ manageable(bool, HeapDumpBeforeFullGC, false, \ - "Dump heap to file before any major stop-world GC") \ + "Dump heap to file before any major stop-the-world GC") \ \ manageable(bool, HeapDumpAfterFullGC, false, \ - "Dump heap to file after any major stop-world GC") \ + "Dump heap to file after any major stop-the-world GC") \ \ manageable(bool, HeapDumpOnOutOfMemoryError, false, \ "Dump heap to file when java.lang.OutOfMemoryError is thrown") \ \ manageable(ccstr, HeapDumpPath, NULL, \ - "When HeapDumpOnOutOfMemoryError is on, the path (filename or" \ - "directory) of the dump file (defaults to java_pid.hprof" \ + "When HeapDumpOnOutOfMemoryError is on, the path (filename or " \ + "directory) of the dump file (defaults to java_pid.hprof " \ "in the working directory)") \ \ develop(uintx, SegmentedHeapDumpThreshold, 2*G, \ @@ -863,10 +911,10 @@ "Execute breakpoint upon encountering VM warning") \ \ develop(bool, TraceVMOperation, false, \ - "Trace vm operations") \ + "Trace VM operations") \ \ develop(bool, UseFakeTimers, false, \ - "Tells whether the VM should use system time or a fake timer") \ + "Tell whether the VM should use system time or a fake timer") \ \ product(ccstr, NativeMemoryTracking, "off", \ "Native memory tracking options") \ @@ -876,7 +924,7 @@ \ diagnostic(bool, AutoShutdownNMT, true, \ "Automatically shutdown native memory tracking under stress " \ - "situation. When set to false, native memory tracking tries to " \ + "situations. When set to false, native memory tracking tries to " \ "stay alive at the expense of JVM performance") \ \ diagnostic(bool, LogCompilation, false, \ @@ -886,12 +934,12 @@ "Print compilations") \ \ diagnostic(bool, TraceNMethodInstalls, false, \ - "Trace nmethod intallation") \ + "Trace nmethod installation") \ \ diagnostic(intx, ScavengeRootsInCode, 2, \ - "0: do not allow scavengable oops in the code cache; " \ - "1: allow scavenging from the code cache; " \ - "2: emit as many constants as the compiler can see") \ + "0: do not allow scavengable oops in the code cache; " \ + "1: allow scavenging from the code cache; " \ + "2: emit as many constants as the compiler can see") \ \ product(bool, AlwaysRestoreFPU, false, \ "Restore the FPU control word after every JNI call (expensive)") \ @@ -912,7 +960,7 @@ "Print assembly code (using external disassembler.so)") \ \ diagnostic(ccstr, PrintAssemblyOptions, NULL, \ - "Options string passed to disassembler.so") \ + "Print options string passed to disassembler.so") \ \ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ @@ -933,20 +981,21 @@ "Print exception handler tables for all nmethods when generated") \ \ develop(bool, StressCompiledExceptionHandlers, false, \ - "Exercise compiled exception handlers") \ + "Exercise compiled exception handlers") \ \ develop(bool, InterceptOSException, false, \ - "Starts debugger when an implicit OS (e.g., NULL) " \ + "Start debugger when an implicit OS (e.g. NULL) " \ "exception happens") \ \ product(bool, PrintCodeCache, false, \ "Print the code cache memory usage when exiting") \ \ develop(bool, PrintCodeCache2, false, \ - "Print detailed usage info on the code cache when exiting") \ + "Print detailed usage information on the code cache when exiting")\ \ product(bool, PrintCodeCacheOnCompilation, false, \ - "Print the code cache memory usage each time a method is compiled") \ + "Print the code cache memory usage each time a method is " \ + "compiled") \ \ diagnostic(bool, PrintStubCode, false, \ "Print generated stub code") \ @@ -958,40 +1007,40 @@ "Omit backtraces for some 'hot' exceptions in optimized code") \ \ product(bool, ProfilerPrintByteCodeStatistics, false, \ - "Prints byte code statictics when dumping profiler output") \ + "Print bytecode statistics when dumping profiler output") \ \ product(bool, ProfilerRecordPC, false, \ - "Collects tick for each 16 byte interval of compiled code") \ + "Collect ticks for each 16 byte interval of compiled code") \ \ product(bool, ProfileVM, false, \ - "Profiles ticks that fall within VM (either in the VM Thread " \ + "Profile ticks that fall within VM (either in the VM Thread " \ "or VM code called through stubs)") \ \ product(bool, ProfileIntervals, false, \ - "Prints profiles for each interval (see ProfileIntervalsTicks)") \ + "Print profiles for each interval (see ProfileIntervalsTicks)") \ \ notproduct(bool, ProfilerCheckIntervals, false, \ - "Collect and print info on spacing of profiler ticks") \ + "Collect and print information on spacing of profiler ticks") \ \ develop(bool, PrintJVMWarnings, false, \ - "Prints warnings for unimplemented JVM functions") \ + "Print warnings for unimplemented JVM functions") \ \ product(bool, PrintWarnings, true, \ - "Prints JVM warnings to output stream") \ + "Print JVM warnings to output stream") \ \ notproduct(uintx, WarnOnStalledSpinLock, 0, \ - "Prints warnings for stalled SpinLocks") \ + "Print warnings for stalled SpinLocks") \ \ product(bool, RegisterFinalizersAtInit, true, \ "Register finalizable objects at end of Object. or " \ "after allocation") \ \ develop(bool, RegisterReferences, true, \ - "Tells whether the VM should register soft/weak/final/phantom " \ + "Tell whether the VM should register soft/weak/final/phantom " \ "references") \ \ develop(bool, IgnoreRewrites, false, \ - "Supress rewrites of bytecodes in the oopmap generator. " \ + "Suppress rewrites of bytecodes in the oopmap generator. " \ "This is unsafe!") \ \ develop(bool, PrintCodeCacheExtension, false, \ @@ -1001,8 +1050,7 @@ "Enable the security JVM functions") \ \ develop(bool, ProtectionDomainVerification, true, \ - "Verifies protection domain before resolution in system " \ - "dictionary") \ + "Verify protection domain before resolution in system dictionary")\ \ product(bool, ClassUnloading, true, \ "Do unloading of classes") \ @@ -1015,14 +1063,14 @@ "Write memory usage profiling to log file") \ \ notproduct(bool, PrintSystemDictionaryAtExit, false, \ - "Prints the system dictionary at exit") \ + "Print the system dictionary at exit") \ \ experimental(intx, PredictedLoadedClassCount, 0, \ - "Experimental: Tune loaded class cache starting size.") \ + "Experimental: Tune loaded class cache starting size") \ \ diagnostic(bool, UnsyncloadClass, false, \ "Unstable: VM calls loadClass unsynchronized. Custom " \ - "class loader must call VM synchronized for findClass " \ + "class loader must call VM synchronized for findClass " \ "and defineClass.") \ \ product(bool, AlwaysLockClassLoader, false, \ @@ -1038,22 +1086,22 @@ "Call loadClassInternal() rather than loadClass()") \ \ product_pd(bool, DontYieldALot, \ - "Throw away obvious excess yield calls (for SOLARIS only)") \ + "Throw away obvious excess yield calls (for Solaris only)") \ \ product_pd(bool, ConvertSleepToYield, \ - "Converts sleep(0) to thread yield " \ - "(may be off for SOLARIS to improve GUI)") \ + "Convert sleep(0) to thread yield " \ + "(may be off for Solaris to improve GUI)") \ \ product(bool, ConvertYieldToSleep, false, \ - "Converts yield to a sleep of MinSleepInterval to simulate Win32 "\ - "behavior (SOLARIS only)") \ + "Convert yield to a sleep of MinSleepInterval to simulate Win32 " \ + "behavior (Solaris only)") \ \ product(bool, UseBoundThreads, true, \ - "Bind user level threads to kernel threads (for SOLARIS only)") \ + "Bind user level threads to kernel threads (for Solaris only)") \ \ develop(bool, UseDetachedThreads, true, \ "Use detached threads that are recycled upon termination " \ - "(for SOLARIS only)") \ + "(for Solaris only)") \ \ product(bool, UseLWPSynchronization, true, \ "Use LWP-based instead of libthread-based synchronization " \ @@ -1063,41 +1111,43 @@ "(Unstable) Various monitor synchronization tunables") \ \ product(intx, EmitSync, 0, \ - "(Unsafe,Unstable) " \ - " Controls emission of inline sync fast-path code") \ + "(Unsafe, Unstable) " \ + "Control emission of inline sync fast-path code") \ \ product(intx, MonitorBound, 0, "Bound Monitor population") \ \ product(bool, MonitorInUseLists, false, "Track Monitors for Deflation") \ \ - product(intx, SyncFlags, 0, "(Unsafe,Unstable) Experimental Sync flags" ) \ - \ - product(intx, SyncVerbose, 0, "(Unstable)" ) \ - \ - product(intx, ClearFPUAtPark, 0, "(Unsafe,Unstable)" ) \ + product(intx, SyncFlags, 0, "(Unsafe, Unstable) Experimental Sync flags") \ + \ + product(intx, SyncVerbose, 0, "(Unstable)") \ + \ + product(intx, ClearFPUAtPark, 0, "(Unsafe, Unstable)") \ \ product(intx, hashCode, 5, \ - "(Unstable) select hashCode generation algorithm" ) \ + "(Unstable) select hashCode generation algorithm") \ \ product(intx, WorkAroundNPTLTimedWaitHang, 1, \ - "(Unstable, Linux-specific)" \ - " avoid NPTL-FUTEX hang pthread_cond_timedwait" ) \ + "(Unstable, Linux-specific) " \ + "avoid NPTL-FUTEX hang pthread_cond_timedwait") \ \ product(bool, FilterSpuriousWakeups, true, \ "Prevent spurious or premature wakeups from object.wait " \ "(Solaris only)") \ \ - product(intx, NativeMonitorTimeout, -1, "(Unstable)" ) \ - product(intx, NativeMonitorFlags, 0, "(Unstable)" ) \ - product(intx, NativeMonitorSpinLimit, 20, "(Unstable)" ) \ + product(intx, NativeMonitorTimeout, -1, "(Unstable)") \ + \ + product(intx, NativeMonitorFlags, 0, "(Unstable)") \ + \ + product(intx, NativeMonitorSpinLimit, 20, "(Unstable)") \ \ develop(bool, UsePthreads, false, \ "Use pthread-based instead of libthread-based synchronization " \ "(SPARC only)") \ \ product(bool, AdjustConcurrency, false, \ - "call thr_setconcurrency at thread create time to avoid " \ - "LWP starvation on MP systems (For Solaris Only)") \ + "Call thr_setconcurrency at thread creation time to avoid " \ + "LWP starvation on MP systems (for Solaris Only)") \ \ product(bool, ReduceSignalUsage, false, \ "Reduce the use of OS signals in Java and/or the VM") \ @@ -1106,13 +1156,14 @@ "Share vtable stubs (smaller code but worse branch prediction") \ \ develop(bool, LoadLineNumberTables, true, \ - "Tells whether the class file parser loads line number tables") \ + "Tell whether the class file parser loads line number tables") \ \ develop(bool, LoadLocalVariableTables, true, \ - "Tells whether the class file parser loads local variable tables")\ + "Tell whether the class file parser loads local variable tables") \ \ develop(bool, LoadLocalVariableTypeTables, true, \ - "Tells whether the class file parser loads local variable type tables")\ + "Tell whether the class file parser loads local variable type" \ + "tables") \ \ product(bool, AllowUserSignalHandlers, false, \ "Do not complain if the application installs signal handlers " \ @@ -1143,10 +1194,12 @@ \ product(bool, EagerXrunInit, false, \ "Eagerly initialize -Xrun libraries; allows startup profiling, " \ - " but not all -Xrun libraries may support the state of the VM at this time") \ + "but not all -Xrun libraries may support the state of the VM " \ + "at this time") \ \ product(bool, PreserveAllAnnotations, false, \ - "Preserve RuntimeInvisibleAnnotations as well as RuntimeVisibleAnnotations") \ + "Preserve RuntimeInvisibleAnnotations as well " \ + "as RuntimeVisibleAnnotations") \ \ develop(uintx, PreallocatedOutOfMemoryErrorCount, 4, \ "Number of OutOfMemoryErrors preallocated with backtrace") \ @@ -1221,7 +1274,7 @@ "Trace level for JVMTI RedefineClasses") \ \ develop(bool, StressMethodComparator, false, \ - "run the MethodComparator on all loaded methods") \ + "Run the MethodComparator on all loaded methods") \ \ /* change to false by default sometime after Mustang */ \ product(bool, VerifyMergedCPBytecodes, true, \ @@ -1255,7 +1308,7 @@ "Trace dependencies") \ \ develop(bool, VerifyDependencies, trueInDebug, \ - "Exercise and verify the compilation dependency mechanism") \ + "Exercise and verify the compilation dependency mechanism") \ \ develop(bool, TraceNewOopMapGeneration, false, \ "Trace OopMapGeneration") \ @@ -1273,7 +1326,7 @@ "Trace monitor matching failures during OopMapGeneration") \ \ develop(bool, TraceOopMapRewrites, false, \ - "Trace rewritting of method oops during oop map generation") \ + "Trace rewriting of method oops during oop map generation") \ \ develop(bool, TraceSafepoint, false, \ "Trace safepoint operations") \ @@ -1291,10 +1344,10 @@ "Trace setup time") \ \ develop(bool, TraceProtectionDomainVerification, false, \ - "Trace protection domain verifcation") \ + "Trace protection domain verification") \ \ develop(bool, TraceClearedExceptions, false, \ - "Prints when an exception is forcibly cleared") \ + "Print when an exception is forcibly cleared") \ \ product(bool, TraceClassResolution, false, \ "Trace all constant pool resolutions (for debugging)") \ @@ -1308,7 +1361,7 @@ /* gc */ \ \ product(bool, UseSerialGC, false, \ - "Use the serial garbage collector") \ + "Use the Serial garbage collector") \ \ product(bool, UseG1GC, false, \ "Use the Garbage-First garbage collector") \ @@ -1327,16 +1380,16 @@ "The collection count for the first maximum compaction") \ \ product(bool, UseMaximumCompactionOnSystemGC, true, \ - "In the Parallel Old garbage collector maximum compaction for " \ - "a system GC") \ + "Use maximum compaction in the Parallel Old garbage collector " \ + "for a system GC") \ \ product(uintx, ParallelOldDeadWoodLimiterMean, 50, \ - "The mean used by the par compact dead wood" \ - "limiter (a number between 0-100).") \ + "The mean used by the parallel compact dead wood " \ + "limiter (a number between 0-100)") \ \ product(uintx, ParallelOldDeadWoodLimiterStdDev, 80, \ - "The standard deviation used by the par compact dead wood" \ - "limiter (a number between 0-100).") \ + "The standard deviation used by the parallel compact dead wood " \ + "limiter (a number between 0-100)") \ \ product(uintx, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ @@ -1346,7 +1399,7 @@ "parallel gc will use") \ \ diagnostic(bool, ForceDynamicNumberOfGCThreads, false, \ - "Force dynamic selection of the number of" \ + "Force dynamic selection of the number of " \ "parallel threads parallel gc will use to aid debugging") \ \ product(uintx, HeapSizePerGCThread, ScaleForWordSize(64*M), \ @@ -1357,7 +1410,7 @@ "Trace the dynamic GC thread usage") \ \ develop(bool, ParallelOldGCSplitALot, false, \ - "Provoke splitting (copying data from a young gen space to" \ + "Provoke splitting (copying data from a young gen space to " \ "multiple destination spaces)") \ \ develop(uintx, ParallelOldGCSplitInterval, 3, \ @@ -1367,19 +1420,19 @@ "Number of threads concurrent gc will use") \ \ product(uintx, YoungPLABSize, 4096, \ - "Size of young gen promotion labs (in HeapWords)") \ + "Size of young gen promotion LAB's (in HeapWords)") \ \ product(uintx, OldPLABSize, 1024, \ - "Size of old gen promotion labs (in HeapWords)") \ + "Size of old gen promotion LAB's (in HeapWords)") \ \ product(uintx, GCTaskTimeStampEntries, 200, \ "Number of time stamp entries per gc worker thread") \ \ product(bool, AlwaysTenure, false, \ - "Always tenure objects in eden. (ParallelGC only)") \ + "Always tenure objects in eden (ParallelGC only)") \ \ product(bool, NeverTenure, false, \ - "Never tenure objects in eden, May tenure on overflow " \ + "Never tenure objects in eden, may tenure on overflow " \ "(ParallelGC only)") \ \ product(bool, ScavengeBeforeFullGC, true, \ @@ -1387,14 +1440,14 @@ "used with UseParallelGC") \ \ develop(bool, ScavengeWithObjectsInToSpace, false, \ - "Allow scavenges to occur when to_space contains objects.") \ + "Allow scavenges to occur when to-space contains objects") \ \ product(bool, UseConcMarkSweepGC, false, \ "Use Concurrent Mark-Sweep GC in the old generation") \ \ product(bool, ExplicitGCInvokesConcurrent, false, \ - "A System.gc() request invokes a concurrent collection;" \ - " (effective only when UseConcMarkSweepGC)") \ + "A System.gc() request invokes a concurrent collection; " \ + "(effective only when UseConcMarkSweepGC)") \ \ product(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false, \ "A System.gc() request invokes a concurrent collection and " \ @@ -1402,19 +1455,19 @@ "(effective only when UseConcMarkSweepGC)") \ \ product(bool, GCLockerInvokesConcurrent, false, \ - "The exit of a JNI CS necessitating a scavenge also" \ - " kicks off a bkgrd concurrent collection") \ + "The exit of a JNI critical section necessitating a scavenge, " \ + "also kicks off a background concurrent collection") \ \ product(uintx, GCLockerEdenExpansionPercent, 5, \ - "How much the GC can expand the eden by while the GC locker " \ + "How much the GC can expand the eden by while the GC locker " \ "is active (as a percentage)") \ \ diagnostic(intx, GCLockerRetryAllocationCount, 2, \ - "Number of times to retry allocations when" \ - " blocked by the GC locker") \ + "Number of times to retry allocations when " \ + "blocked by the GC locker") \ \ develop(bool, UseCMSAdaptiveFreeLists, true, \ - "Use Adaptive Free Lists in the CMS generation") \ + "Use adaptive free lists in the CMS generation") \ \ develop(bool, UseAsyncConcMarkSweepGC, true, \ "Use Asynchronous Concurrent Mark-Sweep GC in the old generation")\ @@ -1429,44 +1482,46 @@ "Use passing of collection from background to foreground") \ \ product(bool, UseParNewGC, false, \ - "Use parallel threads in the new generation.") \ + "Use parallel threads in the new generation") \ \ product(bool, ParallelGCVerbose, false, \ - "Verbose output for parallel GC.") \ + "Verbose output for parallel gc") \ \ product(uintx, ParallelGCBufferWastePct, 10, \ - "Wasted fraction of parallel allocation buffer.") \ + "Wasted fraction of parallel allocation buffer") \ \ diagnostic(bool, ParallelGCRetainPLAB, false, \ - "Retain parallel allocation buffers across scavenges; " \ - " -- disabled because this currently conflicts with " \ - " parallel card scanning under certain conditions ") \ + "Retain parallel allocation buffers across scavenges; " \ + "it is disabled because this currently conflicts with " \ + "parallel card scanning under certain conditions.") \ \ product(uintx, TargetPLABWastePct, 10, \ "Target wasted space in last buffer as percent of overall " \ "allocation") \ \ product(uintx, PLABWeight, 75, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponentially decaying average for ResizePLAB.") \ + "Percentage (0-100) used to weigh the current sample when " \ + "computing exponentially decaying average for ResizePLAB") \ \ product(bool, ResizePLAB, true, \ - "Dynamically resize (survivor space) promotion labs") \ + "Dynamically resize (survivor space) promotion LAB's") \ \ product(bool, PrintPLAB, false, \ - "Print (survivor space) promotion labs sizing decisions") \ + "Print (survivor space) promotion LAB's sizing decisions") \ \ product(intx, ParGCArrayScanChunk, 50, \ - "Scan a subset and push remainder, if array is bigger than this") \ + "Scan a subset of object array and push remainder, if array is " \ + "bigger than this") \ \ product(bool, ParGCUseLocalOverflow, false, \ "Instead of a global overflow list, use local overflow stacks") \ \ product(bool, ParGCTrimOverflow, true, \ - "Eagerly trim the local overflow lists (when ParGCUseLocalOverflow") \ + "Eagerly trim the local overflow lists " \ + "(when ParGCUseLocalOverflow)") \ \ notproduct(bool, ParGCWorkQueueOverflowALot, false, \ - "Whether we should simulate work queue overflow in ParNew") \ + "Simulate work queue overflow in ParNew") \ \ notproduct(uintx, ParGCWorkQueueOverflowInterval, 1000, \ "An `interval' counter that determines how frequently " \ @@ -1484,43 +1539,46 @@ "during card table scanning") \ \ product(uintx, CMSParPromoteBlocksToClaim, 16, \ - "Number of blocks to attempt to claim when refilling CMS LAB for "\ - "parallel GC.") \ + "Number of blocks to attempt to claim when refilling CMS LAB's " \ + "for parallel GC") \ \ product(uintx, OldPLABWeight, 50, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponentially decaying average for resizing CMSParPromoteBlocksToClaim.") \ + "Percentage (0-100) used to weight the current sample when " \ + "computing exponentially decaying average for resizing " \ + "CMSParPromoteBlocksToClaim") \ \ product(bool, ResizeOldPLAB, true, \ - "Dynamically resize (old gen) promotion labs") \ + "Dynamically resize (old gen) promotion LAB's") \ \ product(bool, PrintOldPLAB, false, \ - "Print (old gen) promotion labs sizing decisions") \ + "Print (old gen) promotion LAB's sizing decisions") \ \ product(uintx, CMSOldPLABMin, 16, \ - "Min size of CMS gen promotion lab caches per worker per blksize")\ + "Minimum size of CMS gen promotion LAB caches per worker " \ + "per block size") \ \ product(uintx, CMSOldPLABMax, 1024, \ - "Max size of CMS gen promotion lab caches per worker per blksize")\ + "Maximum size of CMS gen promotion LAB caches per worker " \ + "per block size") \ \ product(uintx, CMSOldPLABNumRefills, 4, \ - "Nominal number of refills of CMS gen promotion lab cache" \ - " per worker per block size") \ + "Nominal number of refills of CMS gen promotion LAB cache " \ + "per worker per block size") \ \ product(bool, CMSOldPLABResizeQuicker, false, \ - "Whether to react on-the-fly during a scavenge to a sudden" \ - " change in block demand rate") \ + "React on-the-fly during a scavenge to a sudden " \ + "change in block demand rate") \ \ product(uintx, CMSOldPLABToleranceFactor, 4, \ - "The tolerance of the phase-change detector for on-the-fly" \ - " PLAB resizing during a scavenge") \ + "The tolerance of the phase-change detector for on-the-fly " \ + "PLAB resizing during a scavenge") \ \ product(uintx, CMSOldPLABReactivityFactor, 2, \ - "The gain in the feedback loop for on-the-fly PLAB resizing" \ - " during a scavenge") \ + "The gain in the feedback loop for on-the-fly PLAB resizing " \ + "during a scavenge") \ \ product(bool, AlwaysPreTouch, false, \ - "It forces all freshly committed pages to be pre-touched.") \ + "Force all freshly committed pages to be pre-touched") \ \ product_pd(uintx, CMSYoungGenPerWorker, \ "The maximum size of young gen chosen by default per GC worker " \ @@ -1530,64 +1588,67 @@ "Whether CMS GC should operate in \"incremental\" mode") \ \ product(uintx, CMSIncrementalDutyCycle, 10, \ - "CMS incremental mode duty cycle (a percentage, 0-100). If" \ - "CMSIncrementalPacing is enabled, then this is just the initial" \ - "value") \ + "Percentage (0-100) of CMS incremental mode duty cycle. If " \ + "CMSIncrementalPacing is enabled, then this is just the initial " \ + "value.") \ \ product(bool, CMSIncrementalPacing, true, \ "Whether the CMS incremental mode duty cycle should be " \ "automatically adjusted") \ \ product(uintx, CMSIncrementalDutyCycleMin, 0, \ - "Lower bound on the duty cycle when CMSIncrementalPacing is " \ - "enabled (a percentage, 0-100)") \ + "Minimum percentage (0-100) of the CMS incremental duty cycle " \ + "used when CMSIncrementalPacing is enabled") \ \ product(uintx, CMSIncrementalSafetyFactor, 10, \ "Percentage (0-100) used to add conservatism when computing the " \ "duty cycle") \ \ product(uintx, CMSIncrementalOffset, 0, \ - "Percentage (0-100) by which the CMS incremental mode duty cycle" \ - " is shifted to the right within the period between young GCs") \ + "Percentage (0-100) by which the CMS incremental mode duty cycle "\ + "is shifted to the right within the period between young GCs") \ \ product(uintx, CMSExpAvgFactor, 50, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponential averages for CMS statistics.") \ + "Percentage (0-100) used to weigh the current sample when " \ + "computing exponential averages for CMS statistics") \ \ product(uintx, CMS_FLSWeight, 75, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponentially decating averages for CMS FLS statistics.") \ + "Percentage (0-100) used to weigh the current sample when " \ + "computing exponentially decaying averages for CMS FLS " \ + "statistics") \ \ product(uintx, CMS_FLSPadding, 1, \ - "The multiple of deviation from mean to use for buffering" \ - "against volatility in free list demand.") \ + "The multiple of deviation from mean to use for buffering " \ + "against volatility in free list demand") \ \ product(uintx, FLSCoalescePolicy, 2, \ - "CMS: Aggression level for coalescing, increasing from 0 to 4") \ + "CMS: aggressiveness level for coalescing, increasing " \ + "from 0 to 4") \ \ product(bool, FLSAlwaysCoalesceLarge, false, \ - "CMS: Larger free blocks are always available for coalescing") \ + "CMS: larger free blocks are always available for coalescing") \ \ product(double, FLSLargestBlockCoalesceProximity, 0.99, \ - "CMS: the smaller the percentage the greater the coalition force")\ + "CMS: the smaller the percentage the greater the coalescing " \ + "force") \ \ product(double, CMSSmallCoalSurplusPercent, 1.05, \ - "CMS: the factor by which to inflate estimated demand of small" \ - " block sizes to prevent coalescing with an adjoining block") \ + "CMS: the factor by which to inflate estimated demand of small " \ + "block sizes to prevent coalescing with an adjoining block") \ \ product(double, CMSLargeCoalSurplusPercent, 0.95, \ - "CMS: the factor by which to inflate estimated demand of large" \ - " block sizes to prevent coalescing with an adjoining block") \ + "CMS: the factor by which to inflate estimated demand of large " \ + "block sizes to prevent coalescing with an adjoining block") \ \ product(double, CMSSmallSplitSurplusPercent, 1.10, \ - "CMS: the factor by which to inflate estimated demand of small" \ - " block sizes to prevent splitting to supply demand for smaller" \ - " blocks") \ + "CMS: the factor by which to inflate estimated demand of small " \ + "block sizes to prevent splitting to supply demand for smaller " \ + "blocks") \ \ product(double, CMSLargeSplitSurplusPercent, 1.00, \ - "CMS: the factor by which to inflate estimated demand of large" \ - " block sizes to prevent splitting to supply demand for smaller" \ - " blocks") \ + "CMS: the factor by which to inflate estimated demand of large " \ + "block sizes to prevent splitting to supply demand for smaller " \ + "blocks") \ \ product(bool, CMSExtrapolateSweep, false, \ "CMS: cushion for block demand during sweep") \ @@ -1599,11 +1660,11 @@ \ product(uintx, CMS_SweepPadding, 1, \ "The multiple of deviation from mean to use for buffering " \ - "against volatility in inter-sweep duration.") \ + "against volatility in inter-sweep duration") \ \ product(uintx, CMS_SweepTimerThresholdMillis, 10, \ "Skip block flux-rate sampling for an epoch unless inter-sweep " \ - "duration exceeds this threhold in milliseconds") \ + "duration exceeds this threshold in milliseconds") \ \ develop(bool, CMSTraceIncrementalMode, false, \ "Trace CMS incremental mode") \ @@ -1618,14 +1679,15 @@ "Whether class unloading enabled when using CMS GC") \ \ product(uintx, CMSClassUnloadingMaxInterval, 0, \ - "When CMS class unloading is enabled, the maximum CMS cycle count"\ - " for which classes may not be unloaded") \ + "When CMS class unloading is enabled, the maximum CMS cycle " \ + "count for which classes may not be unloaded") \ \ product(bool, CMSCompactWhenClearAllSoftRefs, true, \ - "Compact when asked to collect CMS gen with clear_all_soft_refs") \ + "Compact when asked to collect CMS gen with " \ + "clear_all_soft_refs()") \ \ product(bool, UseCMSCompactAtFullCollection, true, \ - "Use mark sweep compact at full collections") \ + "Use Mark-Sweep-Compact algorithm at full collections") \ \ product(uintx, CMSFullGCsBeforeCompaction, 0, \ "Number of CMS full collection done before compaction if > 0") \ @@ -1647,38 +1709,37 @@ "Warn in case of excessive CMS looping") \ \ develop(bool, CMSOverflowEarlyRestoration, false, \ - "Whether preserved marks should be restored early") \ + "Restore preserved marks early") \ \ product(uintx, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ "Size of marking stack") \ \ product(uintx, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \ - "Max size of marking stack") \ + "Maximum size of marking stack") \ \ notproduct(bool, CMSMarkStackOverflowALot, false, \ - "Whether we should simulate frequent marking stack / work queue" \ - " overflow") \ + "Simulate frequent marking stack / work queue overflow") \ \ notproduct(uintx, CMSMarkStackOverflowInterval, 1000, \ - "An `interval' counter that determines how frequently" \ - " we simulate overflow; a smaller number increases frequency") \ + "An \"interval\" counter that determines how frequently " \ + "to simulate overflow; a smaller number increases frequency") \ \ product(uintx, CMSMaxAbortablePrecleanLoops, 0, \ - "(Temporary, subject to experimentation)" \ + "(Temporary, subject to experimentation) " \ "Maximum number of abortable preclean iterations, if > 0") \ \ product(intx, CMSMaxAbortablePrecleanTime, 5000, \ - "(Temporary, subject to experimentation)" \ - "Maximum time in abortable preclean in ms") \ + "(Temporary, subject to experimentation) " \ + "Maximum time in abortable preclean (in milliseconds)") \ \ product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \ - "(Temporary, subject to experimentation)" \ + "(Temporary, subject to experimentation) " \ "Nominal minimum work per abortable preclean iteration") \ \ manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \ - "(Temporary, subject to experimentation)" \ - " Time that we sleep between iterations when not given" \ - " enough work per iteration") \ + "(Temporary, subject to experimentation) " \ + "Time that we sleep between iterations when not given " \ + "enough work per iteration") \ \ product(uintx, CMSRescanMultiple, 32, \ "Size (in cards) of CMS parallel rescan task") \ @@ -1696,23 +1757,24 @@ "Whether parallel remark enabled (only if ParNewGC)") \ \ product(bool, CMSParallelSurvivorRemarkEnabled, true, \ - "Whether parallel remark of survivor space" \ - " enabled (effective only if CMSParallelRemarkEnabled)") \ + "Whether parallel remark of survivor space " \ + "enabled (effective only if CMSParallelRemarkEnabled)") \ \ product(bool, CMSPLABRecordAlways, true, \ - "Whether to always record survivor space PLAB bdries" \ - " (effective only if CMSParallelSurvivorRemarkEnabled)") \ + "Always record survivor space PLAB boundaries (effective only " \ + "if CMSParallelSurvivorRemarkEnabled)") \ \ product(bool, CMSEdenChunksRecordAlways, true, \ - "Whether to always record eden chunks used for " \ - "the parallel initial mark or remark of eden" ) \ + "Always record eden chunks used for the parallel initial mark " \ + "or remark of eden") \ \ product(bool, CMSPrintEdenSurvivorChunks, false, \ "Print the eden and the survivor chunks used for the parallel " \ "initial mark or remark of the eden/survivor spaces") \ \ product(bool, CMSConcurrentMTEnabled, true, \ - "Whether multi-threaded concurrent work enabled (if ParNewGC)") \ + "Whether multi-threaded concurrent work enabled " \ + "(effective only if ParNewGC)") \ \ product(bool, CMSPrecleaningEnabled, true, \ "Whether concurrent precleaning enabled") \ @@ -1721,12 +1783,12 @@ "Maximum number of precleaning iteration passes") \ \ product(uintx, CMSPrecleanNumerator, 2, \ - "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence" \ - " ratio") \ + "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \ + "ratio") \ \ product(uintx, CMSPrecleanDenominator, 3, \ - "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence" \ - " ratio") \ + "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \ + "ratio") \ \ product(bool, CMSPrecleanRefLists1, true, \ "Preclean ref lists during (initial) preclean phase") \ @@ -1741,7 +1803,7 @@ "Preclean survivors during abortable preclean phase") \ \ product(uintx, CMSPrecleanThreshold, 1000, \ - "Don't re-iterate if #dirty cards less than this") \ + "Do not iterate again if number of dirty cards is less than this")\ \ product(bool, CMSCleanOnEnter, true, \ "Clean-on-enter optimization for reducing number of dirty cards") \ @@ -1750,14 +1812,16 @@ "Choose variant (1,2) of verification following remark") \ \ product(uintx, CMSScheduleRemarkEdenSizeThreshold, 2*M, \ - "If Eden used is below this value, don't try to schedule remark") \ + "If Eden size is below this, do not try to schedule remark") \ \ product(uintx, CMSScheduleRemarkEdenPenetration, 50, \ - "The Eden occupancy % at which to try and schedule remark pause") \ + "The Eden occupancy percentage (0-100) at which " \ + "to try and schedule remark pause") \ \ product(uintx, CMSScheduleRemarkSamplingRatio, 5, \ - "Start sampling Eden top at least before yg occupancy reaches" \ - " 1/ of the size at which we plan to schedule remark") \ + "Start sampling eden top at least before young gen " \ + "occupancy reaches 1/ of the size at which " \ + "we plan to schedule remark") \ \ product(uintx, CMSSamplingGrain, 16*K, \ "The minimum distance between eden samples for CMS (see above)") \ @@ -1779,27 +1843,27 @@ "should start a collection cycle") \ \ product(bool, CMSYield, true, \ - "Yield between steps of concurrent mark & sweep") \ + "Yield between steps of CMS") \ \ product(uintx, CMSBitMapYieldQuantum, 10*M, \ - "Bitmap operations should process at most this many bits" \ + "Bitmap operations should process at most this many bits " \ "between yields") \ \ product(bool, CMSDumpAtPromotionFailure, false, \ "Dump useful information about the state of the CMS old " \ - " generation upon a promotion failure.") \ + "generation upon a promotion failure") \ \ product(bool, CMSPrintChunksInDump, false, \ "In a dump enabled by CMSDumpAtPromotionFailure, include " \ - " more detailed information about the free chunks.") \ + "more detailed information about the free chunks") \ \ product(bool, CMSPrintObjectsInDump, false, \ "In a dump enabled by CMSDumpAtPromotionFailure, include " \ - " more detailed information about the allocated objects.") \ + "more detailed information about the allocated objects") \ \ diagnostic(bool, FLSVerifyAllHeapReferences, false, \ - "Verify that all refs across the FLS boundary " \ - " are to valid objects") \ + "Verify that all references across the FLS boundary " \ + "are to valid objects") \ \ diagnostic(bool, FLSVerifyLists, false, \ "Do lots of (expensive) FreeListSpace verification") \ @@ -1811,17 +1875,18 @@ "Do lots of (expensive) FLS dictionary verification") \ \ develop(bool, VerifyBlockOffsetArray, false, \ - "Do (expensive!) block offset array verification") \ + "Do (expensive) block offset array verification") \ \ diagnostic(bool, BlockOffsetArrayUseUnallocatedBlock, false, \ - "Maintain _unallocated_block in BlockOffsetArray" \ - " (currently applicable only to CMS collector)") \ + "Maintain _unallocated_block in BlockOffsetArray " \ + "(currently applicable only to CMS collector)") \ \ develop(bool, TraceCMSState, false, \ "Trace the state of the CMS collection") \ \ product(intx, RefDiscoveryPolicy, 0, \ - "Whether reference-based(0) or referent-based(1)") \ + "Select type of reference discovery policy: " \ + "reference-based(0) or referent-based(1)") \ \ product(bool, ParallelRefProcEnabled, false, \ "Enable parallel reference processing whenever possible") \ @@ -1849,7 +1914,7 @@ "denotes 'do constant GC cycles'.") \ \ product(bool, UseCMSInitiatingOccupancyOnly, false, \ - "Only use occupancy as a crierion for starting a CMS collection") \ + "Only use occupancy as a criterion for starting a CMS collection")\ \ product(uintx, CMSIsTooFullPercentage, 98, \ "An absolute ceiling above which CMS will always consider the " \ @@ -1861,7 +1926,7 @@ \ notproduct(bool, CMSVerifyReturnedBytes, false, \ "Check that all the garbage collected was returned to the " \ - "free lists.") \ + "free lists") \ \ notproduct(bool, ScavengeALot, false, \ "Force scavenge at every Nth exit from the runtime system " \ @@ -1876,16 +1941,16 @@ \ product(bool, PrintPromotionFailure, false, \ "Print additional diagnostic information following " \ - " promotion failure") \ + "promotion failure") \ \ notproduct(bool, PromotionFailureALot, false, \ "Use promotion failure handling on every youngest generation " \ "collection") \ \ develop(uintx, PromotionFailureALotCount, 1000, \ - "Number of promotion failures occurring at ParGCAllocBuffer" \ + "Number of promotion failures occurring at ParGCAllocBuffer " \ "refill attempts (ParNew) or promotion attempts " \ - "(other young collectors) ") \ + "(other young collectors)") \ \ develop(uintx, PromotionFailureALotInterval, 5, \ "Total collections between promotion failures alot") \ @@ -1904,7 +1969,7 @@ "Ratio of hard spins to calls to yield") \ \ develop(uintx, ObjArrayMarkingStride, 512, \ - "Number of ObjArray elements to push onto the marking stack" \ + "Number of object array elements to push onto the marking stack " \ "before pushing a continuation entry") \ \ develop(bool, MetadataAllocationFailALot, false, \ @@ -1912,7 +1977,7 @@ "MetadataAllocationFailALotInterval") \ \ develop(uintx, MetadataAllocationFailALotInterval, 1000, \ - "metadata allocation failure alot interval") \ + "Metadata allocation failure a lot interval") \ \ develop(bool, MetaDataDeallocateALot, false, \ "Deallocation bunches of metadata at intervals controlled by " \ @@ -1931,7 +1996,7 @@ "Trace virtual space metadata allocations") \ \ notproduct(bool, ExecuteInternalVMTests, false, \ - "Enable execution of internal VM tests.") \ + "Enable execution of internal VM tests") \ \ notproduct(bool, VerboseInternalVMTests, false, \ "Turn on logging for internal VM tests.") \ @@ -1939,7 +2004,7 @@ product_pd(bool, UseTLAB, "Use thread-local object allocation") \ \ product_pd(bool, ResizeTLAB, \ - "Dynamically resize tlab size for threads") \ + "Dynamically resize TLAB size for threads") \ \ product(bool, ZeroTLAB, false, \ "Zero out the newly created TLAB") \ @@ -1951,7 +2016,8 @@ "Print various TLAB related information") \ \ product(bool, TLABStats, true, \ - "Print various TLAB related information") \ + "Provide more detailed and expensive TLAB statistics " \ + "(with PrintTLAB)") \ \ EMBEDDED_ONLY(product(bool, LowMemoryProtection, true, \ "Enable LowMemoryProtection")) \ @@ -1985,14 +2051,14 @@ "Fraction (1/n) of real memory used for initial heap size") \ \ develop(uintx, MaxVirtMemFraction, 2, \ - "Maximum fraction (1/n) of virtual memory used for ergonomically" \ + "Maximum fraction (1/n) of virtual memory used for ergonomically "\ "determining maximum heap size") \ \ product(bool, UseAutoGCSelectPolicy, false, \ "Use automatic collection selection policy") \ \ product(uintx, AutoGCSelectPauseMillis, 5000, \ - "Automatic GC selection pause threshhold in ms") \ + "Automatic GC selection pause threshold in milliseconds") \ \ product(bool, UseAdaptiveSizePolicy, true, \ "Use adaptive generation sizing policies") \ @@ -2007,7 +2073,7 @@ "Use adaptive young-old sizing policies at major collections") \ \ product(bool, UseAdaptiveSizePolicyWithSystemGC, false, \ - "Use statistics from System.GC for adaptive size policy") \ + "Include statistics from System.gc() for adaptive size policy") \ \ product(bool, UseAdaptiveGCBoundary, false, \ "Allow young-old boundary to move") \ @@ -2019,16 +2085,16 @@ "Resize the virtual spaces of the young or old generations") \ \ product(uintx, AdaptiveSizeThroughPutPolicy, 0, \ - "Policy for changeing generation size for throughput goals") \ + "Policy for changing generation size for throughput goals") \ \ product(uintx, AdaptiveSizePausePolicy, 0, \ "Policy for changing generation size for pause goals") \ \ develop(bool, PSAdjustTenuredGenForMinorPause, false, \ - "Adjust tenured generation to achive a minor pause goal") \ + "Adjust tenured generation to achieve a minor pause goal") \ \ develop(bool, PSAdjustYoungGenForMajorPause, false, \ - "Adjust young generation to achive a major pause goal") \ + "Adjust young generation to achieve a major pause goal") \ \ product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \ "Number of steps where heuristics is used before data is used") \ @@ -2083,14 +2149,15 @@ "Decay factor to TenuredGenerationSizeIncrement") \ \ product(uintx, MaxGCPauseMillis, max_uintx, \ - "Adaptive size policy maximum GC pause time goal in msec, " \ - "or (G1 Only) the max. GC time per MMU time slice") \ + "Adaptive size policy maximum GC pause time goal in millisecond, "\ + "or (G1 Only) the maximum GC time per MMU time slice") \ \ product(uintx, GCPauseIntervalMillis, 0, \ "Time slice for MMU specification") \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ - "Adaptive size policy maximum GC minor pause time goal in msec") \ + "Adaptive size policy maximum GC minor pause time goal " \ + "in millisecond") \ \ product(uintx, GCTimeRatio, 99, \ "Adaptive size policy application time to GC time ratio") \ @@ -2118,8 +2185,8 @@ "before an OutOfMemory error is thrown") \ \ product(uintx, GCTimeLimit, 98, \ - "Limit of proportion of time spent in GC before an OutOfMemory" \ - "error is thrown (used with GCHeapFreeLimit)") \ + "Limit of the proportion of time spent in GC before " \ + "an OutOfMemoryError is thrown (used with GCHeapFreeLimit)") \ \ product(uintx, GCHeapFreeLimit, 2, \ "Minimum percentage of free space after a full GC before an " \ @@ -2141,7 +2208,7 @@ "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ \ diagnostic(bool, VerifySilently, false, \ - "Don't print print the verification progress") \ + "Do not print the verification progress") \ \ diagnostic(bool, VerifyDuringStartup, false, \ "Verify memory system before executing any Java code " \ @@ -2164,7 +2231,7 @@ \ diagnostic(bool, DeferInitialCardMark, false, \ "When +ReduceInitialCardMarks, explicitly defer any that " \ - "may arise from new_pre_store_barrier") \ + "may arise from new_pre_store_barrier") \ \ diagnostic(bool, VerifyRememberedSets, false, \ "Verify GC remembered sets") \ @@ -2173,10 +2240,10 @@ "Verify GC object start array if verify before/after") \ \ product(bool, DisableExplicitGC, false, \ - "Tells whether calling System.gc() does a full GC") \ + "Ignore calls to System.gc()") \ \ notproduct(bool, CheckMemoryInitialization, false, \ - "Checks memory initialization") \ + "Check memory initialization") \ \ product(bool, CollectGen0First, false, \ "Collect youngest generation before each full GC") \ @@ -2197,44 +2264,45 @@ "Stride through processors when distributing processes") \ \ product(uintx, CMSCoordinatorYieldSleepCount, 10, \ - "number of times the coordinator GC thread will sleep while " \ + "Number of times the coordinator GC thread will sleep while " \ "yielding before giving up and resuming GC") \ \ product(uintx, CMSYieldSleepCount, 0, \ - "number of times a GC thread (minus the coordinator) " \ + "Number of times a GC thread (minus the coordinator) " \ "will sleep while yielding before giving up and resuming GC") \ \ /* gc tracing */ \ manageable(bool, PrintGC, false, \ - "Print message at garbage collect") \ + "Print message at garbage collection") \ \ manageable(bool, PrintGCDetails, false, \ - "Print more details at garbage collect") \ + "Print more details at garbage collection") \ \ manageable(bool, PrintGCDateStamps, false, \ - "Print date stamps at garbage collect") \ + "Print date stamps at garbage collection") \ \ manageable(bool, PrintGCTimeStamps, false, \ - "Print timestamps at garbage collect") \ + "Print timestamps at garbage collection") \ \ product(bool, PrintGCTaskTimeStamps, false, \ "Print timestamps for individual gc worker thread tasks") \ \ develop(intx, ConcGCYieldTimeout, 0, \ - "If non-zero, assert that GC threads yield within this # of ms.") \ + "If non-zero, assert that GC threads yield within this " \ + "number of milliseconds") \ \ notproduct(bool, TraceMarkSweep, false, \ "Trace mark sweep") \ \ product(bool, PrintReferenceGC, false, \ "Print times spent handling reference objects during GC " \ - " (enabled only when PrintGCDetails)") \ + "(enabled only when PrintGCDetails)") \ \ develop(bool, TraceReferenceGC, false, \ "Trace handling of soft/weak/final/phantom references") \ \ develop(bool, TraceFinalizerRegistration, false, \ - "Trace registration of final references") \ + "Trace registration of final references") \ \ notproduct(bool, TraceScavenge, false, \ "Trace scavenge") \ @@ -2271,7 +2339,7 @@ "Print heap layout before and after each GC") \ \ product_rw(bool, PrintHeapAtGCExtended, false, \ - "Prints extended information about the layout of the heap " \ + "Print extended information about the layout of the heap " \ "when -XX:+PrintHeapAtGC is set") \ \ product(bool, PrintHeapAtSIGBREAK, true, \ @@ -2308,45 +2376,45 @@ "Trace actions of the GC task threads") \ \ product(bool, PrintParallelOldGCPhaseTimes, false, \ - "Print the time taken by each parallel old gc phase." \ - "PrintGCDetails must also be enabled.") \ + "Print the time taken by each phase in ParallelOldGC " \ + "(PrintGCDetails must also be enabled)") \ \ develop(bool, TraceParallelOldGCMarkingPhase, false, \ - "Trace parallel old gc marking phase") \ + "Trace marking phase in ParallelOldGC") \ \ develop(bool, TraceParallelOldGCSummaryPhase, false, \ - "Trace parallel old gc summary phase") \ + "Trace summary phase in ParallelOldGC") \ \ develop(bool, TraceParallelOldGCCompactionPhase, false, \ - "Trace parallel old gc compaction phase") \ + "Trace compaction phase in ParallelOldGC") \ \ develop(bool, TraceParallelOldGCDensePrefix, false, \ - "Trace parallel old gc dense prefix computation") \ + "Trace dense prefix computation for ParallelOldGC") \ \ develop(bool, IgnoreLibthreadGPFault, false, \ "Suppress workaround for libthread GP fault") \ \ product(bool, PrintJNIGCStalls, false, \ - "Print diagnostic message when GC is stalled" \ + "Print diagnostic message when GC is stalled " \ "by JNI critical section") \ \ experimental(double, ObjectCountCutOffPercent, 0.5, \ "The percentage of the used heap that the instances of a class " \ - "must occupy for the class to generate a trace event.") \ + "must occupy for the class to generate a trace event") \ \ /* GC log rotation setting */ \ \ product(bool, UseGCLogFileRotation, false, \ - "Prevent large gclog file for long running app. " \ - "Requires -Xloggc:") \ + "Rotate gclog files (for long running applications). It requires "\ + "-Xloggc:") \ \ product(uintx, NumberOfGCLogFiles, 0, \ - "Number of gclog files in rotation, " \ - "Default: 0, no rotation") \ + "Number of gclog files in rotation " \ + "(default: 0, no rotation)") \ \ product(uintx, GCLogFileSize, 0, \ - "GC log file size, Default: 0 bytes, no rotation " \ - "Only valid with UseGCLogFileRotation") \ + "GC log file size (default: 0 bytes, no rotation). " \ + "It requires UseGCLogFileRotation") \ \ /* JVMTI heap profiling */ \ \ @@ -2423,40 +2491,40 @@ "Generate range checks for array accesses") \ \ develop_pd(bool, ImplicitNullChecks, \ - "generate code for implicit null checks") \ + "Generate code for implicit null checks") \ \ product(bool, PrintSafepointStatistics, false, \ - "print statistics about safepoint synchronization") \ + "Print statistics about safepoint synchronization") \ \ product(intx, PrintSafepointStatisticsCount, 300, \ - "total number of safepoint statistics collected " \ + "Total number of safepoint statistics collected " \ "before printing them out") \ \ product(intx, PrintSafepointStatisticsTimeout, -1, \ - "print safepoint statistics only when safepoint takes" \ - " more than PrintSafepointSatisticsTimeout in millis") \ + "Print safepoint statistics only when safepoint takes " \ + "more than PrintSafepointSatisticsTimeout in millis") \ \ product(bool, TraceSafepointCleanupTime, false, \ - "print the break down of clean up tasks performed during" \ - " safepoint") \ + "Print the break down of clean up tasks performed during " \ + "safepoint") \ \ product(bool, Inline, true, \ - "enable inlining") \ + "Enable inlining") \ \ product(bool, ClipInlining, true, \ - "clip inlining if aggregate method exceeds DesiredMethodLimit") \ + "Clip inlining if aggregate method exceeds DesiredMethodLimit") \ \ develop(bool, UseCHA, true, \ - "enable CHA") \ + "Enable CHA") \ \ product(bool, UseTypeProfile, true, \ "Check interpreter profile for historically monomorphic calls") \ \ notproduct(bool, TimeCompiler, false, \ - "time the compiler") \ + "Time the compiler") \ \ diagnostic(bool, PrintInlining, false, \ - "prints inlining optimizations") \ + "Print inlining optimizations") \ \ product(bool, UsePopCountInstruction, false, \ "Use population count instruction") \ @@ -2468,57 +2536,59 @@ "Print when methods are replaced do to recompilation") \ \ develop(bool, PrintMethodFlushing, false, \ - "print the nmethods being flushed") \ + "Print the nmethods being flushed") \ \ develop(bool, UseRelocIndex, false, \ - "use an index to speed random access to relocations") \ + "Use an index to speed random access to relocations") \ \ develop(bool, StressCodeBuffers, false, \ - "Exercise code buffer expansion and other rare state changes") \ + "Exercise code buffer expansion and other rare state changes") \ \ diagnostic(bool, DebugNonSafepoints, trueInDebug, \ - "Generate extra debugging info for non-safepoints in nmethods") \ + "Generate extra debugging information for non-safepoints in " \ + "nmethods") \ \ product(bool, PrintVMOptions, false, \ - "Print flags that appeared on the command line") \ + "Print flags that appeared on the command line") \ \ product(bool, IgnoreUnrecognizedVMOptions, false, \ - "Ignore unrecognized VM options") \ + "Ignore unrecognized VM options") \ \ product(bool, PrintCommandLineFlags, false, \ - "Print flags specified on command line or set by ergonomics") \ + "Print flags specified on command line or set by ergonomics") \ \ product(bool, PrintFlagsInitial, false, \ - "Print all VM flags before argument processing and exit VM") \ + "Print all VM flags before argument processing and exit VM") \ \ product(bool, PrintFlagsFinal, false, \ - "Print all VM flags after argument and ergonomic processing") \ + "Print all VM flags after argument and ergonomic processing") \ \ notproduct(bool, PrintFlagsWithComments, false, \ - "Print all VM flags with default values and descriptions and exit")\ + "Print all VM flags with default values and descriptions and " \ + "exit") \ \ diagnostic(bool, SerializeVMOutput, true, \ - "Use a mutex to serialize output to tty and LogFile") \ + "Use a mutex to serialize output to tty and LogFile") \ \ diagnostic(bool, DisplayVMOutput, true, \ - "Display all VM output on the tty, independently of LogVMOutput") \ + "Display all VM output on the tty, independently of LogVMOutput") \ \ diagnostic(bool, LogVMOutput, false, \ - "Save VM output to LogFile") \ + "Save VM output to LogFile") \ \ diagnostic(ccstr, LogFile, NULL, \ - "If LogVMOutput or LogCompilation is on, save VM output to " \ - "this file [default: ./hotspot_pid%p.log] (%p replaced with pid)") \ + "If LogVMOutput or LogCompilation is on, save VM output to " \ + "this file [default: ./hotspot_pid%p.log] (%p replaced with pid)")\ \ product(ccstr, ErrorFile, NULL, \ - "If an error occurs, save the error data to this file " \ - "[default: ./hs_err_pid%p.log] (%p replaced with pid)") \ + "If an error occurs, save the error data to this file " \ + "[default: ./hs_err_pid%p.log] (%p replaced with pid)") \ \ product(bool, DisplayVMOutputToStderr, false, \ - "If DisplayVMOutput is true, display all VM output to stderr") \ + "If DisplayVMOutput is true, display all VM output to stderr") \ \ product(bool, DisplayVMOutputToStdout, false, \ - "If DisplayVMOutput is true, display all VM output to stdout") \ + "If DisplayVMOutput is true, display all VM output to stdout") \ \ product(bool, UseHeavyMonitors, false, \ "use heavyweight instead of lightweight Java monitors") \ @@ -2542,7 +2612,7 @@ \ notproduct(ccstr, AbortVMOnExceptionMessage, NULL, \ "Call fatal if the exception pointed by AbortVMOnException " \ - "has this message.") \ + "has this message") \ \ develop(bool, DebugVtables, false, \ "add debugging code to vtable dispatch") \ @@ -2609,29 +2679,29 @@ \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ - "counts method invocations") \ + "Count method invocations") \ \ notproduct(bool, CountRuntimeCalls, false, \ - "counts VM runtime calls") \ + "Count VM runtime calls") \ \ develop(bool, CountJNICalls, false, \ - "counts jni method invocations") \ + "Count jni method invocations") \ \ notproduct(bool, CountJVMCalls, false, \ - "counts jvm method invocations") \ + "Count jvm method invocations") \ \ notproduct(bool, CountRemovableExceptions, false, \ - "count exceptions that could be replaced by branches due to " \ + "Count exceptions that could be replaced by branches due to " \ "inlining") \ \ notproduct(bool, ICMissHistogram, false, \ - "produce histogram of IC misses") \ + "Produce histogram of IC misses") \ \ notproduct(bool, PrintClassStatistics, false, \ - "prints class statistics at end of run") \ + "Print class statistics at end of run") \ \ notproduct(bool, PrintMethodStatistics, false, \ - "prints method statistics at end of run") \ + "Print method statistics at end of run") \ \ /* interpreter */ \ develop(bool, ClearInterpreterLocals, false, \ @@ -2645,7 +2715,7 @@ "Rewrite frequently used bytecode pairs into a single bytecode") \ \ diagnostic(bool, PrintInterpreter, false, \ - "Prints the generated interpreter code") \ + "Print the generated interpreter code") \ \ product(bool, UseInterpreter, true, \ "Use interpreter for non-compiled methods") \ @@ -2663,8 +2733,8 @@ "Use fast method entry code for accessor methods") \ \ product_pd(bool, UseOnStackReplacement, \ - "Use on stack replacement, calls runtime if invoc. counter " \ - "overflows in loop") \ + "Use on stack replacement, calls runtime if invoc. counter " \ + "overflows in loop") \ \ notproduct(bool, TraceOnStackReplacement, false, \ "Trace on stack replacement") \ @@ -2712,10 +2782,10 @@ "Trace frequency based inlining") \ \ develop_pd(bool, InlineIntrinsics, \ - "Inline intrinsics that can be statically resolved") \ + "Inline intrinsics that can be statically resolved") \ \ product_pd(bool, ProfileInterpreter, \ - "Profile at the bytecode level during interpretation") \ + "Profile at the bytecode level during interpretation") \ \ develop_pd(bool, ProfileTraps, \ "Profile deoptimization traps at the bytecode level") \ @@ -2725,7 +2795,7 @@ "CompileThreshold) before using the method's profile") \ \ develop(bool, PrintMethodData, false, \ - "Print the results of +ProfileInterpreter at end of run") \ + "Print the results of +ProfileInterpreter at end of run") \ \ develop(bool, VerifyDataPointer, trueInDebug, \ "Verify the method data pointer during interpreter profiling") \ @@ -2740,7 +2810,7 @@ \ /* compilation */ \ product(bool, UseCompiler, true, \ - "use compilation") \ + "Use Just-In-Time compilation") \ \ develop(bool, TraceCompilationPolicy, false, \ "Trace compilation policy") \ @@ -2749,20 +2819,21 @@ "Time the compilation policy") \ \ product(bool, UseCounterDecay, true, \ - "adjust recompilation counters") \ + "Adjust recompilation counters") \ \ develop(intx, CounterHalfLifeTime, 30, \ - "half-life time of invocation counters (in secs)") \ + "Half-life time of invocation counters (in seconds)") \ \ develop(intx, CounterDecayMinIntervalLength, 500, \ - "Min. ms. between invocation of CounterDecay") \ + "The minimum interval (in milliseconds) between invocation of " \ + "CounterDecay") \ \ product(bool, AlwaysCompileLoopMethods, false, \ - "when using recompilation, never interpret methods " \ + "When using recompilation, never interpret methods " \ "containing loops") \ \ product(bool, DontCompileHugeMethods, true, \ - "don't compile methods > HugeMethodLimit") \ + "Do not compile methods > HugeMethodLimit") \ \ /* Bytecode escape analysis estimation. */ \ product(bool, EstimateArgEscape, true, \ @@ -2772,10 +2843,10 @@ "How much tracing to do of bytecode escape analysis estimates") \ \ product(intx, MaxBCEAEstimateLevel, 5, \ - "Maximum number of nested calls that are analyzed by BC EA.") \ + "Maximum number of nested calls that are analyzed by BC EA") \ \ product(intx, MaxBCEAEstimateSize, 150, \ - "Maximum bytecode size of a method to be analyzed by BC EA.") \ + "Maximum bytecode size of a method to be analyzed by BC EA") \ \ product(intx, AllocatePrefetchStyle, 1, \ "0 = no prefetch, " \ @@ -2790,7 +2861,8 @@ "Number of lines to prefetch ahead of array allocation pointer") \ \ product(intx, AllocateInstancePrefetchLines, 1, \ - "Number of lines to prefetch ahead of instance allocation pointer") \ + "Number of lines to prefetch ahead of instance allocation " \ + "pointer") \ \ product(intx, AllocatePrefetchStepSize, 16, \ "Step size in bytes of sequential prefetch instructions") \ @@ -2810,8 +2882,8 @@ "(0 means off)") \ \ product(intx, MaxJavaStackTraceDepth, 1024, \ - "Max. no. of lines in the stack trace for Java exceptions " \ - "(0 means all)") \ + "The maximum number of lines in the stack trace for Java " \ + "exceptions (0 means all)") \ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ "Guarantee a safepoint (at least) every so many milliseconds " \ @@ -2830,11 +2902,15 @@ product(intx, NmethodSweepCheckInterval, 5, \ "Compilers wake up every n seconds to possibly sweep nmethods") \ \ + product(intx, NmethodSweepActivity, 10, \ + "Removes cold nmethods from code cache if > 0. Higher values " \ + "result in more aggressive sweeping") \ + \ notproduct(bool, LogSweeper, false, \ - "Keep a ring buffer of sweeper activity") \ + "Keep a ring buffer of sweeper activity") \ \ notproduct(intx, SweeperLogEntries, 1024, \ - "Number of records in the ring buffer of sweeper activity") \ + "Number of records in the ring buffer of sweeper activity") \ \ notproduct(intx, MemProfilingInterval, 500, \ "Time between each invocation of the MemProfiler") \ @@ -2877,34 +2953,35 @@ "less than this") \ \ product(intx, MaxInlineSize, 35, \ - "maximum bytecode size of a method to be inlined") \ + "The maximum bytecode size of a method to be inlined") \ \ product_pd(intx, FreqInlineSize, \ - "maximum bytecode size of a frequent method to be inlined") \ + "The maximum bytecode size of a frequent method to be inlined") \ \ product(intx, MaxTrivialSize, 6, \ - "maximum bytecode size of a trivial method to be inlined") \ + "The maximum bytecode size of a trivial method to be inlined") \ \ product(intx, MinInliningThreshold, 250, \ - "min. invocation count a method needs to have to be inlined") \ + "The minimum invocation count a method needs to have to be " \ + "inlined") \ \ develop(intx, MethodHistogramCutoff, 100, \ - "cutoff value for method invoc. histogram (+CountCalls)") \ + "The cutoff value for method invocation histogram (+CountCalls)") \ \ develop(intx, ProfilerNumberOfInterpretedMethods, 25, \ - "# of interpreted methods to show in profile") \ + "Number of interpreted methods to show in profile") \ \ develop(intx, ProfilerNumberOfCompiledMethods, 25, \ - "# of compiled methods to show in profile") \ + "Number of compiled methods to show in profile") \ \ develop(intx, ProfilerNumberOfStubMethods, 25, \ - "# of stub methods to show in profile") \ + "Number of stub methods to show in profile") \ \ develop(intx, ProfilerNumberOfRuntimeStubNodes, 25, \ - "# of runtime stub nodes to show in profile") \ + "Number of runtime stub nodes to show in profile") \ \ product(intx, ProfileIntervalsTicks, 100, \ - "# of ticks between printing of interval profile " \ + "Number of ticks between printing of interval profile " \ "(+ProfileIntervals)") \ \ notproduct(intx, ScavengeALotInterval, 1, \ @@ -2925,7 +3002,7 @@ \ develop(intx, MinSleepInterval, 1, \ "Minimum sleep() interval (milliseconds) when " \ - "ConvertSleepToYield is off (used for SOLARIS)") \ + "ConvertSleepToYield is off (used for Solaris)") \ \ develop(intx, ProfilerPCTickThreshold, 15, \ "Number of ticks in a PC buckets to be a hotspot") \ @@ -2940,22 +3017,22 @@ "Mark nmethods non-entrant at registration") \ \ diagnostic(intx, MallocVerifyInterval, 0, \ - "if non-zero, verify C heap after every N calls to " \ + "If non-zero, verify C heap after every N calls to " \ "malloc/realloc/free") \ \ diagnostic(intx, MallocVerifyStart, 0, \ - "if non-zero, start verifying C heap after Nth call to " \ + "If non-zero, start verifying C heap after Nth call to " \ "malloc/realloc/free") \ \ diagnostic(uintx, MallocMaxTestWords, 0, \ - "if non-zero, max # of Words that malloc/realloc can allocate " \ - "(for testing only)") \ + "If non-zero, maximum number of words that malloc/realloc can " \ + "allocate (for testing only)") \ \ product(intx, TypeProfileWidth, 2, \ - "number of receiver types to record in call/cast profile") \ + "Number of receiver types to record in call/cast profile") \ \ develop(intx, BciProfileWidth, 2, \ - "number of return bci's to record in ret profile") \ + "Number of return bci's to record in ret profile") \ \ product(intx, PerMethodRecompilationCutoff, 400, \ "After recompiling N times, stay in the interpreter (-1=>'Inf')") \ @@ -3022,7 +3099,7 @@ "Percentage of Eden that can be wasted") \ \ product(uintx, TLABRefillWasteFraction, 64, \ - "Max TLAB waste at a refill (internal fragmentation)") \ + "Maximum TLAB waste at a refill (internal fragmentation)") \ \ product(uintx, TLABWasteIncrement, 4, \ "Increment allowed waste at slow allocation") \ @@ -3031,7 +3108,7 @@ "Ratio of eden/survivor space size") \ \ product(uintx, NewRatio, 2, \ - "Ratio of new/old generation sizes") \ + "Ratio of old/new generation sizes") \ \ product_pd(uintx, NewSizeThreadIncrease, \ "Additional size added to desired new generation size per " \ @@ -3048,28 +3125,30 @@ "class pointers are used") \ \ product(uintx, MinHeapFreeRatio, 40, \ - "Min percentage of heap free after GC to avoid expansion") \ + "The minimum percentage of heap free after GC to avoid expansion")\ \ product(uintx, MaxHeapFreeRatio, 70, \ - "Max percentage of heap free after GC to avoid shrinking") \ + "The maximum percentage of heap free after GC to avoid shrinking")\ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ \ product(uintx, MinHeapDeltaBytes, ScaleForWordSize(128*K), \ - "Min change in heap space due to GC (in bytes)") \ + "The minimum change in heap space due to GC (in bytes)") \ \ product(uintx, MinMetaspaceExpansion, ScaleForWordSize(256*K), \ - "Min expansion of Metaspace (in bytes)") \ + "The minimum expansion of Metaspace (in bytes)") \ \ product(uintx, MinMetaspaceFreeRatio, 40, \ - "Min percentage of Metaspace free after GC to avoid expansion") \ + "The minimum percentage of Metaspace free after GC to avoid " \ + "expansion") \ \ product(uintx, MaxMetaspaceFreeRatio, 70, \ - "Max percentage of Metaspace free after GC to avoid shrinking") \ + "The maximum percentage of Metaspace free after GC to avoid " \ + "shrinking") \ \ product(uintx, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \ - "Max expansion of Metaspace without full GC (in bytes)") \ + "The maximum expansion of Metaspace without full GC (in bytes)") \ \ product(uintx, QueuedAllocationWarningCount, 0, \ "Number of times an allocation that queues behind a GC " \ @@ -3091,13 +3170,14 @@ "Desired percentage of survivor space used after scavenge") \ \ product(uintx, MarkSweepDeadRatio, 5, \ - "Percentage (0-100) of the old gen allowed as dead wood." \ - "Serial mark sweep treats this as both the min and max value." \ - "CMS uses this value only if it falls back to mark sweep." \ - "Par compact uses a variable scale based on the density of the" \ - "generation and treats this as the max value when the heap is" \ - "either completely full or completely empty. Par compact also" \ - "has a smaller default value; see arguments.cpp.") \ + "Percentage (0-100) of the old gen allowed as dead wood. " \ + "Serial mark sweep treats this as both the minimum and maximum " \ + "value. " \ + "CMS uses this value only if it falls back to mark sweep. " \ + "Par compact uses a variable scale based on the density of the " \ + "generation and treats this as the maximum value when the heap " \ + "is either completely full or completely empty. Par compact " \ + "also has a smaller default value; see arguments.cpp.") \ \ product(uintx, MarkSweepAlwaysCompactCount, 4, \ "How often should we fully compact the heap (ignoring the dead " \ @@ -3116,27 +3196,27 @@ "Census for CMS' FreeListSpace") \ \ develop(uintx, GCExpandToAllocateDelayMillis, 0, \ - "Delay in ms between expansion and allocation") \ + "Delay between expansion and allocation (in milliseconds)") \ \ develop(uintx, GCWorkerDelayMillis, 0, \ - "Delay in ms in scheduling GC workers") \ + "Delay in scheduling GC workers (in milliseconds)") \ \ product(intx, DeferThrSuspendLoopCount, 4000, \ "(Unstable) Number of times to iterate in safepoint loop " \ - " before blocking VM threads ") \ + "before blocking VM threads ") \ \ product(intx, DeferPollingPageLoopCount, -1, \ "(Unsafe,Unstable) Number of iterations in safepoint loop " \ "before changing safepoint polling page to RO ") \ \ - product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ + product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ \ product(bool, PSChunkLargeArrays, true, \ - "true: process large arrays in chunks") \ + "Process large arrays in chunks") \ \ product(uintx, GCDrainStackTargetSize, 64, \ - "how many entries we'll try to leave on the stack during " \ - "parallel GC") \ + "Number of entries we will try to leave on the stack " \ + "during parallel gc") \ \ /* stack parameters */ \ product_pd(intx, StackYellowPages, \ @@ -3146,8 +3226,8 @@ "Number of red zone (unrecoverable overflows) pages") \ \ product_pd(intx, StackShadowPages, \ - "Number of shadow zone (for overflow checking) pages" \ - " this should exceed the depth of the VM and native call stack") \ + "Number of shadow zone (for overflow checking) pages " \ + "this should exceed the depth of the VM and native call stack") \ \ product_pd(intx, ThreadStackSize, \ "Thread Stack Size (in Kbytes)") \ @@ -3187,60 +3267,51 @@ "Reserved code cache size (in bytes) - maximum code cache size") \ \ product(uintx, CodeCacheMinimumFreeSpace, 500*K, \ - "When less than X space left, we stop compiling.") \ + "When less than X space left, we stop compiling") \ \ product_pd(uintx, CodeCacheExpansionSize, \ "Code cache expansion size (in bytes)") \ \ develop_pd(uintx, CodeCacheMinBlockLength, \ - "Minimum number of segments in a code cache block.") \ + "Minimum number of segments in a code cache block") \ \ notproduct(bool, ExitOnFullCodeCache, false, \ - "Exit the VM if we fill the code cache.") \ + "Exit the VM if we fill the code cache") \ \ product(bool, UseCodeCacheFlushing, true, \ "Attempt to clean the code cache before shutting off compiler") \ \ - product(intx, MinCodeCacheFlushingInterval, 30, \ - "Min number of seconds between code cache cleaning sessions") \ - \ - product(uintx, CodeCacheFlushingMinimumFreeSpace, 1500*K, \ - "When less than X space left, start code cache cleaning") \ - \ - product(uintx, CodeCacheFlushingFraction, 2, \ - "Fraction of the code cache that is flushed when full") \ - \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ "switch") \ \ develop(intx, StopInterpreterAt, 0, \ - "Stops interpreter execution at specified bytecode number") \ + "Stop interpreter execution at specified bytecode number") \ \ develop(intx, TraceBytecodesAt, 0, \ - "Traces bytecodes starting with specified bytecode number") \ + "Trace bytecodes starting with specified bytecode number") \ \ /* compiler interface */ \ develop(intx, CIStart, 0, \ - "the id of the first compilation to permit") \ + "The id of the first compilation to permit") \ \ develop(intx, CIStop, -1, \ - "the id of the last compilation to permit") \ + "The id of the last compilation to permit") \ \ develop(intx, CIStartOSR, 0, \ - "the id of the first osr compilation to permit " \ + "The id of the first osr compilation to permit " \ "(CICountOSR must be on)") \ \ develop(intx, CIStopOSR, -1, \ - "the id of the last osr compilation to permit " \ + "The id of the last osr compilation to permit " \ "(CICountOSR must be on)") \ \ develop(intx, CIBreakAtOSR, -1, \ - "id of osr compilation to break at") \ + "The id of osr compilation to break at") \ \ develop(intx, CIBreakAt, -1, \ - "id of compilation to break at") \ + "The id of compilation to break at") \ \ product(ccstrlist, CompileOnly, "", \ "List of methods (pkg/class.name) to restrict compilation to") \ @@ -3259,11 +3330,11 @@ "[default: ./replay_pid%p.log] (%p replaced with pid)") \ \ develop(intx, ReplaySuppressInitializers, 2, \ - "Controls handling of class initialization during replay" \ - "0 - don't do anything special" \ - "1 - treat all class initializers as empty" \ - "2 - treat class initializers for application classes as empty" \ - "3 - allow all class initializers to run during bootstrap but" \ + "Control handling of class initialization during replay: " \ + "0 - don't do anything special; " \ + "1 - treat all class initializers as empty; " \ + "2 - treat class initializers for application classes as empty; " \ + "3 - allow all class initializers to run during bootstrap but " \ " pretend they are empty after starting replay") \ \ develop(bool, ReplayIgnoreInitErrors, false, \ @@ -3292,14 +3363,15 @@ "0 : Normal. "\ " VM chooses priorities that are appropriate for normal "\ " applications. On Solaris NORM_PRIORITY and above are mapped "\ - " to normal native priority. Java priorities below NORM_PRIORITY"\ - " map to lower native priority values. On Windows applications"\ - " are allowed to use higher native priorities. However, with "\ - " ThreadPriorityPolicy=0, VM will not use the highest possible"\ - " native priority, THREAD_PRIORITY_TIME_CRITICAL, as it may "\ - " interfere with system threads. On Linux thread priorities "\ - " are ignored because the OS does not support static priority "\ - " in SCHED_OTHER scheduling class which is the only choice for"\ + " to normal native priority. Java priorities below " \ + " NORM_PRIORITY map to lower native priority values. On "\ + " Windows applications are allowed to use higher native "\ + " priorities. However, with ThreadPriorityPolicy=0, VM will "\ + " not use the highest possible native priority, "\ + " THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with "\ + " system threads. On Linux thread priorities are ignored "\ + " because the OS does not support static priority in "\ + " SCHED_OTHER scheduling class which is the only choice for "\ " non-root, non-realtime applications. "\ "1 : Aggressive. "\ " Java thread priorities map over to the entire range of "\ @@ -3330,16 +3402,35 @@ product(bool, VMThreadHintNoPreempt, false, \ "(Solaris only) Give VM thread an extra quanta") \ \ - product(intx, JavaPriority1_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority2_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority3_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority4_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority5_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority6_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority7_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority8_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority9_To_OSPriority, -1, "Map Java priorities to OS priorities") \ - product(intx, JavaPriority10_To_OSPriority,-1, "Map Java priorities to OS priorities") \ + product(intx, JavaPriority1_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority2_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority3_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority4_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority5_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority6_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority7_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority8_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority9_To_OSPriority, -1, \ + "Map Java priorities to OS priorities") \ + \ + product(intx, JavaPriority10_To_OSPriority,-1, \ + "Map Java priorities to OS priorities") \ \ experimental(bool, UseCriticalJavaThreadPriority, false, \ "Java thread priority 10 maps to critical scheduling priority") \ @@ -3370,37 +3461,38 @@ "Used with +TraceLongCompiles") \ \ product(intx, StarvationMonitorInterval, 200, \ - "Pause between each check in ms") \ + "Pause between each check (in milliseconds)") \ \ /* recompilation */ \ product_pd(intx, CompileThreshold, \ "number of interpreted method invocations before (re-)compiling") \ \ product_pd(intx, BackEdgeThreshold, \ - "Interpreter Back edge threshold at which an OSR compilation is invoked")\ + "Interpreter Back edge threshold at which an OSR compilation is " \ + "invoked") \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ - "Interpreter (tier 0) invocation notification frequency.") \ + "Interpreter (tier 0) invocation notification frequency") \ \ product(intx, Tier2InvokeNotifyFreqLog, 11, \ - "C1 without MDO (tier 2) invocation notification frequency.") \ + "C1 without MDO (tier 2) invocation notification frequency") \ \ product(intx, Tier3InvokeNotifyFreqLog, 10, \ "C1 with MDO profiling (tier 3) invocation notification " \ - "frequency.") \ + "frequency") \ \ product(intx, Tier23InlineeNotifyFreqLog, 20, \ "Inlinee invocation (tiers 2 and 3) notification frequency") \ \ product(intx, Tier0BackedgeNotifyFreqLog, 10, \ - "Interpreter (tier 0) invocation notification frequency.") \ + "Interpreter (tier 0) invocation notification frequency") \ \ product(intx, Tier2BackedgeNotifyFreqLog, 14, \ - "C1 without MDO (tier 2) invocation notification frequency.") \ + "C1 without MDO (tier 2) invocation notification frequency") \ \ product(intx, Tier3BackedgeNotifyFreqLog, 13, \ "C1 with MDO profiling (tier 3) invocation notification " \ - "frequency.") \ + "frequency") \ \ product(intx, Tier2CompileThreshold, 0, \ "threshold at which tier 2 compilation is invoked") \ @@ -3417,7 +3509,7 @@ \ product(intx, Tier3CompileThreshold, 2000, \ "Threshold at which tier 3 compilation is invoked (invocation " \ - "minimum must be satisfied.") \ + "minimum must be satisfied") \ \ product(intx, Tier3BackEdgeThreshold, 60000, \ "Back edge threshold at which tier 3 OSR compilation is invoked") \ @@ -3431,7 +3523,7 @@ \ product(intx, Tier4CompileThreshold, 15000, \ "Threshold at which tier 4 compilation is invoked (invocation " \ - "minimum must be satisfied.") \ + "minimum must be satisfied") \ \ product(intx, Tier4BackEdgeThreshold, 40000, \ "Back edge threshold at which tier 4 OSR compilation is invoked") \ @@ -3460,12 +3552,12 @@ "Stop at given compilation level") \ \ product(intx, Tier0ProfilingStartPercentage, 200, \ - "Start profiling in interpreter if the counters exceed tier 3" \ + "Start profiling in interpreter if the counters exceed tier 3 " \ "thresholds by the specified percentage") \ \ product(uintx, IncreaseFirstTierCompileThresholdAt, 50, \ - "Increase the compile threshold for C1 compilation if the code" \ - "cache is filled by the specified percentage.") \ + "Increase the compile threshold for C1 compilation if the code " \ + "cache is filled by the specified percentage") \ \ product(intx, TieredRateUpdateMinTime, 1, \ "Minimum rate sampling interval (in milliseconds)") \ @@ -3480,24 +3572,26 @@ "Print tiered events notifications") \ \ product_pd(intx, OnStackReplacePercentage, \ - "NON_TIERED number of method invocations/branches (expressed as %"\ - "of CompileThreshold) before (re-)compiling OSR code") \ + "NON_TIERED number of method invocations/branches (expressed as " \ + "% of CompileThreshold) before (re-)compiling OSR code") \ \ product(intx, InterpreterProfilePercentage, 33, \ - "NON_TIERED number of method invocations/branches (expressed as %"\ - "of CompileThreshold) before profiling in the interpreter") \ + "NON_TIERED number of method invocations/branches (expressed as " \ + "% of CompileThreshold) before profiling in the interpreter") \ \ develop(intx, MaxRecompilationSearchLength, 10, \ - "max. # frames to inspect searching for recompilee") \ + "The maximum number of frames to inspect when searching for " \ + "recompilee") \ \ develop(intx, MaxInterpretedSearchLength, 3, \ - "max. # interp. frames to skip when searching for recompilee") \ + "The maximum number of interpreted frames to skip when searching "\ + "for recompilee") \ \ develop(intx, DesiredMethodLimit, 8000, \ - "desired max. method size (in bytecodes) after inlining") \ + "The desired maximum method size (in bytecodes) after inlining") \ \ develop(intx, HugeMethodLimit, 8000, \ - "don't compile methods larger than this if " \ + "Don't compile methods larger than this if " \ "+DontCompileHugeMethods") \ \ /* New JDK 1.4 reflection implementation */ \ @@ -3519,7 +3613,7 @@ "in InvocationTargetException. See 6531596") \ \ develop(bool, VerifyLambdaBytecodes, false, \ - "Force verification of jdk 8 lambda metafactory bytecodes.") \ + "Force verification of jdk 8 lambda metafactory bytecodes") \ \ develop(intx, FastSuperclassLimit, 8, \ "Depth of hardwired instanceof accelerator array") \ @@ -3543,18 +3637,19 @@ /* flags for performance data collection */ \ \ product(bool, UsePerfData, falseInEmbedded, \ - "Flag to disable jvmstat instrumentation for performance testing" \ - "and problem isolation purposes.") \ + "Flag to disable jvmstat instrumentation for performance testing "\ + "and problem isolation purposes") \ \ product(bool, PerfDataSaveToFile, false, \ "Save PerfData memory to hsperfdata_ file on exit") \ \ product(ccstr, PerfDataSaveFile, NULL, \ - "Save PerfData memory to the specified absolute pathname," \ - "%p in the file name if present will be replaced by pid") \ - \ - product(intx, PerfDataSamplingInterval, 50 /*ms*/, \ - "Data sampling interval in milliseconds") \ + "Save PerfData memory to the specified absolute pathname. " \ + "The string %p in the file name (if present) " \ + "will be replaced by pid") \ + \ + product(intx, PerfDataSamplingInterval, 50, \ + "Data sampling interval (in milliseconds)") \ \ develop(bool, PerfTraceDataCreation, false, \ "Trace creation of Performance Data Entries") \ @@ -3579,7 +3674,7 @@ "Bypass Win32 file system criteria checks (Windows Only)") \ \ product(intx, UnguardOnExecutionViolation, 0, \ - "Unguard page and retry on no-execute fault (Win32 only)" \ + "Unguard page and retry on no-execute fault (Win32 only) " \ "0=off, 1=conservative, 2=aggressive") \ \ /* Serviceability Support */ \ @@ -3588,7 +3683,7 @@ "Create JMX Management Server") \ \ product(bool, DisableAttachMechanism, false, \ - "Disable mechanism that allows tools to attach to this VM") \ + "Disable mechanism that allows tools to attach to this VM") \ \ product(bool, StartAttachListener, false, \ "Always start Attach Listener at VM startup") \ @@ -3611,9 +3706,9 @@ "Require shared spaces for metadata") \ \ product(bool, DumpSharedSpaces, false, \ - "Special mode: JVM reads a class list, loads classes, builds " \ - "shared spaces, and dumps the shared spaces to a file to be " \ - "used in future JVM runs.") \ + "Special mode: JVM reads a class list, loads classes, builds " \ + "shared spaces, and dumps the shared spaces to a file to be " \ + "used in future JVM runs") \ \ product(bool, PrintSharedSpaces, false, \ "Print usage of shared spaces") \ @@ -3686,11 +3781,14 @@ "Relax the access control checks in the verifier") \ \ diagnostic(bool, PrintDTraceDOF, false, \ - "Print the DTrace DOF passed to the system for JSDT probes") \ + "Print the DTrace DOF passed to the system for JSDT probes") \ \ product(uintx, StringTableSize, defaultStringTableSize, \ "Number of buckets in the interned String table") \ \ + experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \ + "Number of buckets in the JVM internal Symbol table") \ + \ develop(bool, TraceDefaultMethods, false, \ "Trace the default method processing steps") \ \ @@ -3699,8 +3797,8 @@ \ product(bool, UseVMInterruptibleIO, false, \ "(Unstable, Solaris-specific) Thread interrupt before or with " \ - "EINTR for I/O operations results in OS_INTRPT. The default value"\ - " of this flag is true for JDK 6 and earlier") \ + "EINTR for I/O operations results in OS_INTRPT. The default " \ + "value of this flag is true for JDK 6 and earlier") \ \ diagnostic(bool, WhiteBoxAPI, false, \ "Enable internal testing APIs") \ @@ -3721,6 +3819,7 @@ \ product(bool, EnableTracing, false, \ "Enable event-based tracing") \ + \ product(bool, UseLockedTracing, false, \ "Use locked-tracing when doing event-based tracing") @@ -3730,20 +3829,20 @@ */ // Interface macros -#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PD_PRODUCT_FLAG(type, name, doc) extern "C" type name; -#define DECLARE_DIAGNOSTIC_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PD_PRODUCT_FLAG(type, name, doc) extern "C" type name; +#define DECLARE_DIAGNOSTIC_FLAG(type, name, value, doc) extern "C" type name; #define DECLARE_EXPERIMENTAL_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_MANAGEABLE_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PRODUCT_RW_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_MANAGEABLE_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PRODUCT_RW_FLAG(type, name, value, doc) extern "C" type name; #ifdef PRODUCT -#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) const type name = value; -#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) const type name = pd_##name; -#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) +#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type CONST_##name; const type name = value; +#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type CONST_##name; const type name = pd_##name; +#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type CONST_##name; #else -#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name; -#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name; +#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type name; #endif // Special LP64 flags, product only needed for now. #ifdef _LP64 @@ -3753,23 +3852,23 @@ #endif // _LP64 // Implementation macros -#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name; -#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name; +#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value; #define MATERIALIZE_EXPERIMENTAL_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value; #ifdef PRODUCT -#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) /* flag name is constant */ -#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) /* flag name is constant */ -#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) +#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type CONST_##name = value; +#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type CONST_##name = pd_##name; +#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type CONST_##name = value; #else -#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name; -#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name; +#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value; #endif #ifdef _LP64 -#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value; #else #define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) /* flag is constant */ #endif // _LP64 diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/globals_extension.hpp --- a/src/share/vm/runtime/globals_extension.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/globals_extension.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -34,64 +34,42 @@ // Parens left off in the following for the enum decl below. #define FLAG_MEMBER(flag) Flag_##flag -#define RUNTIME_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define RUNTIME_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_MANAGEABLE_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_PRODUCT_RW_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) +#define RUNTIME_MANAGEABLE_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PRODUCT_RW_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #else - #define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#else -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER, RUNTIME_LP64_PRODUCT_FLAG_MEMBER) @@ -114,64 +92,42 @@ #define FLAG_MEMBER_WITH_TYPE(flag,type) Flag_##flag##_##type -#define RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) +#define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #else - #define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#else -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define ARCH_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define ARCH_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE, @@ -233,19 +189,19 @@ #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) -#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), COMMAND_LINE)) -#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), ERGONOMIC)) +#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::COMMAND_LINE)) +#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::ERGONOMIC)) // Can't put the following in CommandLineFlags because // of a circular dependency on the enum definition. class CommandLineFlagsEx : CommandLineFlags { public: - static void boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin); - static void intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin); - static void uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin); - static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin); - static void doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin); - static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin); + static void boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin); + static void intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); + static void uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); + static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); + static void doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); + static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); static bool is_default(CommandLineFlag flag); static bool is_ergo(CommandLineFlag flag); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/javaCalls.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,7 @@ for(int i = 0; i < _size; i++) { if (_is_oop[i]) { // Handle conversion - _value[i] = (intptr_t)Handle::raw_resolve((oop *)_value[i]); + _value[i] = cast_from_oop(Handle::raw_resolve((oop *)_value[i])); } } // Return argument vector diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/reflectionUtils.cpp --- a/src/share/vm/runtime/reflectionUtils.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/reflectionUtils.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,11 @@ #include "memory/universe.inline.hpp" #include "runtime/reflectionUtils.hpp" -KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only) { - _klass = klass; +KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, + bool classes_only, bool walk_defaults) { + _klass = _base_klass = klass; + _base_class_search_defaults = false; + _defaults_checked = false; if (classes_only) { _interfaces = Universe::the_empty_klass_array(); } else { @@ -37,6 +40,7 @@ _interface_index = _interfaces->length(); _local_only = local_only; _classes_only = classes_only; + _walk_defaults = walk_defaults; } bool KlassStream::eos() { @@ -45,7 +49,13 @@ if (!_klass->is_interface() && _klass->super() != NULL) { // go up superclass chain (not for interfaces) _klass = _klass->super(); + // Next for method walks, walk default methods + } else if (_walk_defaults && (_defaults_checked == false) && (_base_klass->default_methods() != NULL)) { + _base_class_search_defaults = true; + _klass = _base_klass; + _defaults_checked = true; } else { + // Next walk transitive interfaces if (_interface_index > 0) { _klass = _interfaces->at(--_interface_index); } else { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/reflectionUtils.hpp --- a/src/share/vm/runtime/reflectionUtils.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/reflectionUtils.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -38,7 +38,7 @@ // and (super)interfaces. Streaming is done in reverse order (subclasses first, // interfaces last). // -// for (KlassStream st(k, false, false); !st.eos(); st.next()) { +// for (KlassStream st(k, false, false, false); !st.eos(); st.next()) { // Klass* k = st.klass(); // ... // } @@ -46,17 +46,21 @@ class KlassStream VALUE_OBJ_CLASS_SPEC { protected: instanceKlassHandle _klass; // current klass/interface iterated over - Array* _interfaces; // transitive interfaces for initial class + instanceKlassHandle _base_klass; // initial klass/interface to iterate over + Array* _interfaces; // transitive interfaces for initial class int _interface_index; // current interface being processed bool _local_only; // process initial class/interface only bool _classes_only; // process classes only (no interfaces) + bool _walk_defaults; // process default methods + bool _base_class_search_defaults; // time to process default methods + bool _defaults_checked; // already checked for default methods int _index; - virtual int length() const = 0; + virtual int length() = 0; public: // constructor - KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only); + KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only, bool walk_defaults); // testing bool eos(); @@ -67,6 +71,8 @@ // accessors instanceKlassHandle klass() const { return _klass; } int index() const { return _index; } + bool base_class_search_defaults() const { return _base_class_search_defaults; } + void base_class_search_defaults(bool b) { _base_class_search_defaults = b; } }; @@ -81,17 +87,24 @@ class MethodStream : public KlassStream { private: - int length() const { return methods()->length(); } - Array* methods() const { return _klass->methods(); } + int length() { return methods()->length(); } + Array* methods() { + if (base_class_search_defaults()) { + base_class_search_defaults(false); + return _klass->default_methods(); + } else { + return _klass->methods(); + } + } public: MethodStream(instanceKlassHandle klass, bool local_only, bool classes_only) - : KlassStream(klass, local_only, classes_only) { + : KlassStream(klass, local_only, classes_only, true) { _index = length(); next(); } void next() { _index--; } - Method* method() const { return methods()->at(index()); } + Method* method() { return methods()->at(index()); } }; @@ -107,13 +120,13 @@ class FieldStream : public KlassStream { private: - int length() const { return _klass->java_fields_count(); } + int length() { return _klass->java_fields_count(); } fieldDescriptor _fd_buf; public: FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only) - : KlassStream(klass, local_only, classes_only) { + : KlassStream(klass, local_only, classes_only, false) { _index = length(); next(); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/safepoint.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -519,8 +519,8 @@ } { - TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime); - NMethodSweeper::scan_stacks(); + TraceTime t4("mark nmethods", TraceSafepointCleanupTime); + NMethodSweeper::mark_active_nmethods(); } if (SymbolTable::needs_rehashing()) { @@ -745,14 +745,14 @@ #endif static void print_ptrs(intptr_t oldptr, intptr_t newptr, bool wasoop) { - bool is_oop = newptr ? ((oop)newptr)->is_oop() : false; + bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; tty->print_cr(PTR_FORMAT PTR_PAD " %s %c " PTR_FORMAT PTR_PAD " %s %s", oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); } static void print_longs(jlong oldptr, jlong newptr, bool wasoop) { - bool is_oop = newptr ? ((oop)(intptr_t)newptr)->is_oop() : false; + bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; tty->print_cr(PTR64_FORMAT " %s %c " PTR64_FORMAT " %s %s", oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -577,7 +577,7 @@ assert(caller.is_interpreted_frame(), ""); int args_size = ArgumentSizeComputer(sig).size() + 1; assert(args_size <= caller.interpreter_frame_expression_stack_size(), "receiver must be on interpreter stack"); - oop result = (oop) *caller.interpreter_frame_tos_at(args_size - 1); + oop result = cast_to_oop(*caller.interpreter_frame_tos_at(args_size - 1)); assert(Universe::heap()->is_in(result) && result->is_oop(), "receiver must be an oop"); return result; } @@ -2875,7 +2875,7 @@ ObjectSynchronizer::inflate_helper(kptr2->obj()); // Now the displaced header is free to move buf[i++] = (intptr_t)lock->displaced_header(); - buf[i++] = (intptr_t)kptr2->obj(); + buf[i++] = cast_from_oop(kptr2->obj()); } } assert( i - max_locals == active_monitor_count*2, "found the expected number of monitors" ); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/sweeper.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -127,64 +127,79 @@ #define SWEEP(nm) #endif +nmethod* NMethodSweeper::_current = NULL; // Current nmethod +long NMethodSweeper::_traversals = 0; // Nof. stack traversals performed +int NMethodSweeper::_seen = 0; // Nof. nmethods we have currently processed in current pass of CodeCache +int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep +int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep +int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep -long NMethodSweeper::_traversals = 0; // No. of stack traversals performed -nmethod* NMethodSweeper::_current = NULL; // Current nmethod -int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache -int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep -int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep -int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep - -volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +volatile int NMethodSweeper::_invocations = 0; // Nof. invocations left until we are completed with this pass volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. -jint NMethodSweeper::_locked_seen = 0; +jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; -bool NMethodSweeper::_resweep = false; -jint NMethodSweeper::_flush_token = 0; -jlong NMethodSweeper::_last_full_flush_time = 0; -int NMethodSweeper::_highest_marked = 0; -int NMethodSweeper::_dead_compile_ids = 0; -long NMethodSweeper::_last_flush_traversal_id = 0; +bool NMethodSweeper::_request_mark_phase = false; -int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache int NMethodSweeper::_total_nof_methods_reclaimed = 0; -jlong NMethodSweeper::_total_time_sweeping = 0; -jlong NMethodSweeper::_total_time_this_sweep = 0; -jlong NMethodSweeper::_peak_sweep_time = 0; -jlong NMethodSweeper::_peak_sweep_fraction_time = 0; -jlong NMethodSweeper::_total_disconnect_time = 0; -jlong NMethodSweeper::_peak_disconnect_time = 0; +jlong NMethodSweeper::_total_time_sweeping = 0; +jlong NMethodSweeper::_total_time_this_sweep = 0; +jlong NMethodSweeper::_peak_sweep_time = 0; +jlong NMethodSweeper::_peak_sweep_fraction_time = 0; +int NMethodSweeper::_hotness_counter_reset_val = 0; + class MarkActivationClosure: public CodeBlobClosure { public: virtual void do_code_blob(CodeBlob* cb) { - // If we see an activation belonging to a non_entrant nmethod, we mark it. - if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { - ((nmethod*)cb)->mark_as_seen_on_stack(); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*)cb; + nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val()); + // If we see an activation belonging to a non_entrant nmethod, we mark it. + if (nm->is_not_entrant()) { + nm->mark_as_seen_on_stack(); + } } } }; static MarkActivationClosure mark_activation_closure; +class SetHotnessClosure: public CodeBlobClosure { +public: + virtual void do_code_blob(CodeBlob* cb) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*)cb; + nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val()); + } + } +}; +static SetHotnessClosure set_hotness_closure; + + +int NMethodSweeper::hotness_counter_reset_val() { + if (_hotness_counter_reset_val == 0) { + _hotness_counter_reset_val = (ReservedCodeCacheSize < M) ? 1 : (ReservedCodeCacheSize / M) * 2; + } + return _hotness_counter_reset_val; +} bool NMethodSweeper::sweep_in_progress() { return (_current != NULL); } -void NMethodSweeper::scan_stacks() { +// Scans the stacks of all Java threads and marks activations of not-entrant methods. +// No need to synchronize access, since 'mark_active_nmethods' is always executed at a +// safepoint. +void NMethodSweeper::mark_active_nmethods() { assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); - if (!MethodFlushing) return; - - // No need to synchronize access, since this is always executed at a - // safepoint. - - // Make sure CompiledIC_lock in unlocked, since we might update some - // inline caches. If it is, we just bail-out and try later. - if (CompiledIC_lock->is_locked() || Patching_lock->is_locked()) return; + // If we do not want to reclaim not-entrant or zombie methods there is no need + // to scan stacks + if (!MethodFlushing) { + return; + } // Check for restart assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid"); - if (!sweep_in_progress() && _resweep) { + if (!sweep_in_progress() && need_marking_phase()) { _seen = 0; _invocations = NmethodSweepFraction; _current = CodeCache::first_nmethod(); @@ -197,30 +212,22 @@ Threads::nmethods_do(&mark_activation_closure); // reset the flags since we started a scan from the beginning. - _resweep = false; + reset_nmethod_marking(); _locked_seen = 0; _not_entrant_seen_on_stack = 0; + } else { + // Only set hotness counter + Threads::nmethods_do(&set_hotness_closure); } - if (UseCodeCacheFlushing) { - // only allow new flushes after the interval is complete. - jlong now = os::javaTimeMillis(); - jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; - jlong curr_interval = now - _last_full_flush_time; - if (curr_interval > max_interval) { - _flush_token = 0; - } - - if (!CodeCache::needs_flushing() && !CompileBroker::should_compile_new_jobs()) { - CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); - log_sweep("restart_compiler"); - } - } + OrderAccess::storestore(); } void NMethodSweeper::possibly_sweep() { assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); - if (!MethodFlushing || !sweep_in_progress()) return; + if (!MethodFlushing || !sweep_in_progress()) { + return; + } if (_invocations > 0) { // Only one thread at a time will sweep @@ -258,8 +265,7 @@ if (!CompileBroker::should_compile_new_jobs()) { // If we have turned off compilations we might as well do full sweeps // in order to reach the clean state faster. Otherwise the sleeping compiler - // threads will slow down sweeping. After a few iterations the cache - // will be clean and sweeping stops (_resweep will not be set) + // threads will slow down sweeping. _invocations = 1; } @@ -271,9 +277,11 @@ int todo = (CodeCache::nof_nmethods() - _seen) / _invocations; int swept_count = 0; + assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); assert(!CodeCache_lock->owned_by_self(), "just checking"); + int freed_memory = 0; { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -299,7 +307,7 @@ // Now ready to process nmethod and give up CodeCache_lock { MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - process_nmethod(_current); + freed_memory += process_nmethod(_current); } _seen++; _current = next; @@ -308,11 +316,11 @@ assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); - if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) { + if (!sweep_in_progress() && !need_marking_phase() && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were // nmethods we were unable to process either because they were - // locked or were still on stack. We don't have to aggresively - // clean them up so just stop scanning. We could scan once more + // locked or were still on stack. We don't have to aggressively + // clean them up so just stop scanning. We could scan once more // but that complicates the control logic and it's unlikely to // matter much. if (PrintMethodFlushing) { @@ -351,9 +359,16 @@ log_sweep("finished"); } - // Sweeper is the only case where memory is released, - // check here if it is time to restart the compiler. - if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs() && !CodeCache::needs_flushing()) { + // Sweeper is the only case where memory is released, check here if it + // is time to restart the compiler. Only checking if there is a certain + // amount of free memory in the code cache might lead to re-enabling + // compilation although no memory has been released. For example, there are + // cases when compilation was disabled although there is 4MB (or more) free + // memory in the code cache. The reason is code cache fragmentation. Therefore, + // it only makes sense to re-enable compilation if we have actually freed memory. + // Note that typically several kB are released for sweeping 16MB of the code + // cache. As a result, 'freed_memory' > 0 to restart the compiler. + if (UseCodeCacheFlushing && (!CompileBroker::should_compile_new_jobs() && (freed_memory > 0))) { CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); log_sweep("restart_compiler"); } @@ -367,8 +382,8 @@ _thread = CompilerThread::current(); if (!nm->is_zombie() && !nm->is_unloaded()) { // Only expose live nmethods for scanning - _thread->set_scanned_nmethod(nm); - } + _thread->set_scanned_nmethod(nm); + } } ~NMethodMarker() { _thread->set_scanned_nmethod(NULL); @@ -392,20 +407,20 @@ nm->flush(); } -void NMethodSweeper::process_nmethod(nmethod *nm) { +int NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); + int freed_memory = 0; // Make sure this nmethod doesn't get unloaded during the scan, - // since the locks acquired below might safepoint. + // since safepoints may happen during acquired below locks. NMethodMarker nmm(nm); - SWEEP(nm); // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods if (nm->is_alive()) { - // Clean-up all inline caches that points to zombie/non-reentrant methods + // Clean inline caches that point to zombie/non-entrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); @@ -413,18 +428,19 @@ _locked_seen++; SWEEP(nm); } - return; + return freed_memory; } if (nm->is_zombie()) { - // If it is first time, we see nmethod then we mark it. Otherwise, - // we reclame it. When we have seen a zombie method twice, we know that + // If it is the first time we see nmethod then we mark it. Otherwise, + // we reclaim it. When we have seen a zombie method twice, we know that // there are no inline caches that refer to it. if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); } + freed_memory = nm->total_size(); release_nmethod(nm); _flushed_count++; } else { @@ -432,19 +448,19 @@ tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); } nm->mark_for_reclamation(); - _resweep = true; + request_nmethod_marking(); _marked_count++; SWEEP(nm); } } else if (nm->is_not_entrant()) { - // If there is no current activations of this method on the + // If there are no current activations of this method on the // stack we can safely convert it to a zombie method if (nm->can_not_entrant_be_converted()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } nm->make_zombie(); - _resweep = true; + request_nmethod_marking(); _zombified_count++; SWEEP(nm); } else { @@ -459,159 +475,57 @@ } } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie - if (PrintMethodFlushing && Verbose) + if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); - + } if (nm->is_osr_method()) { SWEEP(nm); // No inline caches will ever point to osr methods, so we can just remove it + freed_memory = nm->total_size(); release_nmethod(nm); _flushed_count++; } else { nm->make_zombie(); - _resweep = true; + request_nmethod_marking(); _zombified_count++; SWEEP(nm); } } else { - assert(nm->is_alive(), "should be alive"); - if (UseCodeCacheFlushing) { - if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() && - (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) { - // This method has not been called since the forced cleanup happened - nm->make_not_entrant(); + if (!nm->is_locked_by_vm() && !nm->is_osr_method() && !nm->is_native_method()) { + // Do not make native methods and OSR-methods not-entrant + nm->dec_hotness_counter(); + // Get the initial value of the hotness counter. This value depends on the + // ReservedCodeCacheSize + int reset_val = hotness_counter_reset_val(); + int time_since_reset = reset_val - nm->hotness_counter(); + double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity); + // The less free space in the code cache we have - the bigger reverse_free_ratio() is. + // I.e., 'threshold' increases with lower available space in the code cache and a higher + // NmethodSweepActivity. If the current hotness counter - which decreases from its initial + // value until it is reset by stack walking - is smaller than the computed threshold, the + // corresponding nmethod is considered for removal. + if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > 10)) { + // A method is marked as not-entrant if the method is + // 1) 'old enough': nm->hotness_counter() < threshold + // 2) The method was in_use for a minimum amount of time: (time_since_reset > 10) + // The second condition is necessary if we are dealing with very small code cache + // sizes (e.g., <10m) and the code cache size is too small to hold all hot methods. + // The second condition ensures that methods are not immediately made not-entrant + // after compilation. + nm->make_not_entrant(); + request_nmethod_marking(); + } } } - - // Clean-up all inline caches that points to zombie/non-reentrant methods + // Clean-up all inline caches that point to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } -} - -// Code cache unloading: when compilers notice the code cache is getting full, -// they will call a vm op that comes here. This code attempts to speculatively -// unload the oldest half of the nmethods (based on the compile job id) by -// saving the old code in a list in the CodeCache. Then -// execution resumes. If a method so marked is not called by the second sweeper -// stack traversal after the current one, the nmethod will be marked non-entrant and -// got rid of by normal sweeping. If the method is called, the Method*'s -// _code field is restored and the Method*/nmethod -// go back to their normal state. -void NMethodSweeper::handle_full_code_cache(bool is_full) { - - if (is_full) { - // Since code cache is full, immediately stop new compiles - if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { - log_sweep("disable_compiler"); - } - } - - // Make sure only one thread can flush - // The token is reset after CodeCacheMinimumFlushInterval in scan stacks, - // no need to check the timeout here. - jint old = Atomic::cmpxchg( 1, &_flush_token, 0 ); - if (old != 0) { - return; - } - - VM_HandleFullCodeCache op(is_full); - VMThread::execute(&op); - - // resweep again as soon as possible - _resweep = true; + return freed_memory; } -void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { - // If there was a race in detecting full code cache, only run - // one vm op for it or keep the compiler shut off - - jlong disconnect_start_counter = os::elapsed_counter(); - - // Traverse the code cache trying to dump the oldest nmethods - int curr_max_comp_id = CompileBroker::get_compilation_id(); - int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; - - log_sweep("start_cleaning"); - - nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); - jint disconnected = 0; - jint made_not_entrant = 0; - jint nmethod_count = 0; - - while ((nm != NULL)){ - int curr_comp_id = nm->compile_id(); - - // OSR methods cannot be flushed like this. Also, don't flush native methods - // since they are part of the JDK in most cases - if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) { - - // only count methods that can be speculatively disconnected - nmethod_count++; - - if (nm->is_in_use() && (curr_comp_id < flush_target)) { - if ((nm->method()->code() == nm)) { - // This method has not been previously considered for - // unloading or it was restored already - CodeCache::speculatively_disconnect(nm); - disconnected++; - } else if (nm->is_speculatively_disconnected()) { - // This method was previously considered for preemptive unloading and was not called since then - CompilationPolicy::policy()->delay_compilation(nm->method()); - nm->make_not_entrant(); - made_not_entrant++; - } - - if (curr_comp_id > _highest_marked) { - _highest_marked = curr_comp_id; - } - } - } - nm = CodeCache::alive_nmethod(CodeCache::next(nm)); - } - - // remember how many compile_ids wheren't seen last flush. - _dead_compile_ids = curr_max_comp_id - nmethod_count; - - log_sweep("stop_cleaning", - "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", - disconnected, made_not_entrant); - - // Shut off compiler. Sweeper will start over with a new stack scan and - // traversal cycle and turn it back on if it clears enough space. - if (is_full) { - _last_full_flush_time = os::javaTimeMillis(); - } - - jlong disconnect_end_counter = os::elapsed_counter(); - jlong disconnect_time = disconnect_end_counter - disconnect_start_counter; - _total_disconnect_time += disconnect_time; - _peak_disconnect_time = MAX2(disconnect_time, _peak_disconnect_time); - - EventCleanCodeCache event(UNTIMED); - if (event.should_commit()) { - event.set_starttime(disconnect_start_counter); - event.set_endtime(disconnect_end_counter); - event.set_disconnectedCount(disconnected); - event.set_madeNonEntrantCount(made_not_entrant); - event.commit(); - } - _number_of_flushes++; - - // After two more traversals the sweeper will get rid of unrestored nmethods - _last_flush_traversal_id = _traversals; - _resweep = true; -#ifdef ASSERT - - if(PrintMethodFlushing && Verbose) { - tty->print_cr("### sweeper: unload time: " INT64_FORMAT, (jlong)disconnect_time); - } -#endif -} - - // Print out some state information about the current sweep and the // state of the code cache if it's requested. void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/sweeper.hpp --- a/src/share/vm/runtime/sweeper.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/sweeper.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -27,8 +27,30 @@ // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches -// - reclamation of unreferences zombie nmethods -// +// - reclamation of nmethods +// Removing nmethods from the code cache includes two operations +// 1) mark active nmethods +// Is done in 'mark_active_nmethods()'. This function is called at a +// safepoint and marks all nmethods that are active on a thread's stack. +// 2) sweep nmethods +// Is done in sweep_code_cache(). This function is the only place in the +// sweeper where memory is reclaimed. Note that sweep_code_cache() is not +// called at a safepoint. However, sweep_code_cache() stops executing if +// another thread requests a safepoint. Consequently, 'mark_active_nmethods()' +// and sweep_code_cache() cannot execute at the same time. +// To reclaim memory, nmethods are first marked as 'not-entrant'. Methods can +// be made not-entrant by (i) the sweeper, (ii) deoptimization, (iii) dependency +// invalidation, and (iv) being replaced be a different method version (tiered +// compilation). Not-entrant nmethod cannot be called by Java threads, but they +// can still be active on the stack. To ensure that active nmethod are not reclaimed, +// we have to wait until the next marking phase has completed. If a not-entrant +// nmethod was NOT marked as active, it can be converted to 'zombie' state. To safely +// remove the nmethod, all inline caches (IC) that point to the the nmethod must be +// cleared. After that, the nmethod can be evicted from the code cache. Each nmethod's +// state change happens during separate sweeps. It may take at least 3 sweeps before an +// nmethod's space is freed. Sweeping is currently done by compiler threads between +// compilations or at least each 5 sec (NmethodSweepCheckInterval) when the code cache +// is full. class NMethodSweeper : public AllStatic { static long _traversals; // Stack scan count, also sweep ID. @@ -41,46 +63,38 @@ static volatile int _invocations; // No. of invocations left until we are completed with this pass static volatile int _sweep_started; // Flag to control conc sweeper - //The following are reset in scan_stacks and synchronized by the safepoint - static bool _resweep; // Indicates that a change has happend and we want another sweep, - // always checked and reset at a safepoint so memory will be in sync. - static int _locked_seen; // Number of locked nmethods encountered during the scan + //The following are reset in mark_active_nmethods and synchronized by the safepoint + static bool _request_mark_phase; // Indicates that a change has happend and we need another mark pahse, + // always checked and reset at a safepoint so memory will be in sync. + static int _locked_seen; // Number of locked nmethods encountered during the scan static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack - static jint _flush_token; // token that guards method flushing, making sure it is executed only once. - - // These are set during a flush, a VM-operation - static long _last_flush_traversal_id; // trav number at last flush unloading - static jlong _last_full_flush_time; // timestamp of last emergency unloading - - // These are synchronized by the _sweep_started token - static int _highest_marked; // highest compile id dumped at last emergency unloading - static int _dead_compile_ids; // number of compile ids that where not in the cache last flush // Stat counters - static int _number_of_flushes; // Total of full traversals caused by full cache static int _total_nof_methods_reclaimed; // Accumulated nof methods flushed static jlong _total_time_sweeping; // Accumulated time sweeping static jlong _total_time_this_sweep; // Total time this sweep static jlong _peak_sweep_time; // Peak time for a full sweep static jlong _peak_sweep_fraction_time; // Peak time sweeping one fraction - static jlong _total_disconnect_time; // Total time cleaning code mem - static jlong _peak_disconnect_time; // Peak time cleaning code mem - static void process_nmethod(nmethod *nm); + static int process_nmethod(nmethod *nm); static void release_nmethod(nmethod* nm); - static void log_sweep(const char* msg, const char* format = NULL, ...); static bool sweep_in_progress(); + static void sweep_code_cache(); + static void request_nmethod_marking() { _request_mark_phase = true; } + static void reset_nmethod_marking() { _request_mark_phase = false; } + static bool need_marking_phase() { return _request_mark_phase; } + + static int _hotness_counter_reset_val; public: static long traversal_count() { return _traversals; } - static int number_of_flushes() { return _number_of_flushes; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } static jlong total_time_sweeping() { return _total_time_sweeping; } static jlong peak_sweep_time() { return _peak_sweep_time; } static jlong peak_sweep_fraction_time() { return _peak_sweep_fraction_time; } - static jlong total_disconnect_time() { return _total_disconnect_time; } - static jlong peak_disconnect_time() { return _peak_disconnect_time; } + static void log_sweep(const char* msg, const char* format = NULL, ...); + #ifdef ASSERT static bool is_sweeping(nmethod* which) { return _current == which; } @@ -90,19 +104,18 @@ static void report_events(); #endif - static void scan_stacks(); // Invoked at the end of each safepoint - static void sweep_code_cache(); // Concurrent part of sweep job - static void possibly_sweep(); // Compiler threads call this to sweep + static void mark_active_nmethods(); // Invoked at the end of each safepoint + static void possibly_sweep(); // Compiler threads call this to sweep - static void notify(nmethod* nm) { + static int sort_nmethods_by_hotness(nmethod** nm1, nmethod** nm2); + static int hotness_counter_reset_val(); + + static void notify() { // Request a new sweep of the code cache from the beginning. No // need to synchronize the setting of this flag since it only // changes to false at safepoint so we can never overwrite it with false. - _resweep = true; + request_nmethod_marking(); } - - static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate - static void speculative_disconnect_nmethods(bool was_full); // Called by vm op to deal with alloc failure }; #endif // SHARE_VM_RUNTIME_SWEEPER_HPP diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/synchronizer.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -154,7 +154,7 @@ static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache static volatile int MonitorFreeCount = 0 ; // # on gFreeList static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation -#define CHAINMARKER ((oop)-1) +#define CHAINMARKER (cast_to_oop(-1)) // ----------------------------------------------------------------------------- // Fast Monitor Enter/Exit @@ -510,7 +510,7 @@ // then for each thread on the list, set the flag and unpark() the thread. // This is conceptually similar to muxAcquire-muxRelease, except that muxRelease // wakes at most one thread whereas we need to wake the entire list. - int ix = (intptr_t(obj) >> 5) & (NINFLATIONLOCKS-1) ; + int ix = (cast_from_oop(obj) >> 5) & (NINFLATIONLOCKS-1) ; int YieldThenBlock = 0 ; assert (ix >= 0 && ix < NINFLATIONLOCKS, "invariant") ; assert ((NINFLATIONLOCKS & (NINFLATIONLOCKS-1)) == 0, "invariant") ; @@ -565,7 +565,7 @@ // This variation has the property of being stable (idempotent) // between STW operations. This can be useful in some of the 1-0 // synchronization schemes. - intptr_t addrBits = intptr_t(obj) >> 3 ; + intptr_t addrBits = cast_from_oop(obj) >> 3 ; value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ; } else if (hashCode == 2) { @@ -575,7 +575,7 @@ value = ++GVars.hcSequence ; } else if (hashCode == 4) { - value = intptr_t(obj) ; + value = cast_from_oop(obj) ; } else { // Marsaglia's xor-shift scheme with thread-specific state // This is probably the best overall implementation -- we'll @@ -1321,7 +1321,7 @@ if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (intptr_t) object, (intptr_t) object->mark(), + (void *) object, (intptr_t) object->mark(), object->klass()->external_name()); } } @@ -1371,7 +1371,7 @@ if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (intptr_t) object, (intptr_t) object->mark(), + (void *) object, (intptr_t) object->mark(), object->klass()->external_name()); } } @@ -1439,7 +1439,7 @@ if (obj->is_instance()) { ResourceMark rm; tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (intptr_t) obj, (intptr_t) obj->mark(), obj->klass()->external_name()); + (void *) obj, (intptr_t) obj->mark(), obj->klass()->external_name()); } } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/thread.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1444,7 +1444,7 @@ _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; - _exception_oop = NULL; + (void)const_cast(_exception_oop = NULL); _exception_pc = 0; _exception_handler_pc = 0; _is_method_handle_return = 0; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/thread.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -1278,7 +1278,7 @@ address exception_handler_pc() const { return _exception_handler_pc; } bool is_method_handle_return() const { return _is_method_handle_return == 1; } - void set_exception_oop(oop o) { _exception_oop = o; } + void set_exception_oop(oop o) { (void)const_cast(_exception_oop = o); } void set_exception_pc(address a) { _exception_pc = a; } void set_exception_handler_pc(address a) { _exception_handler_pc = a; } void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/vframeArray.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,7 @@ case T_OBJECT: assert(!value->obj_is_scalar_replaced(), "object should be reallocated already"); // preserve object type - _locals->add( new StackValue((intptr_t) (value->get_obj()()), T_OBJECT )); + _locals->add( new StackValue(cast_from_oop((value->get_obj()())), T_OBJECT )); break; case T_CONFLICT: // A dead local. Will be initialized to null/zero. @@ -136,7 +136,7 @@ case T_OBJECT: assert(!value->obj_is_scalar_replaced(), "object should be reallocated already"); // preserve object type - _expressions->add( new StackValue((intptr_t) (value->get_obj()()), T_OBJECT )); + _expressions->add( new StackValue(cast_from_oop((value->get_obj()())), T_OBJECT )); break; case T_CONFLICT: // A dead stack element. Will be initialized to null/zero. diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/virtualspace.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -368,8 +368,15 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { + const size_t max_commit_granularity = os::page_size_for_region(rs.size(), rs.size(), 1); + return initialize_with_granularity(rs, committed_size, max_commit_granularity); +} + +bool VirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t committed_size, size_t max_commit_granularity) { if(!rs.is_reserved()) return false; // allocation failed. assert(_low_boundary == NULL, "VirtualSpace already initialized"); + assert(max_commit_granularity > 0, "Granularity must be non-zero."); + _low_boundary = rs.base(); _high_boundary = low_boundary() + rs.size(); @@ -390,7 +397,7 @@ // No attempt is made to force large page alignment at the very top and // bottom of the space if they are not aligned so already. _lower_alignment = os::vm_page_size(); - _middle_alignment = os::page_size_for_region(rs.size(), rs.size(), 1); + _middle_alignment = max_commit_granularity; _upper_alignment = os::vm_page_size(); // End of each region @@ -966,17 +973,52 @@ class TestVirtualSpace : AllStatic { + enum TestLargePages { + Default, + Disable, + Reserve, + Commit + }; + + static ReservedSpace reserve_memory(size_t reserve_size_aligned, TestLargePages mode) { + switch(mode) { + default: + case Default: + case Reserve: + return ReservedSpace(reserve_size_aligned); + case Disable: + case Commit: + return ReservedSpace(reserve_size_aligned, + os::vm_allocation_granularity(), + /* large */ false, /* exec */ false); + } + } + + static bool initialize_virtual_space(VirtualSpace& vs, ReservedSpace rs, TestLargePages mode) { + switch(mode) { + default: + case Default: + case Reserve: + return vs.initialize(rs, 0); + case Disable: + return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); + case Commit: + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), rs.size(), 1)); + } + } + public: - static void test_virtual_space_actual_committed_space(size_t reserve_size, size_t commit_size) { + static void test_virtual_space_actual_committed_space(size_t reserve_size, size_t commit_size, + TestLargePages mode = Default) { size_t granularity = os::vm_allocation_granularity(); size_t reserve_size_aligned = align_size_up(reserve_size, granularity); - ReservedSpace reserved(reserve_size_aligned); + ReservedSpace reserved = reserve_memory(reserve_size_aligned, mode); assert(reserved.is_reserved(), "Must be"); VirtualSpace vs; - bool initialized = vs.initialize(reserved, 0); + bool initialized = initialize_virtual_space(vs, reserved, mode); assert(initialized, "Failed to initialize VirtualSpace"); vs.expand_by(commit_size, false); @@ -986,7 +1028,10 @@ } else { assert_ge(vs.actual_committed_size(), commit_size); // Approximate the commit granularity. - size_t commit_granularity = UseLargePages ? os::large_page_size() : os::vm_page_size(); + // Make sure that we don't commit using large pages + // if large pages has been disabled for this VirtualSpace. + size_t commit_granularity = (mode == Disable || !UseLargePages) ? + os::vm_page_size() : os::large_page_size(); assert_lt(vs.actual_committed_size(), commit_size + commit_granularity); } @@ -1042,9 +1087,40 @@ test_virtual_space_actual_committed_space(10 * M, 10 * M); } + static void test_virtual_space_disable_large_pages() { + if (!UseLargePages) { + return; + } + // These test cases verify that if we force VirtualSpace to disable large pages + test_virtual_space_actual_committed_space(10 * M, 0, Disable); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Disable); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Disable); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Disable); + + test_virtual_space_actual_committed_space(10 * M, 0, Reserve); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Reserve); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Reserve); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Reserve); + + test_virtual_space_actual_committed_space(10 * M, 0, Commit); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Commit); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Commit); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Commit); + } + static void test_virtual_space() { test_virtual_space_actual_committed_space(); test_virtual_space_actual_committed_space_one_large_page(); + test_virtual_space_disable_large_pages(); } }; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/virtualspace.hpp --- a/src/share/vm/runtime/virtualspace.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/virtualspace.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -178,6 +178,7 @@ public: // Initialization VirtualSpace(); + bool initialize_with_granularity(ReservedSpace rs, size_t committed_byte_size, size_t max_commit_ganularity); bool initialize(ReservedSpace rs, size_t committed_byte_size); // Destruction diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -27,7 +27,6 @@ #include "classfile/javaClasses.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" -#include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "ci/ciField.hpp" #include "ci/ciInstance.hpp" @@ -176,6 +175,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/parse.hpp" @@ -288,6 +288,7 @@ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ nonstatic_field(InstanceKlass, _array_klasses, Klass*) \ nonstatic_field(InstanceKlass, _methods, Array*) \ + nonstatic_field(InstanceKlass, _default_methods, Array*) \ nonstatic_field(InstanceKlass, _local_interfaces, Array*) \ nonstatic_field(InstanceKlass, _transitive_interfaces, Array*) \ nonstatic_field(InstanceKlass, _fields, Array*) \ @@ -322,6 +323,7 @@ nonstatic_field(nmethodBucket, _count, int) \ nonstatic_field(nmethodBucket, _next, nmethodBucket*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ + nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ @@ -714,11 +716,17 @@ nonstatic_field(PlaceholderEntry, _loader_data, ClassLoaderData*) \ \ /**************************/ \ - /* ProctectionDomainEntry */ \ + /* ProtectionDomainEntry */ \ /**************************/ \ \ nonstatic_field(ProtectionDomainEntry, _next, ProtectionDomainEntry*) \ - nonstatic_field(ProtectionDomainEntry, _protection_domain, oop) \ + nonstatic_field(ProtectionDomainEntry, _pd_cache, ProtectionDomainCacheEntry*) \ + \ + /*******************************/ \ + /* ProtectionDomainCacheEntry */ \ + /*******************************/ \ + \ + nonstatic_field(ProtectionDomainCacheEntry, _literal, oop) \ \ /*************************/ \ /* LoaderConstraintEntry */ \ @@ -841,7 +849,7 @@ nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ - nonstatic_field(nmethod, _state, unsigned char) \ + nonstatic_field(nmethod, _state, volatile unsigned char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ nonstatic_field(nmethod, _deoptimize_mh_offset, int) \ @@ -1185,11 +1193,10 @@ /* -XX flags */ \ /*********************/ \ \ - nonstatic_field(Flag, type, const char*) \ - nonstatic_field(Flag, name, const char*) \ - unchecked_nonstatic_field(Flag, addr, sizeof(void*)) /* NOTE: no type */ \ - nonstatic_field(Flag, kind, const char*) \ - nonstatic_field(Flag, origin, FlagValueOrigin) \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) /* NOTE: no type */ \ + nonstatic_field(Flag, _flags, Flag::Flags) \ static_field(Flag, flags, Flag*) \ static_field(Flag, numFlags, size_t) \ \ @@ -1360,6 +1367,7 @@ declare_integer_type(long) \ declare_integer_type(char) \ declare_unsigned_integer_type(unsigned char) \ + declare_unsigned_integer_type(volatile unsigned char) \ declare_unsigned_integer_type(u_char) \ declare_unsigned_integer_type(unsigned int) \ declare_unsigned_integer_type(uint) \ @@ -1382,6 +1390,7 @@ declare_toplevel_type(char**) \ declare_toplevel_type(u_char*) \ declare_toplevel_type(unsigned char*) \ + declare_toplevel_type(volatile unsigned char*) \ \ /*******************************************************************/ \ /* Types which it will be handy to have available over in the SA */ \ @@ -1560,6 +1569,7 @@ declare_toplevel_type(SystemDictionary) \ declare_toplevel_type(vmSymbols) \ declare_toplevel_type(ProtectionDomainEntry) \ + declare_toplevel_type(ProtectionDomainCacheEntry) \ \ declare_toplevel_type(GenericGrowableArray) \ declare_toplevel_type(GrowableArray) \ @@ -1928,6 +1938,9 @@ declare_c2_type(CmpF3Node, CmpFNode) \ declare_c2_type(CmpDNode, CmpNode) \ declare_c2_type(CmpD3Node, CmpDNode) \ + declare_c2_type(MathExactNode, MultiNode) \ + declare_c2_type(AddExactINode, MathExactNode) \ + declare_c2_type(FlagsProjNode, ProjNode) \ declare_c2_type(BoolNode, Node) \ declare_c2_type(AbsNode, Node) \ declare_c2_type(AbsINode, AbsNode) \ @@ -2074,7 +2087,7 @@ declare_integer_type(JavaThreadState) \ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ - declare_integer_type(FlagValueOrigin) \ + declare_integer_type(Flag::Flags) \ COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ @@ -2082,7 +2095,7 @@ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ - declare_type(Array, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ \ declare_integer_type(AccessFlags) /* FIXME: wrong type (not integer) */\ declare_toplevel_type(address) /* FIXME: should this be an integer type? */\ @@ -2242,12 +2255,6 @@ declare_preprocessor_constant("PERFDATA_BIG_ENDIAN", PERFDATA_BIG_ENDIAN) \ declare_preprocessor_constant("PERFDATA_LITTLE_ENDIAN", PERFDATA_LITTLE_ENDIAN) \ \ - /***************/ \ - /* SymbolTable */ \ - /***************/ \ - \ - declare_constant(SymbolTable::symbol_table_size) \ - \ /***********************************/ \ /* LoaderConstraintTable constants */ \ /***********************************/ \ diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/vm_operations.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -173,10 +173,6 @@ SymbolTable::unlink(); } -void VM_HandleFullCodeCache::doit() { - NMethodSweeper::speculative_disconnect_nmethods(_is_full); -} - void VM_Verify::doit() { Universe::heap()->prepare_for_verify(); Universe::verify(_silent); diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/runtime/vm_operations.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -51,7 +51,6 @@ template(DeoptimizeAll) \ template(ZombieAll) \ template(UnlinkSymbols) \ - template(HandleFullCodeCache) \ template(Verify) \ template(PrintJNI) \ template(HeapDumper) \ @@ -261,16 +260,6 @@ bool allow_nested_vm_operations() const { return true; } }; -class VM_HandleFullCodeCache: public VM_Operation { - private: - bool _is_full; - public: - VM_HandleFullCodeCache(bool is_full) { _is_full = is_full; } - VMOp_Type type() const { return VMOp_HandleFullCodeCache; } - void doit(); - bool allow_nested_vm_operations() const { return true; } -}; - #ifndef PRODUCT class VM_DeoptimizeAll: public VM_Operation { private: diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/attachListener.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -245,7 +245,7 @@ } value = (tmp != 0); } - bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::boolAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -263,7 +263,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::intxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -282,7 +282,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -301,7 +301,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -316,7 +316,7 @@ out->print_cr("flag value must be a string"); return JNI_ERR; } - bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (res) { FREE_C_HEAP_ARRAY(char, value, mtInternal); } else { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/classLoadingService.cpp --- a/src/share/vm/services/classLoadingService.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/classLoadingService.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ len = name->utf8_length(); \ } \ HS_DTRACE_PROBE4(hotspot, class__##type, \ - data, len, (clss)->class_loader(), (shared)); \ + data, len, SOLARIS_ONLY((void *))(clss)->class_loader(), (shared)); \ } #else /* USDT2 */ @@ -202,7 +202,7 @@ MutexLocker m(Management_lock); // verbose will be set to the previous value - bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, Flag::MANAGEMENT); assert(succeed, "Setting TraceClassLoading flag fails"); reset_trace_class_unloading(); @@ -213,7 +213,7 @@ void ClassLoadingService::reset_trace_class_unloading() { assert(Management_lock->owned_by_self(), "Must own the Management_lock"); bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); - bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, Flag::MANAGEMENT); assert(succeed, "Setting TraceClassUnLoading flag fails"); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/dtraceAttacher.cpp --- a/src/share/vm/services/dtraceAttacher.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/dtraceAttacher.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -51,7 +51,7 @@ static void set_bool_flag(const char* flag, bool value) { CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value, - ATTACH_ON_DEMAND); + Flag::ATTACH_ON_DEMAND); } // Enable only the "fine grained" flags. Do *not* touch diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/heapDumper.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -563,7 +563,7 @@ } void DumpWriter::write_objectID(oop o) { - address a = (address)((uintptr_t)o); + address a = (address)o; #ifdef _LP64 write_u8((u8)a); #else diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/management.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1643,9 +1643,13 @@ int num_entries = 0; for (int i = 0; i < nFlags; i++) { Flag* flag = &Flag::flags[i]; + // Exclude notproduct and develop flags in product builds. + if (flag->is_constant_in_binary()) { + continue; + } // Exclude the locked (experimental, diagnostic) flags if (flag->is_unlocked() || flag->is_unlocker()) { - Handle s = java_lang_String::create_from_str(flag->name, CHECK_0); + Handle s = java_lang_String::create_from_str(flag->_name, CHECK_0); flags_ah->obj_at_put(num_entries, s()); num_entries++; } @@ -1669,7 +1673,7 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { - flag_name = java_lang_String::create_from_str(flag->name, CHECK_false); + flag_name = java_lang_String::create_from_str(flag->_name, CHECK_false); } else { flag_name = name; } @@ -1698,23 +1702,23 @@ global->writeable = flag->is_writeable(); global->external = flag->is_external(); - switch (flag->origin) { - case DEFAULT: + switch (flag->get_origin()) { + case Flag::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case COMMAND_LINE: + case Flag::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case ENVIRON_VAR: + case Flag::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case CONFIG_FILE: + case Flag::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case MANAGEMENT: + case Flag::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case ERGONOMIC: + case Flag::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; default: @@ -1781,6 +1785,10 @@ int num_entries = 0; for (int i = 0; i < nFlags && num_entries < count; i++) { Flag* flag = &Flag::flags[i]; + // Exclude notproduct and develop flags in product builds. + if (flag->is_constant_in_binary()) { + continue; + } // Exclude the locked (diagnostic, experimental) flags if ((flag->is_unlocked() || flag->is_unlocker()) && add_global_entry(env, null_h, &globals[num_entries], flag, THREAD)) { @@ -1813,23 +1821,23 @@ bool succeed; if (flag->is_bool()) { bool bvalue = (new_value.z == JNI_TRUE ? true : false); - succeed = CommandLineFlags::boolAtPut(name, &bvalue, MANAGEMENT); + succeed = CommandLineFlags::boolAtPut(name, &bvalue, Flag::MANAGEMENT); } else if (flag->is_intx()) { intx ivalue = (intx)new_value.j; - succeed = CommandLineFlags::intxAtPut(name, &ivalue, MANAGEMENT); + succeed = CommandLineFlags::intxAtPut(name, &ivalue, Flag::MANAGEMENT); } else if (flag->is_uintx()) { uintx uvalue = (uintx)new_value.j; - succeed = CommandLineFlags::uintxAtPut(name, &uvalue, MANAGEMENT); + succeed = CommandLineFlags::uintxAtPut(name, &uvalue, Flag::MANAGEMENT); } else if (flag->is_uint64_t()) { uint64_t uvalue = (uint64_t)new_value.j; - succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, MANAGEMENT); + succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, Flag::MANAGEMENT); } else if (flag->is_ccstr()) { oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { THROW(vmSymbols::java_lang_NullPointerException()); } ccstr svalue = java_lang_String::as_utf8_string(str); - succeed = CommandLineFlags::ccstrAtPut(name, &svalue, MANAGEMENT); + succeed = CommandLineFlags::ccstrAtPut(name, &svalue, Flag::MANAGEMENT); } assert(succeed, "Setting flag should succeed"); JVM_END diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/memoryManager.cpp --- a/src/share/vm/services/memoryManager.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/memoryManager.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ MemoryManager::MemoryManager() { _num_pools = 0; - _memory_mgr_obj = NULL; + (void)const_cast(_memory_mgr_obj = NULL); } void MemoryManager::add_pool(MemoryPool* pool) { diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/memoryPool.cpp --- a/src/share/vm/services/memoryPool.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/memoryPool.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ _name = name; _initial_size = init_size; _max_size = max_size; - _memory_pool_obj = NULL; + (void)const_cast(_memory_pool_obj = NULL); _available_for_allocation = true; _num_managers = 0; _type = type; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/memoryService.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -515,7 +515,7 @@ bool MemoryService::set_verbose(bool verbose) { MutexLocker m(Management_lock); // verbose will be set to the previous value - bool succeed = CommandLineFlags::boolAtPut((char*)"PrintGC", &verbose, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"PrintGC", &verbose, Flag::MANAGEMENT); assert(succeed, "Setting PrintGC flag fails"); ClassLoadingService::reset_trace_class_unloading(); @@ -618,4 +618,3 @@ MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime, _recordGCEndTime, _countCollection, _cause); } - diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/services/memoryService.hpp --- a/src/share/vm/services/memoryService.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/services/memoryService.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -148,6 +148,12 @@ static void track_code_cache_memory_usage() { track_memory_pool_usage(_code_heap_pool); } + static void track_metaspace_memory_usage() { + track_memory_pool_usage(_metaspace_pool); + } + static void track_compressed_class_memory_usage() { + track_memory_pool_usage(_compressed_class_pool); + } static void track_memory_pool_usage(MemoryPool* pool); static void gc_begin(bool fullGC, bool recordGCBeginTime, diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/trace/trace.xml --- a/src/share/vm/trace/trace.xml Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/trace/trace.xml Mon Oct 21 14:08:09 2013 +0100 @@ -313,13 +313,6 @@ - - - - - = 0; } - T at(int i) const { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return _data[i]; } - void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); _data[i] = x; } - T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return &_data[i]; } + T at(int i) const { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return _data[i]; } + void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); _data[i] = x; } + T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return &_data[i]; } int find(const T& x) { return index_of(x); } T at_acquire(const int which) { return OrderAccess::load_acquire(adr_at(which)); } diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/utilities/globalDefinitions.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -326,12 +326,18 @@ const int max_method_code_size = 64*K - 1; // JVM spec, 2nd ed. section 4.8.1 (p.134) +// Default ProtectionDomainCacheSize values + +const int defaultProtectionDomainCacheSize = NOT_LP64(137) LP64_ONLY(2017); //---------------------------------------------------------------------------------------------------- // Default and minimum StringTableSize values const int defaultStringTableSize = NOT_LP64(1009) LP64_ONLY(60013); -const int minimumStringTableSize=1009; +const int minimumStringTableSize = 1009; + +const int defaultSymbolTableSize = 20011; +const int minimumSymbolTableSize = 1009; //---------------------------------------------------------------------------------------------------- @@ -967,9 +973,9 @@ // (These must be implemented as #defines because C++ compilers are // not obligated to inline non-integral constants!) #define badAddress ((address)::badAddressVal) -#define badOop ((oop)::badOopVal) +#define badOop (cast_to_oop(::badOopVal)) #define badHeapWord (::badHeapWordVal) -#define badJNIHandle ((oop)::badJNIHandleVal) +#define badJNIHandle (cast_to_oop(::badJNIHandleVal)) // Default TaskQueue size is 16K (32-bit) or 128K (64-bit) #define TASKQUEUE_SIZE (NOT_LP64(1<<14) LP64_ONLY(1<<17)) diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/utilities/globalDefinitions_visCPP.hpp --- a/src/share/vm/utilities/globalDefinitions_visCPP.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/utilities/globalDefinitions_visCPP.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -189,6 +189,10 @@ #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union (needed in windows.h) #pragma warning( disable : 4511 ) // copy constructor could not be generated #pragma warning( disable : 4291 ) // no matching operator delete found; memory will not be freed if initialization thows an exception +#ifdef CHECK_UNHANDLED_OOPS +#pragma warning( disable : 4521 ) // class has multiple copy ctors of a single type +#pragma warning( disable : 4522 ) // class has multiple assignment operators of a single type +#endif // CHECK_UNHANDLED_OOPS #if _MSC_VER >= 1400 #pragma warning( disable : 4996 ) // unsafe string functions. Same as define _CRT_SECURE_NO_WARNINGS/_CRT_SECURE_NO_DEPRICATE #endif diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/utilities/hashtable.cpp --- a/src/share/vm/utilities/hashtable.cpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/utilities/hashtable.cpp Mon Oct 21 14:08:09 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -356,9 +356,9 @@ template class Hashtable; template class Hashtable; template class Hashtable; -#ifdef SOLARIS +#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) template class Hashtable; -#endif +#endif // SOLARIS || CHECK_UNHANDLED_OOPS template class Hashtable; template class Hashtable; template class HashtableEntry; diff -r 6fa574bfd32a -r 6795fcebbf42 src/share/vm/utilities/taskqueue.hpp --- a/src/share/vm/utilities/taskqueue.hpp Thu Oct 03 19:13:12 2013 +0100 +++ b/src/share/vm/utilities/taskqueue.hpp Mon Oct 21 14:08:09 2013 +0100 @@ -322,11 +322,11 @@ // Attempts to claim a task from the "local" end of the queue (the most // recently pushed). If successful, returns true and sets t to the task; // otherwise, returns false (the queue is empty). - inline bool pop_local(E& t); + inline bool pop_local(volatile E& t); // Like pop_local(), but uses the "global" end of the queue (the least // recently pushed). - bool pop_global(E& t); + bool pop_global(volatile E& t); // Delete any resource associated with the queue. ~GenericTaskQueue(); @@ -424,7 +424,7 @@ } template -bool GenericTaskQueue::pop_global(E& t) { +bool GenericTaskQueue::pop_global(volatile E& t) { Age oldAge = _age.get(); // Architectures with weak memory model require a barrier here // to guarantee that bottom is not older than age, @@ -701,7 +701,7 @@ } template inline bool -GenericTaskQueue::pop_local(E& t) { +GenericTaskQueue::pop_local(volatile E& t) { uint localBot = _bottom; // This value cannot be N-1. That can only occur as a result of // the assignment to bottom in this method. If it does, this method @@ -799,7 +799,7 @@ } volatile ObjArrayTask& operator =(const volatile ObjArrayTask& t) volatile { - _obj = t._obj; + (void)const_cast(_obj = t._obj); _index = t._index; return *this; } diff -r 6fa574bfd32a -r 6795fcebbf42 test/TEST.groups --- a/test/TEST.groups Thu Oct 03 19:13:12 2013 +0100 +++ b/test/TEST.groups Mon Oct 21 14:08:09 2013 +0100 @@ -27,7 +27,7 @@ # - compact1, compact2, compact3, full JRE, JDK # # In addition they support testing of the minimal VM on compact1 and compact2. -# Essentially this defines groups based around the specified API's and VM +# Essentially this defines groups based around the specified API's and VM # services available in the runtime. # # The groups are defined hierarchically in two forms: @@ -44,9 +44,9 @@ # by listing the top-level test directories. # # To use a group simply list it on the jtreg command line eg: -# jtreg :jdk +# jtreg :jdk # runs all tests. While -# jtreg :compact2 +# jtreg :compact2 # runs those tests that only require compact1 and compact2 API's. # @@ -65,11 +65,11 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java \ gc/metaspace/TestMetaspacePerfCounters.java \ runtime/6819213/TestBootNativeLibraryPath.java \ - runtime/6878713/Test6878713.sh \ runtime/6925573/SortMethodsTest.java \ runtime/7107135/Test7107135.sh \ runtime/7158988/FieldMonitor.java \ runtime/7194254/Test7194254.java \ + runtime/8026365/InvokeSpecialAnonTest.java \ runtime/jsig/Test8017498.sh \ runtime/Metaspace/FragmentMetaspace.java \ runtime/NMT/BaselineWithParameter.java \ @@ -85,7 +85,9 @@ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ runtime/XCheckJniJsig/XCheckJSig.java \ - serviceability/attach/AttachWithStalePidFile.java + serviceability/attach/AttachWithStalePidFile.java \ + serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java + # JRE adds further tests to compact3 # @@ -139,7 +141,7 @@ -:needs_jdk # Tests that require compact2 API's and a full VM -# +# needs_full_vm_compact2 = # Compact 1 adds full VM tests @@ -193,6 +195,7 @@ serviceability/ \ compiler/ \ testlibrary/ \ + testlibrary_tests/ \ sanity/ \ runtime/ \ gc/ \ diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/CondTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/CondTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile CondTest.java Verify.java + * @run main CondTest + * + */ + +import java.lang.ArithmeticException; + +public class CondTest { + public static int result = 0; + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + runTest(); + } + } + + public static void runTest() { + int i = 7; + while (java.lang.Math.addExact(i, result) < 89361) { + if ((java.lang.Math.addExact(i, i) & 1) == 1) { + i += 3; + } else if ((i & 5) == 4) { + i += 7; + } else if ((i & 0xf) == 6) { + i += 2; + } else { + i += 1; + } + result += 2; + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/ConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/ConstantTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test constant addExact + * @compile ConstantTest.java Verify.java + * @run main ConstantTest + * + */ + +import java.lang.ArithmeticException; + +public class ConstantTest { + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + Verify.verify(5, 7); + Verify.verify(Integer.MAX_VALUE, 1); + Verify.verify(Integer.MIN_VALUE, -1); + Verify.verify(Integer.MAX_VALUE, -1); + Verify.verify(Integer.MIN_VALUE, 1); + Verify.verify(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2); + Verify.verify(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3); + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/LoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/LoadTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile LoadTest.java Verify.java + * @run main LoadTest + * + */ + +import java.lang.ArithmeticException; + +public class LoadTest { + public static java.util.Random rnd = new java.util.Random(); + public static int[] values = new int[256]; + + public static void main(String[] args) { + for (int i = 0; i < values.length; ++i) { + values[i] = rnd.nextInt(); + } + + for (int i = 0; i < 50000; ++i) { + Verify.verify(values[i & 255], values[i & 255] - i); + Verify.verify(values[i & 255] + i, values[i & 255] - i); + Verify.verify(values[i & 255], values[i & 255]); + if ((i & 1) == 1 && i > 5) { + Verify.verify(values[i & 255] + i, values[i & 255] - i); + } else { + Verify.verify(values[i & 255] - i, values[i & 255] + i); + } + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/LoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/LoopDependentTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile LoopDependentTest.java Verify.java + * @run main LoopDependentTest + * + */ + +import java.lang.ArithmeticException; + +public class LoopDependentTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + for (int i = 0; i < 50000; ++i) { + Verify.verify(rnd1 + i, rnd2 + i); + Verify.verify(rnd1 + i, rnd2 + (i & 0xff)); + Verify.verify(rnd1 - i, rnd2 - (i & 0xff)); + Verify.verify(rnd1 + i + 1, rnd2 + i + 2); + Verify.verify(rnd1 + i * 2, rnd2 + i); + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/NonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NonConstantTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile NonConstantTest.java Verify.java + * @run main NonConstantTest + * + */ + +import java.lang.ArithmeticException; + +public class NonConstantTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + Verify.verify(rnd1, rnd2); + Verify.verify(rnd1, rnd2 + 1); + Verify.verify(rnd1 + 1, rnd2); + Verify.verify(rnd1 - 1, rnd2); + Verify.verify(rnd1, rnd2 - 1); + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/intrinsics/mathexact/Verify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/Verify.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class Verify { + public static String throwWord(boolean threw) { + return (threw ? "threw" : "didn't throw"); + } + + public static void verify(int a, int b) { + boolean exception1 = false, exception2 = false; + int result1 = 0, result2 = 0; + try { + result1 = testIntrinsic(a, b); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = testNonIntrinsic(a, b); + } catch (ArithmeticException e) { + exception2 = true; + } + + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version " + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version returned: " + a + " while NonIntrinsic version returned: " + b); + } + } + + public static int testIntrinsic(int a, int b) { + return java.lang.Math.addExact(a, b); + } + + public static int testNonIntrinsic(int a, int b) { + return safeAddExact(a, b); + } + + // Copied java.lang.Math.addExact to avoid intrinsification + public static int safeAddExact(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * A minimal classloader for loading bytecodes that could not result from + * properly compiled Java. + * + * @author dr2chase + */ +public class ByteClassLoader extends ClassLoader { + /** + * (pre)load class name using classData for the definition. + * + * @param name + * @param classData + * @return + */ + public Class loadBytes(String name, byte[] classData) { + Class clazz = defineClass(name, classData, 0, classData.length); + resolveClass(clazz); + return clazz; + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/jsr292/methodHandleExceptions/C.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/C.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * Test class -- implements I, which provides default for m, but this class + * declares it abstract which (should) hide the interface default, and throw + * an abstract method error if it is called (calling it requires bytecode hacking + * or inconsistent compilation). + */ +public abstract class C implements I { + public abstract int m(); +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/jsr292/methodHandleExceptions/I.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/I.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +public interface I { + default public int m() { return 1; } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.lang.reflect.InvocationTargetException; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * @test + * @bug 8025260 + * @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path + * + * @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java + * @run main/othervm TestAMEnotNPE + */ + +public class TestAMEnotNPE implements Opcodes { + + /** + * The bytes for D, a NOT abstract class extending abstract class C + * without supplying an implementation for abstract method m. + * There is a default method in the interface I, but it should lose to + * the abstract class. + + class D extends C { + D() { super(); } + // does not define m + } + + * @return + * @throws Exception + */ + public static byte[] bytesForD() throws Exception { + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "C", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + + /** + * The bytecodes for an invokeExact of a particular methodHandle, I.m, invoked on a D + + class T { + T() { super(); } // boring constructor + int test() { + MethodHandle mh = `I.m():int`; + D d = new D(); + return mh.invokeExact(d); // Should explode here, AbstractMethodError + } + } + + * @return + * @throws Exception + */ + public static byte[] bytesForT() throws Exception { + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null); + mv.visitCode(); + mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I")); + mv.visitTypeInsn(NEW, "D"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "D", "", "()V"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I"); + mv.visitInsn(IRETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + public static void main(String args[] ) throws Throwable { + ByteClassLoader bcl = new ByteClassLoader(); + Class d = bcl.loadBytes("D", bytesForD()); + Class t = bcl.loadBytes("T", bytesForT()); + try { + Object result = t.getMethod("test").invoke(null); + System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw no exception"); + throw new Error("Missing expected exception"); + } catch (InvocationTargetException e) { + Throwable th = e.getCause(); + if (th instanceof AbstractMethodError) { + th.printStackTrace(System.out); + System.out.println("PASS, saw expected exception (AbstractMethodError, wrapped in InvocationTargetException)."); + } else { + System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th); + throw th; + } + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/CompilerWhiteBoxTest.java --- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -74,6 +74,9 @@ protected static final int THRESHOLD; /** count of invocation to triger OSR compilation */ protected static final long BACKEDGE_THRESHOLD; + /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ + protected static final String MODE + = System.getProperty("java.vm.info"); static { if (TIERED_COMPILATION) { @@ -202,7 +205,7 @@ if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { throw new RuntimeException(method + " osr_comp_level must be == 0"); } - } + } /** * Checks, that {@linkplain #method} is compiled. diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/DeoptimizeAllTest.java --- a/test/compiler/whitebox/DeoptimizeAllTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -53,6 +53,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } compile(); checkCompiled(); WHITE_BOX.deoptimizeAll(); diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/DeoptimizeMethodTest.java --- a/test/compiler/whitebox/DeoptimizeMethodTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -53,6 +53,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } compile(); checkCompiled(); deoptimize(); diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/EnqueueMethodForCompilationTest.java --- a/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -70,12 +70,10 @@ int compLevel = getCompLevel(); int bci = WHITE_BOX.getMethodEntryBci(method); - System.out.println("bci = " + bci); - printInfo(); deoptimize(); - printInfo(); checkNotCompiled(); - printInfo(); + WHITE_BOX.clearMethodState(method); + WHITE_BOX.enqueueMethodForCompilation(method, compLevel, bci); checkCompiled(); deoptimize(); diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/IsMethodCompilableTest.java --- a/test/compiler/whitebox/IsMethodCompilableTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -68,6 +68,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); } diff -r 6fa574bfd32a -r 6795fcebbf42 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -62,6 +62,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } checkNotCompiled(); if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/g1/TestSummarizeRSetStats.java --- a/test/gc/g1/TestSummarizeRSetStats.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/gc/g1/TestSummarizeRSetStats.java Mon Oct 21 14:08:09 2013 +0100 @@ -25,140 +25,61 @@ * @test TestSummarizeRSetStats.java * @bug 8013895 * @library /testlibrary - * @build TestSummarizeRSetStats + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStats * @summary Verify output of -XX:+G1SummarizeRSetStats * @run main TestSummarizeRSetStats * * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. */ -import com.oracle.java.testlibrary.*; -import java.lang.Thread; -import java.util.ArrayList; -import java.util.Arrays; - -class RunSystemGCs { - // 4M size, both are directly allocated into the old gen - static Object[] largeObject1 = new Object[1024 * 1024]; - static Object[] largeObject2 = new Object[1024 * 1024]; - - static int[] temp; - - public static void main(String[] args) { - // create some cross-references between these objects - for (int i = 0; i < largeObject1.length; i++) { - largeObject1[i] = largeObject2; - } - - for (int i = 0; i < largeObject2.length; i++) { - largeObject2[i] = largeObject1; - } - - int numGCs = Integer.parseInt(args[0]); - - if (numGCs > 0) { - // try to force a minor collection: the young gen is 4M, the - // amount of data allocated below is roughly that (4*1024*1024 + - // some header data) - for (int i = 0; i < 1024 ; i++) { - temp = new int[1024]; - } - } - - for (int i = 0; i < numGCs - 1; i++) { - System.gc(); - } - } -} - public class TestSummarizeRSetStats { - public static String runTest(String[] additionalArgs, int numGCs) throws Exception { - ArrayList finalargs = new ArrayList(); - String[] defaultArgs = new String[] { - "-XX:+UseG1GC", - "-Xmn4m", - "-Xmx20m", - "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking - "-XX:+PrintGC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:G1HeapRegionSize=1M", - }; - - finalargs.addAll(Arrays.asList(defaultArgs)); - - if (additionalArgs != null) { - finalargs.addAll(Arrays.asList(additionalArgs)); - } - - finalargs.add(RunSystemGCs.class.getName()); - finalargs.add(String.valueOf(numGCs)); - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - finalargs.toArray(new String[0])); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - output.shouldHaveExitValue(0); - - String result = output.getStdout(); - return result; - } - - private static void expectStatistics(String result, int expectedCumulative, int expectedPeriodic) throws Exception { - int actualTotal = result.split("Concurrent RS processed").length - 1; - int actualCumulative = result.split("Cumulative RS summary").length - 1; - - if (expectedCumulative != actualCumulative) { - throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); - } - - if (expectedPeriodic != (actualTotal - actualCumulative)) { - throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); - } - } - public static void main(String[] args) throws Exception { String result; - // no RSet statistics output - result = runTest(null, 0); - expectStatistics(result, 0, 0); + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } - // no RSet statistics output - result = runTest(null, 2); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // no RSet statistics output - result = runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); - expectStatistics(result, 1, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // two times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); - expectStatistics(result, 1, 1); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); - // four times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 1, 3); + // four times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 6); - // three times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); - expectStatistics(result, 1, 2); + // three times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 4); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); - expectStatistics(result, 1, 1); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); } } diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/g1/TestSummarizeRSetStatsPerRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsPerRegion.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestSummarizeRSetStatsPerRegion.java + * @bug 8014078 + * @library /testlibrary + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStatsPerRegion + * @summary Verify output of -XX:+G1SummarizeRSetStats in regards to per-region type output + * @run main TestSummarizeRSetStatsPerRegion + */ + +import com.oracle.java.testlibrary.*; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +public class TestSummarizeRSetStatsPerRegion { + + public static void main(String[] args) throws Exception { + String result; + + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 2); + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/g1/TestSummarizeRSetStatsThreads.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsThreads.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestSummarizeRSetStatsThreads + * @bug 8025441 + * @summary Ensure that various values of worker threads/concurrent + * refinement threads do not crash the VM. + * @key gc + * @library /testlibrary + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestSummarizeRSetStatsThreads { + + private static void runTest(int refinementThreads, int workerThreads) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+G1SummarizeRSetStats", + "-XX:G1ConcRefinementThreads=" + refinementThreads, + "-XX:ParallelGCThreads=" + workerThreads, + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // check output to contain the string "Concurrent RS threads times (s)" followed by + // the correct number of values in the next line. + + // a zero in refinement thread numbers indicates that the value in ParallelGCThreads should be used. + // Additionally use at least one thread. + int expectedNumRefinementThreads = refinementThreads == 0 ? workerThreads : refinementThreads; + expectedNumRefinementThreads = Math.max(1, expectedNumRefinementThreads); + // create the pattern made up of n copies of a floating point number pattern + String numberPattern = String.format("%0" + expectedNumRefinementThreads + "d", 0) + .replace("0", "\\s+\\d+\\.\\d+"); + String pattern = "Concurrent RS threads times \\(s\\)$" + numberPattern + "$"; + Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStdout()); + + if (!m.find()) { + throw new Exception("Could not find correct output for concurrent RS threads times in stdout," + + " should match the pattern \"" + pattern + "\", but stdout is \n" + output.getStdout()); + } + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + // different valid combinations of number of refinement and gc worker threads + runTest(0, 0); + runTest(0, 5); + runTest(5, 0); + runTest(10, 10); + runTest(1, 2); + runTest(4, 3); + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/g1/TestSummarizeRSetStatsTools.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsTools.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Common helpers for TestSummarizeRSetStats* tests + */ + +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +import com.oracle.java.testlibrary.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +class VerifySummaryOutput { + // 4M size, both are directly allocated into the old gen + static Object[] largeObject1 = new Object[1024 * 1024]; + static Object[] largeObject2 = new Object[1024 * 1024]; + + static int[] temp; + + public static void main(String[] args) { + // create some cross-references between these objects + for (int i = 0; i < largeObject1.length; i++) { + largeObject1[i] = largeObject2; + } + + for (int i = 0; i < largeObject2.length; i++) { + largeObject2[i] = largeObject1; + } + + int numGCs = Integer.parseInt(args[0]); + + if (numGCs > 0) { + // try to force a minor collection: the young gen is 4M, the + // amount of data allocated below is roughly that (4*1024*1024 + + // some header data) + for (int i = 0; i < 1024 ; i++) { + temp = new int[1024]; + } + } + + for (int i = 0; i < numGCs - 1; i++) { + System.gc(); + } + } +} + +public class TestSummarizeRSetStatsTools { + + // the VM is currently run using G1GC, i.e. trying to test G1 functionality. + public static boolean testingG1GC() { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + + VMOption option = diagnostic.getVMOption("UseG1GC"); + if (option.getValue().equals("false")) { + System.out.println("Skipping this test. It is only a G1 test."); + return false; + } + return true; + } + + public static String runTest(String[] additionalArgs, int numGCs) throws Exception { + ArrayList finalargs = new ArrayList(); + String[] defaultArgs = new String[] { + "-XX:+UseG1GC", + "-XX:+UseCompressedOops", + "-Xmn4m", + "-Xmx20m", + "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking + "-XX:+PrintGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:G1HeapRegionSize=1M", + }; + + finalargs.addAll(Arrays.asList(defaultArgs)); + + if (additionalArgs != null) { + finalargs.addAll(Arrays.asList(additionalArgs)); + } + + finalargs.add(VerifySummaryOutput.class.getName()); + finalargs.add(String.valueOf(numGCs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + String result = output.getStdout(); + return result; + } + + private static void checkCounts(int expected, int actual, String which) throws Exception { + if (expected != actual) { + throw new Exception("RSet summaries mention " + which + " regions an incorrect number of times. Expected " + expected + ", got " + actual); + } + } + + public static void expectPerRegionRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + expectRSetSummaries(result, expectedCumulative, expectedPeriodic); + int actualYoung = result.split("Young regions").length - 1; + int actualHumonguous = result.split("Humonguous regions").length - 1; + int actualFree = result.split("Free regions").length - 1; + int actualOther = result.split("Old regions").length - 1; + + // the strings we check for above are printed four times per summary + int expectedPerRegionTypeInfo = (expectedCumulative + expectedPeriodic) * 4; + + checkCounts(expectedPerRegionTypeInfo, actualYoung, "Young"); + checkCounts(expectedPerRegionTypeInfo, actualHumonguous, "Humonguous"); + checkCounts(expectedPerRegionTypeInfo, actualFree, "Free"); + checkCounts(expectedPerRegionTypeInfo, actualOther, "Old"); + } + + public static void expectRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + int actualTotal = result.split("concurrent refinement").length - 1; + int actualCumulative = result.split("Cumulative RS summary").length - 1; + + if (expectedCumulative != actualCumulative) { + throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); + } + + if (expectedPeriodic != (actualTotal - actualCumulative)) { + throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); + } + } +} + diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/metaspace/G1AddMetaspaceDependency.java --- a/test/gc/metaspace/G1AddMetaspaceDependency.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/gc/metaspace/G1AddMetaspaceDependency.java Mon Oct 21 14:08:09 2013 +0100 @@ -107,7 +107,6 @@ Loader f_loader = new Loader(b_name, b_bytes, a_name, a_loader); Loader g_loader = new Loader(b_name, b_bytes, a_name, a_loader); - byte[] b = new byte[20 * 2 << 20]; Class c; c = b_loader.loadClass(b_name); c = c_loader.loadClass(b_name); diff -r 6fa574bfd32a -r 6795fcebbf42 test/gc/metaspace/TestPerfCountersAndMemoryPools.java --- a/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Mon Oct 21 14:08:09 2013 +0100 @@ -29,10 +29,11 @@ /* @test TestPerfCountersAndMemoryPools * @bug 8023476 + * @library /testlibrary * @summary Tests that a MemoryPoolMXBeans and PerfCounters for metaspace * report the same data. - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools */ public class TestPerfCountersAndMemoryPools { public static void main(String[] args) throws Exception { @@ -43,11 +44,11 @@ } } - private static MemoryUsage getMemoryUsage(String memoryPoolName) { + private static MemoryPoolMXBean getMemoryPool(String memoryPoolName) { List pools = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean pool : pools) { if (pool.getName().equals(memoryPoolName)) { - return pool.getUsage(); + return pool; } } @@ -57,19 +58,18 @@ private static void checkMemoryUsage(String memoryPoolName, String perfNS) throws Exception { - // Need to do a gc before each comparison to update the perf counters + MemoryPoolMXBean pool = getMemoryPool(memoryPoolName); - System.gc(); - MemoryUsage mu = getMemoryUsage(memoryPoolName); - assertEQ(getMinCapacity(perfNS), mu.getInit()); - + // Must do a GC to update performance counters System.gc(); - mu = getMemoryUsage(memoryPoolName); - assertEQ(getUsed(perfNS), mu.getUsed()); + assertEQ(getMinCapacity(perfNS), pool.getUsage().getInit()); + // Must do a second GC to update the perfomance counters again, since + // the call pool.getUsage().getInit() could have allocated some + // metadata. System.gc(); - mu = getMemoryUsage(memoryPoolName); - assertEQ(getCapacity(perfNS), mu.getCommitted()); + assertEQ(getUsed(perfNS), pool.getUsage().getUsed()); + assertEQ(getCapacity(perfNS), pool.getUsage().getCommitted()); } private static long getMinCapacity(String ns) throws Exception { diff -r 6fa574bfd32a -r 6795fcebbf42 test/runtime/6888954/vmerrors.sh --- a/test/runtime/6888954/vmerrors.sh Thu Oct 03 19:13:12 2013 +0100 +++ b/test/runtime/6888954/vmerrors.sh Mon Oct 21 14:08:09 2013 +0100 @@ -1,3 +1,25 @@ +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + # @test # @bug 6888954 # @bug 8015884 @@ -63,6 +85,7 @@ [ $i -lt 10 ] && i2=0$i "$TESTJAVA/bin/java" $TESTVMOPTS -XX:+IgnoreUnrecognizedVMOptions \ + -XX:-TransmitErrorReport \ -XX:ErrorHandlerTest=${i} -version > ${i2}.out 2>&1 # If ErrorHandlerTest is ignored (product build), stop. diff -r 6fa574bfd32a -r 6795fcebbf42 test/runtime/8026365/InvokeSpecialAnonTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8026365/InvokeSpecialAnonTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8026365 + * @summary Test invokespecial of host class method from an anonymous class + * @author Robert Field + * @library /testlibrary + * @compile -XDignore.symbol.file InvokeSpecialAnonTest.java + * @run main ClassFileInstaller InvokeSpecialAnonTest AnonTester + * @run main/othervm -Xbootclasspath/a:. -Xverify:all InvokeSpecialAnonTest + */ +import jdk.internal.org.objectweb.asm.*; +import java.lang.reflect.Constructor; +import sun.misc.Unsafe; + +public class InvokeSpecialAnonTest implements Opcodes { + + static byte[] anonClassBytes() throws Exception { + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(V1_8, ACC_FINAL + ACC_SUPER, "Anon", null, "java/lang/Object", null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "m", "(LInvokeSpecialAnonTest;)I", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKESPECIAL, "InvokeSpecialAnonTest", "privMethod", "()I"); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + private int privMethod() { return 1234; } + + public static void main(String[] args) throws Exception { + Class klass = InvokeSpecialAnonTest.class; + try { + Class result = AnonTester.defineTest(klass, anonClassBytes()); + System.out.println("Passed."); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } +} + + +class AnonTester { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + public static Class defineTest(Class targetClass, byte[] classBytes) throws Exception { + return UNSAFE.defineAnonymousClass(targetClass, classBytes, null); + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/runtime/memory/LargePages/TestLargePagesFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/memory/LargePages/TestLargePagesFlags.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test TestLargePagesFlags + * @summary Tests how large pages are choosen depending on the given large pages flag combinations. + * @library /testlibrary + * @run main TestLargePagesFlags + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; +import java.util.ArrayList; + +public class TestLargePagesFlags { + + public static void main(String [] args) throws Exception { + if (!Platform.isLinux()) { + System.out.println("Skipping. TestLargePagesFlags has only been implemented for Linux."); + return; + } + + testUseTransparentHugePages(); + testUseHugeTLBFS(); + testUseSHM(); + testCombinations(); + } + + public static void testUseTransparentHugePages() throws Exception { + if (!canUse(UseTransparentHugePages(true))) { + System.out.println("Skipping testUseTransparentHugePages"); + return; + } + + // -XX:-UseLargePages overrides all other flags. + new FlagTester() + .use(UseLargePages(false), + UseTransparentHugePages(true)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Explicitly turn on UseTransparentHugePages. + new FlagTester() + .use(UseTransparentHugePages(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(true), + UseHugeTLBFS(false), + UseSHM(false)); + + new FlagTester() + .use(UseLargePages(true), + UseTransparentHugePages(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(true), + UseHugeTLBFS(false), + UseSHM(false)); + + // Setting a specific large pages flag will turn + // off heuristics to choose large pages type. + new FlagTester() + .use(UseLargePages(true), + UseTransparentHugePages(false)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Don't turn on UseTransparentHugePages + // unless the user explicitly asks for them. + new FlagTester() + .use(UseLargePages(true)) + .expect( + UseTransparentHugePages(false)); + } + + public static void testUseHugeTLBFS() throws Exception { + if (!canUse(UseHugeTLBFS(true))) { + System.out.println("Skipping testUseHugeTLBFS"); + return; + } + + // -XX:-UseLargePages overrides all other flags. + new FlagTester() + .use(UseLargePages(false), + UseHugeTLBFS(true)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Explicitly turn on UseHugeTLBFS. + new FlagTester() + .use(UseHugeTLBFS(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(true), + UseSHM(false)); + + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(true), + UseSHM(false)); + + // Setting a specific large pages flag will turn + // off heuristics to choose large pages type. + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(false)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Using UseLargePages will default to UseHugeTLBFS large pages. + new FlagTester() + .use(UseLargePages(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(true), + UseSHM(false)); + } + + public static void testUseSHM() throws Exception { + if (!canUse(UseSHM(true))) { + System.out.println("Skipping testUseSHM"); + return; + } + + // -XX:-UseLargePages overrides all other flags. + new FlagTester() + .use(UseLargePages(false), + UseSHM(true)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Explicitly turn on UseSHM. + new FlagTester() + .use(UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(true)) ; + + new FlagTester() + .use(UseLargePages(true), + UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(true)) ; + + // Setting a specific large pages flag will turn + // off heuristics to choose large pages type. + new FlagTester() + .use(UseLargePages(true), + UseSHM(false)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + // Setting UseLargePages can allow the system to choose + // UseHugeTLBFS instead of UseSHM, but never UseTransparentHugePages. + new FlagTester() + .use(UseLargePages(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false)); + } + + public static void testCombinations() throws Exception { + if (!canUse(UseSHM(true)) || !canUse(UseHugeTLBFS(true))) { + System.out.println("Skipping testUseHugeTLBFSAndUseSHMCombination"); + return; + } + + // UseHugeTLBFS takes precedence over SHM. + + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(true), + UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(true), + UseSHM(false)); + + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(false), + UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(true)); + + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(true), + UseSHM(false)) + .expect( + UseLargePages(true), + UseTransparentHugePages(false), + UseHugeTLBFS(true), + UseSHM(false)); + + new FlagTester() + .use(UseLargePages(true), + UseHugeTLBFS(false), + UseSHM(false)) + .expect( + UseLargePages(false), + UseTransparentHugePages(false), + UseHugeTLBFS(false), + UseSHM(false)); + + + if (!canUse(UseTransparentHugePages(true))) { + return; + } + + // UseTransparentHugePages takes precedence. + + new FlagTester() + .use(UseLargePages(true), + UseTransparentHugePages(true), + UseHugeTLBFS(true), + UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(true), + UseHugeTLBFS(false), + UseSHM(false)); + + new FlagTester() + .use(UseTransparentHugePages(true), + UseHugeTLBFS(true), + UseSHM(true)) + .expect( + UseLargePages(true), + UseTransparentHugePages(true), + UseHugeTLBFS(false), + UseSHM(false)); + } + + private static class FlagTester { + private Flag [] useFlags; + + public FlagTester use(Flag... useFlags) { + this.useFlags = useFlags; + return this; + } + + public void expect(Flag... expectedFlags) throws Exception { + if (useFlags == null) { + throw new IllegalStateException("Must run use() before expect()"); + } + + OutputAnalyzer output = executeNewJVM(useFlags); + + for (Flag flag : expectedFlags) { + System.out.println("Looking for: " + flag.flagString()); + String strValue = output.firstMatch(".* " + flag.name() + " .* :?= (\\S+).*", 1); + + if (strValue == null) { + throw new RuntimeException("Flag " + flag.name() + " couldn't be found"); + } + + if (!flag.value().equals(strValue)) { + throw new RuntimeException("Wrong value for: " + flag.name() + + " expected: " + flag.value() + + " got: " + strValue); + } + } + + output.shouldHaveExitValue(0); + } + } + + private static OutputAnalyzer executeNewJVM(Flag... flags) throws Exception { + ArrayList args = new ArrayList<>(); + for (Flag flag : flags) { + args.add(flag.flagString()); + } + args.add("-XX:+PrintFlagsFinal"); + args.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + return output; + } + + private static boolean canUse(Flag flag) { + try { + new FlagTester().use(flag).expect(flag); + } catch (Exception e) { + return false; + } + + return true; + } + + private static Flag UseLargePages(boolean value) { + return new BooleanFlag("UseLargePages", value); + } + + private static Flag UseTransparentHugePages(boolean value) { + return new BooleanFlag("UseTransparentHugePages", value); + } + + private static Flag UseHugeTLBFS(boolean value) { + return new BooleanFlag("UseHugeTLBFS", value); + } + + private static Flag UseSHM(boolean value) { + return new BooleanFlag("UseSHM", value); + } + + private static class BooleanFlag implements Flag { + private String name; + private boolean value; + + BooleanFlag(String name, boolean value) { + this.name = name; + this.value = value; + } + + public String flagString() { + return "-XX:" + (value ? "+" : "-") + name; + } + + public String name() { + return name; + } + + public String value() { + return Boolean.toString(value); + } + } + + private static interface Flag { + public String flagString(); + public String name(); + public String value(); + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/runtime/memory/ReserveMemory.java --- a/test/runtime/memory/ReserveMemory.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/runtime/memory/ReserveMemory.java Mon Oct 21 14:08:09 2013 +0100 @@ -56,6 +56,7 @@ "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", + "-XX:-TransmitErrorReport", "ReserveMemory", "test"); diff -r 6fa574bfd32a -r 6795fcebbf42 test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import sun.management.VMManagement; + +public class JMapHProfLargeHeapProc { + private static final List heapGarbage = new ArrayList<>(); + + public static void main(String[] args) throws Exception { + + buildLargeHeap(args); + + // Print our pid on stdout + System.out.println("PID[" + getProcessId() + "]"); + + // Wait for input before termination + System.in.read(); + } + + private static void buildLargeHeap(String[] args) { + for (long i = 0; i < Integer.parseInt(args[0]); i++) { + heapGarbage.add(new byte[1024]); + } + } + + public static int getProcessId() throws Exception { + + // Get the current process id using a reflection hack + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + Field jvm = runtime.getClass().getDeclaredField("jvm"); + + jvm.setAccessible(true); + VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); + + Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); + + pid_method.setAccessible(true); + + int pid = (Integer) pid_method.invoke(mgmt); + + return pid; + } + +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Scanner; + +import com.oracle.java.testlibrary.Asserts; +import com.oracle.java.testlibrary.JDKToolFinder; +import com.oracle.java.testlibrary.JDKToolLauncher; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; + +/* + * @test + * @bug 6313383 + * @key regression + * @summary Regression test for hprof export issue due to large heaps (>2G) + * @library /testlibrary + * @compile JMapHProfLargeHeapProc.java + * @run main JMapHProfLargeHeapTest + */ + +public class JMapHProfLargeHeapTest { + private static final String HEAP_DUMP_FILE_NAME = "heap.hprof"; + private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1"; + private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2"; + private static final long M = 1024L; + private static final long G = 1024L * M; + + public static void main(String[] args) throws Exception { + // If we are on MacOSX, test if JMap tool is signed, otherwise return + // since test will fail with privilege error. + if (Platform.isOSX()) { + String jmapToolPath = JDKToolFinder.getCurrentJDKTool("jmap"); + ProcessBuilder codesignProcessBuilder = new ProcessBuilder( + "codesign", "-v", jmapToolPath); + Process codesignProcess = codesignProcessBuilder.start(); + OutputAnalyzer analyser = new OutputAnalyzer(codesignProcess); + try { + analyser.shouldNotContain("code object is not signed at all"); + System.out.println("Signed jmap found at: " + jmapToolPath); + } catch (Exception e) { + // Abort since we can't know if the test will work + System.out + .println("Test aborted since we are on MacOSX and the jmap tool is not signed."); + return; + } + } + + // Small heap 22 megabytes, should create 1.0.1 file format + testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_1); + + /** + * This test was deliberately commented out since the test system lacks + * support to handle the requirements for this kind of heap size in a + * good way. If or when it becomes possible to run this kind of tests in + * the test environment the test should be enabled again. + * */ + // Large heap 2,2 gigabytes, should create 1.0.2 file format + // testHProfFileFormat("-Xmx4g", 2 * G + 2 * M, HPROF_HEADER_1_0_2); + } + + private static void testHProfFileFormat(String vmArgs, long heapSize, + String expectedFormat) throws Exception, IOException, + InterruptedException, FileNotFoundException { + ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder( + vmArgs, "JMapHProfLargeHeapProc", String.valueOf(heapSize)); + procBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + Process largeHeapProc = procBuilder.start(); + + try (Scanner largeHeapScanner = new Scanner( + largeHeapProc.getInputStream());) { + String pidstring = null; + while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) { + Thread.sleep(500); + } + int pid = Integer.parseInt(pidstring.substring(4, + pidstring.length() - 1)); + System.out.println("Extracted pid: " + pid); + + JDKToolLauncher jMapLauncher = JDKToolLauncher + .create("jmap", false); + jMapLauncher.addToolArg("-dump:format=b,file=" + pid + "-" + + HEAP_DUMP_FILE_NAME); + jMapLauncher.addToolArg(String.valueOf(pid)); + + ProcessBuilder jMapProcessBuilder = new ProcessBuilder( + jMapLauncher.getCommand()); + System.out.println("jmap command: " + + Arrays.toString(jMapLauncher.getCommand())); + + Process jMapProcess = jMapProcessBuilder.start(); + OutputAnalyzer analyzer = new OutputAnalyzer(jMapProcess); + analyzer.shouldHaveExitValue(0); + analyzer.shouldContain(pid + "-" + HEAP_DUMP_FILE_NAME); + analyzer.shouldContain("Heap dump file created"); + + largeHeapProc.getOutputStream().write('\n'); + + File dumpFile = new File(pid + "-" + HEAP_DUMP_FILE_NAME); + Asserts.assertTrue(dumpFile.exists(), "Heap dump file not found."); + + try (Reader reader = new BufferedReader(new FileReader(dumpFile))) { + CharBuffer buf = CharBuffer.allocate(expectedFormat.length()); + reader.read(buf); + buf.clear(); + Asserts.assertEQ(buf.toString(), expectedFormat, + "Wrong file format. Expected '" + expectedFormat + + "', but found '" + buf.toString() + "'"); + } + + System.out.println("Success!"); + + } finally { + largeHeapProc.destroyForcibly(); + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/AssertsTest.java --- a/test/testlibrary/AssertsTest.java Thu Oct 03 19:13:12 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import static com.oracle.java.testlibrary.Asserts.*; - -/* @test - * @summary Tests the different assertions in the Assert class - * @library /testlibrary - */ -public class AssertsTest { - private static class Foo implements Comparable { - final int id; - public Foo(int id) { - this.id = id; - } - - public int compareTo(Foo f) { - return new Integer(id).compareTo(new Integer(f.id)); - } - } - - public static void main(String[] args) throws Exception { - testLessThan(); - testLessThanOrEqual(); - testEquals(); - testGreaterThanOrEqual(); - testGreaterThan(); - testNotEquals(); - testNull(); - testNotNull(); - testTrue(); - testFalse(); - } - - private static void testLessThan() throws Exception { - expectPass(Assertion.LT, 1, 2); - - expectFail(Assertion.LT, 2, 2); - expectFail(Assertion.LT, 2, 1); - expectFail(Assertion.LT, null, 2); - expectFail(Assertion.LT, 2, null); - } - - private static void testLessThanOrEqual() throws Exception { - expectPass(Assertion.LTE, 1, 2); - expectPass(Assertion.LTE, 2, 2); - - expectFail(Assertion.LTE, 3, 2); - expectFail(Assertion.LTE, null, 2); - expectFail(Assertion.LTE, 2, null); - } - - private static void testEquals() throws Exception { - expectPass(Assertion.EQ, 1, 1); - expectPass(Assertion.EQ, null, null); - - Foo f1 = new Foo(1); - expectPass(Assertion.EQ, f1, f1); - - Foo f2 = new Foo(1); - expectFail(Assertion.EQ, f1, f2); - expectFail(Assertion.LTE, null, 2); - expectFail(Assertion.LTE, 2, null); - } - - private static void testGreaterThanOrEqual() throws Exception { - expectPass(Assertion.GTE, 1, 1); - expectPass(Assertion.GTE, 2, 1); - - expectFail(Assertion.GTE, 1, 2); - expectFail(Assertion.GTE, null, 2); - expectFail(Assertion.GTE, 2, null); - } - - private static void testGreaterThan() throws Exception { - expectPass(Assertion.GT, 2, 1); - - expectFail(Assertion.GT, 1, 1); - expectFail(Assertion.GT, 1, 2); - expectFail(Assertion.GT, null, 2); - expectFail(Assertion.GT, 2, null); - } - - private static void testNotEquals() throws Exception { - expectPass(Assertion.NE, null, 1); - expectPass(Assertion.NE, 1, null); - - Foo f1 = new Foo(1); - Foo f2 = new Foo(1); - expectPass(Assertion.NE, f1, f2); - - expectFail(Assertion.NE, null, null); - expectFail(Assertion.NE, f1, f1); - expectFail(Assertion.NE, 1, 1); - } - - private static void testNull() throws Exception { - expectPass(Assertion.NULL, null); - - expectFail(Assertion.NULL, 1); - } - - private static void testNotNull() throws Exception { - expectPass(Assertion.NOTNULL, 1); - - expectFail(Assertion.NOTNULL, null); - } - - private static void testTrue() throws Exception { - expectPass(Assertion.TRUE, true); - - expectFail(Assertion.TRUE, false); - } - - private static void testFalse() throws Exception { - expectPass(Assertion.FALSE, false); - - expectFail(Assertion.FALSE, true); - } - - private static > void expectPass(Assertion assertion, T ... args) - throws Exception { - Assertion.run(assertion, args); - } - - private static > void expectFail(Assertion assertion, T ... args) - throws Exception { - try { - Assertion.run(assertion, args); - } catch (RuntimeException e) { - return; - } - throw new Exception("Expected " + Assertion.format(assertion, (Object[]) args) + - " to throw a RuntimeException"); - } - -} - -enum Assertion { - LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE; - - public static > void run(Assertion assertion, T ... args) { - String msg = "Expected " + format(assertion, args) + " to pass"; - switch (assertion) { - case LT: - assertLessThan(args[0], args[1], msg); - break; - case LTE: - assertLessThanOrEqual(args[0], args[1], msg); - break; - case EQ: - assertEquals(args[0], args[1], msg); - break; - case GTE: - assertGreaterThanOrEqual(args[0], args[1], msg); - break; - case GT: - assertGreaterThan(args[0], args[1], msg); - break; - case NE: - assertNotEquals(args[0], args[1], msg); - break; - case NULL: - assertNull(args == null ? args : args[0], msg); - break; - case NOTNULL: - assertNotNull(args == null ? args : args[0], msg); - break; - case FALSE: - assertFalse((Boolean) args[0], msg); - break; - case TRUE: - assertTrue((Boolean) args[0], msg); - break; - default: - // do nothing - } - } - - public static String format(Assertion assertion, Object ... args) { - switch (assertion) { - case LT: - return asString("assertLessThan", args); - case LTE: - return asString("assertLessThanOrEqual", args); - case EQ: - return asString("assertEquals", args); - case GTE: - return asString("assertGreaterThanOrEquals", args); - case GT: - return asString("assertGreaterThan", args); - case NE: - return asString("assertNotEquals", args); - case NULL: - return asString("assertNull", args); - case NOTNULL: - return asString("assertNotNull", args); - case FALSE: - return asString("assertFalse", args); - case TRUE: - return asString("assertTrue", args); - default: - return ""; - } - } - - private static String asString(String assertion, Object ... args) { - if (args == null) { - return String.format("%s(null)", assertion); - } - if (args.length == 1) { - return String.format("%s(%s)", assertion, args[0]); - } else { - return String.format("%s(%s, %s)", assertion, args[0], args[1]); - } - } -} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/OutputAnalyzerReportingTest.java --- a/test/testlibrary/OutputAnalyzerReportingTest.java Thu Oct 03 19:13:12 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @summary Test the OutputAnalyzer reporting functionality, - * such as printing additional diagnostic info - * (exit code, stdout, stderr, command line, etc.) - * @library /testlibrary - */ - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - - -public class OutputAnalyzerReportingTest { - - public static void main(String[] args) throws Exception { - // Create the output analyzer under test - String stdout = "aaaaaa"; - String stderr = "bbbbbb"; - OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); - - // Expected summary values should be the same for all cases, - // since the outputAnalyzer object is the same - String expectedExitValue = "-1"; - String expectedSummary = - " stdout: [" + stdout + "];\n" + - " stderr: [" + stderr + "]\n" + - " exitValue = " + expectedExitValue + "\n"; - - - DiagnosticSummaryTestRunner testRunner = - new DiagnosticSummaryTestRunner(); - - // should have exit value - testRunner.init(expectedSummary); - int unexpectedExitValue = 2; - try { - output.shouldHaveExitValue(unexpectedExitValue); - } catch (RuntimeException e) { } - testRunner.closeAndCheckResults(); - - // should not contain - testRunner.init(expectedSummary); - try { - output.shouldNotContain(stdout); - } catch (RuntimeException e) { } - testRunner.closeAndCheckResults(); - - // should contain - testRunner.init(expectedSummary); - try { - output.shouldContain("unexpected-stuff"); - } catch (RuntimeException e) { } - testRunner.closeAndCheckResults(); - - // should not match - testRunner.init(expectedSummary); - try { - output.shouldNotMatch("[a]"); - } catch (RuntimeException e) { } - testRunner.closeAndCheckResults(); - - // should match - testRunner.init(expectedSummary); - try { - output.shouldMatch("[qwerty]"); - } catch (RuntimeException e) { } - testRunner.closeAndCheckResults(); - - } - - private static class DiagnosticSummaryTestRunner { - private ByteArrayOutputStream byteStream = - new ByteArrayOutputStream(10000); - - private String expectedSummary = ""; - private PrintStream errStream; - - - public void init(String expectedSummary) { - this.expectedSummary = expectedSummary; - byteStream.reset(); - errStream = new PrintStream(byteStream); - System.setErr(errStream); - } - - public void closeAndCheckResults() { - // check results - errStream.close(); - String stdErrStr = byteStream.toString(); - if (!stdErrStr.contains(expectedSummary)) { - throw new RuntimeException("The output does not contain " - + "the diagnostic message, or the message is incorrect"); - } - } - } - -} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/OutputAnalyzerTest.java --- a/test/testlibrary/OutputAnalyzerTest.java Thu Oct 03 19:13:12 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Test the OutputAnalyzer utility class - * @library /testlibrary - */ - -import com.oracle.java.testlibrary.OutputAnalyzer; - -public class OutputAnalyzerTest { - - public static void main(String args[]) throws Exception { - - String stdout = "aaaaaa"; - String stderr = "bbbbbb"; - - // Regexps used for testing pattern matching of the test input - String stdoutPattern = "[a]"; - String stderrPattern = "[b]"; - String nonExistingPattern = "[c]"; - - OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); - - if (!stdout.equals(output.getStdout())) { - throw new Exception("getStdout() returned '" + output.getStdout() + "', expected '" + stdout + "'"); - } - - if (!stderr.equals(output.getStderr())) { - throw new Exception("getStderr() returned '" + output.getStderr() + "', expected '" + stderr + "'"); - } - - try { - output.shouldContain(stdout); - output.stdoutShouldContain(stdout); - output.shouldContain(stderr); - output.stderrShouldContain(stderr); - } catch (RuntimeException e) { - throw new Exception("shouldContain() failed", e); - } - - try { - output.shouldContain("cccc"); - throw new Exception("shouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stdoutShouldContain(stderr); - throw new Exception("stdoutShouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stderrShouldContain(stdout); - throw new Exception("stdoutShouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.shouldNotContain("cccc"); - output.stdoutShouldNotContain("cccc"); - output.stderrShouldNotContain("cccc"); - } catch (RuntimeException e) { - throw new Exception("shouldNotContain() failed", e); - } - - try { - output.shouldNotContain(stdout); - throw new Exception("shouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stdoutShouldNotContain(stdout); - throw new Exception("shouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stderrShouldNotContain(stderr); - throw new Exception("shouldContain() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - // Should match - try { - output.shouldMatch(stdoutPattern); - output.stdoutShouldMatch(stdoutPattern); - output.shouldMatch(stderrPattern); - output.stderrShouldMatch(stderrPattern); - } catch (RuntimeException e) { - throw new Exception("shouldMatch() failed", e); - } - - try { - output.shouldMatch(nonExistingPattern); - throw new Exception("shouldMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stdoutShouldMatch(stderrPattern); - throw new Exception( - "stdoutShouldMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stderrShouldMatch(stdoutPattern); - throw new Exception( - "stderrShouldMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - // Should not match - try { - output.shouldNotMatch(nonExistingPattern); - output.stdoutShouldNotMatch(nonExistingPattern); - output.stderrShouldNotMatch(nonExistingPattern); - } catch (RuntimeException e) { - throw new Exception("shouldNotMatch() failed", e); - } - - try { - output.shouldNotMatch(stdoutPattern); - throw new Exception("shouldNotMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stdoutShouldNotMatch(stdoutPattern); - throw new Exception("shouldNotMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - try { - output.stderrShouldNotMatch(stderrPattern); - throw new Exception("shouldNotMatch() failed to throw exception"); - } catch (RuntimeException e) { - // expected - } - - { - String aaaa = "aaaa"; - String result = output.firstMatch(aaaa); - if (!aaaa.equals(result)) { - throw new Exception("firstMatch(String) faild to match. Expected: " + aaaa + " got: " + result); - } - } - - { - String aa = "aa"; - String aa_grouped_aa = aa + "(" + aa + ")"; - String result = output.firstMatch(aa_grouped_aa, 1); - if (!aa.equals(result)) { - throw new Exception("firstMatch(String, int) failed to match. Expected: " + aa + " got: " + result); - } - } - } -} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java --- a/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java Mon Oct 21 14:08:09 2013 +0100 @@ -23,20 +23,17 @@ package com.oracle.java.testlibrary; -import java.util.List; import java.util.ArrayList; import java.util.Arrays; - -import com.oracle.java.testlibrary.JDKToolFinder; -import com.oracle.java.testlibrary.ProcessTools; +import java.util.List; /** * A utility for constructing command lines for starting JDK tool processes. * * The JDKToolLauncher can in particular be combined with a - * java.lang.ProcessBuilder to easily run a JDK tool. For example, the - * following code run {@code jmap -heap} against a process with GC logging - * turned on for the {@code jmap} process: + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following + * code run {@code jmap -heap} against a process with GC logging turned on for + * the {@code jmap} process: * *
  * {@code
@@ -55,19 +52,39 @@
     private final List vmArgs = new ArrayList();
     private final List toolArgs = new ArrayList();
 
-    private JDKToolLauncher(String tool) {
-        executable = JDKToolFinder.getJDKTool(tool);
+    private JDKToolLauncher(String tool, boolean useCompilerJDK) {
+        if (useCompilerJDK) {
+            executable = JDKToolFinder.getJDKTool(tool);
+        } else {
+            executable = JDKToolFinder.getCurrentJDKTool(tool);
+        }
         vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs()));
     }
 
     /**
+     * Creates a new JDKToolLauncher for the specified tool. Using tools path
+     * from the compiler JDK.
+     *
+     * @param tool
+     *            The name of the tool
+     * @return A new JDKToolLauncher
+     */
+    public static JDKToolLauncher create(String tool) {
+        return new JDKToolLauncher(tool, true);
+    }
+
+    /**
      * Creates a new JDKToolLauncher for the specified tool.
      *
-     * @param tool The name of the tool
+     * @param tool
+     *            The name of the tool
+     * @param useCompilerPath
+     *            If true use the compiler JDK path, otherwise use the tested
+     *            JDK path.
      * @return A new JDKToolLauncher
      */
-    public static JDKToolLauncher create(String tool) {
-        return new JDKToolLauncher(tool);
+    public static JDKToolLauncher create(String tool, boolean useCompilerJDK) {
+        return new JDKToolLauncher(tool, useCompilerJDK);
     }
 
     /**
@@ -80,7 +97,8 @@
      * automatically added.
      *
      *
-     * @param arg The argument to VM running the tool
+     * @param arg
+     *            The argument to VM running the tool
      * @return The JDKToolLauncher instance
      */
     public JDKToolLauncher addVMArg(String arg) {
@@ -91,7 +109,8 @@
     /**
      * Adds an argument to the tool.
      *
-     * @param arg The argument to the tool
+     * @param arg
+     *            The argument to the tool
      * @return The JDKToolLauncher instance
      */
     public JDKToolLauncher addToolArg(String arg) {
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/com/oracle/java/testlibrary/Platform.java
--- a/test/testlibrary/com/oracle/java/testlibrary/Platform.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/com/oracle/java/testlibrary/Platform.java	Mon Oct 21 14:08:09 2013 +0100
@@ -24,50 +24,80 @@
 package com.oracle.java.testlibrary;
 
 public class Platform {
-  private static final String osName = System.getProperty("os.name");
-  private static final String dataModel = System.getProperty("sun.arch.data.model");
-  private static final String vmVersion = System.getProperty("java.vm.version");
-  private static final String osArch = System.getProperty("os.arch");
+    private static final String osName      = System.getProperty("os.name");
+    private static final String dataModel   = System.getProperty("sun.arch.data.model");
+    private static final String vmVersion   = System.getProperty("java.vm.version");
+    private static final String osArch      = System.getProperty("os.arch");
 
-  public static boolean is64bit() {
-    return dataModel.equals("64");
-  }
+    public static boolean is32bit() {
+        return dataModel.equals("32");
+    }
+
+    public static boolean is64bit() {
+        return dataModel.equals("64");
+    }
+
+    public static boolean isSolaris() {
+        return isOs("sunos");
+    }
 
-  public static boolean isSolaris() {
-    return osName.toLowerCase().startsWith("sunos");
-  }
+    public static boolean isWindows() {
+        return isOs("win");
+    }
+
+    public static boolean isOSX() {
+        return isOs("mac");
+    }
 
-  public static boolean isWindows() {
-    return osName.toLowerCase().startsWith("win");
-  }
+    public static boolean isLinux() {
+        return isOs("linux");
+    }
 
-  public static boolean isOSX() {
-    return osName.toLowerCase().startsWith("mac");
-  }
+    private static boolean isOs(String osname) {
+        return osName.toLowerCase().startsWith(osname.toLowerCase());
+    }
+
+    public static String getOsName() {
+        return osName;
+    }
 
-  public static boolean isLinux() {
-    return osName.toLowerCase().startsWith("linux");
-  }
+    public static boolean isDebugBuild() {
+        return vmVersion.toLowerCase().contains("debug");
+    }
+
+    public static String getVMVersion() {
+        return vmVersion;
+    }
 
-  public static String getOsName() {
-    return osName;
-  }
+    // Returns true for sparc and sparcv9.
+    public static boolean isSparc() {
+        return isArch("sparc");
+    }
 
-  public static boolean isDebugBuild() {
-    return vmVersion.toLowerCase().contains("debug");
-  }
+    public static boolean isARM() {
+        return isArch("arm");
+    }
 
-  public static String getVMVersion() {
-    return vmVersion;
-  }
+    public static boolean isPPC() {
+        return isArch("ppc");
+    }
+
+    public static boolean isX86() {
+        // On Linux it's 'i386', Windows 'x86'
+        return (isArch("i386") || isArch("x86"));
+    }
 
-  // Returns true for sparc and sparcv9.
-  public static boolean isSparc() {
-    return osArch.toLowerCase().startsWith("sparc");
-  }
+    public static boolean isX64() {
+        // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64'
+        return (isArch("amd64") || isArch("x86_64"));
+    }
 
-  public static String getOsArch() {
-    return osArch;
-  }
+    private static boolean isArch(String archname) {
+        return osArch.toLowerCase().startsWith(archname.toLowerCase());
+    }
+
+    public static String getOsArch() {
+        return osArch;
+    }
 
 }
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Mon Oct 21 14:08:09 2013 +0100
@@ -36,8 +36,7 @@
 import java.nio.file.attribute.*;
 
 /**
- * * Handler for dirs containing classes to compile.
- * @author igor.ignatyev@oracle.com
+ * Handler for dirs containing classes to compile.
  */
 public class ClassPathDirEntry extends PathHandler {
 
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Mon Oct 21 14:08:09 2013 +0100
@@ -35,7 +35,6 @@
 
 /**
  * Handler for jar-files containing classes to compile.
- * @author igor.ignatyev@oracle.com
  */
 public class ClassPathJarEntry extends PathHandler {
 
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Mon Oct 21 14:08:09 2013 +0100
@@ -31,8 +31,6 @@
 
 /**
  * Handler for dirs containing jar-files with classes to compile.
- *
- * @author igor.ignatyev@oracle.com
  */
 public class ClassPathJarInDirEntry extends PathHandler {
 
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Mon Oct 21 14:08:09 2013 +0100
@@ -32,8 +32,6 @@
 
 /**
  * Handler for files containing a list of classes to compile.
- *
- * @author igor.ignatyev@oracle.com
  */
 public class ClassesListInFile extends PathHandler {
     public ClassesListInFile(Path root, Executor executor) {
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Mon Oct 21 14:08:09 2013 +0100
@@ -32,9 +32,6 @@
 import java.util.List;
 import java.util.concurrent.*;
 
-/**
- * @author igor.ignatyev@oracle.com
- */
 public class CompileTheWorld {
     /**
      * Entry point. Compiles classes in {@code args}, or all classes in
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Mon Oct 21 14:08:09 2013 +0100
@@ -36,8 +36,6 @@
 /**
  * Provide method to compile whole class.
  * Also contains compiled methods and classes counters.
- *
- * @author igor.ignatyev@oracle.com
  */
 public class Compiler {
     private Compiler() { }
diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java
--- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Thu Oct 03 19:13:12 2013 +0100
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Mon Oct 21 14:08:09 2013 +0100
@@ -35,10 +35,7 @@
 
 /**
  * Abstract handler for path.
- * 

* Concrete subclasses should implement method {@link #process()}. - * - * @author igor.ignatyev@oracle.com */ public abstract class PathHandler { private static final Pattern JAR_IN_DIR_PATTERN diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Thu Oct 03 19:13:12 2013 +0100 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Mon Oct 21 14:08:09 2013 +0100 @@ -31,8 +31,6 @@ /** * Auxiliary methods. - * - * @author igor.ignatyev@oracle.com */ public class Utils { /** diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary_tests/AssertsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/AssertsTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static com.oracle.java.testlibrary.Asserts.*; + +/* @test + * @summary Tests the different assertions in the Assert class + * @library /testlibrary + */ +public class AssertsTest { + private static class Foo implements Comparable { + final int id; + public Foo(int id) { + this.id = id; + } + + public int compareTo(Foo f) { + return new Integer(id).compareTo(new Integer(f.id)); + } + } + + public static void main(String[] args) throws Exception { + testLessThan(); + testLessThanOrEqual(); + testEquals(); + testGreaterThanOrEqual(); + testGreaterThan(); + testNotEquals(); + testNull(); + testNotNull(); + testTrue(); + testFalse(); + } + + private static void testLessThan() throws Exception { + expectPass(Assertion.LT, 1, 2); + + expectFail(Assertion.LT, 2, 2); + expectFail(Assertion.LT, 2, 1); + expectFail(Assertion.LT, null, 2); + expectFail(Assertion.LT, 2, null); + } + + private static void testLessThanOrEqual() throws Exception { + expectPass(Assertion.LTE, 1, 2); + expectPass(Assertion.LTE, 2, 2); + + expectFail(Assertion.LTE, 3, 2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testEquals() throws Exception { + expectPass(Assertion.EQ, 1, 1); + expectPass(Assertion.EQ, null, null); + + Foo f1 = new Foo(1); + expectPass(Assertion.EQ, f1, f1); + + Foo f2 = new Foo(1); + expectFail(Assertion.EQ, f1, f2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testGreaterThanOrEqual() throws Exception { + expectPass(Assertion.GTE, 1, 1); + expectPass(Assertion.GTE, 2, 1); + + expectFail(Assertion.GTE, 1, 2); + expectFail(Assertion.GTE, null, 2); + expectFail(Assertion.GTE, 2, null); + } + + private static void testGreaterThan() throws Exception { + expectPass(Assertion.GT, 2, 1); + + expectFail(Assertion.GT, 1, 1); + expectFail(Assertion.GT, 1, 2); + expectFail(Assertion.GT, null, 2); + expectFail(Assertion.GT, 2, null); + } + + private static void testNotEquals() throws Exception { + expectPass(Assertion.NE, null, 1); + expectPass(Assertion.NE, 1, null); + + Foo f1 = new Foo(1); + Foo f2 = new Foo(1); + expectPass(Assertion.NE, f1, f2); + + expectFail(Assertion.NE, null, null); + expectFail(Assertion.NE, f1, f1); + expectFail(Assertion.NE, 1, 1); + } + + private static void testNull() throws Exception { + expectPass(Assertion.NULL, null); + + expectFail(Assertion.NULL, 1); + } + + private static void testNotNull() throws Exception { + expectPass(Assertion.NOTNULL, 1); + + expectFail(Assertion.NOTNULL, null); + } + + private static void testTrue() throws Exception { + expectPass(Assertion.TRUE, true); + + expectFail(Assertion.TRUE, false); + } + + private static void testFalse() throws Exception { + expectPass(Assertion.FALSE, false); + + expectFail(Assertion.FALSE, true); + } + + private static > void expectPass(Assertion assertion, T ... args) + throws Exception { + Assertion.run(assertion, args); + } + + private static > void expectFail(Assertion assertion, T ... args) + throws Exception { + try { + Assertion.run(assertion, args); + } catch (RuntimeException e) { + return; + } + throw new Exception("Expected " + Assertion.format(assertion, (Object[]) args) + + " to throw a RuntimeException"); + } + +} + +enum Assertion { + LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE; + + public static > void run(Assertion assertion, T ... args) { + String msg = "Expected " + format(assertion, args) + " to pass"; + switch (assertion) { + case LT: + assertLessThan(args[0], args[1], msg); + break; + case LTE: + assertLessThanOrEqual(args[0], args[1], msg); + break; + case EQ: + assertEquals(args[0], args[1], msg); + break; + case GTE: + assertGreaterThanOrEqual(args[0], args[1], msg); + break; + case GT: + assertGreaterThan(args[0], args[1], msg); + break; + case NE: + assertNotEquals(args[0], args[1], msg); + break; + case NULL: + assertNull(args == null ? args : args[0], msg); + break; + case NOTNULL: + assertNotNull(args == null ? args : args[0], msg); + break; + case FALSE: + assertFalse((Boolean) args[0], msg); + break; + case TRUE: + assertTrue((Boolean) args[0], msg); + break; + default: + // do nothing + } + } + + public static String format(Assertion assertion, Object ... args) { + switch (assertion) { + case LT: + return asString("assertLessThan", args); + case LTE: + return asString("assertLessThanOrEqual", args); + case EQ: + return asString("assertEquals", args); + case GTE: + return asString("assertGreaterThanOrEquals", args); + case GT: + return asString("assertGreaterThan", args); + case NE: + return asString("assertNotEquals", args); + case NULL: + return asString("assertNull", args); + case NOTNULL: + return asString("assertNotNull", args); + case FALSE: + return asString("assertFalse", args); + case TRUE: + return asString("assertTrue", args); + default: + return ""; + } + } + + private static String asString(String assertion, Object ... args) { + if (args == null) { + return String.format("%s(null)", assertion); + } + if (args.length == 1) { + return String.format("%s(%s)", assertion, args[0]); + } else { + return String.format("%s(%s, %s)", assertion, args[0], args[1]); + } + } +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary_tests/OutputAnalyzerReportingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/OutputAnalyzerReportingTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @summary Test the OutputAnalyzer reporting functionality, + * such as printing additional diagnostic info + * (exit code, stdout, stderr, command line, etc.) + * @library /testlibrary + */ + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class OutputAnalyzerReportingTest { + + public static void main(String[] args) throws Exception { + // Create the output analyzer under test + String stdout = "aaaaaa"; + String stderr = "bbbbbb"; + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); + + // Expected summary values should be the same for all cases, + // since the outputAnalyzer object is the same + String expectedExitValue = "-1"; + String expectedSummary = + " stdout: [" + stdout + "];\n" + + " stderr: [" + stderr + "]\n" + + " exitValue = " + expectedExitValue + "\n"; + + + DiagnosticSummaryTestRunner testRunner = + new DiagnosticSummaryTestRunner(); + + // should have exit value + testRunner.init(expectedSummary); + int unexpectedExitValue = 2; + try { + output.shouldHaveExitValue(unexpectedExitValue); + } catch (RuntimeException e) { } + testRunner.closeAndCheckResults(); + + // should not contain + testRunner.init(expectedSummary); + try { + output.shouldNotContain(stdout); + } catch (RuntimeException e) { } + testRunner.closeAndCheckResults(); + + // should contain + testRunner.init(expectedSummary); + try { + output.shouldContain("unexpected-stuff"); + } catch (RuntimeException e) { } + testRunner.closeAndCheckResults(); + + // should not match + testRunner.init(expectedSummary); + try { + output.shouldNotMatch("[a]"); + } catch (RuntimeException e) { } + testRunner.closeAndCheckResults(); + + // should match + testRunner.init(expectedSummary); + try { + output.shouldMatch("[qwerty]"); + } catch (RuntimeException e) { } + testRunner.closeAndCheckResults(); + + } + + private static class DiagnosticSummaryTestRunner { + private ByteArrayOutputStream byteStream = + new ByteArrayOutputStream(10000); + + private String expectedSummary = ""; + private PrintStream errStream; + + + public void init(String expectedSummary) { + this.expectedSummary = expectedSummary; + byteStream.reset(); + errStream = new PrintStream(byteStream); + System.setErr(errStream); + } + + public void closeAndCheckResults() { + // check results + errStream.close(); + String stdErrStr = byteStream.toString(); + if (!stdErrStr.contains(expectedSummary)) { + throw new RuntimeException("The output does not contain " + + "the diagnostic message, or the message is incorrect"); + } + } + } + +} diff -r 6fa574bfd32a -r 6795fcebbf42 test/testlibrary_tests/OutputAnalyzerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/OutputAnalyzerTest.java Mon Oct 21 14:08:09 2013 +0100 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the OutputAnalyzer utility class + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class OutputAnalyzerTest { + + public static void main(String args[]) throws Exception { + + String stdout = "aaaaaa"; + String stderr = "bbbbbb"; + + // Regexps used for testing pattern matching of the test input + String stdoutPattern = "[a]"; + String stderrPattern = "[b]"; + String nonExistingPattern = "[c]"; + + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); + + if (!stdout.equals(output.getStdout())) { + throw new Exception("getStdout() returned '" + output.getStdout() + "', expected '" + stdout + "'"); + } + + if (!stderr.equals(output.getStderr())) { + throw new Exception("getStderr() returned '" + output.getStderr() + "', expected '" + stderr + "'"); + } + + try { + output.shouldContain(stdout); + output.stdoutShouldContain(stdout); + output.shouldContain(stderr); + output.stderrShouldContain(stderr); + } catch (RuntimeException e) { + throw new Exception("shouldContain() failed", e); + } + + try { + output.shouldContain("cccc"); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldContain(stderr); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldContain(stdout); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.shouldNotContain("cccc"); + output.stdoutShouldNotContain("cccc"); + output.stderrShouldNotContain("cccc"); + } catch (RuntimeException e) { + throw new Exception("shouldNotContain() failed", e); + } + + try { + output.shouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotContain(stderr); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + // Should match + try { + output.shouldMatch(stdoutPattern); + output.stdoutShouldMatch(stdoutPattern); + output.shouldMatch(stderrPattern); + output.stderrShouldMatch(stderrPattern); + } catch (RuntimeException e) { + throw new Exception("shouldMatch() failed", e); + } + + try { + output.shouldMatch(nonExistingPattern); + throw new Exception("shouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldMatch(stderrPattern); + throw new Exception( + "stdoutShouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldMatch(stdoutPattern); + throw new Exception( + "stderrShouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + // Should not match + try { + output.shouldNotMatch(nonExistingPattern); + output.stdoutShouldNotMatch(nonExistingPattern); + output.stderrShouldNotMatch(nonExistingPattern); + } catch (RuntimeException e) { + throw new Exception("shouldNotMatch() failed", e); + } + + try { + output.shouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotMatch(stderrPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + { + String aaaa = "aaaa"; + String result = output.firstMatch(aaaa); + if (!aaaa.equals(result)) { + throw new Exception("firstMatch(String) faild to match. Expected: " + aaaa + " got: " + result); + } + } + + { + String aa = "aa"; + String aa_grouped_aa = aa + "(" + aa + ")"; + String result = output.firstMatch(aa_grouped_aa, 1); + if (!aa.equals(result)) { + throw new Exception("firstMatch(String, int) failed to match. Expected: " + aa + " got: " + result); + } + } + } +}