# HG changeset patch # User asaha # Date 1270616817 25200 # Node ID 895d9ade6111a096d14d5ea4d37cd2e6b3e11ea7 # Parent 9bb91718aaf2cf802bca0422467e07eb054ac7ce# Parent 09ac706c2623ec689a6adacc26ede6ce467f0cc7 Merge diff -r 09ac706c2623 -r 895d9ade6111 .hgtags --- a/.hgtags Wed Mar 24 17:16:33 2010 -0700 +++ b/.hgtags Tue Apr 06 22:06:57 2010 -0700 @@ -83,3 +83,6 @@ ffc8d176b84bcfb5ac21302b4feb3b0c0d69b97c jdk7-b84 6c9796468b91dcbb39e09dfa1baf9779ac45eb66 jdk7-b85 418bc80ce13995149eadc9eecbba21d7a9fa02ae hs17-b10 +bf823ef06b4f211e66988d76a2e2669be5c0820e jdk7-b86 +07226e9eab8f74b37346b32715f829a2ef2c3188 hs18-b01 +e7e7e36ccdb5d56edd47e5744351202d38f3b7ad jdk7-b87 diff -r 09ac706c2623 -r 895d9ade6111 agent/src/os/linux/libproc_impl.c --- a/agent/src/os/linux/libproc_impl.c Wed Mar 24 17:16:33 2010 -0700 +++ b/agent/src/os/linux/libproc_impl.c Tue Apr 06 22:06:57 2010 -0700 @@ -174,7 +174,7 @@ return NULL; } - newlib->symtab = build_symtab(newlib->fd); + newlib->symtab = build_symtab(newlib->fd, libname); if (newlib->symtab == NULL) { print_debug("symbol table build failed for %s\n", newlib->name); } diff -r 09ac706c2623 -r 895d9ade6111 agent/src/os/linux/symtab.c --- a/agent/src/os/linux/symtab.c Wed Mar 24 17:16:33 2010 -0700 +++ b/agent/src/os/linux/symtab.c Tue Apr 06 22:06:57 2010 -0700 @@ -53,8 +53,274 @@ struct hsearch_data *hash_table; } symtab_t; -// read symbol table from given fd. -struct symtab* build_symtab(int fd) { + +// Directory that contains global debuginfo files. In theory it +// should be possible to change this, but in a Java environment there +// is no obvious place to put a user interface to do it. Maybe this +// could be set with an environment variable. +static const char debug_file_directory[] = "/usr/lib/debug"; + +/* The CRC used in gnu_debuglink, retrieved from + http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ +unsigned int gnu_debuglink_crc32 (unsigned int crc, + unsigned char *buf, size_t len) +{ + static const unsigned int crc32_table[256] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + unsigned char *end; + + crc = ~crc & 0xffffffff; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc & 0xffffffff; +} + +/* Open a debuginfo file and check its CRC. If it exists and the CRC + matches return its fd. */ +static int +open_debug_file (const char *pathname, unsigned int crc) +{ + unsigned int file_crc = 0; + unsigned char buffer[8 * 1024]; + + int fd = pathmap_open(pathname); + + if (fd < 0) + return -1; + + lseek(fd, 0, SEEK_SET); + + for (;;) { + int len = read(fd, buffer, sizeof buffer); + if (len <= 0) + break; + file_crc = gnu_debuglink_crc32(file_crc, buffer, len); + } + + if (crc == file_crc) + return fd; + else { + close(fd); + return -1; + } +} + +/* Find an ELF section. */ +static struct elf_section *find_section_by_name(char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + ELF_SHDR* cursct = NULL; + char *strtab; + int cnt; + + if (scn_cache[ehdr->e_shstrndx].c_data == NULL) { + if ((scn_cache[ehdr->e_shstrndx].c_data + = read_section_data(fd, ehdr, cursct)) == NULL) { + return NULL; + } + } + + strtab = scn_cache[ehdr->e_shstrndx].c_data; + + for (cursct = shbuf, cnt = 0; + cnt < ehdr->e_shnum; + cnt++, cursct++) { + if (strcmp(cursct->sh_name + strtab, name) == 0) { + scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct); + return &scn_cache[cnt]; + } + } + + return NULL; +} + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file. */ +static int open_file_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + int debug_fd; + struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, + shbuf, scn_cache); + if (debug_link == NULL) + return -1; + char *debug_filename = debug_link->c_data; + int offset = (strlen(debug_filename) + 4) >> 2; + static unsigned int crc; + crc = ((unsigned int*)debug_link->c_data)[offset]; + char *debug_pathname = malloc(strlen(debug_filename) + + strlen(name) + + strlen(".debug/") + + strlen(debug_file_directory) + + 2); + strcpy(debug_pathname, name); + char *last_slash = strrchr(debug_pathname, '/'); + if (last_slash == NULL) + return -1; + + /* Look in the same directory as the object. */ + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in a subdirectory named ".debug". */ + strcpy(last_slash+1, ".debug/"); + strcat(last_slash, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in /usr/lib/debug + the full pathname. */ + strcpy(debug_pathname, debug_file_directory); + strcat(debug_pathname, name); + last_slash = strrchr(debug_pathname, '/'); + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + free(debug_pathname); + return -1; +} + +static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo); + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file and read a symbol table from it. */ +static struct symtab *build_symtab_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache); + + if (fd >= 0) { + struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); + close(fd); + return symtab; + } + + return NULL; +} + +// Given a build_id, find the associated debuginfo file +static char * +build_id_to_debug_filename (size_t size, unsigned char *data) +{ + char *filename, *s; + + filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * size + (sizeof ".debug" - 1) + 1); + s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); + if (size > 0) + { + size--; + s += sprintf (s, "%02x", *data++); + } + if (size > 0) + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", *data++); + strcpy (s, ".debug"); + + return filename; +} + +// Read a build ID note. Try to open any associated debuginfo file +// and return its symtab +static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note) +{ + int fd; + struct symtab *symtab = NULL; + + unsigned char *bytes + = (unsigned char*)(note+1) + note->n_namesz; + unsigned char *filename + = (build_id_to_debug_filename (note->n_descsz, bytes)); + + fd = pathmap_open(filename); + if (fd >= 0) { + symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); + close(fd); + } + free(filename); + + return symtab; +} + +// read symbol table from given fd. If try_debuginfo) is true, also +// try to open an associated debuginfo file +static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) { ELF_EHDR ehdr; char *names = NULL; struct symtab* symtab = NULL; @@ -66,6 +332,7 @@ ELF_SHDR* cursct = NULL; ELF_PHDR* phbuf = NULL; ELF_PHDR* phdr = NULL; + int sym_section = SHT_DYNSYM; uintptr_t baseaddr = (uintptr_t)-1; @@ -90,18 +357,23 @@ for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) { scn_cache[cnt].c_shdr = cursct; - if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB) { + if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB + || cursct->sh_type == SHT_NOTE || cursct->sh_type == SHT_DYNSYM) { if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) { goto quit; } } + if (cursct->sh_type == SHT_SYMTAB) { + // Full symbol table available so use that + sym_section = cursct->sh_type; + } cursct++; } for (cnt = 1; cnt < ehdr.e_shnum; cnt++) { ELF_SHDR *shdr = scn_cache[cnt].c_shdr; - if (shdr->sh_type == SHT_SYMTAB) { + if (shdr->sh_type == sym_section) { ELF_SYM *syms; int j, n, rslt; size_t size; @@ -163,6 +435,45 @@ } } + // Look for a separate debuginfo file. + if (try_debuginfo) { + + // We prefer a debug symtab to an object's own symtab, so look in + // the debuginfo file. We stash a copy of the old symtab in case + // there is no debuginfo. + struct symtab* prev_symtab = symtab; + symtab = NULL; + +#ifdef NT_GNU_BUILD_ID + // First we look for a Build ID + for (cursct = shbuf, cnt = 0; + symtab == NULL && cnt < ehdr.e_shnum; + cnt++) { + if (cursct->sh_type == SHT_NOTE) { + Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; + if (note->n_type == NT_GNU_BUILD_ID) { + symtab = build_symtab_from_build_id(note); + } + } + cursct++; + } +#endif + + // Then, if that doesn't work, the debug link + if (symtab == NULL) { + symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf, + scn_cache); + } + + // If we still haven't found a symtab, use the object's own symtab. + if (symtab != NULL) { + if (prev_symtab != NULL) + destroy_symtab(prev_symtab); + } else { + symtab = prev_symtab; + } + } + quit: if (shbuf) free(shbuf); if (phbuf) free(phbuf); @@ -177,6 +488,11 @@ return symtab; } +struct symtab* build_symtab(int fd, const char *filename) { + return build_symtab_internal(fd, filename, /* try_debuginfo */ true); +} + + void destroy_symtab(struct symtab* symtab) { if (!symtab) return; if (symtab->strs) free(symtab->strs); diff -r 09ac706c2623 -r 895d9ade6111 agent/src/os/linux/symtab.h --- a/agent/src/os/linux/symtab.h Wed Mar 24 17:16:33 2010 -0700 +++ b/agent/src/os/linux/symtab.h Tue Apr 06 22:06:57 2010 -0700 @@ -32,7 +32,7 @@ struct symtab; // build symbol table for a given ELF file descriptor -struct symtab* build_symtab(int fd); +struct symtab* build_symtab(int fd, const char *filename); // destroy the symbol table void destroy_symtab(struct symtab* symtab); diff -r 09ac706c2623 -r 895d9ade6111 make/hotspot_version --- a/make/hotspot_version Wed Mar 24 17:16:33 2010 -0700 +++ b/make/hotspot_version Tue Apr 06 22:06:57 2010 -0700 @@ -31,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2009 +HOTSPOT_VM_COPYRIGHT=Copyright 2010 -HS_MAJOR_VER=17 +HS_MAJOR_VER=18 HS_MINOR_VER=0 -HS_BUILD_NUMBER=10 +HS_BUILD_NUMBER=02 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r 09ac706c2623 -r 895d9ade6111 make/linux/makefiles/build_vm_def.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/linux/makefiles/build_vm_def.sh Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,5 @@ +#!/bin/sh + +nm --defined-only $* | awk ' + { if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" } + ' diff -r 09ac706c2623 -r 895d9ade6111 make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Wed Mar 24 17:16:33 2010 -0700 +++ b/make/linux/makefiles/mapfile-vers-debug Tue Apr 06 22:06:57 2010 -0700 @@ -290,6 +290,9 @@ # This is for Forte Analyzer profiling support. AsyncGetCallTrace; + + # INSERT VTABLE SYMBOLS HERE + local: *; }; diff -r 09ac706c2623 -r 895d9ade6111 make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Wed Mar 24 17:16:33 2010 -0700 +++ b/make/linux/makefiles/mapfile-vers-product Tue Apr 06 22:06:57 2010 -0700 @@ -285,6 +285,9 @@ # This is for Forte Analyzer profiling support. AsyncGetCallTrace; + + # INSERT VTABLE SYMBOLS HERE + local: *; }; diff -r 09ac706c2623 -r 895d9ade6111 make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Wed Mar 24 17:16:33 2010 -0700 +++ b/make/linux/makefiles/vm.make Tue Apr 06 22:06:57 2010 -0700 @@ -121,14 +121,21 @@ vm_version.o: $(filter-out vm_version.o,$(JVM_OBJ_FILES)) -mapfile : $(MAPFILE) +mapfile : $(MAPFILE) vm.def rm -f $@ - cat $^ > $@ + awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE") \ + { system ("cat vm.def"); } \ + else \ + { print $$0 } \ + }' > $@ < $(MAPFILE) mapfile_reorder : mapfile $(REORDERFILE) rm -f $@ cat $^ > $@ +vm.def: $(Res_Files) $(Obj_Files) + sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@ + ifeq ($(ZERO_LIBARCH), ppc64) STATIC_CXX = false else diff -r 09ac706c2623 -r 895d9ade6111 make/windows/build.bat --- a/make/windows/build.bat Wed Mar 24 17:16:33 2010 -0700 +++ b/make/windows/build.bat Tue Apr 06 22:06:57 2010 -0700 @@ -28,6 +28,9 @@ REM Since we don't have uname and we could be cross-compiling, REM Use the compiler to determine which ARCH we are building REM +REM Note: Running this batch file from the Windows command shell requires +REM that "grep" be accessible on the PATH. An MKS install does this. +REM cl 2>&1 | grep "IA-64" >NUL if %errorlevel% == 0 goto isia64 cl 2>&1 | grep "AMD64" >NUL @@ -57,11 +60,12 @@ if "%1" == "product" goto test1 if "%1" == "debug" goto test1 if "%1" == "fastdebug" goto test1 +if "%1" == "tree" goto test1 goto usage :test1 if "%2" == "core" goto test2 -if "%2" == "kernel" goto test2 +if "%2" == "kernel" goto test2 if "%2" == "compiler1" goto test2 if "%2" == "compiler2" goto test2 if "%2" == "tiered" goto test2 @@ -70,6 +74,7 @@ goto usage :test2 +if "%1" == "tree" goto build_tree REM check_j2se_version REM jvmti.make requires J2SE 1.4.x or newer. REM If not found then fail fast. @@ -93,6 +98,10 @@ nmake -f %3/make/windows/build.make Variant=compiler2 WorkSpace=%3 BootStrapDir=%4 BuildUser="%USERNAME%" HOTSPOT_BUILD_VERSION=%5 ADLC_ONLY=1 %1 goto end +:build_tree +nmake -f %3/make/windows/build.make Variant=%2 WorkSpace=%3 BootStrapDir=%4 BuildUser="%USERNAME%" HOTSPOT_BUILD_VERSION="%5" %1 +goto end + :usage echo Usage: build flavor version workspace bootstrap_dir [build_id] [windbg_home] echo. @@ -100,8 +109,10 @@ echo flavor is "product", "debug" or "fastdebug", echo version is "core", "kernel", "compiler1", "compiler2", or "tiered", echo workspace is source directory without trailing slash, -echo bootstrap_dir is a full path to echo a JDK in which bin/java -echo and bin/javac are present and working, and echo build_id is an +echo bootstrap_dir is a full path to a JDK in which bin/java +echo and bin/javac are present and working, and build_id is an echo optional build identifier displayed by java -version +exit /b 1 :end +exit /b %errorlevel% diff -r 09ac706c2623 -r 895d9ade6111 make/windows/build.make --- a/make/windows/build.make Wed Mar 24 17:16:33 2010 -0700 +++ b/make/windows/build.make Tue Apr 06 22:06:57 2010 -0700 @@ -27,6 +27,9 @@ # environment variables (Variant, WorkSpace, BootStrapDir, BuildUser, HOTSPOT_BUILD_VERSION) # are passed in as command line arguments. +# Note: Running nmake or build.bat from the Windows command shell requires +# that "sh" be accessible on the PATH. An MKS install does this. + # SA components are built if BUILD_WIN_SA=1 is specified. # See notes in README. This produces files: # 1. sa-jdi.jar - This is built before building jvm.dll @@ -233,6 +236,12 @@ cd $(variantDir) nmake -nologo -f $(WorkSpace)\make\windows\makefiles\top.make BUILD_FLAVOR=product DEVELOP=1 ARCH=$(ARCH) +# target to create just the directory structure +tree: checks $(variantDir) $(variantDir)\local.make sanity + mkdir $(variantDir)\product + mkdir $(variantDir)\debug + mkdir $(variantDir)\fastdebug + sanity: @ echo; @ cd $(variantDir) diff -r 09ac706c2623 -r 895d9ade6111 make/windows/create.bat --- a/make/windows/create.bat Wed Mar 24 17:16:33 2010 -0700 +++ b/make/windows/create.bat Tue Apr 06 22:06:57 2010 -0700 @@ -36,6 +36,9 @@ REM Since we don't have uname and we could be cross-compiling, REM Use the compiler to determine which ARCH we are building REM +REM Note: Running this batch file from the Windows command shell requires +REM that "grep" be accessible on the PATH. An MKS install does this. +REM cl 2>&1 | grep "IA-64" >NUL if %errorlevel% == 0 goto isia64 cl 2>&1 | grep "AMD64" >NUL diff -r 09ac706c2623 -r 895d9ade6111 make/windows/get_msc_ver.sh --- a/make/windows/get_msc_ver.sh Wed Mar 24 17:16:33 2010 -0700 +++ b/make/windows/get_msc_ver.sh Tue Apr 06 22:06:57 2010 -0700 @@ -22,6 +22,8 @@ # # +set -e + # This shell script echoes "MSC_VER=" # It ignores the micro version component. # Examples: @@ -38,17 +40,20 @@ # sh, and it has been found that sometimes `which sh` fails. if [ "x$HotSpotMksHome" != "x" ]; then - MKS_HOME="$HotSpotMksHome" + TOOL_DIR="$HotSpotMksHome" else - SH=`which sh` - MKS_HOME=`dirname "$SH"` + # HotSpotMksHome is not set so use the directory that contains "sh". + # This works with both MKS and Cygwin. + SH=`which sh` + TOOL_DIR=`dirname "$SH"` fi -HEAD="$MKS_HOME/head" -ECHO="$MKS_HOME/echo" -EXPR="$MKS_HOME/expr" -CUT="$MKS_HOME/cut" -SED="$MKS_HOME/sed" +DIRNAME="$TOOL_DIR/dirname" +HEAD="$TOOL_DIR/head" +ECHO="$TOOL_DIR/echo" +EXPR="$TOOL_DIR/expr" +CUT="$TOOL_DIR/cut" +SED="$TOOL_DIR/sed" if [ "x$FORCE_MSC_VER" != "x" ]; then echo "MSC_VER=$FORCE_MSC_VER" @@ -70,7 +75,15 @@ if [ "x$FORCE_LINK_VER" != "x" ]; then echo "LINK_VER=$FORCE_LINK_VER" else - LINK_VER_RAW=`link 2>&1 | "$HEAD" -n 1 | "$SED" 's/.*Version[\ ]*\([0-9][0-9.]*\).*/\1/'` + # use the "link" command that is co-located with the "cl" command + cl_cmd=`which cl` + if [ "x$cl_cmd" != "x" ]; then + link_cmd=`$DIRNAME "$cl_cmd"`/link + else + # which can't find "cl" so just use which ever "link" we find + link_cmd="link" + fi + LINK_VER_RAW=`"$link_cmd" 2>&1 | "$HEAD" -n 1 | "$SED" 's/.*Version[\ ]*\([0-9][0-9.]*\).*/\1/'` LINK_VER_MAJOR=`"$ECHO" $LINK_VER_RAW | "$CUT" -d'.' -f1` LINK_VER_MINOR=`"$ECHO" $LINK_VER_RAW | "$CUT" -d'.' -f2` LINK_VER_MICRO=`"$ECHO" $LINK_VER_RAW | "$CUT" -d'.' -f3` diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -377,6 +377,16 @@ } + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + __ call(SharedRuntime::deopt_blob()->unpack_with_reexecution()); + __ delayed()->nop(); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + + void ArrayCopyStub::emit_code(LIR_Assembler* ce) { //---------------slow case: call to native----------------- __ bind(_entry); diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/c1_FrameMap_sparc.hpp --- a/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,3 +143,6 @@ static bool is_caller_save_register (LIR_Opr reg); static bool is_caller_save_register (Register r); + + // JSR 292 + static LIR_Opr& method_handle_invoke_SP_save_opr() { return L7_opr; } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -378,12 +378,7 @@ int offset = code_offset(); - if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) { - __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - } - - __ call(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type); + __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type); __ delayed()->nop(); debug_only(__ stop("should have gone to the caller");) assert(code_offset() - offset <= exception_handler_size, "overflow"); @@ -685,29 +680,29 @@ } -void LIR_Assembler::call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info) { - __ call(entry, rtype); +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + __ call(op->addr(), rtype); // the peephole pass fills the delay slot } -void LIR_Assembler::ic_call(address entry, CodeEmitInfo* info) { +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { RelocationHolder rspec = virtual_call_Relocation::spec(pc()); __ set_oop((jobject)Universe::non_oop_word(), G5_inline_cache_reg); __ relocate(rspec); - __ call(entry, relocInfo::none); + __ call(op->addr(), relocInfo::none); // the peephole pass fills the delay slot } -void LIR_Assembler::vtable_call(int vtable_offset, CodeEmitInfo* info) { - add_debug_info_for_null_check_here(info); +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { + add_debug_info_for_null_check_here(op->info()); __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), G3_scratch); - if (__ is_simm13(vtable_offset) ) { - __ ld_ptr(G3_scratch, vtable_offset, G5_method); + if (__ is_simm13(op->vtable_offset())) { + __ ld_ptr(G3_scratch, op->vtable_offset(), G5_method); } else { // This will generate 2 instructions - __ set(vtable_offset, G5_method); + __ set(op->vtable_offset(), G5_method); // ld_ptr, set_hi, set __ ld_ptr(G3_scratch, G5_method, G5_method); } @@ -717,6 +712,16 @@ } +void LIR_Assembler::preserve_SP(LIR_OpJavaCall* op) { + Unimplemented(); +} + + +void LIR_Assembler::restore_SP(LIR_OpJavaCall* op) { + Unimplemented(); +} + + // load with 32-bit displacement int LIR_Assembler::load(Register s, int disp, Register d, BasicType ld_type, CodeEmitInfo *info) { int load_offset = code_offset(); @@ -1067,7 +1072,8 @@ LIR_Const* c = src->as_constant_ptr(); switch (c->type()) { case T_INT: - case T_FLOAT: { + case T_FLOAT: + case T_ADDRESS: { Register src_reg = O7; int value = c->as_jint_bits(); if (value == 0) { @@ -1123,7 +1129,8 @@ } switch (c->type()) { case T_INT: - case T_FLOAT: { + case T_FLOAT: + case T_ADDRESS: { LIR_Opr tmp = FrameMap::O7_opr; int value = c->as_jint_bits(); if (value == 0) { @@ -1195,6 +1202,7 @@ switch (c->type()) { case T_INT: + case T_ADDRESS: { jint con = c->as_jint(); if (to_reg->is_single_cpu()) { diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,17 +42,6 @@ } -void C1_MacroAssembler::method_exit(bool restore_frame) { - // this code must be structured this way so that the return - // instruction can be a safepoint. - if (restore_frame) { - restore(); - } - retl(); - delayed()->nop(); -} - - void C1_MacroAssembler::explicit_null_check(Register base) { Unimplemented(); } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -677,7 +677,7 @@ __ add(I7, frame::pc_return_offset, Oissuing_pc->after_save()); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - Oissuing_pc->after_save()); + G2_thread, Oissuing_pc->after_save()); __ verify_not_null_oop(Oexception->after_save()); __ jmp(O0, 0); __ delayed()->restore(); @@ -985,7 +985,6 @@ void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_maps, OopMap* oop_map, bool) { Label no_deopt; - Label no_handler; __ verify_not_null_oop(Oexception); @@ -1003,9 +1002,14 @@ // whether it had a handler or not we will deoptimize // by entering the deopt blob with a pending exception. +#ifdef ASSERT + Label done; __ tst(O0); - __ br(Assembler::zero, false, Assembler::pn, no_handler); + __ br(Assembler::notZero, false, Assembler::pn, done); __ delayed()->nop(); + __ stop("should have found address"); + __ bind(done); +#endif // restore the registers that were saved at the beginning and jump to the exception handler. restore_live_registers(sasm); @@ -1013,20 +1017,6 @@ __ jmp(O0, 0); __ delayed()->restore(); - __ bind(no_handler); - __ mov(L0, I7); // restore return address - - // restore exception oop - __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), Oexception->after_save()); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset())); - - __ restore(); - - AddressLiteral exc(Runtime1::entry_for(Runtime1::unwind_exception_id)); - __ jump_to(exc, G4); - __ delayed()->nop(); - - oop_maps->add_gc_map(call_offset, oop_map); } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -244,9 +244,10 @@ } -void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) { +void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) { mov(arg_1, O0); - MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 1); + mov(arg_2, O1); + MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 2); } #endif /* CC_INTERP */ diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ bool check_exception = true); #ifndef CC_INTERP - void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1); + void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2); // Generate a subtype check: branch to ok_is_subtype if sub_klass is // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3. diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/sparc.ad Tue Apr 06 22:06:57 2010 -0700 @@ -1803,8 +1803,9 @@ // to implement the UseStrictFP mode. const bool Matcher::strict_fp_requires_explicit_rounding = false; -// Do floats take an entire double register or just half? -const bool Matcher::float_in_double = false; +// Are floats conerted to double when stored to stack during deoptimization? +// Sparc does not handle callee-save floats. +bool Matcher::float_in_double() { return false; } // Do ints take an entire long register or just half? // Note that we if-def off of _LP64. diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -379,7 +379,7 @@ __ save_frame(0); // compensates for compiler weakness __ add(O7->after_save(), frame::pc_return_offset, Lscratch); // save the issuing PC BLOCK_COMMENT("call exception_handler_for_return_address"); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), Lscratch); + __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), G2_thread, Lscratch); __ mov(O0, handler_reg); __ restore(); // compensates for compiler weakness diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/stubRoutines_sparc.hpp --- a/src/cpu/sparc/vm/stubRoutines_sparc.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/stubRoutines_sparc.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,13 @@ enum /* platform_dependent_constants */ { // %%%%%%%% May be able to shrink this a lot - code_size1 = 20000, // simply increase if too small (assembler will crash if too small) - code_size2 = 20000 // simply increase if too small (assembler will crash if too small) + code_size1 = 20000, // simply increase if too small (assembler will crash if too small) + code_size2 = 20000 // simply increase if too small (assembler will crash if too small) +}; + +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 5000 }; class Sparc { diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1822,7 +1822,7 @@ __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller __ super_call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - Oissuing_pc->after_save()); + G2_thread, Oissuing_pc->after_save()); // The caller's SP was adjusted upon method entry to accomodate // the callee's non-argument locals. Undo that adjustment. diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/assembler_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -8460,6 +8460,7 @@ subptr(str1, result); // Restore counter shrl(str1, 1); addl(cnt1, str1); + decrementl(cnt1); lea(str1, Address(result, 2)); // Reload string // Load substr diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -373,6 +373,14 @@ } +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + __ call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack_with_reexecution())); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + + void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); __ bind(_entry); diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/c1_FrameMap_x86.hpp --- a/src/cpu/x86/vm/c1_FrameMap_x86.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/c1_FrameMap_x86.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,3 +126,6 @@ assert(i >= 0 && i < nof_caller_save_xmm_regs, "out of bounds"); return _caller_save_xmm_regs[i]; } + + // JSR 292 + static LIR_Opr& method_handle_invoke_SP_save_opr() { return rbp_opr; } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -436,40 +436,18 @@ int offset = code_offset(); - // if the method does not have an exception handler, then there is - // no reason to search for one - if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) { - // the exception oop and pc are in rax, and rdx - // no other registers need to be preserved, so invalidate them - __ invalidate_registers(false, true, true, false, true, true); - - // check that there is really an exception - __ verify_not_null_oop(rax); - - // search an exception handler (rax: exception oop, rdx: throwing pc) - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_nofpu_id))); - - // if the call returns here, then the exception handler for particular - // exception doesn't exist -> unwind activation and forward exception to caller - } - - // the exception oop is in rax, + // the exception oop and pc are in rax, and rdx // no other registers need to be preserved, so invalidate them - __ invalidate_registers(false, true, true, true, true, true); + __ invalidate_registers(false, true, true, false, true, true); // check that there is really an exception __ verify_not_null_oop(rax); - // unlock the receiver/klass if necessary - // rax,: exception - ciMethod* method = compilation()->method(); - if (method->is_synchronized() && GenerateSynchronizationCode) { - monitorexit(FrameMap::rbx_oop_opr, FrameMap::rcx_opr, SYNC_header, 0, rax); - } - - // unwind activation and forward exception to caller - // rax,: exception - __ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); + // search an exception handler (rax: exception oop, rdx: throwing pc) + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_nofpu_id))); + + __ stop("should not reach here"); + assert(code_offset() - offset <= exception_handler_size, "overflow"); __ end_a_stub(); @@ -495,8 +473,10 @@ int offset = code_offset(); InternalAddress here(__ pc()); + __ pushptr(here.addr()); __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + assert(code_offset() - offset <= deopt_handler_size, "overflow"); __ end_a_stub(); @@ -593,7 +573,7 @@ } // Pop the stack before the safepoint code - __ leave(); + __ remove_frame(initial_frame_size_in_bytes()); bool result_is_oop = result->is_valid() ? result->is_oop() : false; @@ -648,7 +628,8 @@ LIR_Const* c = src->as_constant_ptr(); switch (c->type()) { - case T_INT: { + case T_INT: + case T_ADDRESS: { assert(patch_code == lir_patch_none, "no patching handled here"); __ movl(dest->as_register(), c->as_jint()); break; @@ -731,6 +712,7 @@ switch (c->type()) { case T_INT: // fall through case T_FLOAT: + case T_ADDRESS: __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jint_bits()); break; @@ -766,6 +748,7 @@ switch (type) { case T_INT: // fall through case T_FLOAT: + case T_ADDRESS: __ movl(as_Address(addr), c->as_jint_bits()); break; @@ -2738,6 +2721,7 @@ switch (code) { case lir_static_call: case lir_optvirtual_call: + case lir_dynamic_call: offset += NativeCall::displacement_offset; break; case lir_icvirtual_call: @@ -2753,30 +2737,41 @@ } -void LIR_Assembler::call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info) { +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0, "must be aligned"); - __ call(AddressLiteral(entry, rtype)); - add_call_info(code_offset(), info); + __ call(AddressLiteral(op->addr(), rtype)); + add_call_info(code_offset(), op->info(), op->is_method_handle_invoke()); } -void LIR_Assembler::ic_call(address entry, CodeEmitInfo* info) { +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { RelocationHolder rh = virtual_call_Relocation::spec(pc()); __ movoop(IC_Klass, (jobject)Universe::non_oop_word()); assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0, "must be aligned"); - __ call(AddressLiteral(entry, rh)); - add_call_info(code_offset(), info); + __ call(AddressLiteral(op->addr(), rh)); + add_call_info(code_offset(), op->info(), op->is_method_handle_invoke()); } /* Currently, vtable-dispatch is only enabled for sparc platforms */ -void LIR_Assembler::vtable_call(int vtable_offset, CodeEmitInfo* info) { +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { ShouldNotReachHere(); } + +void LIR_Assembler::preserve_SP(LIR_OpJavaCall* op) { + __ movptr(FrameMap::method_handle_invoke_SP_save_opr()->as_register(), rsp); +} + + +void LIR_Assembler::restore_SP(LIR_OpJavaCall* op) { + __ movptr(rsp, FrameMap::method_handle_invoke_SP_save_opr()->as_register()); +} + + void LIR_Assembler::emit_static_call_stub() { address call_pc = __ pc(); address stub = __ start_a_stub(call_stub_size); @@ -2829,10 +2824,12 @@ } else { unwind_id = Runtime1::handle_exception_nofpu_id; } + __ call(RuntimeAddress(Runtime1::entry_for(unwind_id))); } else { - unwind_id = Runtime1::unwind_exception_id; + // remove the activation + __ remove_frame(initial_frame_size_in_bytes()); + __ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); } - __ call(RuntimeAddress(Runtime1::entry_for(unwind_id))); // enough room for two byte trap __ nop(); diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/c1_MacroAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -317,14 +317,6 @@ } -void C1_MacroAssembler::method_exit(bool restore_frame) { - if (restore_frame) { - leave(); - } - ret(0); -} - - void C1_MacroAssembler::build_frame(int frame_size_in_bytes) { // Make sure there is enough stack space for this method's activation. // Note that we do this before doing an enter(). This matches the @@ -333,7 +325,7 @@ // between the two compilers. generate_stack_overflow_check(frame_size_in_bytes); - enter(); + push(rbp); #ifdef TIERED // c2 leaves fpu stack dirty. Clean it on entry if (UseSSE < 2 ) { @@ -344,6 +336,12 @@ } +void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) { + increment(rsp, frame_size_in_bytes); // Does not emit code for frame_size == 0 + pop(rbp); +} + + void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) { if (C1Breakpoint) int3(); inline_cache_check(receiver, ic_klass); diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -688,18 +688,21 @@ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); oop_maps->add_gc_map(call_offset, oop_map); - // rax,: handler address or NULL if no handler exists + // rax,: handler address // will be the deopt blob if nmethod was deoptimized while we looked up // handler regardless of whether handler existed in the nmethod. // only rax, is valid at this time, all other registers have been destroyed by the runtime call __ invalidate_registers(false, true, true, true, true, true); +#ifdef ASSERT // Do we have an exception handler in the nmethod? - Label no_handler; Label done; __ testptr(rax, rax); - __ jcc(Assembler::zero, no_handler); + __ jcc(Assembler::notZero, done); + __ stop("no handler found"); + __ bind(done); +#endif // exception handler found // patch the return address -> the stub will directly return to the exception handler @@ -712,36 +715,14 @@ __ leave(); __ ret(0); - __ bind(no_handler); - // no exception handler found in this method, so the exception is - // forwarded to the caller (using the unwind code of the nmethod) - // there is no need to restore the registers - - // restore the real return address that was saved before the RT-call - __ movptr(real_return_addr, Address(rsp, temp_1_off * VMRegImpl::stack_slot_size)); - __ movptr(Address(rbp, 1*BytesPerWord), real_return_addr); - - // load address of JavaThread object for thread-local data - NOT_LP64(__ get_thread(thread);) - // restore exception oop into rax, (convention for unwind code) - __ movptr(exception_oop, Address(thread, JavaThread::exception_oop_offset())); - - // clear exception fields in JavaThread because they are no longer needed - // (fields must be cleared because they are processed by GC otherwise) - __ movptr(Address(thread, JavaThread::exception_oop_offset()), NULL_WORD); - __ movptr(Address(thread, JavaThread::exception_pc_offset()), NULL_WORD); - - // pop the stub frame off - __ leave(); - - generate_unwind_exception(sasm); - __ stop("should not reach here"); } void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // incoming parameters const Register exception_oop = rax; + // callee-saved copy of exception_oop during runtime call + const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14); // other registers used in this stub const Register exception_pc = rdx; const Register handler_addr = rbx; @@ -769,38 +750,39 @@ // clear the FPU stack in case any FPU results are left behind __ empty_FPU_stack(); - // leave activation of nmethod - __ leave(); - // store return address (is on top of stack after leave) + // save exception_oop in callee-saved register to preserve it during runtime calls + __ verify_not_null_oop(exception_oop); + __ movptr(exception_oop_callee_saved, exception_oop); + + NOT_LP64(__ get_thread(thread);) + // Get return address (is on top of stack after leave). __ movptr(exception_pc, Address(rsp, 0)); - __ verify_oop(exception_oop); - - // save exception oop from rax, to stack before call - __ push(exception_oop); + // search the exception handler address of the caller (using the return address) + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); + // rax: exception handler address of the caller - // search the exception handler address of the caller (using the return address) - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), exception_pc); - // rax,: exception handler address of the caller - - // only rax, is valid at this time, all other registers have been destroyed by the call - __ invalidate_registers(false, true, true, true, true, true); + // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call. + __ invalidate_registers(false, true, true, true, false, true); // move result of call into correct register __ movptr(handler_addr, rax); - // restore exception oop in rax, (required convention of exception handler) - __ pop(exception_oop); + // Restore exception oop to RAX (required convention of exception handler). + __ movptr(exception_oop, exception_oop_callee_saved); - __ verify_oop(exception_oop); + // verify that there is really a valid exception in rax + __ verify_not_null_oop(exception_oop); // get throwing pc (= return address). // rdx has been destroyed by the call, so it must be set again // the pop is also necessary to simulate the effect of a ret(0) __ pop(exception_pc); - // verify that that there is really a valid exception in rax, - __ verify_not_null_oop(exception_oop); + // Restore SP from BP if the exception PC is a MethodHandle call site. + NOT_LP64(__ get_thread(thread);) + __ cmpl(Address(thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); // continue at exception handler (return address removed) // note: do *not* remove arguments when unwinding the @@ -808,9 +790,9 @@ // all arguments on the stack when entering the // runtime to determine the exception handler // (GC happens at call site with arguments!) - // rax,: exception oop + // rax: exception oop // rdx: throwing pc - // rbx,: exception handler + // rbx: exception handler __ jmp(handler_addr); } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,13 +60,13 @@ } #ifdef ASSERT -static void verify_argslot(MacroAssembler* _masm, Register rax_argslot, +static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, const char* error_message) { // Verify that argslot lies within (rsp, rbp]. Label L_ok, L_bad; - __ cmpptr(rax_argslot, rbp); + __ cmpptr(argslot_reg, rbp); __ jccb(Assembler::above, L_bad); - __ cmpptr(rsp, rax_argslot); + __ cmpptr(rsp, argslot_reg); __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop(error_message); @@ -178,22 +178,6 @@ // Now move the argslot down, to point to the opened-up space. __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); - - if (TaggedStackInterpreter && arg_mask != _INSERT_NO_MASK) { - // The caller has specified a bitmask of tags to put into the opened space. - // This only works when the arg_slots value is an assembly-time constant. - int constant_arg_slots = arg_slots.as_constant() / stack_move_unit(); - int tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes(); - for (int slot = 0; slot < constant_arg_slots; slot++) { - BasicType slot_type = ((arg_mask & (1 << slot)) == 0 ? T_OBJECT : T_INT); - int slot_offset = Interpreter::stackElementSize() * slot; - Address tag_addr(rax_argslot, slot_offset + tag_offset); - __ movptr(tag_addr, frame::tag_for_basic_type(slot_type)); - } - // Note that the new argument slots are tagged properly but contain - // garbage at this point. The value portions must be initialized - // by the caller. (Especially references!) - } } // Helper to remove argument slots from the stack. @@ -206,18 +190,9 @@ (!arg_slots.is_register() ? rsp : arg_slots.as_register())); #ifdef ASSERT - { - // Verify that [argslot..argslot+size) lies within (rsp, rbp). - Label L_ok, L_bad; - __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); - __ cmpptr(rbx_temp, rbp); - __ jccb(Assembler::above, L_bad); - __ cmpptr(rsp, rax_argslot); - __ jccb(Assembler::below, L_ok); - __ bind(L_bad); - __ stop("deleted argument(s) must fall within current frame"); - __ bind(L_ok); - } + // Verify that [argslot..argslot+size) lies within (rsp, rbp). + __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); + verify_argslot(_masm, rbx_temp, "deleted argument(s) must fall within current frame"); if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); @@ -321,12 +296,6 @@ Address rcx_amh_conversion( rcx_recv, sun_dyn_AdapterMethodHandle::conversion_offset_in_bytes() ); Address vmarg; // __ argument_address(vmargslot) - int tag_offset = -1; - if (TaggedStackInterpreter) { - tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes(); - assert(tag_offset = wordSize, "stack grows as expected"); - } - const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes(); if (have_entry(ek)) { @@ -372,11 +341,8 @@ __ mov(rsp, rsi); // cut the stack back to where the caller started // Repush the arguments as if coming from the interpreter. - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_INT)); __ push(rdx_code); - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT)); __ push(rcx_fail); - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT)); __ push(rax_want); Register rbx_method = rbx_temp; @@ -397,7 +363,6 @@ // Do something that is at least causes a valid throw from the interpreter. __ bind(no_method); __ pop(rax_want); - if (TaggedStackInterpreter) __ pop(rcx_fail); __ pop(rcx_fail); __ push(rax_want); __ push(rcx_fail); @@ -510,18 +475,10 @@ case _bound_long_direct_mh: { bool direct_to_method = (ek >= _bound_ref_direct_mh); - BasicType arg_type = T_ILLEGAL; - if (ek == _bound_long_mh || ek == _bound_long_direct_mh) { - arg_type = T_LONG; - } else if (ek == _bound_int_mh || ek == _bound_int_direct_mh) { - arg_type = T_INT; - } else { - assert(ek == _bound_ref_mh || ek == _bound_ref_direct_mh, "must be ref"); - arg_type = T_OBJECT; - } - int arg_slots = type2size[arg_type]; - int arg_mask = (arg_type == T_OBJECT ? _INSERT_REF_MASK : - arg_slots == 1 ? _INSERT_INT_MASK : _INSERT_LONG_MASK); + BasicType arg_type = T_ILLEGAL; + int arg_mask = _INSERT_NO_MASK; + int arg_slots = -1; + get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots); // make room for the new argument: __ movl(rax_argslot, rcx_bmh_vmargslot); @@ -584,7 +541,7 @@ Label done; __ movptr(rdx_temp, vmarg); - __ testl(rdx_temp, rdx_temp); + __ testptr(rdx_temp, rdx_temp); __ jccb(Assembler::zero, done); // no cast if null __ load_klass(rdx_temp, rdx_temp); @@ -660,13 +617,10 @@ } break; default: - assert(false, ""); + ShouldNotReachHere(); } - goto finish_int_conversion; - } - finish_int_conversion: - { + // Do the requested conversion and store the value. Register rbx_vminfo = rbx_temp; __ movl(rbx_vminfo, rcx_amh_conversion); assert(CONV_VMINFO_SHIFT == 0, "preshifted"); @@ -692,7 +646,7 @@ __ shrl(rdx_temp /*, rcx*/); __ bind(done); - __ movl(vmarg, rdx_temp); + __ movl(vmarg, rdx_temp); // Store the value. __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv __ jump_to_method_handle_entry(rcx_recv, rdx_temp); @@ -715,9 +669,14 @@ switch (ek) { case _adapter_opt_i2l: { +#ifdef _LP64 + __ movslq(rdx_temp, vmarg1); // Load sign-extended + __ movq(vmarg1, rdx_temp); // Store into first slot +#else __ movl(rdx_temp, vmarg1); - __ sarl(rdx_temp, 31); // __ extend_sign() + __ sarl(rdx_temp, BitsPerInt - 1); // __ extend_sign() __ movl(vmarg2, rdx_temp); // store second word +#endif } break; case _adapter_opt_unboxl: @@ -727,14 +686,19 @@ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG); assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), ""); __ null_check(rdx_temp, value_offset); +#ifdef _LP64 + __ movq(rbx_temp, Address(rdx_temp, value_offset)); + __ movq(vmarg1, rbx_temp); +#else __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt)); __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt)); __ movl(vmarg1, rbx_temp); __ movl(vmarg2, rdx_temp); +#endif } break; default: - assert(false, ""); + ShouldNotReachHere(); } __ movptr(rcx_recv, rcx_mh_vmtarget); @@ -768,20 +732,9 @@ if (ek == _adapter_opt_f2d) { __ fld_s(vmarg); // load float to ST0 __ fstp_s(vmarg); // store single - } else if (!TaggedStackInterpreter) { + } else { __ fld_d(vmarg); // load double to ST0 __ fstp_s(vmarg); // store single - } else { - Address vmarg_tag = vmarg.plus_disp(tag_offset); - Address vmarg2 = vmarg.plus_disp(Interpreter::stackElementSize()); - // vmarg2_tag does not participate in this code - Register rbx_tag = rbx_temp; - __ movl(rbx_tag, vmarg_tag); // preserve tag - __ movl(rdx_temp, vmarg2); // get second word of double - __ movl(vmarg_tag, rdx_temp); // align with first word - __ fld_d(vmarg); // load double to ST0 - __ movl(vmarg_tag, rbx_tag); // restore tag - __ fstp_s(vmarg); // store single } #endif //_LP64 @@ -812,19 +765,8 @@ case _adapter_opt_rot_2_up: case _adapter_opt_rot_2_down: { - int rotate = 0, swap_slots = 0; - switch ((int)ek) { - case _adapter_opt_swap_1: swap_slots = 1; break; - case _adapter_opt_swap_2: swap_slots = 2; break; - case _adapter_opt_rot_1_up: swap_slots = 1; rotate++; break; - case _adapter_opt_rot_1_down: swap_slots = 1; rotate--; break; - case _adapter_opt_rot_2_up: swap_slots = 2; rotate++; break; - case _adapter_opt_rot_2_down: swap_slots = 2; rotate--; break; - default: assert(false, ""); - } - - // the real size of the move must be doubled if TaggedStackInterpreter: - int swap_bytes = (int)( swap_slots * Interpreter::stackElementWords() * wordSize ); + int swap_bytes = 0, rotate = 0; + get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate); // 'argslot' is the position of the first argument to swap __ movl(rax_argslot, rcx_amh_vmargslot); @@ -925,8 +867,8 @@ // 'stack_move' is negative number of words to duplicate Register rdx_stack_move = rdx_temp; - __ movl(rdx_stack_move, rcx_amh_conversion); - __ sarl(rdx_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdx_stack_move, rcx_amh_conversion); + __ sarptr(rdx_stack_move, CONV_STACK_MOVE_SHIFT); int argslot0_num = 0; Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num)); @@ -988,8 +930,8 @@ // 'stack_move' is number of words to drop Register rdi_stack_move = rdi; - __ movl(rdi_stack_move, rcx_amh_conversion); - __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdi_stack_move, rcx_amh_conversion); + __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); remove_arg_slots(_masm, rdi_stack_move, rax_argslot, rbx_temp, rdx_temp); @@ -1014,11 +956,7 @@ case _adapter_opt_spread_more: { // spread an array out into a group of arguments - int length_constant = -1; - switch (ek) { - case _adapter_opt_spread_0: length_constant = 0; break; - case _adapter_opt_spread_1: length_constant = 1; break; - } + int length_constant = get_ek_adapter_opt_spread_info(ek); // find the address of the array argument __ movl(rax_argslot, rcx_amh_vmargslot); @@ -1079,8 +1017,8 @@ __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize())); // 'stack_move' is negative number of words to insert Register rdi_stack_move = rdi; - __ movl(rdi_stack_move, rcx_amh_conversion); - __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdi_stack_move, rcx_amh_conversion); + __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); Register rsi_temp = rsi_array; // spill this insert_arg_slots(_masm, rdi_stack_move, -1, rax_argslot, rbx_temp, rsi_temp); @@ -1114,10 +1052,6 @@ __ movptr(rbx_temp, Address(rsi_source, 0)); __ movptr(Address(rax_argslot, 0), rbx_temp); __ addptr(rsi_source, type2aelembytes(elem_type)); - if (TaggedStackInterpreter) { - __ movptr(Address(rax_argslot, tag_offset), - frame::tag_for_basic_type(elem_type)); - } __ addptr(rax_argslot, Interpreter::stackElementSize()); __ cmpptr(rax_argslot, rdx_argslot_limit); __ jccb(Assembler::less, loop); @@ -1131,11 +1065,7 @@ __ movptr(rbx_temp, Address(rsi_array, elem_offset)); __ movptr(Address(rax_argslot, slot_offset), rbx_temp); elem_offset += type2aelembytes(elem_type); - if (TaggedStackInterpreter) { - __ movptr(Address(rax_argslot, slot_offset + tag_offset), - frame::tag_for_basic_type(elem_type)); - } - slot_offset += Interpreter::stackElementSize(); + slot_offset += Interpreter::stackElementSize(); } } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -369,7 +369,7 @@ // The pending exception in Thread is converted into a Java-level exception. // // Contract with Java-level exception handlers: - // rax,: exception + // rax: exception // rdx: throwing pc // // NOTE: At entry of this stub, exception-pc must be on stack !! @@ -377,6 +377,12 @@ address generate_forward_exception() { StubCodeMark mark(this, "StubRoutines", "forward exception"); address start = __ pc(); + const Register thread = rcx; + + // other registers used in this stub + const Register exception_oop = rax; + const Register handler_addr = rbx; + const Register exception_pc = rdx; // Upon entry, the sp points to the return address returning into Java // (interpreted or compiled) code; i.e., the return address becomes the @@ -389,8 +395,8 @@ #ifdef ASSERT // make sure this code is only executed if there is a pending exception { Label L; - __ get_thread(rcx); - __ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD); + __ get_thread(thread); + __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (1)"); __ bind(L); @@ -398,33 +404,40 @@ #endif // compute exception handler into rbx, - __ movptr(rax, Address(rsp, 0)); + __ get_thread(thread); + __ movptr(exception_pc, Address(rsp, 0)); BLOCK_COMMENT("call exception_handler_for_return_address"); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rax); - __ mov(rbx, rax); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); + __ mov(handler_addr, rax); - // setup rax, & rdx, remove return address & clear pending exception - __ get_thread(rcx); - __ pop(rdx); - __ movptr(rax, Address(rcx, Thread::pending_exception_offset())); - __ movptr(Address(rcx, Thread::pending_exception_offset()), NULL_WORD); + // setup rax & rdx, remove return address & clear pending exception + __ get_thread(thread); + __ pop(exception_pc); + __ movptr(exception_oop, Address(thread, Thread::pending_exception_offset())); + __ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); #ifdef ASSERT // make sure exception is set { Label L; - __ testptr(rax, rax); + __ testptr(exception_oop, exception_oop); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (2)"); __ bind(L); } #endif + // Verify that there is really a valid exception in RAX. + __ verify_oop(exception_oop); + + // Restore SP from BP if the exception PC is a MethodHandle call site. + __ cmpl(Address(thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); + // continue at exception handler (return address removed) - // rax,: exception - // rbx,: exception handler + // rax: exception + // rbx: exception handler // rdx: throwing pc - __ verify_oop(rax); - __ jmp(rbx); + __ jmp(handler_addr); return start; } @@ -2263,16 +2276,6 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // generic method handle stubs - if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) { - for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; - ek < MethodHandles::_EK_LIMIT; - ek = MethodHandles::EntryKind(1 + (int)ek)) { - StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek); - } - } - generate_math_stubs(); } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -466,7 +466,7 @@ BLOCK_COMMENT("call exception_handler_for_return_address"); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - c_rarg0); + r15_thread, c_rarg0); __ mov(rbx, rax); // setup rax & rdx, remove return address & clear pending exception @@ -3009,16 +3009,6 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // generic method handle stubs - if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) { - for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; - ek < MethodHandles::_EK_LIMIT; - ek = MethodHandles::EntryKind(1 + (int)ek)) { - StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek); - } - } - generate_math_stubs(); } diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/stubRoutines_x86_32.hpp --- a/src/cpu/x86/vm/stubRoutines_x86_32.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/stubRoutines_x86_32.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,11 @@ code_size2 = 22000 // simply increase if too small (assembler will crash if too small) }; +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 5000 +}; + class x86 { friend class StubGenerator; friend class VMStructs; diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/stubRoutines_x86_64.hpp --- a/src/cpu/x86/vm/stubRoutines_x86_64.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/stubRoutines_x86_64.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,14 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _call_stub_return_address; } -enum platform_dependent_constants -{ - code_size1 = 19000, // simply increase if too small (assembler will - // crash if too small) - code_size2 = 22000 // simply increase if too small (assembler will - // crash if too small) +enum platform_dependent_constants { + code_size1 = 19000, // simply increase if too small (assembler will crash if too small) + code_size2 = 22000 // simply increase if too small (assembler will crash if too small) +}; + +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 13000 }; class x86 { diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1550,6 +1550,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // Entry point in previous activation (i.e., if the caller was interpreted) Interpreter::_rethrow_exception_entry = __ pc(); + const Register thread = rcx; // Restore sp to interpreter_frame_last_sp even though we are going // to empty the expression stack for the exception processing. @@ -1598,10 +1599,10 @@ // Set the popframe_processing bit in pending_popframe_condition indicating that we are // currently handling popframe, so that call_VMs that may happen later do not trigger new // popframe handling cycles. - __ get_thread(rcx); - __ movl(rdx, Address(rcx, JavaThread::popframe_condition_offset())); + __ get_thread(thread); + __ movl(rdx, Address(thread, JavaThread::popframe_condition_offset())); __ orl(rdx, JavaThread::popframe_processing_bit); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), rdx); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), rdx); { // Check to see whether we are returning to a deoptimized frame. @@ -1629,8 +1630,8 @@ __ subptr(rdi, rax); __ addptr(rdi, wordSize); // Save these arguments - __ get_thread(rcx); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), rcx, rax, rdi); + __ get_thread(thread); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), thread, rax, rdi); __ remove_activation(vtos, rdx, /* throw_monitor_exception */ false, @@ -1638,8 +1639,8 @@ /* notify_jvmdi */ false); // Inform deoptimization that it is responsible for restoring these arguments - __ get_thread(rcx); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), JavaThread::popframe_force_deopt_reexecution_bit); + __ get_thread(thread); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_force_deopt_reexecution_bit); // Continue in deoptimization handler __ jmp(rdx); @@ -1665,12 +1666,12 @@ // expression stack if necessary. __ mov(rax, rsp); __ movptr(rbx, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize)); - __ get_thread(rcx); + __ get_thread(thread); // PC must point into interpreter here - __ set_last_Java_frame(rcx, noreg, rbp, __ pc()); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), rcx, rax, rbx); - __ get_thread(rcx); - __ reset_last_Java_frame(rcx, true, true); + __ set_last_Java_frame(thread, noreg, rbp, __ pc()); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), thread, rax, rbx); + __ get_thread(thread); + __ reset_last_Java_frame(thread, true, true); // Restore the last_sp and null it out __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize)); __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); @@ -1684,8 +1685,8 @@ } // Clear the popframe condition flag - __ get_thread(rcx); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), JavaThread::popframe_inactive); + __ get_thread(thread); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_inactive); __ dispatch_next(vtos); // end of PopFrame support @@ -1694,27 +1695,27 @@ // preserve exception over this code sequence __ pop_ptr(rax); - __ get_thread(rcx); - __ movptr(Address(rcx, JavaThread::vm_result_offset()), rax); + __ get_thread(thread); + __ movptr(Address(thread, JavaThread::vm_result_offset()), rax); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, rdx, false, true, false); // restore exception - __ get_thread(rcx); - __ movptr(rax, Address(rcx, JavaThread::vm_result_offset())); - __ movptr(Address(rcx, JavaThread::vm_result_offset()), NULL_WORD); + __ get_thread(thread); + __ movptr(rax, Address(thread, JavaThread::vm_result_offset())); + __ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD); __ verify_oop(rax); // Inbetween activations - previous activation type unknown yet // compute continuation point - the continuation point expects // the following registers set up: // - // rax,: exception + // rax: exception // rdx: return address/pc that threw exception // rsp: expression stack of caller - // rbp,: rbp, of caller + // rbp: rbp, of caller __ push(rax); // save exception __ push(rdx); // save return address - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rdx); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, rdx); __ mov(rbx, rax); // save exception handler __ pop(rdx); // restore return address __ pop(rax); // restore exception @@ -1728,6 +1729,7 @@ // address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { address entry = __ pc(); + const Register thread = rcx; __ restore_bcp(); __ restore_locals(); @@ -1735,8 +1737,8 @@ __ empty_FPU_stack(); __ load_earlyret_value(state); - __ get_thread(rcx); - __ movptr(rcx, Address(rcx, JavaThread::jvmti_thread_state_offset())); + __ get_thread(thread); + __ movptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset())); const Address cond_addr(rcx, JvmtiThreadState::earlyret_state_offset()); // Clear the earlyret state diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1741,7 +1741,7 @@ __ push(rdx); // save return address __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - rdx); + r15_thread, rdx); __ mov(rbx, rax); // save exception handler __ pop(rdx); // restore return address __ pop(rax); // restore exception diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2915,12 +2915,8 @@ __ andl(recv, 0xFF); // recv count is 0 based? Address recv_addr(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)); - if (is_invokedynamic) { - __ lea(recv, recv_addr); - } else { - __ movptr(recv, recv_addr); - __ verify_oop(recv); - } + __ movptr(recv, recv_addr); + __ verify_oop(recv); } // do null check if needed diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2860,12 +2860,8 @@ __ andl(recv, 0xFF); if (TaggedStackInterpreter) __ shll(recv, 1); // index*2 Address recv_addr(rsp, recv, Address::times_8, -Interpreter::expr_offset_in_bytes(1)); - if (is_invokedynamic) { - __ lea(recv, recv_addr); - } else { - __ movptr(recv, recv_addr); - __ verify_oop(recv); - } + __ movptr(recv, recv_addr); + __ verify_oop(recv); } // do null check if needed diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/x86_32.ad Tue Apr 06 22:06:57 2010 -0700 @@ -1444,8 +1444,10 @@ // to implement the UseStrictFP mode. const bool Matcher::strict_fp_requires_explicit_rounding = true; -// Do floats take an entire double register or just half? -const bool Matcher::float_in_double = true; +// Are floats conerted to double when stored to stack during deoptimization? +// On x32 it is stored with convertion only when FPU is used for floats. +bool Matcher::float_in_double() { return (UseSSE == 0); } + // Do ints take an entire long register or just half? const bool Matcher::int_in_long = false; diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Tue Apr 06 22:06:57 2010 -0700 @@ -2074,8 +2074,10 @@ // implement the UseStrictFP mode. const bool Matcher::strict_fp_requires_explicit_rounding = true; -// Do floats take an entire double register or just half? -const bool Matcher::float_in_double = true; +// Are floats conerted to double when stored to stack during deoptimization? +// On x64 it is stored without convertion so we can use normal access. +bool Matcher::float_in_double() { return false; } + // Do ints take an entire long register or just half? const bool Matcher::int_in_long = true; diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -206,7 +206,6 @@ // Update the invocation counter if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) { - thread->set_do_not_unlock(); InvocationCounter *counter = method->invocation_counter(); counter->increment(); if (counter->reached_InvocationLimit()) { @@ -215,7 +214,6 @@ if (HAS_PENDING_EXCEPTION) goto unwind_and_return; } - thread->clr_do_not_unlock(); } // Lock if necessary diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/zero/vm/methodHandles_zero.cpp --- a/src/cpu/zero/vm/methodHandles_zero.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/zero/vm/methodHandles_zero.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,6 +1,6 @@ /* * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2009 Red Hat, Inc. + * Copyright 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,4 +23,10 @@ * */ -// This file is intentionally empty +#include "incls/_precompiled.incl" +#include "incls/_methodHandles_zero.cpp.incl" + +void MethodHandles::generate_method_handle_stub(MacroAssembler* masm, + MethodHandles::EntryKind ek) { + ShouldNotCallThis(); +} diff -r 09ac706c2623 -r 895d9ade6111 src/cpu/zero/vm/stubRoutines_zero.hpp --- a/src/cpu/zero/vm/stubRoutines_zero.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/cpu/zero/vm/stubRoutines_zero.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,6 +1,6 @@ /* * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008, 2009 Red Hat, Inc. + * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,10 @@ code_size2 = 0 // if these are too small. Simply increase }; // them if that happens. + enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 0 + }; + #ifdef IA32 class x86 { friend class VMStructs; diff -r 09ac706c2623 -r 895d9ade6111 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os/linux/vm/os_linux.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -22,6 +22,8 @@ * */ +# define __STDC_FORMAT_MACROS + // do not include precompiled header file # include "incls/_os_linux.cpp.incl" @@ -53,6 +55,8 @@ # include # include # include +# include +# include #define MAX_PATH (2 * K) @@ -2492,6 +2496,91 @@ != MAP_FAILED; } +// Linux uses a growable mapping for the stack, and if the mapping for +// the stack guard pages is not removed when we detach a thread the +// stack cannot grow beyond the pages where the stack guard was +// mapped. If at some point later in the process the stack expands to +// that point, the Linux kernel cannot expand the stack any further +// because the guard pages are in the way, and a segfault occurs. +// +// However, it's essential not to split the stack region by unmapping +// a region (leaving a hole) that's already part of the stack mapping, +// so if the stack mapping has already grown beyond the guard pages at +// the time we create them, we have to truncate the stack mapping. +// So, we need to know the extent of the stack mapping when +// create_stack_guard_pages() is called. + +// Find the bounds of the stack mapping. Return true for success. +// +// We only need this for stacks that are growable: at the time of +// writing thread stacks don't use growable mappings (i.e. those +// creeated with MAP_GROWSDOWN), and aren't marked "[stack]", so this +// only applies to the main thread. +static bool +get_stack_bounds(uintptr_t *bottom, uintptr_t *top) +{ + FILE *f = fopen("/proc/self/maps", "r"); + if (f == NULL) + return false; + + while (!feof(f)) { + size_t dummy; + char *str = NULL; + ssize_t len = getline(&str, &dummy, f); + if (len == -1) { + fclose(f); + return false; + } + + if (len > 0 && str[len-1] == '\n') { + str[len-1] = 0; + len--; + } + + static const char *stack_str = "[stack]"; + if (len > (ssize_t)strlen(stack_str) + && (strcmp(str + len - strlen(stack_str), stack_str) == 0)) { + if (sscanf(str, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) { + uintptr_t sp = (uintptr_t)__builtin_frame_address(0); + if (sp >= *bottom && sp <= *top) { + free(str); + fclose(f); + return true; + } + } + } + free(str); + } + fclose(f); + return false; +} + +// If the (growable) stack mapping already extends beyond the point +// where we're going to put our guard pages, truncate the mapping at +// that point by munmap()ping it. This ensures that when we later +// munmap() the guard pages we don't leave a hole in the stack +// mapping. +bool os::create_stack_guard_pages(char* addr, size_t size) { + uintptr_t stack_extent, stack_base; + if (get_stack_bounds(&stack_extent, &stack_base)) { + if (stack_extent < (uintptr_t)addr) + ::munmap((void*)stack_extent, (uintptr_t)addr - stack_extent); + } + + return os::commit_memory(addr, size); +} + +// If this is a growable mapping, remove the guard pages entirely by +// munmap()ping them. If not, just call uncommit_memory(). +bool os::remove_stack_guard_pages(char* addr, size_t size) { + uintptr_t stack_extent, stack_base; + if (get_stack_bounds(&stack_extent, &stack_base)) { + return ::munmap(addr, size) == 0; + } + + return os::uncommit_memory(addr, size); +} + static address _highest_vm_reserved_address = NULL; // If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory diff -r 09ac706c2623 -r 895d9ade6111 src/os/solaris/dtrace/hotspot.d --- a/src/os/solaris/dtrace/hotspot.d Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os/solaris/dtrace/hotspot.d Tue Apr 06 22:06:57 2010 -0700 @@ -25,9 +25,20 @@ provider hotspot { probe class__loaded(char*, uintptr_t, void*, uintptr_t); probe class__unloaded(char*, uintptr_t, void*, uintptr_t); + probe class__initialization__required(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__recursive(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__concurrent(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__erroneous(char*, uintptr_t, void*, intptr_t, int); + probe class__initialization__super__failed(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__clinit(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__error(char*, uintptr_t, void*, intptr_t,int); + probe class__initialization__end(char*, uintptr_t, void*, intptr_t,int); probe vm__init__begin(); probe vm__init__end(); probe vm__shutdown(); + probe vmops__request(char*, uintptr_t, int); + probe vmops__begin(char*, uintptr_t, int); + probe vmops__end(char*, uintptr_t, int); probe gc__begin(uintptr_t); probe gc__end(); probe mem__pool__gc__begin( @@ -38,6 +49,12 @@ uintptr_t, uintptr_t, uintptr_t, uintptr_t); probe thread__start(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); probe thread__stop(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + probe thread__sleep__begin(long long); + probe thread__sleep__end(int); + probe thread__yield(); + probe thread__park__begin(uintptr_t, int, long long); + probe thread__park__end(uintptr_t); + probe thread__unpark(uintptr_t); probe method__compile__begin( char*, uintptr_t, char*, uintptr_t, char*, uintptr_t, char*, uintptr_t); probe method__compile__end( diff -r 09ac706c2623 -r 895d9ade6111 src/os/solaris/vm/attachListener_solaris.cpp --- a/src/os/solaris/vm/attachListener_solaris.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os/solaris/vm/attachListener_solaris.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -668,13 +668,18 @@ } } - if (strcmp(name, "ExtendedDTraceProbes") != 0) { - out->print_cr("flag '%s' cannot be changed", name); - return JNI_ERR; + if (strcmp(name, "ExtendedDTraceProbes") == 0) { + DTrace::set_extended_dprobes(flag); + return JNI_OK; } - DTrace::set_extended_dprobes(flag); - return JNI_OK; + if (strcmp(name, "DTraceMonitorProbes") == 0) { + DTrace::set_monitor_dprobes(flag); + return JNI_OK; + } + + out->print_cr("flag '%s' cannot be changed", name); + return JNI_ERR; } void AttachListener::pd_detachall() { diff -r 09ac706c2623 -r 895d9ade6111 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2698,6 +2698,14 @@ } } +bool os::create_stack_guard_pages(char* addr, size_t size) { + return os::commit_memory(addr, size); +} + +bool os::remove_stack_guard_pages(char* addr, size_t size) { + return os::uncommit_memory(addr, size); +} + // Change the page size in a given range. void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned."); diff -r 09ac706c2623 -r 895d9ade6111 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os/windows/vm/os_windows.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2803,6 +2803,14 @@ return VirtualFree(addr, 0, MEM_RELEASE) != 0; } +bool os::create_stack_guard_pages(char* addr, size_t size) { + return os::commit_memory(addr, size); +} + +bool os::remove_stack_guard_pages(char* addr, size_t size) { + return os::uncommit_memory(addr, size); +} + // Set protections specified bool os::protect_memory(char* addr, size_t bytes, ProtType prot, bool is_committed) { diff -r 09ac706c2623 -r 895d9ade6111 src/os_cpu/linux_zero/vm/globals_linux_zero.hpp --- a/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,6 +1,6 @@ /* * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,10 @@ // define_pd_global(bool, DontYieldALot, false); +define_pd_global(intx, ThreadStackSize, 1536); #ifdef _LP64 -define_pd_global(intx, ThreadStackSize, 1536); define_pd_global(intx, VMThreadStackSize, 1024); #else -define_pd_global(intx, ThreadStackSize, 1024); define_pd_global(intx, VMThreadStackSize, 512); #endif // _LP64 define_pd_global(intx, SurvivorRatio, 8); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,11 +222,15 @@ } } else { LoadField* lf = x->array()->as_LoadField(); - if (lf != NULL && lf->field()->is_constant()) { - ciObject* c = lf->field()->constant_value().as_object(); - if (c->is_array()) { - ciArray* array = (ciArray*) c; - set_constant(array->length()); + if (lf != NULL) { + ciField* field = lf->field(); + if (field->is_constant() && field->is_static()) { + // final static field + ciObject* c = field->constant_value().as_object(); + if (c->is_array()) { + ciArray* array = (ciArray*) c; + set_constant(array->length()); + } } } } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -415,6 +415,28 @@ }; +//------------------------------------------------------------------------------ +// DeoptimizeStub +// +class DeoptimizeStub : public CodeStub { +private: + CodeEmitInfo* _info; + +public: + DeoptimizeStub(CodeEmitInfo* info) : _info(new CodeEmitInfo(info)) {} + + virtual void emit_code(LIR_Assembler* e); + virtual CodeEmitInfo* info() const { return _info; } + virtual bool is_exception_throw_stub() const { return true; } + virtual void visit(LIR_OpVisitState* visitor) { + visitor->do_slow_case(_info); + } +#ifndef PRODUCT + virtual void print_name(outputStream* out) const { out->print("DeoptimizeStub"); } +#endif // PRODUCT +}; + + class SimpleExceptionStub: public CodeStub { private: LIR_Opr _obj; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1524,18 +1524,14 @@ code = Bytecodes::_invokespecial; } - if (code == Bytecodes::_invokedynamic) { - BAILOUT("invokedynamic NYI"); // FIXME - return; - } - // NEEDS_CLEANUP // I've added the target-is_loaded() test below but I don't really understand // how klass->is_loaded() can be true and yet target->is_loaded() is false. // this happened while running the JCK invokevirtual tests under doit. TKR ciMethod* cha_monomorphic_target = NULL; ciMethod* exact_target = NULL; - if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded()) { + if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() && + !target->is_method_handle_invoke()) { Value receiver = NULL; ciInstanceKlass* receiver_klass = NULL; bool type_is_exact = false; @@ -1681,11 +1677,20 @@ CHECK_BAILOUT(); // inlining not successful => standard invoke - bool is_static = code == Bytecodes::_invokestatic; + bool is_loaded = target->is_loaded(); + bool has_receiver = + code == Bytecodes::_invokespecial || + code == Bytecodes::_invokevirtual || + code == Bytecodes::_invokeinterface; + bool is_invokedynamic = code == Bytecodes::_invokedynamic; ValueType* result_type = as_ValueType(target->return_type()); + + // We require the debug info to be the "state before" because + // invokedynamics may deoptimize. + ValueStack* state_before = is_invokedynamic ? state()->copy() : NULL; + Values* args = state()->pop_arguments(target->arg_size_no_receiver()); - Value recv = is_static ? NULL : apop(); - bool is_loaded = target->is_loaded(); + Value recv = has_receiver ? apop() : NULL; int vtable_index = methodOopDesc::invalid_vtable_index; #ifdef SPARC @@ -1723,7 +1728,7 @@ profile_call(recv, target_klass); } - Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target); + Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before); // push result append_split(result); @@ -2862,20 +2867,18 @@ _initial_state = state_at_entry(); start_block->merge(_initial_state); - BlockBegin* sync_handler = NULL; - if (method()->is_synchronized() || _compilation->env()->dtrace_method_probes()) { - // setup an exception handler to do the unlocking and/or notification - sync_handler = new BlockBegin(-1); - sync_handler->set(BlockBegin::exception_entry_flag); - sync_handler->set(BlockBegin::is_on_work_list_flag); - sync_handler->set(BlockBegin::default_exception_handler_flag); - - ciExceptionHandler* desc = new ciExceptionHandler(method()->holder(), 0, method()->code_size(), -1, 0); - XHandler* h = new XHandler(desc); - h->set_entry_block(sync_handler); - scope_data()->xhandlers()->append(h); - scope_data()->set_has_handler(); - } + // setup an exception handler to do the unlocking and/or + // notification and unwind the frame. + BlockBegin* sync_handler = new BlockBegin(-1); + sync_handler->set(BlockBegin::exception_entry_flag); + sync_handler->set(BlockBegin::is_on_work_list_flag); + sync_handler->set(BlockBegin::default_exception_handler_flag); + + ciExceptionHandler* desc = new ciExceptionHandler(method()->holder(), 0, method()->code_size(), -1, 0); + XHandler* h = new XHandler(desc); + h->set_entry_block(sync_handler); + scope_data()->xhandlers()->append(h); + scope_data()->set_has_handler(); // complete graph _vmap = new ValueMap(); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_IR.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,10 +259,10 @@ } -void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset) { +void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool is_method_handle_invoke) { // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); - _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/); + _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/, is_method_handle_invoke); recorder->end_safepoint(pc_offset); } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_IR.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,7 +242,7 @@ //Whether we should reexecute this bytecode for deopt bool should_reexecute(); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost) { + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost, bool is_method_handle_invoke = false) { if (caller() != NULL) { // Order is significant: Must record caller first. caller()->record_debug_info(recorder, pc_offset, false/*topmost*/); @@ -252,7 +252,6 @@ DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; - bool is_method_handle_invoke = false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } @@ -303,7 +302,7 @@ int bci() const { return _bci; } void add_register_oop(LIR_Opr opr); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool is_method_handle_invoke = false); CodeEmitInfo* next() const { return _next; } void set_next(CodeEmitInfo* next) { _next = next; } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_Instruction.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -334,13 +334,14 @@ Invoke::Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args, - int vtable_index, ciMethod* target) + int vtable_index, ciMethod* target, ValueStack* state_before) : StateSplit(result_type) , _code(code) , _recv(recv) , _args(args) , _vtable_index(vtable_index) , _target(target) + , _state_before(state_before) { set_flag(TargetIsLoadedFlag, target->is_loaded()); set_flag(TargetIsFinalFlag, target_is_loaded() && target->is_final_method()); @@ -355,6 +356,9 @@ _signature = new BasicTypeList(number_of_arguments() + (has_receiver() ? 1 : 0)); if (has_receiver()) { _signature->append(as_BasicType(receiver()->type())); + } else if (is_invokedynamic()) { + // Add the synthetic MethodHandle argument to the signature. + _signature->append(T_OBJECT); } for (int i = 0; i < number_of_arguments(); i++) { ValueType* t = argument_at(i)->type(); @@ -364,6 +368,13 @@ } +void Invoke::state_values_do(void f(Value*)) { + StateSplit::state_values_do(f); + if (state_before() != NULL) state_before()->values_do(f); + if (state() != NULL) state()->values_do(f); +} + + // Implementation of Contant intx Constant::hash() const { if (_state == NULL) { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_Instruction.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1134,17 +1134,18 @@ LEAF(Invoke, StateSplit) private: - Bytecodes::Code _code; - Value _recv; - Values* _args; - BasicTypeList* _signature; - int _vtable_index; - ciMethod* _target; + Bytecodes::Code _code; + Value _recv; + Values* _args; + BasicTypeList* _signature; + int _vtable_index; + ciMethod* _target; + ValueStack* _state_before; // Required for deoptimization. public: // creation Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args, - int vtable_index, ciMethod* target); + int vtable_index, ciMethod* target, ValueStack* state_before); // accessors Bytecodes::Code code() const { return _code; } @@ -1155,6 +1156,7 @@ int vtable_index() const { return _vtable_index; } BasicTypeList* signature() const { return _signature; } ciMethod* target() const { return _target; } + ValueStack* state_before() const { return _state_before; } // Returns false if target is not loaded bool target_is_final() const { return check_flag(TargetIsFinalFlag); } @@ -1162,6 +1164,9 @@ // Returns false if target is not loaded bool target_is_strictfp() const { return check_flag(TargetIsStrictfpFlag); } + // JSR 292 support + bool is_invokedynamic() const { return code() == Bytecodes::_invokedynamic; } + // generic virtual bool can_trap() const { return true; } virtual void input_values_do(void f(Value*)) { @@ -1169,6 +1174,7 @@ if (has_receiver()) f(&_recv); for (int i = 0; i < _args->length(); i++) f(_args->adr_at(i)); } + virtual void state_values_do(void f(Value*)); }; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LIR.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ return LIR_OprFact::oopConst(type->as_ObjectType()->encoding()); } } - case addressTag: return LIR_OprFact::intConst(type->as_AddressConstant()->value()); + case addressTag: return LIR_OprFact::addressConst(type->as_AddressConstant()->value()); case intTag : return LIR_OprFact::intConst(type->as_IntConstant()->value()); case floatTag : return LIR_OprFact::floatConst(type->as_FloatConstant()->value()); case longTag : return LIR_OprFact::longConst(type->as_LongConstant()->value()); @@ -89,7 +89,7 @@ LIR_Opr LIR_OprFact::dummy_value_type(ValueType* type) { switch (type->tag()) { case objectTag: return LIR_OprFact::oopConst(NULL); - case addressTag: + case addressTag:return LIR_OprFact::addressConst(0); case intTag: return LIR_OprFact::intConst(0); case floatTag: return LIR_OprFact::floatConst(0.0); case longTag: return LIR_OprFact::longConst(0); @@ -689,9 +689,10 @@ case lir_static_call: case lir_optvirtual_call: case lir_icvirtual_call: - case lir_virtual_call: { - assert(op->as_OpJavaCall() != NULL, "must be"); - LIR_OpJavaCall* opJavaCall = (LIR_OpJavaCall*)op; + case lir_virtual_call: + case lir_dynamic_call: { + LIR_OpJavaCall* opJavaCall = op->as_OpJavaCall(); + assert(opJavaCall != NULL, "must be"); if (opJavaCall->_receiver->is_valid()) do_input(opJavaCall->_receiver); @@ -704,6 +705,7 @@ } if (opJavaCall->_info) do_info(opJavaCall->_info); + if (opJavaCall->is_method_handle_invoke()) do_temp(FrameMap::method_handle_invoke_SP_save_opr()); do_call(); if (opJavaCall->_result->is_valid()) do_output(opJavaCall->_result); @@ -1410,6 +1412,7 @@ // LIR_Address void LIR_Const::print_value_on(outputStream* out) const { switch (type()) { + case T_ADDRESS:out->print("address:%d",as_jint()); break; case T_INT: out->print("int:%d", as_jint()); break; case T_LONG: out->print("lng:%lld", as_jlong()); break; case T_FLOAT: out->print("flt:%f", as_jfloat()); break; @@ -1590,6 +1593,7 @@ case lir_optvirtual_call: s = "optvirtual"; break; case lir_icvirtual_call: s = "icvirtual"; break; case lir_virtual_call: s = "virtual"; break; + case lir_dynamic_call: s = "dynamic"; break; // LIR_OpArrayCopy case lir_arraycopy: s = "arraycopy"; break; // LIR_OpLock diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LIR.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -85,9 +85,10 @@ void type_check(BasicType t) const { assert(type() == t, "type check"); } void type_check(BasicType t1, BasicType t2) const { assert(type() == t1 || type() == t2, "type check"); } + void type_check(BasicType t1, BasicType t2, BasicType t3) const { assert(type() == t1 || type() == t2 || type() == t3, "type check"); } public: - LIR_Const(jint i) { _value.set_type(T_INT); _value.set_jint(i); } + LIR_Const(jint i, bool is_address=false) { _value.set_type(is_address?T_ADDRESS:T_INT); _value.set_jint(i); } LIR_Const(jlong l) { _value.set_type(T_LONG); _value.set_jlong(l); } LIR_Const(jfloat f) { _value.set_type(T_FLOAT); _value.set_jfloat(f); } LIR_Const(jdouble d) { _value.set_type(T_DOUBLE); _value.set_jdouble(d); } @@ -105,7 +106,7 @@ virtual BasicType type() const { return _value.get_type(); } virtual LIR_Const* as_constant() { return this; } - jint as_jint() const { type_check(T_INT ); return _value.get_jint(); } + jint as_jint() const { type_check(T_INT, T_ADDRESS); return _value.get_jint(); } jlong as_jlong() const { type_check(T_LONG ); return _value.get_jlong(); } jfloat as_jfloat() const { type_check(T_FLOAT ); return _value.get_jfloat(); } jdouble as_jdouble() const { type_check(T_DOUBLE); return _value.get_jdouble(); } @@ -120,7 +121,7 @@ #endif - jint as_jint_bits() const { type_check(T_FLOAT, T_INT); return _value.get_jint(); } + jint as_jint_bits() const { type_check(T_FLOAT, T_INT, T_ADDRESS); return _value.get_jint(); } jint as_jint_lo_bits() const { if (type() == T_DOUBLE) { return low(jlong_cast(_value.get_jdouble())); @@ -718,6 +719,7 @@ static LIR_Opr intptrConst(void* p) { return (LIR_Opr)(new LIR_Const(p)); } static LIR_Opr intptrConst(intptr_t v) { return (LIR_Opr)(new LIR_Const((void*)v)); } static LIR_Opr illegal() { return (LIR_Opr)-1; } + static LIR_Opr addressConst(jint i) { return (LIR_Opr)(new LIR_Const(i, true)); } static LIR_Opr value_type(ValueType* type); static LIR_Opr dummy_value_type(ValueType* type); @@ -840,6 +842,7 @@ , lir_optvirtual_call , lir_icvirtual_call , lir_virtual_call + , lir_dynamic_call , end_opJavaCall , begin_opArrayCopy , lir_arraycopy @@ -1052,6 +1055,16 @@ LIR_Opr receiver() const { return _receiver; } ciMethod* method() const { return _method; } + // JSR 292 support. + bool is_invokedynamic() const { return code() == lir_dynamic_call; } + bool is_method_handle_invoke() const { + return + is_invokedynamic() // An invokedynamic is always a MethodHandle call site. + || + (method()->holder()->name() == ciSymbol::java_dyn_MethodHandle() && + method()->name() == ciSymbol::invoke_name()); + } + intptr_t vtable_offset() const { assert(_code == lir_virtual_call, "only have vtable for real vcall"); return (intptr_t) addr(); @@ -1766,6 +1779,10 @@ intptr_t vtable_offset, LIR_OprList* arguments, CodeEmitInfo* info) { append(new LIR_OpJavaCall(lir_virtual_call, method, receiver, result, vtable_offset, arguments, info)); } + void call_dynamic(ciMethod* method, LIR_Opr receiver, LIR_Opr result, + address dest, LIR_OprList* arguments, CodeEmitInfo* info) { + append(new LIR_OpJavaCall(lir_dynamic_call, method, receiver, result, dest, arguments, info)); + } void get_thread(LIR_Opr result) { append(new LIR_Op0(lir_get_thread, result)); } void word_align() { append(new LIR_Op0(lir_word_align)); } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -301,9 +301,9 @@ } -void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo) { +void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo, bool is_method_handle_invoke) { flush_debug_info(pc_offset); - cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset); + cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset, is_method_handle_invoke); if (cinfo->exception_handlers() != NULL) { compilation()->add_exception_handlers_for_pco(pc_offset, cinfo->exception_handlers()); } @@ -413,6 +413,12 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { verify_oop_map(op->info()); + // JSR 292 + // Preserve the SP over MethodHandle call sites. + if (op->is_method_handle_invoke()) { + preserve_SP(op); + } + if (os::is_MP()) { // must align calls sites, otherwise they can't be updated atomically on MP hardware align_call(op->code()); @@ -423,19 +429,25 @@ switch (op->code()) { case lir_static_call: - call(op->addr(), relocInfo::static_call_type, op->info()); + call(op, relocInfo::static_call_type); break; case lir_optvirtual_call: - call(op->addr(), relocInfo::opt_virtual_call_type, op->info()); + case lir_dynamic_call: + call(op, relocInfo::opt_virtual_call_type); break; case lir_icvirtual_call: - ic_call(op->addr(), op->info()); + ic_call(op); break; case lir_virtual_call: - vtable_call(op->vtable_offset(), op->info()); + vtable_call(op); break; default: ShouldNotReachHere(); } + + if (op->is_method_handle_invoke()) { + restore_SP(op); + } + #if defined(X86) && defined(TIERED) // C2 leave fpu stack dirty clean it if (UseSSE < 2) { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -82,7 +82,7 @@ Address as_Address_hi(LIR_Address* addr); // debug information - void add_call_info(int pc_offset, CodeEmitInfo* cinfo); + void add_call_info(int pc_offset, CodeEmitInfo* cinfo, bool is_method_handle_invoke = false); void add_debug_info_for_branch(CodeEmitInfo* info); void add_debug_info_for_div0(int pc_offset, CodeEmitInfo* cinfo); void add_debug_info_for_div0_here(CodeEmitInfo* info); @@ -205,9 +205,13 @@ void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op); void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result); - void ic_call(address destination, CodeEmitInfo* info); - void vtable_call(int vtable_offset, CodeEmitInfo* info); - void call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info); + void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); + void ic_call( LIR_OpJavaCall* op); + void vtable_call( LIR_OpJavaCall* op); + + // JSR 292 + void preserve_SP(LIR_OpJavaCall* op); + void restore_SP( LIR_OpJavaCall* op); void osr_entry(); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2284,7 +2284,7 @@ void LIRGenerator::invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list) { - int i = x->has_receiver() ? 1 : 0; + int i = (x->has_receiver() || x->is_invokedynamic()) ? 1 : 0; for (; i < args->length(); i++) { LIRItem* param = args->at(i); LIR_Opr loc = arg_list->at(i); @@ -2322,6 +2322,10 @@ LIRItem* receiver = new LIRItem(x->receiver(), this); argument_items->append(receiver); } + if (x->is_invokedynamic()) { + // Insert a dummy for the synthetic MethodHandle argument. + argument_items->append(NULL); + } int idx = x->has_receiver() ? 1 : 0; for (int i = 0; i < x->number_of_arguments(); i++) { LIRItem* param = new LIRItem(x->argument_at(i), this); @@ -2371,6 +2375,9 @@ CodeEmitInfo* info = state_for(x, x->state()); + // invokedynamics can deoptimize. + CodeEmitInfo* deopt_info = x->is_invokedynamic() ? state_for(x, x->state_before()) : NULL; + invoke_load_arguments(x, args, arg_list); if (x->has_receiver()) { @@ -2407,6 +2414,47 @@ __ call_virtual(x->target(), receiver, result_register, vtable_offset, arg_list, info); } break; + case Bytecodes::_invokedynamic: { + ciBytecodeStream bcs(x->scope()->method()); + bcs.force_bci(x->bci()); + assert(bcs.cur_bc() == Bytecodes::_invokedynamic, "wrong stream"); + ciCPCache* cpcache = bcs.get_cpcache(); + + // Get CallSite offset from constant pool cache pointer. + int index = bcs.get_method_index(); + size_t call_site_offset = cpcache->get_f1_offset(index); + + // If this invokedynamic call site hasn't been executed yet in + // the interpreter, the CallSite object in the constant pool + // cache is still null and we need to deoptimize. + if (cpcache->is_f1_null_at(index)) { + // Cannot re-use same xhandlers for multiple CodeEmitInfos, so + // clone all handlers. This is handled transparently in other + // places by the CodeEmitInfo cloning logic but is handled + // specially here because a stub isn't being used. + x->set_exception_handlers(new XHandlers(x->exception_handlers())); + + DeoptimizeStub* deopt_stub = new DeoptimizeStub(deopt_info); + __ jump(deopt_stub); + } + + // Use the receiver register for the synthetic MethodHandle + // argument. + receiver = LIR_Assembler::receiverOpr(); + LIR_Opr tmp = new_register(objectType); + + // Load CallSite object from constant pool cache. + __ oop2reg(cpcache->constant_encoding(), tmp); + __ load(new LIR_Address(tmp, call_site_offset, T_OBJECT), tmp); + + // Load target MethodHandle from CallSite object. + __ load(new LIR_Address(tmp, java_dyn_CallSite::target_offset_in_bytes(), T_OBJECT), receiver); + + __ call_dynamic(x->target(), receiver, result_register, + SharedRuntime::get_resolve_opt_virtual_call_stub(), + arg_list, info); + break; + } default: ShouldNotReachHere(); break; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_LinearScan.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2479,6 +2479,15 @@ return 2; } + case T_ADDRESS: { +#ifdef _LP64 + scope_values->append(new ConstantLongValue(c->as_jint())); +#else + scope_values->append(new ConstantIntValue(c->as_jint())); +#endif + return 1; + } + default: ShouldNotReachHere(); return -1; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/c1/c1_MacroAssembler.hpp --- a/src/share/vm/c1/c1_MacroAssembler.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/c1/c1_MacroAssembler.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ void inline_cache_check(Register receiver, Register iCache); void build_frame(int frame_size_in_bytes); - void method_exit(bool restore_frame); + void remove_frame(int frame_size_in_bytes); void unverified_entry(Register receiver, Register ic_klass); void verified_entry(); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/ci/ciCPCache.cpp --- a/src/share/vm/ci/ciCPCache.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/ci/ciCPCache.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,16 @@ // ------------------------------------------------------------------ +// ciCPCache::is_f1_null_at +bool ciCPCache::is_f1_null_at(int index) { + VM_ENTRY_MARK; + constantPoolCacheOop cpcache = (constantPoolCacheOop) get_oop(); + oop f1 = cpcache->secondary_entry_at(index)->f1(); + return (f1 == NULL); +} + + +// ------------------------------------------------------------------ // ciCPCache::print // // Print debugging information about the cache. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/ci/ciCPCache.hpp --- a/src/share/vm/ci/ciCPCache.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/ci/ciCPCache.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,5 +39,7 @@ // requested entry. size_t get_f1_offset(int index); + bool is_f1_null_at(int index); + void print(); }; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/ci/ciConstant.cpp --- a/src/share/vm/ci/ciConstant.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/ci/ciConstant.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -36,7 +36,7 @@ basictype_to_str(basic_type())); switch (basic_type()) { case T_BOOLEAN: - tty->print("%s", bool_to_str(_value._int == 0)); + tty->print("%s", bool_to_str(_value._int != 0)); break; case T_CHAR: case T_BYTE: diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/code/codeBlob.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,7 +249,6 @@ size += round_to(buffer_size, oopSize); assert(name != NULL, "must provide a name"); { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) BufferBlob(name, size); } @@ -271,7 +270,6 @@ unsigned int size = allocation_size(cb, sizeof(BufferBlob)); assert(name != NULL, "must provide a name"); { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) BufferBlob(name, size, cb); } @@ -298,10 +296,48 @@ MemoryService::track_code_cache_memory_usage(); } -bool BufferBlob::is_adapter_blob() const { - return (strcmp(AdapterHandlerEntry::name, name()) == 0); + +//---------------------------------------------------------------------------------------------------- +// Implementation of AdapterBlob + +AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + AdapterBlob* blob = NULL; + unsigned int size = allocation_size(cb, sizeof(AdapterBlob)); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) AdapterBlob(size, cb); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; } + +//---------------------------------------------------------------------------------------------------- +// Implementation of MethodHandlesAdapterBlob + +MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + MethodHandlesAdapterBlob* blob = NULL; + unsigned int size = sizeof(MethodHandlesAdapterBlob); + // align the size to CodeEntryAlignment + size = align_code_offset(size); + size += round_to(buffer_size, oopSize); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) MethodHandlesAdapterBlob(size); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; +} + + //---------------------------------------------------------------------------------------------------- // Implementation of RuntimeStub diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/code/codeBlob.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,14 +90,15 @@ void flush(); // Typing - virtual bool is_buffer_blob() const { return false; } - virtual bool is_nmethod() const { return false; } - virtual bool is_runtime_stub() const { return false; } - virtual bool is_deoptimization_stub() const { return false; } - virtual bool is_uncommon_trap_stub() const { return false; } - virtual bool is_exception_stub() const { return false; } - virtual bool is_safepoint_stub() const { return false; } - virtual bool is_adapter_blob() const { return false; } + virtual bool is_buffer_blob() const { return false; } + virtual bool is_nmethod() const { return false; } + virtual bool is_runtime_stub() const { return false; } + virtual bool is_deoptimization_stub() const { return false; } + virtual bool is_uncommon_trap_stub() const { return false; } + virtual bool is_exception_stub() const { return false; } + virtual bool is_safepoint_stub() const { return false; } + virtual bool is_adapter_blob() const { return false; } + virtual bool is_method_handles_adapter_blob() const { return false; } virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } @@ -221,6 +222,9 @@ class BufferBlob: public CodeBlob { friend class VMStructs; + friend class AdapterBlob; + friend class MethodHandlesAdapterBlob; + private: // Creation support BufferBlob(const char* name, int size); @@ -236,8 +240,7 @@ static void free(BufferBlob* buf); // Typing - bool is_buffer_blob() const { return true; } - bool is_adapter_blob() const; + virtual bool is_buffer_blob() const { return true; } // GC/Verification support void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } @@ -255,6 +258,40 @@ //---------------------------------------------------------------------------------------------------- +// AdapterBlob: used to hold C2I/I2C adapters + +class AdapterBlob: public BufferBlob { +private: + AdapterBlob(int size) : BufferBlob("I2C/C2I adapters", size) {} + AdapterBlob(int size, CodeBuffer* cb) : BufferBlob("I2C/C2I adapters", size, cb) {} + +public: + // Creation + static AdapterBlob* create(CodeBuffer* cb); + + // Typing + virtual bool is_adapter_blob() const { return true; } +}; + + +//---------------------------------------------------------------------------------------------------- +// MethodHandlesAdapterBlob: used to hold MethodHandles adapters + +class MethodHandlesAdapterBlob: public BufferBlob { +private: + MethodHandlesAdapterBlob(int size) : BufferBlob("MethodHandles adapters", size) {} + MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {} + +public: + // Creation + static MethodHandlesAdapterBlob* create(int buffer_size); + + // Typing + virtual bool is_method_handles_adapter_blob() const { return true; } +}; + + +//---------------------------------------------------------------------------------------------------- // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine class RuntimeStub: public CodeBlob { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/compiler/compileBroker.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -988,10 +988,12 @@ } if (method->is_not_compilable(comp_level)) return NULL; - nmethod* saved = CodeCache::find_and_remove_saved_code(method()); - if (saved != NULL) { - method->set_code(method, saved); - return saved; + if (UseCodeCacheFlushing) { + nmethod* saved = CodeCache::find_and_remove_saved_code(method()); + if (saved != NULL) { + method->set_code(method, saved); + return saved; + } } } else { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -46,9 +46,9 @@ _processor_count = os::active_processor_count(); - if (CMSConcurrentMTEnabled && (ParallelCMSThreads > 1)) { + if (CMSConcurrentMTEnabled && (ConcGCThreads > 1)) { assert(_processor_count > 0, "Processor count is suspect"); - _concurrent_processor_count = MIN2((uint) ParallelCMSThreads, + _concurrent_processor_count = MIN2((uint) ConcGCThreads, (uint) _processor_count); } else { _concurrent_processor_count = 1; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -606,7 +606,7 @@ assert(_modUnionTable.covers(_span), "_modUnionTable inconsistency?"); } - if (!_markStack.allocate(CMSMarkStackSize)) { + if (!_markStack.allocate(MarkStackSize)) { warning("Failed to allocate CMS Marking Stack"); return; } @@ -617,13 +617,13 @@ // Support for multi-threaded concurrent phases if (ParallelGCThreads > 0 && CMSConcurrentMTEnabled) { - if (FLAG_IS_DEFAULT(ParallelCMSThreads)) { + if (FLAG_IS_DEFAULT(ConcGCThreads)) { // just for now - FLAG_SET_DEFAULT(ParallelCMSThreads, (ParallelGCThreads + 3)/4); - } - if (ParallelCMSThreads > 1) { + FLAG_SET_DEFAULT(ConcGCThreads, (ParallelGCThreads + 3)/4); + } + if (ConcGCThreads > 1) { _conc_workers = new YieldingFlexibleWorkGang("Parallel CMS Threads", - ParallelCMSThreads, true); + ConcGCThreads, true); if (_conc_workers == NULL) { warning("GC/CMS: _conc_workers allocation failure: " "forcing -CMSConcurrentMTEnabled"); @@ -634,13 +634,13 @@ } } if (!CMSConcurrentMTEnabled) { - ParallelCMSThreads = 0; + ConcGCThreads = 0; } else { // Turn off CMSCleanOnEnter optimization temporarily for // the MT case where it's not fixed yet; see 6178663. CMSCleanOnEnter = false; } - assert((_conc_workers != NULL) == (ParallelCMSThreads > 1), + assert((_conc_workers != NULL) == (ConcGCThreads > 1), "Inconsistency"); // Parallel task queues; these are shared for the @@ -648,7 +648,7 @@ // are not shared with parallel scavenge (ParNew). { uint i; - uint num_queues = (uint) MAX2(ParallelGCThreads, ParallelCMSThreads); + uint num_queues = (uint) MAX2(ParallelGCThreads, ConcGCThreads); if ((CMSParallelRemarkEnabled || CMSConcurrentMTEnabled || ParallelRefProcEnabled) @@ -723,8 +723,9 @@ // Support for parallelizing survivor space rescan if (CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) { - size_t max_plab_samples = cp->max_gen0_size()/ - ((SurvivorRatio+2)*MinTLABSize); + const size_t max_plab_samples = + ((DefNewGeneration*)_young_gen)->max_survivor_size()/MinTLABSize; + _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples); _cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads); @@ -3657,7 +3658,7 @@ assert(_revisitStack.isEmpty(), "tabula rasa"); DEBUG_ONLY(RememberKlassesChecker cmx(should_unload_classes());) bool result = false; - if (CMSConcurrentMTEnabled && ParallelCMSThreads > 0) { + if (CMSConcurrentMTEnabled && ConcGCThreads > 0) { result = do_marking_mt(asynch); } else { result = do_marking_st(asynch); @@ -4174,10 +4175,10 @@ } bool CMSCollector::do_marking_mt(bool asynch) { - assert(ParallelCMSThreads > 0 && conc_workers() != NULL, "precondition"); + assert(ConcGCThreads > 0 && conc_workers() != NULL, "precondition"); // In the future this would be determined ergonomically, based // on #cpu's, # active mutator threads (and load), and mutation rate. - int num_workers = ParallelCMSThreads; + int num_workers = ConcGCThreads; CompactibleFreeListSpace* cms_space = _cmsGen->cmsSpace(); CompactibleFreeListSpace* perm_space = _permGen->cmsSpace(); @@ -6429,8 +6430,8 @@ // For now we take the expedient path of just disabling the // messages for the problematic case.) void CMSMarkStack::expand() { - assert(_capacity <= CMSMarkStackSizeMax, "stack bigger than permitted"); - if (_capacity == CMSMarkStackSizeMax) { + assert(_capacity <= MarkStackSizeMax, "stack bigger than permitted"); + if (_capacity == MarkStackSizeMax) { if (_hit_limit++ == 0 && !CMSConcurrentMTEnabled && PrintGCDetails) { // We print a warning message only once per CMS cycle. gclog_or_tty->print_cr(" (benign) Hit CMSMarkStack max size limit"); @@ -6438,7 +6439,7 @@ return; } // Double capacity if possible - size_t new_capacity = MIN2(_capacity*2, CMSMarkStackSizeMax); + size_t new_capacity = MIN2(_capacity*2, MarkStackSizeMax); // Do not give up existing stack until we have managed to // get the double capacity that we desired. ReservedSpace rs(ReservedSpace::allocation_align_size_up( diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -44,20 +44,20 @@ { // Ergomonically select initial concurrent refinement parameters - if (FLAG_IS_DEFAULT(G1ConcRefineGreenZone)) { - FLAG_SET_DEFAULT(G1ConcRefineGreenZone, MAX2(ParallelGCThreads, 1)); + if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { + FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, MAX2(ParallelGCThreads, 1)); } - set_green_zone(G1ConcRefineGreenZone); + set_green_zone(G1ConcRefinementGreenZone); - if (FLAG_IS_DEFAULT(G1ConcRefineYellowZone)) { - FLAG_SET_DEFAULT(G1ConcRefineYellowZone, green_zone() * 3); + if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) { + FLAG_SET_DEFAULT(G1ConcRefinementYellowZone, green_zone() * 3); } - set_yellow_zone(MAX2(G1ConcRefineYellowZone, green_zone())); + set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); - if (FLAG_IS_DEFAULT(G1ConcRefineRedZone)) { - FLAG_SET_DEFAULT(G1ConcRefineRedZone, yellow_zone() * 2); + if (FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) { + FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2); } - set_red_zone(MAX2(G1ConcRefineRedZone, yellow_zone())); + set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); _n_worker_threads = thread_num(); // We need one extra thread to do the young gen rset size sampling. _n_threads = _n_worker_threads + 1; @@ -76,15 +76,15 @@ } void ConcurrentG1Refine::reset_threshold_step() { - if (FLAG_IS_DEFAULT(G1ConcRefineThresholdStep)) { + if (FLAG_IS_DEFAULT(G1ConcRefinementThresholdStep)) { _thread_threshold_step = (yellow_zone() - green_zone()) / (worker_thread_num() + 1); } else { - _thread_threshold_step = G1ConcRefineThresholdStep; + _thread_threshold_step = G1ConcRefinementThresholdStep; } } int ConcurrentG1Refine::thread_num() { - return MAX2((G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads, 1); + return MAX2((G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads : ParallelGCThreads, 1); } void ConcurrentG1Refine::init() { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -39,7 +39,8 @@ * running. If the length becomes red (max queue length) the mutators start * processing the buffers. * - * There are some interesting cases (with G1AdaptiveConcRefine turned off): + * There are some interesting cases (when G1UseAdaptiveConcRefinement + * is turned off): * 1) green = yellow = red = 0. In this case the mutator will process all * buffers. Except for those that are created by the deferred updates * machinery during a collection. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp --- a/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -107,7 +107,7 @@ if (_should_terminate) { break; } - _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefineServiceInterval); + _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis); } } @@ -127,7 +127,7 @@ void ConcurrentG1RefineThread::activate() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (_worker_id > 0) { - if (G1TraceConcurrentRefinement) { + if (G1TraceConcRefinement) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d", _worker_id, _threshold, (int)dcqs.completed_buffers_num()); @@ -143,7 +143,7 @@ void ConcurrentG1RefineThread::deactivate() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (_worker_id > 0) { - if (G1TraceConcurrentRefinement) { + if (G1TraceConcRefinement) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d", _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num()); @@ -218,9 +218,13 @@ void ConcurrentG1RefineThread::yield() { - if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-yield"); + if (G1TraceConcRefinement) { + gclog_or_tty->print_cr("G1-Refine-yield"); + } _sts.yield("G1 refine"); - if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-yield-end"); + if (G1TraceConcRefinement) { + gclog_or_tty->print_cr("G1-Refine-yield-end"); + } } void ConcurrentG1RefineThread::stop() { @@ -241,7 +245,9 @@ Terminator_lock->wait(); } } - if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-stop"); + if (G1TraceConcRefinement) { + gclog_or_tty->print_cr("G1-Refine-stop"); + } } void ConcurrentG1RefineThread::print() const { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -447,7 +447,7 @@ gclog_or_tty->print_cr("[global] init, heap start = "PTR_FORMAT", " "heap end = "PTR_FORMAT, _heap_start, _heap_end); - _markStack.allocate(G1MarkStackSize); + _markStack.allocate(MarkStackSize); _regionStack.allocate(G1MarkRegionStackSize); // Create & start a ConcurrentMark thread. @@ -461,7 +461,7 @@ assert(_markBitMap2.covers(rs), "_markBitMap2 inconsistency"); SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); - satb_qs.set_buffer_size(G1SATBLogBufferSize); + satb_qs.set_buffer_size(G1SATBBufferSize); int size = (int) MAX2(ParallelGCThreads, (size_t)1); _par_cleanup_thread_state = NEW_C_HEAP_ARRAY(ParCleanupThreadState*, size); @@ -483,8 +483,8 @@ _accum_task_vtime[i] = 0.0; } - if (ParallelMarkingThreads > ParallelGCThreads) { - vm_exit_during_initialization("Can't have more ParallelMarkingThreads " + if (ConcGCThreads > ParallelGCThreads) { + vm_exit_during_initialization("Can't have more ConcGCThreads " "than ParallelGCThreads."); } if (ParallelGCThreads == 0) { @@ -494,11 +494,11 @@ _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else { - if (ParallelMarkingThreads > 0) { - // notice that ParallelMarkingThreads overwrites G1MarkingOverheadPercent + if (ConcGCThreads > 0) { + // notice that ConcGCThreads overwrites G1MarkingOverheadPercent // if both are set - _parallel_marking_threads = ParallelMarkingThreads; + _parallel_marking_threads = ConcGCThreads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else if (G1MarkingOverheadPercent > 0) { @@ -760,7 +760,10 @@ rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - satb_mq_set.set_active_all_threads(true); + // This is the start of the marking cycle, we're expected all + // threads to have SATB queues with active set to false. + satb_mq_set.set_active_all_threads(true, /* new active value */ + false /* expected_active */); // update_g1_committed() will be called at the end of an evac pause // when marking is on. So, it's also called at the end of the @@ -1079,7 +1082,11 @@ gclog_or_tty->print_cr("\nRemark led to restart for overflow."); } else { // We're done with marking. - JavaThread::satb_mark_queue_set().set_active_all_threads(false); + // This is the end of the marking cycle, we're expected all + // threads to have SATB queues with active set to true. + JavaThread::satb_mark_queue_set().set_active_all_threads( + false, /* new active value */ + true /* expected_active */); if (VerifyDuringGC) { HandleMark hm; // handle scope @@ -2586,7 +2593,11 @@ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.abandon_partial_marking(); - satb_mq_set.set_active_all_threads(false); + // This can be called either during or outside marking, we'll read + // the expected_active value from the SATB queue set. + satb_mq_set.set_active_all_threads( + false, /* new active value */ + satb_mq_set.is_active() /* expected_active */); } static void print_ms_time_info(const char* prefix, const char* name, @@ -3704,7 +3715,14 @@ // enough to point to the next possible object header (the // bitmap knows by how much we need to move it as it knows its // granularity). - move_finger_to(_nextMarkBitMap->nextWord(_finger)); + assert(_finger < _region_limit, "invariant"); + HeapWord* new_finger = _nextMarkBitMap->nextWord(_finger); + // Check if bitmap iteration was aborted while scanning the last object + if (new_finger >= _region_limit) { + giveup_current_region(); + } else { + move_finger_to(new_finger); + } } } // At this point we have either completed iterating over the diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -24,8 +24,8 @@ class G1CollectedHeap; class CMTask; -typedef GenericTaskQueue CMTaskQueue; -typedef GenericTaskQueueSet CMTaskQueueSet; +typedef GenericTaskQueue CMTaskQueue; +typedef GenericTaskQueueSet CMTaskQueueSet; // A generic CM bit map. This is essentially a wrapper around the BitMap // class, with one bit per (1<<_shifter) HeapWords. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -583,7 +583,7 @@ res->zero_fill_state() == HeapRegion::Allocated)), "Non-young alloc Regions must be zero filled (and non-H)"); - if (G1PrintRegions) { + if (G1PrintHeapRegions) { if (res != NULL) { gclog_or_tty->print_cr("new alloc region %d:["PTR_FORMAT", "PTR_FORMAT"], " "top "PTR_FORMAT, @@ -2102,18 +2102,21 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { // Return the remaining space in the cur alloc region, but not less than // the min TLAB size. - // Also, no more than half the region size, since we can't allow tlabs to - // grow big enough to accomodate humongous objects. - - // We need to story it locally, since it might change between when we - // test for NULL and when we use it later. + + // Also, this value can be at most the humongous object threshold, + // since we can't allow tlabs to grow big enough to accomodate + // humongous objects. + + // We need to store the cur alloc region locally, since it might change + // between when we test for NULL and when we use it later. ContiguousSpace* cur_alloc_space = _cur_alloc_region; + size_t max_tlab_size = _humongous_object_threshold_in_words * wordSize; + if (cur_alloc_space == NULL) { - return HeapRegion::GrainBytes/2; + return max_tlab_size; } else { - return MAX2(MIN2(cur_alloc_space->free(), - (size_t)(HeapRegion::GrainBytes/2)), - (size_t)MinTLABSize); + return MIN2(MAX2(cur_alloc_space->free(), (size_t)MinTLABSize), + max_tlab_size); } } @@ -2477,7 +2480,7 @@ if (G1SummarizeRSetStats) { g1_rem_set()->print_summary_info(); } - if (G1SummarizeConcurrentMark) { + if (G1SummarizeConcMark) { concurrent_mark()->print_summary_info(); } if (G1SummarizeZFStats) { @@ -3480,7 +3483,7 @@ HeapRegion* r = heap_region_containing(old); if (!r->evacuation_failed()) { r->set_evacuation_failed(true); - if (G1PrintRegions) { + if (G1PrintHeapRegions) { gclog_or_tty->print("evacuation failed in heap region "PTR_FORMAT" " "["PTR_FORMAT","PTR_FORMAT")\n", r, r->bottom(), r->end()); @@ -4002,9 +4005,7 @@ _g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms); _g1h->g1_policy()->record_termination_time(i, term_ms); } - if (G1UseSurvivorSpaces) { - _g1h->g1_policy()->record_thread_age_table(pss.age_table()); - } + _g1h->g1_policy()->record_thread_age_table(pss.age_table()); _g1h->update_surviving_young_words(pss.surviving_young_words()+1); // Clean up any par-expanded rem sets. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -56,8 +56,8 @@ # define IF_G1_DETAILED_STATS(code) #endif -typedef GenericTaskQueue RefToScanQueue; -typedef GenericTaskQueueSet RefToScanQueueSet; +typedef GenericTaskQueue RefToScanQueue; +typedef GenericTaskQueueSet RefToScanQueueSet; typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion ) @@ -1055,7 +1055,12 @@ // Returns "true" iff the given word_size is "very large". static bool isHumongous(size_t word_size) { - return word_size >= _humongous_object_threshold_in_words; + // Note this has to be strictly greater-than as the TLABs + // are capped at the humongous thresold and we want to + // ensure that we don't try to allocate a TLAB as + // humongous and that we don't allocate a humongous + // object in a TLAB. + return word_size > _humongous_object_threshold_in_words; } // Update mod union table with the set of dirty cards. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -270,14 +270,10 @@ _concurrent_mark_cleanup_times_ms->add(0.20); _tenuring_threshold = MaxTenuringThreshold; - if (G1UseSurvivorSpaces) { - // if G1FixedSurvivorSpaceSize is 0 which means the size is not - // fixed, then _max_survivor_regions will be calculated at - // calculate_young_list_target_config during initialization - _max_survivor_regions = G1FixedSurvivorSpaceSize / HeapRegion::GrainBytes; - } else { - _max_survivor_regions = 0; - } + // if G1FixedSurvivorSpaceSize is 0 which means the size is not + // fixed, then _max_survivor_regions will be calculated at + // calculate_young_list_target_config during initialization + _max_survivor_regions = G1FixedSurvivorSpaceSize / HeapRegion::GrainBytes; initialize_all(); } @@ -296,28 +292,54 @@ CollectorPolicy::initialize_flags(); } +// The easiest way to deal with the parsing of the NewSize / +// MaxNewSize / etc. parameteres is to re-use the code in the +// TwoGenerationCollectorPolicy class. This is similar to what +// ParallelScavenge does with its GenerationSizer class (see +// ParallelScavengeHeap::initialize()). We might change this in the +// future, but it's a good start. +class G1YoungGenSizer : public TwoGenerationCollectorPolicy { + size_t size_to_region_num(size_t byte_size) { + return MAX2((size_t) 1, byte_size / HeapRegion::GrainBytes); + } + +public: + G1YoungGenSizer() { + initialize_flags(); + initialize_size_info(); + } + + size_t min_young_region_num() { + return size_to_region_num(_min_gen0_size); + } + size_t initial_young_region_num() { + return size_to_region_num(_initial_gen0_size); + } + size_t max_young_region_num() { + return size_to_region_num(_max_gen0_size); + } +}; + void G1CollectorPolicy::init() { // Set aside an initial future to_space. _g1 = G1CollectedHeap::heap(); - size_t regions = Universe::heap()->capacity() / HeapRegion::GrainBytes; assert(Heap_lock->owned_by_self(), "Locking discipline."); - if (G1SteadyStateUsed < 50) { - vm_exit_during_initialization("G1SteadyStateUsed must be at least 50%."); - } - initialize_gc_policy_counters(); if (G1Gen) { _in_young_gc_mode = true; - if (G1YoungGenSize == 0) { + G1YoungGenSizer sizer; + size_t initial_region_num = sizer.initial_young_region_num(); + + if (UseAdaptiveSizePolicy) { set_adaptive_young_list_length(true); _young_list_fixed_length = 0; } else { set_adaptive_young_list_length(false); - _young_list_fixed_length = (G1YoungGenSize / HeapRegion::GrainBytes); + _young_list_fixed_length = initial_region_num; } _free_regions_at_end_of_collection = _g1->free_regions(); _scan_only_regions_at_end_of_collection = 0; @@ -455,7 +477,7 @@ guarantee( adaptive_young_list_length(), "pre-condition" ); double start_time_sec = os::elapsedTime(); - size_t min_reserve_perc = MAX2((size_t)2, (size_t)G1MinReservePercent); + size_t min_reserve_perc = MAX2((size_t)2, (size_t)G1ReservePercent); min_reserve_perc = MIN2((size_t) 50, min_reserve_perc); size_t reserve_regions = (size_t) ((double) min_reserve_perc * (double) _g1->n_regions() / 100.0); @@ -1110,10 +1132,7 @@ size_t short_lived_so_length = _young_list_so_prefix_length; _short_lived_surv_rate_group->record_scan_only_prefix(short_lived_so_length); tag_scan_only(short_lived_so_length); - - if (G1UseSurvivorSpaces) { - _survivors_age_table.clear(); - } + _survivors_age_table.clear(); assert( verify_young_ages(), "region age verification" ); } @@ -1432,7 +1451,7 @@ record_concurrent_mark_init_end_pre(0.0); size_t min_used_targ = - (_g1->capacity() / 100) * (G1SteadyStateUsed - G1SteadyStateUsedDelta); + (_g1->capacity() / 100) * InitiatingHeapOccupancyPercent; if (cur_used_bytes > min_used_targ) { if (cur_used_bytes <= _prev_collection_pause_used_at_end_bytes) { @@ -1916,7 +1935,7 @@ calculate_young_list_target_config(); // Note that _mmu_tracker->max_gc_time() returns the time in seconds. - double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSUpdatePauseFractionPercent / 100.0; + double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; adjust_concurrent_refinement(update_rs_time, update_rs_processed_buffers, update_rs_time_goal_ms); // @@ -1932,7 +1951,7 @@ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); ConcurrentG1Refine *cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); - if (G1AdaptiveConcRefine) { + if (G1UseAdaptiveConcRefinement) { const int k_gy = 3, k_gr = 6; const double inc_k = 1.1, dec_k = 0.9; @@ -2607,9 +2626,6 @@ // Calculates survivor space parameters. void G1CollectorPolicy::calculate_survivors_policy() { - if (!G1UseSurvivorSpaces) { - return; - } if (G1FixedSurvivorSpaceSize == 0) { _max_survivor_regions = _young_list_target_length / SurvivorRatio; } else { @@ -2628,13 +2644,6 @@ G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t word_size) { assert(_g1->regions_accounted_for(), "Region leakage!"); - // Initiate a pause when we reach the steady-state "used" target. - size_t used_hard = (_g1->capacity() / 100) * G1SteadyStateUsed; - size_t used_soft = - MAX2((_g1->capacity() / 100) * (G1SteadyStateUsed - G1SteadyStateUsedDelta), - used_hard/2); - size_t used = _g1->used(); - double max_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; size_t young_list_length = _g1->young_list_length(); @@ -2867,7 +2876,7 @@ // estimate of the number of live bytes. void G1CollectorPolicy:: add_to_collection_set(HeapRegion* hr) { - if (G1PrintRegions) { + if (G1PrintHeapRegions) { gclog_or_tty->print_cr("added region to cset %d:["PTR_FORMAT", "PTR_FORMAT"], " "top "PTR_FORMAT", young %s", hr->hrs_index(), hr->bottom(), hr->end(), diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1MMUTracker.cpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -88,13 +88,13 @@ // the time slice than what's allowed) // consolidate the two entries with the minimum gap between them // (this might allow less GC time than what's allowed) - guarantee(NOT_PRODUCT(ScavengeALot ||) G1ForgetfulMMUTracker, - "array full, currently we can't recover unless +G1ForgetfulMMUTracker"); + guarantee(NOT_PRODUCT(ScavengeALot ||) G1UseFixedWindowMMUTracker, + "array full, currently we can't recover unless +G1UseFixedWindowMMUTracker"); // In the case where ScavengeALot is true, such overflow is not // uncommon; in such cases, we can, without much loss of precision // or performance (we are GC'ing most of the time anyway!), // simply overwrite the oldest entry in the tracker: this - // is also the behaviour when G1ForgetfulMMUTracker is enabled. + // is also the behaviour when G1UseFixedWindowMMUTracker is enabled. _head_index = trim_index(_head_index + 1); assert(_head_index == _tail_index, "Because we have a full circular buffer"); _tail_index = trim_index(_tail_index + 1); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1MMUTracker.hpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -101,7 +101,7 @@ // If the array is full, an easy fix is to look for the pauses with // the shortest gap between them and consolidate them. // For now, we have taken the expedient alternative of forgetting - // the oldest entry in the event that +G1ForgetfulMMUTracker, thus + // the oldest entry in the event that +G1UseFixedWindowMMUTracker, thus // potentially violating MMU specs for some time thereafter. G1MMUTrackerQueueElem _array[QueueLength]; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -101,6 +101,8 @@ GenMarkSweep::_marking_stack = new (ResourceObj::C_HEAP) GrowableArray(4000, true); + GenMarkSweep::_objarray_stack = + new (ResourceObj::C_HEAP) GrowableArray(50, true); int size = SystemDictionary::number_of_classes() * 2; GenMarkSweep::_revisit_klass_stack = diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -467,7 +467,7 @@ // and they are causing failures. When we resolve said race // conditions, we'll revert back to parallel remembered set // updating and scanning. See CRs 6677707 and 6677708. - if (G1ParallelRSetUpdatingEnabled || (worker_i == 0)) { + if (G1UseParallelRSetUpdating || (worker_i == 0)) { updateRS(worker_i); scanNewRefsRS(oc, worker_i); } else { @@ -476,7 +476,7 @@ _g1p->record_update_rs_time(worker_i, 0.0); _g1p->record_scan_new_refs_time(worker_i, 0.0); } - if (G1ParallelRSetScanningEnabled || (worker_i == 0)) { + if (G1UseParallelRSetScanning || (worker_i == 0)) { scanRS(oc, worker_i); } else { _g1p->record_scan_rs_start_time(worker_i, os::elapsedTime() * 1000.0); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -35,7 +35,7 @@ void G1SATBCardTableModRefBS::enqueue(oop pre_val) { assert(pre_val->is_oop_or_null(true), "Error"); - if (!JavaThread::satb_mark_queue_set().active()) return; + if (!JavaThread::satb_mark_queue_set().is_active()) return; Thread* thr = Thread::current(); if (thr->is_Java_thread()) { JavaThread* jt = (JavaThread*)thr; @@ -51,7 +51,7 @@ G1SATBCardTableModRefBS::write_ref_field_pre_static(T* field, oop new_val, JavaThread* jt) { - if (!JavaThread::satb_mark_queue_set().active()) return; + if (!JavaThread::satb_mark_queue_set().is_active()) return; T heap_oop = oopDesc::load_heap_oop(field); if (!oopDesc::is_null(heap_oop)) { oop pre_val = oopDesc::decode_heap_oop_not_null(heap_oop); @@ -62,7 +62,7 @@ template void G1SATBCardTableModRefBS::write_ref_array_pre_work(T* dst, int count) { - if (!JavaThread::satb_mark_queue_set().active()) return; + if (!JavaThread::satb_mark_queue_set().is_active()) return; T* elem_ptr = dst; for (int i = 0; i < count; i++, elem_ptr++) { T heap_oop = oopDesc::load_heap_oop(elem_ptr); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -37,9 +37,6 @@ develop(intx, G1MarkingOverheadPercent, 0, \ "Overhead of concurrent marking") \ \ - product(uintx, G1YoungGenSize, 0, \ - "Size of the G1 young generation, 0 is the adaptive policy") \ - \ develop(bool, G1Gen, true, \ "If true, it will enable the generational G1") \ \ @@ -70,7 +67,7 @@ develop(intx, G1PausesBtwnConcMark, -1, \ "If positive, fixed number of pauses between conc markings") \ \ - diagnostic(bool, G1SummarizeConcurrentMark, false, \ + diagnostic(bool, G1SummarizeConcMark, false, \ "Summarize concurrent mark info") \ \ diagnostic(bool, G1SummarizeRSetStats, false, \ @@ -85,12 +82,9 @@ diagnostic(bool, G1SummarizeZFStats, false, \ "Summarize zero-filling info") \ \ - diagnostic(bool, G1TraceConcurrentRefinement, false, \ + diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ \ - product(intx, G1MarkStackSize, 2 * 1024 * 1024, \ - "Size of the mark stack for concurrent marking.") \ - \ product(intx, G1MarkRegionStackSize, 1024 * 1024, \ "Size of the region stack for concurrent marking.") \ \ @@ -100,20 +94,13 @@ develop(intx, G1ConcZFMaxRegions, 1, \ "Stop zero-filling when # of zf'd regions reaches") \ \ - product(intx, G1SteadyStateUsed, 90, \ - "If non-0, try to maintain 'used' at this pct (of max)") \ - \ - product(intx, G1SteadyStateUsedDelta, 30, \ - "If G1SteadyStateUsed is non-0, then do pause this number of " \ - "of percentage points earlier if no marking is in progress.") \ - \ develop(bool, G1SATBBarrierPrintNullPreVals, false, \ "If true, count frac of ptr writes with null pre-vals.") \ \ - product(intx, G1SATBLogBufferSize, 1*K, \ + product(intx, G1SATBBufferSize, 1*K, \ "Number of entries in an SATB log buffer.") \ \ - product(intx, G1SATBProcessCompletedThreshold, 20, \ + develop(intx, G1SATBProcessCompletedThreshold, 20, \ "Number of completed buffers that triggers log processing.") \ \ develop(intx, G1ExtraRegionSurvRate, 33, \ @@ -127,7 +114,7 @@ develop(bool, G1SATBPrintStubs, false, \ "If true, print generated stubs for the SATB barrier") \ \ - product(intx, G1ExpandByPercentOfAvailable, 20, \ + experimental(intx, G1ExpandByPercentOfAvailable, 20, \ "When expanding, % of uncommitted space to claim.") \ \ develop(bool, G1RSBarrierRegionFilter, true, \ @@ -165,36 +152,36 @@ product(intx, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ \ - product(intx, G1ConcRefineYellowZone, 0, \ + product(intx, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ \ - product(intx, G1ConcRefineRedZone, 0, \ + product(intx, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ \ - product(intx, G1ConcRefineGreenZone, 0, \ + product(intx, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ \ - product(intx, G1ConcRefineServiceInterval, 300, \ + product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ \ - product(intx, G1ConcRefineThresholdStep, 0, \ + product(intx, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ "activate the next refinement thread if available. " \ "Will be selected ergonomically by default.") \ \ - product(intx, G1RSUpdatePauseFractionPercent, 10, \ + product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ "process RS update buffers during the collection pause.") \ \ - product(bool, G1AdaptiveConcRefine, true, \ + product(bool, G1UseAdaptiveConcRefinement, true, \ "Select green, yellow and red zones adaptively to meet the " \ "the pause requirements.") \ \ @@ -245,15 +232,15 @@ "the number of regions for which we'll print a surv rate " \ "summary.") \ \ - product(bool, G1UseScanOnlyPrefix, false, \ + develop(bool, G1UseScanOnlyPrefix, false, \ "It determines whether the system will calculate an optimum " \ "scan-only set.") \ \ - product(intx, G1MinReservePercent, 10, \ + product(intx, G1ReservePercent, 10, \ "It determines the minimum reserve we should have in the heap " \ "to minimize the probability of promotion failure.") \ \ - diagnostic(bool, G1PrintRegions, false, \ + diagnostic(bool, G1PrintHeapRegions, false, \ "If set G1 will print information on which regions are being " \ "allocated and which are reclaimed.") \ \ @@ -263,9 +250,6 @@ develop(bool, G1HRRSFlushLogBuffersOnVerify, false, \ "Forces flushing of log buffers before verification.") \ \ - product(bool, G1UseSurvivorSpaces, true, \ - "When true, use survivor space.") \ - \ develop(bool, G1FailOnFPError, false, \ "When set, G1 will fail when it encounters an FP 'error', " \ "so as to allow debugging") \ @@ -280,21 +264,21 @@ "If non-0 is the size of the G1 survivor space, " \ "otherwise SurvivorRatio is used to determine the size") \ \ - product(bool, G1ForgetfulMMUTracker, false, \ + product(bool, G1UseFixedWindowMMUTracker, false, \ "If the MMU tracker's memory is full, forget the oldest entry") \ \ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ - experimental(bool, G1ParallelRSetUpdatingEnabled, false, \ + experimental(bool, G1UseParallelRSetUpdating, false, \ "Enables the parallelization of remembered set updating " \ "during evacuation pauses") \ \ - experimental(bool, G1ParallelRSetScanningEnabled, false, \ + experimental(bool, G1UseParallelRSetScanning, false, \ "Enables the parallelization of remembered set scanning " \ "during evacuation pauses") \ \ - product(uintx, G1ParallelRSetThreads, 0, \ + product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ \ diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -25,8 +25,8 @@ # include "incls/_precompiled.incl" # include "incls/_ptrQueue.cpp.incl" -PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm) : - _qset(qset_), _buf(NULL), _index(0), _active(false), +PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm, bool active) : + _qset(qset_), _buf(NULL), _index(0), _active(active), _perm(perm), _lock(NULL) {} diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/ptrQueue.hpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -62,7 +62,7 @@ public: // Initialize this queue to contain a null buffer, and be part of the // given PtrQueueSet. - PtrQueue(PtrQueueSet*, bool perm = false); + PtrQueue(PtrQueueSet*, bool perm = false, bool active = false); // Release any contained resources. void flush(); // Calls flush() when destroyed. @@ -101,6 +101,8 @@ } } + bool is_active() { return _active; } + static int byte_index_to_index(int ind) { assert((ind % oopSize) == 0, "Invariant."); return ind / oopSize; @@ -257,7 +259,7 @@ bool process_completed_buffers() { return _process_completed; } void set_process_completed(bool x) { _process_completed = x; } - bool active() { return _all_active; } + bool is_active() { return _all_active; } // Set the buffer size. Should be called before any "enqueue" operation // can be called. And should only be called once. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/satbQueue.cpp --- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -82,9 +82,57 @@ t->satb_mark_queue().handle_zero_index(); } -void SATBMarkQueueSet::set_active_all_threads(bool b) { +#ifdef ASSERT +void SATBMarkQueueSet::dump_active_values(JavaThread* first, + bool expected_active) { + gclog_or_tty->print_cr("SATB queue active values for Java Threads"); + gclog_or_tty->print_cr(" SATB queue set: active is %s", + (is_active()) ? "TRUE" : "FALSE"); + gclog_or_tty->print_cr(" expected_active is %s", + (expected_active) ? "TRUE" : "FALSE"); + for (JavaThread* t = first; t; t = t->next()) { + bool active = t->satb_mark_queue().is_active(); + gclog_or_tty->print_cr(" thread %s, active is %s", + t->name(), (active) ? "TRUE" : "FALSE"); + } +} +#endif // ASSERT + +void SATBMarkQueueSet::set_active_all_threads(bool b, + bool expected_active) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); + JavaThread* first = Threads::first(); + +#ifdef ASSERT + if (_all_active != expected_active) { + dump_active_values(first, expected_active); + + // I leave this here as a guarantee, instead of an assert, so + // that it will still be compiled in if we choose to uncomment + // the #ifdef ASSERT in a product build. The whole block is + // within an #ifdef ASSERT so the guarantee will not be compiled + // in a product build anyway. + guarantee(false, + "SATB queue set has an unexpected active value"); + } +#endif // ASSERT _all_active = b; - for(JavaThread* t = Threads::first(); t; t = t->next()) { + + for (JavaThread* t = first; t; t = t->next()) { +#ifdef ASSERT + bool active = t->satb_mark_queue().is_active(); + if (active != expected_active) { + dump_active_values(first, expected_active); + + // I leave this here as a guarantee, instead of an assert, so + // that it will still be compiled in if we choose to uncomment + // the #ifdef ASSERT in a product build. The whole block is + // within an #ifdef ASSERT so the guarantee will not be compiled + // in a product build anyway. + guarantee(false, + "thread has an unexpected active value in its SATB queue"); + } +#endif // ASSERT t->satb_mark_queue().set_active(b); } } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/g1/satbQueue.hpp --- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -29,8 +29,7 @@ class ObjPtrQueue: public PtrQueue { public: ObjPtrQueue(PtrQueueSet* qset_, bool perm = false) : - PtrQueue(qset_, perm) - {} + PtrQueue(qset_, perm, qset_->is_active()) { } // Apply the closure to all elements, and reset the index to make the // buffer empty. void apply_closure(ObjectClosure* cl); @@ -55,6 +54,9 @@ // is ignored. bool apply_closure_to_completed_buffer_work(bool par, int worker); +#ifdef ASSERT + void dump_active_values(JavaThread* first, bool expected_active); +#endif // ASSERT public: SATBMarkQueueSet(); @@ -65,9 +67,11 @@ static void handle_zero_index_for_thread(JavaThread* t); - // Apply "set_active(b)" to all thread tloq's. Should be called only - // with the world stopped. - void set_active_all_threads(bool b); + // Apply "set_active(b)" to all Java threads' SATB queues. It should be + // called only with the world stopped. The method will assert that the + // SATB queues of all threads it visits, as well as the SATB queue + // set itself, has an active value same as expected_active. + void set_active_all_threads(bool b, bool expected_active); // Register "blk" as "the closure" for all queues. Only one such closure // is allowed. The "apply_closure_to_completed_buffer" method will apply diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/includeDB_gc_parallelScavenge --- a/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Tue Apr 06 22:06:57 2010 -0700 @@ -175,6 +175,7 @@ psAdaptiveSizePolicy.hpp adaptiveSizePolicy.hpp psCompactionManager.cpp gcTaskManager.hpp +psCompactionManager.cpp objArrayKlass.inline.hpp psCompactionManager.cpp objectStartArray.hpp psCompactionManager.cpp oop.hpp psCompactionManager.cpp oop.inline.hpp @@ -189,6 +190,9 @@ psCompactionManager.hpp allocation.hpp psCompactionManager.hpp taskqueue.hpp +psCompactionManager.inline.hpp psCompactionManager.hpp +psCompactionManager.inline.hpp psParallelCompact.hpp + psGCAdaptivePolicyCounters.hpp gcAdaptivePolicyCounters.hpp psGCAdaptivePolicyCounters.hpp gcPolicyCounters.hpp psGCAdaptivePolicyCounters.hpp psAdaptiveSizePolicy.hpp @@ -379,12 +383,12 @@ pcTasks.cpp jniHandles.hpp pcTasks.cpp jvmtiExport.hpp pcTasks.cpp management.hpp +pcTasks.cpp objArrayKlass.inline.hpp pcTasks.cpp psParallelCompact.hpp pcTasks.cpp pcTasks.hpp pcTasks.cpp oop.inline.hpp pcTasks.cpp oop.pcgc.inline.hpp pcTasks.cpp systemDictionary.hpp -pcTasks.cpp taskqueue.hpp pcTasks.cpp thread.hpp pcTasks.cpp universe.hpp pcTasks.cpp vmThread.hpp diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -48,7 +48,7 @@ _vm_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs); // Do the real work - cm->drain_marking_stacks(&mark_and_push_closure); + cm->follow_marking_stacks(); } @@ -118,7 +118,7 @@ } // Do the real work - cm->drain_marking_stacks(&mark_and_push_closure); + cm->follow_marking_stacks(); // cm->deallocate_stacks(); } @@ -196,17 +196,19 @@ PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm); oop obj = NULL; + ObjArrayTask task; int random_seed = 17; - while(true) { - if (ParCompactionManager::steal(which, &random_seed, obj)) { + do { + while (ParCompactionManager::steal_objarray(which, &random_seed, task)) { + objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); + k->oop_follow_contents(cm, task.obj(), task.index()); + cm->follow_marking_stacks(); + } + while (ParCompactionManager::steal(which, &random_seed, obj)) { obj->follow_contents(cm); - cm->drain_marking_stacks(&mark_and_push_closure); - } else { - if (terminator()->offer_termination()) { - break; - } + cm->follow_marking_stacks(); } - } + } while (!terminator()->offer_termination()); } // diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -28,6 +28,8 @@ PSOldGen* ParCompactionManager::_old_gen = NULL; ParCompactionManager** ParCompactionManager::_manager_array = NULL; OopTaskQueueSet* ParCompactionManager::_stack_array = NULL; +ParCompactionManager::ObjArrayTaskQueueSet* + ParCompactionManager::_objarray_queues = NULL; ObjectStartArray* ParCompactionManager::_start_array = NULL; ParMarkBitMap* ParCompactionManager::_mark_bitmap = NULL; RegionTaskQueueSet* ParCompactionManager::_region_array = NULL; @@ -46,6 +48,11 @@ // We want the overflow stack to be permanent _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray(10, true); + + _objarray_queue.initialize(); + _objarray_overflow_stack = + new (ResourceObj::C_HEAP) ObjArrayOverflowStack(10, true); + #ifdef USE_RegionTaskQueueWithOverflow region_stack()->initialize(); #else @@ -69,6 +76,7 @@ ParCompactionManager::~ParCompactionManager() { delete _overflow_stack; + delete _objarray_overflow_stack; delete _revisit_klass_stack; delete _revisit_mdo_stack; // _manager_array and _stack_array are statics @@ -86,18 +94,21 @@ assert(_manager_array == NULL, "Attempt to initialize twice"); _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1 ); - guarantee(_manager_array != NULL, "Could not initialize promotion manager"); + guarantee(_manager_array != NULL, "Could not allocate manager_array"); _stack_array = new OopTaskQueueSet(parallel_gc_threads); - guarantee(_stack_array != NULL, "Count not initialize promotion manager"); + guarantee(_stack_array != NULL, "Could not allocate stack_array"); + _objarray_queues = new ObjArrayTaskQueueSet(parallel_gc_threads); + guarantee(_objarray_queues != NULL, "Could not allocate objarray_queues"); _region_array = new RegionTaskQueueSet(parallel_gc_threads); - guarantee(_region_array != NULL, "Count not initialize promotion manager"); + guarantee(_region_array != NULL, "Could not allocate region_array"); // Create and register the ParCompactionManager(s) for the worker threads. for(uint i=0; iregister_queue(i, _manager_array[i]->marking_stack()); + _objarray_queues->register_queue(i, &_manager_array[i]->_objarray_queue); #ifdef USE_RegionTaskQueueWithOverflow region_array()->register_queue(i, _manager_array[i]->region_stack()->task_queue()); #else @@ -203,36 +214,30 @@ } } -void ParCompactionManager::drain_marking_stacks(OopClosure* blk) { -#ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - MutableSpace* to_space = heap->young_gen()->to_space(); - MutableSpace* old_space = heap->old_gen()->object_space(); - MutableSpace* perm_space = heap->perm_gen()->object_space(); -#endif /* ASSERT */ - - +void ParCompactionManager::follow_marking_stacks() { do { - - // Drain overflow stack first, so other threads can steal from - // claimed stack while we work. - while(!overflow_stack()->is_empty()) { - oop obj = overflow_stack()->pop(); + // Drain the overflow stack first, to allow stealing from the marking stack. + oop obj; + while (!overflow_stack()->is_empty()) { + overflow_stack()->pop()->follow_contents(this); + } + while (marking_stack()->pop_local(obj)) { obj->follow_contents(this); } - oop obj; - // obj is a reference!!! - while (marking_stack()->pop_local(obj)) { - // It would be nice to assert about the type of objects we might - // pop, but they can come from anywhere, unfortunately. - obj->follow_contents(this); + // Process ObjArrays one at a time to avoid marking stack bloat. + ObjArrayTask task; + if (!_objarray_overflow_stack->is_empty()) { + task = _objarray_overflow_stack->pop(); + objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); + k->oop_follow_contents(this, task.obj(), task.index()); + } else if (_objarray_queue.pop_local(task)) { + objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); + k->oop_follow_contents(this, task.obj(), task.index()); } - } while((marking_stack()->size() != 0) || (overflow_stack()->length() != 0)); + } while (!marking_stacks_empty()); - assert(marking_stack()->size() == 0, "Sanity"); - assert(overflow_stack()->length() == 0, "Sanity"); + assert(marking_stacks_empty(), "Sanity"); } void ParCompactionManager::drain_region_overflow_stack() { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -22,18 +22,6 @@ * */ -// -// psPromotionManager is used by a single thread to manage object survival -// during a scavenge. The promotion manager contains thread local data only. -// -// NOTE! Be carefull when allocating the stacks on cheap. If you are going -// to use a promotion manager in more than one thread, the stacks MUST be -// on cheap. This can lead to memory leaks, though, as they are not auto -// deallocated. -// -// FIX ME FIX ME Add a destructor, and don't rely on the user to drain/flush/deallocate! -// - // Move to some global location #define HAS_BEEN_MOVED 0x1501d01d // End move to some global location @@ -46,8 +34,6 @@ class ParallelCompactData; class ParMarkBitMap; -// Move to it's own file if this works out. - class ParCompactionManager : public CHeapObj { friend class ParallelTaskTerminator; friend class ParMarkBitMap; @@ -72,14 +58,27 @@ // ------------------------ End don't putback if not needed private: + // 32-bit: 4K * 8 = 32KiB; 64-bit: 8K * 16 = 128KiB + #define OBJARRAY_QUEUE_SIZE (1 << NOT_LP64(12) LP64_ONLY(13)) + typedef GenericTaskQueue ObjArrayTaskQueue; + typedef GenericTaskQueueSet ObjArrayTaskQueueSet; + #undef OBJARRAY_QUEUE_SIZE + static ParCompactionManager** _manager_array; static OopTaskQueueSet* _stack_array; + static ObjArrayTaskQueueSet* _objarray_queues; static ObjectStartArray* _start_array; static RegionTaskQueueSet* _region_array; static PSOldGen* _old_gen; +private: OopTaskQueue _marking_stack; GrowableArray* _overflow_stack; + + typedef GrowableArray ObjArrayOverflowStack; + ObjArrayTaskQueue _objarray_queue; + ObjArrayOverflowStack* _objarray_overflow_stack; + // Is there a way to reuse the _marking_stack for the // saving empty regions? For now just create a different // type of TaskQueue. @@ -128,8 +127,8 @@ // Pushes onto the region stack. If the region stack is full, // pushes onto the region overflow stack. void region_stack_push(size_t region_index); - public: +public: Action action() { return _action; } void set_action(Action v) { _action = v; } @@ -163,6 +162,8 @@ // Get a oop for scanning. If returns null, no oop were found. oop retrieve_for_scanning(); + inline void push_objarray(oop obj, size_t index); + // Save region for later processing. Must not fail. void save_for_processing(size_t region_index); // Get a region for processing. If returns null, no region were found. @@ -175,12 +176,17 @@ return stack_array()->steal(queue_num, seed, t); } + static bool steal_objarray(int queue_num, int* seed, ObjArrayTask& t) { + return _objarray_queues->steal(queue_num, seed, t); + } + static bool steal(int queue_num, int* seed, RegionTask& t) { return region_array()->steal(queue_num, seed, t); } - // Process tasks remaining on any stack - void drain_marking_stacks(OopClosure *blk); + // Process tasks remaining on any marking stack + void follow_marking_stacks(); + inline bool marking_stacks_empty() const; // Process tasks remaining on any stack void drain_region_stacks(); @@ -200,3 +206,8 @@ "out of range manager_array access"); return _manager_array[index]; } + +bool ParCompactionManager::marking_stacks_empty() const { + return _marking_stack.size() == 0 && _overflow_stack->is_empty() && + _objarray_queue.size() == 0 && _objarray_overflow_stack->is_empty(); +} diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +void ParCompactionManager::push_objarray(oop obj, size_t index) +{ + ObjArrayTask task(obj, index); + assert(task.is_valid(), "bad ObjArrayTask"); + if (!_objarray_queue.push(task)) { + _objarray_overflow_stack->push(task); + } +} diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -479,6 +479,7 @@ _preserved_oop_stack = NULL; _marking_stack = new (ResourceObj::C_HEAP) GrowableArray(4000, true); + _objarray_stack = new (ResourceObj::C_HEAP) GrowableArray(50, true); int size = SystemDictionary::number_of_classes() * 2; _revisit_klass_stack = new (ResourceObj::C_HEAP) GrowableArray(size, true); @@ -497,6 +498,7 @@ } delete _marking_stack; + delete _objarray_stack; delete _revisit_klass_stack; delete _revisit_mdo_stack; } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -785,7 +785,7 @@ void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); } void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); } -void PSParallelCompact::FollowStackClosure::do_void() { follow_stack(_compaction_manager); } +void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); } void PSParallelCompact::MarkAndPushClosure::do_oop(oop* p) { mark_and_push(_compaction_manager, p); } void PSParallelCompact::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(_compaction_manager, p); } @@ -2376,7 +2376,7 @@ // Follow code cache roots. CodeCache::do_unloading(is_alive_closure(), &mark_and_push_closure, purged_class); - follow_stack(cm); // Flush marking stack. + cm->follow_marking_stacks(); // Flush marking stack. // Update subklass/sibling/implementor links of live klasses // revisit_klass_stack is used in follow_weak_klass_links(). @@ -2389,8 +2389,7 @@ SymbolTable::unlink(is_alive_closure()); StringTable::unlink(is_alive_closure()); - assert(cm->marking_stack()->size() == 0, "stack should be empty by now"); - assert(cm->overflow_stack()->is_empty(), "stack should be empty by now"); + assert(cm->marking_stacks_empty(), "marking stacks should be empty"); } // This should be moved to the shared markSweep code! @@ -2709,22 +2708,6 @@ young_gen->move_and_update(cm); } - -void PSParallelCompact::follow_stack(ParCompactionManager* cm) { - while(!cm->overflow_stack()->is_empty()) { - oop obj = cm->overflow_stack()->pop(); - obj->follow_contents(cm); - } - - oop obj; - // obj is a reference!!! - while (cm->marking_stack()->pop_local(obj)) { - // It would be nice to assert about the type of objects we might - // pop, but they can come from anywhere, unfortunately. - obj->follow_contents(cm); - } -} - void PSParallelCompact::follow_weak_klass_links() { // All klasses on the revisit stack are marked at this point. @@ -2745,7 +2728,7 @@ &keep_alive_closure); } // revisit_klass_stack is cleared in reset() - follow_stack(cm); + cm->follow_marking_stacks(); } } @@ -2776,7 +2759,7 @@ rms->at(j)->follow_weak_refs(is_alive_closure()); } // revisit_mdo_stack is cleared in reset() - follow_stack(cm); + cm->follow_marking_stacks(); } } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -901,7 +901,6 @@ // Mark live objects static void marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction); - static void follow_stack(ParCompactionManager* cm); static void follow_weak_klass_links(); static void follow_mdo_weak_refs(); @@ -1276,7 +1275,7 @@ } } } - follow_stack(cm); + cm->follow_marking_stacks(); } template diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/shared/markSweep.cpp --- a/src/share/vm/gc_implementation/shared/markSweep.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -25,8 +25,9 @@ #include "incls/_precompiled.incl" #include "incls/_markSweep.cpp.incl" -GrowableArray* MarkSweep::_marking_stack = NULL; -GrowableArray* MarkSweep::_revisit_klass_stack = NULL; +GrowableArray* MarkSweep::_marking_stack = NULL; +GrowableArray* MarkSweep::_objarray_stack = NULL; +GrowableArray* MarkSweep::_revisit_klass_stack = NULL; GrowableArray* MarkSweep::_revisit_mdo_stack = NULL; GrowableArray* MarkSweep::_preserved_oop_stack = NULL; @@ -104,11 +105,19 @@ void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(p); } void MarkSweep::follow_stack() { - while (!_marking_stack->is_empty()) { - oop obj = _marking_stack->pop(); - assert (obj->is_gc_marked(), "p must be marked"); - obj->follow_contents(); - } + do { + while (!_marking_stack->is_empty()) { + oop obj = _marking_stack->pop(); + assert (obj->is_gc_marked(), "p must be marked"); + obj->follow_contents(); + } + // Process ObjArrays one at a time to avoid marking stack bloat. + if (!_objarray_stack->is_empty()) { + ObjArrayTask task = _objarray_stack->pop(); + objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint(); + k->oop_follow_contents(task.obj(), task.index()); + } + } while (!_marking_stack->is_empty() || !_objarray_stack->is_empty()); } MarkSweep::FollowStackClosure MarkSweep::follow_stack_closure; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/shared/markSweep.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -110,8 +110,9 @@ // Vars // protected: - // Traversal stack used during phase1 + // Traversal stacks used during phase1 static GrowableArray* _marking_stack; + static GrowableArray* _objarray_stack; // Stack for live klasses to revisit at end of marking phase static GrowableArray* _revisit_klass_stack; // Set (stack) of MDO's to revisit at end of marking phase @@ -188,6 +189,7 @@ template static inline void mark_and_follow(T* p); // Check mark and maybe push on marking stack template static inline void mark_and_push(T* p); + static inline void push_objarray(oop obj, size_t index); static void follow_stack(); // Empty marking stack. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -77,6 +77,12 @@ } } +void MarkSweep::push_objarray(oop obj, size_t index) { + ObjArrayTask task(obj, index); + assert(task.is_valid(), "bad ObjArrayTask"); + _objarray_stack->push(task); +} + template inline void MarkSweep::adjust_pointer(T* p, bool isroot) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/includeDB_compiler1 --- a/src/share/vm/includeDB_compiler1 Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/includeDB_compiler1 Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ // -// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -246,6 +246,7 @@ c1_LIRGenerator.cpp c1_LIRGenerator.hpp c1_LIRGenerator.cpp c1_ValueStack.hpp c1_LIRGenerator.cpp ciArrayKlass.hpp +c1_LIRGenerator.cpp ciCPCache.hpp c1_LIRGenerator.cpp ciInstance.hpp c1_LIRGenerator.cpp heapRegion.hpp c1_LIRGenerator.cpp sharedRuntime.hpp diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/includeDB_core --- a/src/share/vm/includeDB_core Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/includeDB_core Tue Apr 06 22:06:57 2010 -0700 @@ -176,6 +176,7 @@ arguments.cpp oop.inline.hpp arguments.cpp os_.inline.hpp arguments.cpp referenceProcessor.hpp +arguments.cpp taskqueue.hpp arguments.cpp universe.inline.hpp arguments.cpp vm_version_.hpp @@ -540,6 +541,7 @@ ciCPCache.cpp cpCacheOop.hpp ciCPCache.cpp ciCPCache.hpp +ciCPCache.cpp ciUtilities.hpp ciCPCache.hpp ciClassList.hpp ciCPCache.hpp ciObject.hpp @@ -1021,6 +1023,7 @@ codeCache.cpp codeCache.hpp codeCache.cpp dependencies.hpp codeCache.cpp gcLocker.hpp +codeCache.cpp handles.inline.hpp codeCache.cpp icache.hpp codeCache.cpp iterator.hpp codeCache.cpp java.hpp @@ -2014,6 +2017,7 @@ init.cpp icBuffer.hpp init.cpp icache.hpp init.cpp init.hpp +init.cpp methodHandles.hpp init.cpp safepoint.hpp init.cpp sharedRuntime.hpp init.cpp universe.hpp @@ -2022,6 +2026,7 @@ instanceKlass.cpp collectedHeap.inline.hpp instanceKlass.cpp compileBroker.hpp +instanceKlass.cpp dtrace.hpp instanceKlass.cpp fieldDescriptor.hpp instanceKlass.cpp genOopClosures.inline.hpp instanceKlass.cpp handles.inline.hpp @@ -2481,6 +2486,7 @@ jvm.cpp collectedHeap.inline.hpp jvm.cpp copy.hpp jvm.cpp defaultStream.hpp +jvm.cpp dtrace.hpp jvm.cpp dtraceJSDT.hpp jvm.cpp events.hpp jvm.cpp handles.inline.hpp @@ -2722,8 +2728,10 @@ markSweep.cpp compileBroker.hpp markSweep.cpp methodDataOop.hpp +markSweep.cpp objArrayKlass.inline.hpp markSweep.hpp collectedHeap.hpp +markSweep.hpp taskqueue.hpp memRegion.cpp globals.hpp memRegion.cpp memRegion.hpp @@ -2868,6 +2876,7 @@ methodHandles.cpp oopFactory.hpp methodHandles.cpp reflection.hpp methodHandles.cpp signature.hpp +methodHandles.cpp stubRoutines.hpp methodHandles.cpp symbolTable.hpp methodHandles_.cpp allocation.inline.hpp @@ -3052,8 +3061,10 @@ objArrayKlass.cpp genOopClosures.inline.hpp objArrayKlass.cpp handles.inline.hpp objArrayKlass.cpp instanceKlass.hpp +objArrayKlass.cpp markSweep.inline.hpp objArrayKlass.cpp mutexLocker.hpp objArrayKlass.cpp objArrayKlass.hpp +objArrayKlass.cpp objArrayKlass.inline.hpp objArrayKlass.cpp objArrayKlassKlass.hpp objArrayKlass.cpp objArrayOop.hpp objArrayKlass.cpp oop.inline.hpp @@ -3064,11 +3075,12 @@ objArrayKlass.cpp universe.inline.hpp objArrayKlass.cpp vmSymbols.hpp - objArrayKlass.hpp arrayKlass.hpp objArrayKlass.hpp instanceKlass.hpp objArrayKlass.hpp specialized_oop_closures.hpp +objArrayKlass.inline.hpp objArrayKlass.hpp + objArrayKlassKlass.cpp collectedHeap.inline.hpp objArrayKlassKlass.cpp instanceKlass.hpp objArrayKlassKlass.cpp javaClasses.hpp @@ -4094,6 +4106,7 @@ task.hpp top.hpp taskqueue.cpp debug.hpp +taskqueue.cpp oop.inline.hpp taskqueue.cpp os.hpp taskqueue.cpp taskqueue.hpp taskqueue.cpp thread_.inline.hpp @@ -4447,6 +4460,7 @@ unsafe.cpp allocation.inline.hpp unsafe.cpp copy.hpp +unsafe.cpp dtrace.hpp unsafe.cpp globals.hpp unsafe.cpp interfaceSupport.hpp unsafe.cpp jni.h @@ -4618,6 +4632,7 @@ vmThread.cpp collectedHeap.hpp vmThread.cpp compileBroker.hpp +vmThread.cpp dtrace.hpp vmThread.cpp events.hpp vmThread.cpp interfaceSupport.hpp vmThread.cpp methodOop.hpp diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/includeDB_gc_parallel --- a/src/share/vm/includeDB_gc_parallel Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/includeDB_gc_parallel Tue Apr 06 22:06:57 2010 -0700 @@ -115,10 +115,14 @@ objArrayKlass.cpp g1CollectedHeap.inline.hpp objArrayKlass.cpp g1OopClosures.inline.hpp objArrayKlass.cpp oop.pcgc.inline.hpp +objArrayKlass.cpp psCompactionManager.hpp objArrayKlass.cpp psPromotionManager.inline.hpp objArrayKlass.cpp psScavenge.inline.hpp objArrayKlass.cpp parOopClosures.inline.hpp +objArrayKlass.inline.hpp psCompactionManager.inline.hpp +objArrayKlass.inline.hpp psParallelCompact.hpp + oop.pcgc.inline.hpp parNewGeneration.hpp oop.pcgc.inline.hpp parallelScavengeHeap.hpp oop.pcgc.inline.hpp psCompactionManager.hpp diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2328,6 +2328,17 @@ } DEFAULT: +#ifdef ZERO + // Some zero configurations use the C++ interpreter as a + // fallback interpreter and have support for platform + // specific fast bytecodes which aren't supported here, so + // redispatch to the equivalent non-fast bytecode when they + // are encountered. + if (Bytecodes::is_defined((Bytecodes::Code)opcode)) { + opcode = (jubyte)Bytecodes::java_code((Bytecodes::Code)opcode); + goto opcode_switch; + } +#endif fatal2("\t*** Unimplemented opcode: %d = %s\n", opcode, Bytecodes::name((Bytecodes::Code)opcode)); goto finish; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/memory/genMarkSweep.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -159,6 +159,7 @@ _preserved_oop_stack = NULL; _marking_stack = new (ResourceObj::C_HEAP) GrowableArray(4000, true); + _objarray_stack = new (ResourceObj::C_HEAP) GrowableArray(50, true); int size = SystemDictionary::number_of_classes() * 2; _revisit_klass_stack = new (ResourceObj::C_HEAP) GrowableArray(size, true); @@ -194,7 +195,6 @@ void GenMarkSweep::deallocate_stacks() { - if (!UseG1GC) { GenCollectedHeap* gch = GenCollectedHeap::heap(); gch->release_scratch(); @@ -208,6 +208,7 @@ } delete _marking_stack; + delete _objarray_stack; delete _revisit_klass_stack; delete _revisit_mdo_stack; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/memory/genOopClosures.hpp --- a/src/share/vm/memory/genOopClosures.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/memory/genOopClosures.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -28,10 +28,10 @@ class CardTableModRefBS; class DefNewGeneration; -template class GenericTaskQueue; -typedef GenericTaskQueue OopTaskQueue; -template class GenericTaskQueueSet; -typedef GenericTaskQueueSet OopTaskQueueSet; +template class GenericTaskQueue; +typedef GenericTaskQueue OopTaskQueue; +template class GenericTaskQueueSet; +typedef GenericTaskQueueSet OopTaskQueueSet; // Closure for iterating roots from a particular generation // Note: all classes deriving from this MUST call this do_barrier diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/oops/instanceKlass.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -25,6 +25,58 @@ # include "incls/_precompiled.incl" # include "incls/_instanceKlass.cpp.incl" +#ifdef DTRACE_ENABLED + +HS_DTRACE_PROBE_DECL4(hotspot, class__initialization__required, + char*, intptr_t, oop, intptr_t); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__recursive, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__concurrent, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__erroneous, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__super__failed, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__clinit, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__error, + char*, intptr_t, oop, intptr_t, int); +HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__end, + char*, intptr_t, oop, intptr_t, int); + +#define DTRACE_CLASSINIT_PROBE(type, clss, thread_type) \ + { \ + char* data = NULL; \ + int len = 0; \ + symbolOop name = (clss)->name(); \ + if (name != NULL) { \ + data = (char*)name->bytes(); \ + len = name->utf8_length(); \ + } \ + HS_DTRACE_PROBE4(hotspot, class__initialization__##type, \ + data, len, (clss)->class_loader(), thread_type); \ + } + +#define DTRACE_CLASSINIT_PROBE_WAIT(type, clss, thread_type, wait) \ + { \ + char* data = NULL; \ + int len = 0; \ + symbolOop name = (clss)->name(); \ + if (name != NULL) { \ + data = (char*)name->bytes(); \ + len = name->utf8_length(); \ + } \ + HS_DTRACE_PROBE5(hotspot, class__initialization__##type, \ + data, len, (clss)->class_loader(), thread_type, wait); \ + } + +#else // ndef DTRACE_ENABLED + +#define DTRACE_CLASSINIT_PROBE(type, clss, thread_type) +#define DTRACE_CLASSINIT_PROBE_WAIT(type, clss, thread_type, wait) + +#endif // ndef DTRACE_ENABLED + bool instanceKlass::should_be_initialized() const { return !is_initialized(); } @@ -292,6 +344,10 @@ // A class could already be verified, since it has been reflected upon. this_oop->link_class(CHECK); + DTRACE_CLASSINIT_PROBE(required, instanceKlass::cast(this_oop()), -1); + + bool wait = false; + // refer to the JVM book page 47 for description of steps // Step 1 { ObjectLocker ol(this_oop, THREAD); @@ -303,19 +359,25 @@ // we might end up throwing IE from link/symbol resolution sites // that aren't expected to throw. This would wreak havoc. See 6320309. while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) { + wait = true; ol.waitUninterruptibly(CHECK); } // Step 3 - if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) + if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) { + DTRACE_CLASSINIT_PROBE_WAIT(recursive, instanceKlass::cast(this_oop()), -1,wait); return; + } // Step 4 - if (this_oop->is_initialized()) + if (this_oop->is_initialized()) { + DTRACE_CLASSINIT_PROBE_WAIT(concurrent, instanceKlass::cast(this_oop()), -1,wait); return; + } // Step 5 if (this_oop->is_in_error_state()) { + DTRACE_CLASSINIT_PROBE_WAIT(erroneous, instanceKlass::cast(this_oop()), -1,wait); ResourceMark rm(THREAD); const char* desc = "Could not initialize class "; const char* className = this_oop->external_name(); @@ -348,6 +410,7 @@ this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below } + DTRACE_CLASSINIT_PROBE_WAIT(super__failed, instanceKlass::cast(this_oop()), -1,wait); THROW_OOP(e()); } } @@ -356,6 +419,7 @@ { assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl"); JavaThread* jt = (JavaThread*)THREAD; + DTRACE_CLASSINIT_PROBE_WAIT(clinit, instanceKlass::cast(this_oop()), -1,wait); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), @@ -383,6 +447,7 @@ this_oop->set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below } + DTRACE_CLASSINIT_PROBE_WAIT(error, instanceKlass::cast(this_oop()), -1,wait); if (e->is_a(SystemDictionary::Error_klass())) { THROW_OOP(e()); } else { @@ -392,6 +457,7 @@ &args); } } + DTRACE_CLASSINIT_PROBE_WAIT(end, instanceKlass::cast(this_oop()), -1,wait); } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/oops/objArrayKlass.cpp --- a/src/share/vm/oops/objArrayKlass.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/oops/objArrayKlass.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -314,24 +314,24 @@ void objArrayKlass::oop_follow_contents(oop obj) { assert (obj->is_array(), "obj must be array"); - objArrayOop a = objArrayOop(obj); - a->follow_header(); - ObjArrayKlass_OOP_ITERATE( \ - a, p, \ - /* we call mark_and_follow here to avoid excessive marking stack usage */ \ - MarkSweep::mark_and_follow(p)) + objArrayOop(obj)->follow_header(); + if (UseCompressedOops) { + objarray_follow_contents(obj, 0); + } else { + objarray_follow_contents(obj, 0); + } } #ifndef SERIALGC void objArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { - assert (obj->is_array(), "obj must be array"); - objArrayOop a = objArrayOop(obj); - a->follow_header(cm); - ObjArrayKlass_OOP_ITERATE( \ - a, p, \ - /* we call mark_and_follow here to avoid excessive marking stack usage */ \ - PSParallelCompact::mark_and_follow(cm, p)) + assert(obj->is_array(), "obj must be array"); + objArrayOop(obj)->follow_header(cm); + if (UseCompressedOops) { + objarray_follow_contents(cm, obj, 0); + } else { + objarray_follow_contents(cm, obj, 0); + } } #endif // SERIALGC diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/oops/objArrayKlass.hpp --- a/src/share/vm/oops/objArrayKlass.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/oops/objArrayKlass.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -91,10 +91,18 @@ // Garbage collection void oop_follow_contents(oop obj); + inline void oop_follow_contents(oop obj, int index); + template inline void objarray_follow_contents(oop obj, int index); + int oop_adjust_pointers(oop obj); // Parallel Scavenge and Parallel Old PARALLEL_GC_DECLS +#ifndef SERIALGC + inline void oop_follow_contents(ParCompactionManager* cm, oop obj, int index); + template inline void + objarray_follow_contents(ParCompactionManager* cm, oop obj, int index); +#endif // !SERIALGC // Iterators int oop_oop_iterate(oop obj, OopClosure* blk) { @@ -131,5 +139,4 @@ void oop_verify_on(oop obj, outputStream* st); void oop_verify_old_oop(oop obj, oop* p, bool allow_dirty); void oop_verify_old_oop(oop obj, narrowOop* p, bool allow_dirty); - }; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/oops/objArrayKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/objArrayKlass.inline.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,89 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +void objArrayKlass::oop_follow_contents(oop obj, int index) { + if (UseCompressedOops) { + objarray_follow_contents(obj, index); + } else { + objarray_follow_contents(obj, index); + } +} + +template +void objArrayKlass::objarray_follow_contents(oop obj, int index) { + objArrayOop a = objArrayOop(obj); + const size_t len = size_t(a->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)a->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + MarkSweep::mark_and_push(e); + } + + if (end_index < len) { + MarkSweep::push_objarray(a, end_index); // Push the continuation. + } +} + +#ifndef SERIALGC +void objArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj, + int index) { + if (UseCompressedOops) { + objarray_follow_contents(cm, obj, index); + } else { + objarray_follow_contents(cm, obj, index); + } +} + +template +void objArrayKlass::objarray_follow_contents(ParCompactionManager* cm, oop obj, + int index) { + objArrayOop a = objArrayOop(obj); + const size_t len = size_t(a->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)a->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + PSParallelCompact::mark_and_push(cm, e); + } + + if (end_index < len) { + cm->push_objarray(a, end_index); // Push the continuation. + } +} +#endif // #ifndef SERIALGC diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/doCall.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -714,8 +714,6 @@ // iterate through all entries sequentially for (;!handlers.is_done(); handlers.next()) { - // Do nothing if turned off - if( !DeutschShiffmanExceptions ) break; ciExceptionHandler* handler = handlers.handler(); if (handler->is_rethrow()) { @@ -741,46 +739,26 @@ return; // No more handling to be done here! } - // %%% The following logic replicates make_from_klass_unique. - // TO DO: Replace by a subroutine call. Then generalize - // the type check, as noted in the next "%%%" comment. - + // Get the handler's klass ciInstanceKlass* klass = handler->catch_klass(); - if (UseUniqueSubclasses) { - // (We use make_from_klass because it respects UseUniqueSubclasses.) - const TypeOopPtr* tp = TypeOopPtr::make_from_klass(klass); - klass = tp->klass()->as_instance_klass(); + + if (!klass->is_loaded()) { // klass is not loaded? + // fall through into catch_call_exceptions which will emit a + // handler with an uncommon trap. + break; } - // Get the handler's klass - if (!klass->is_loaded()) // klass is not loaded? - break; // Must call Rethrow! if (klass->is_interface()) // should not happen, but... break; // bail out - // See if the loaded exception klass has no subtypes - if (klass->has_subklass()) - break; // Cannot easily do precise test ==> Rethrow - // %%% Now that subclass checking is very fast, we need to rewrite - // this section and remove the option "DeutschShiffmanExceptions". - // The exception processing chain should be a normal typecase pattern, - // with a bailout to the interpreter only in the case of unloaded - // classes. (The bailout should mark the method non-entrant.) - // This rewrite should be placed in GraphKit::, not Parse::. - - // Add a dependence; if any subclass added we need to recompile - // %%% should use stronger assert_unique_concrete_subtype instead - if (!klass->is_final()) { - C->dependencies()->assert_leaf_type(klass); - } - - // Implement precise test + // Check the type of the exception against the catch type const TypeKlassPtr *tk = TypeKlassPtr::make(klass); Node* con = _gvn.makecon(tk); - Node* cmp = _gvn.transform( new (C, 3) CmpPNode(ex_klass_node, con) ); - Node* bol = _gvn.transform( new (C, 2) BoolNode(cmp, BoolTest::ne) ); - { BuildCutout unless(this, bol, PROB_LIKELY(0.7f)); - const TypeInstPtr* tinst = TypeInstPtr::make_exact(TypePtr::NotNull, klass); + Node* not_subtype_ctrl = gen_subtype_check(ex_klass_node, con); + if (!stopped()) { + PreserveJVMState pjvms(this); + const TypeInstPtr* tinst = TypeOopPtr::make_from_klass_unique(klass)->cast_to_ptr_type(TypePtr::NotNull)->is_instptr(); + assert(klass->has_subklass() || tinst->klass_is_exact(), "lost exactness"); Node* ex_oop = _gvn.transform(new (C, 2) CheckCastPPNode(control(), ex_node, tinst)); push_ex_oop(ex_oop); // Push exception oop for handler #ifndef PRODUCT @@ -792,6 +770,7 @@ #endif merge_exception(handler_bci); } + set_control(not_subtype_ctrl); // Come here if exception does not match handler. // Carry on with more handler checks. @@ -800,21 +779,6 @@ assert(!stopped(), "you should return if you finish the chain"); - if (remaining == 1) { - // Further checks do not matter. - } - - if (can_rerun_bytecode()) { - // Do not push_ex_oop here! - // Re-executing the bytecode will reproduce the throwing condition. - bool must_throw = true; - uncommon_trap(Deoptimization::Reason_unhandled, - Deoptimization::Action_none, - (ciKlass*)NULL, (const char*)NULL, // default args - must_throw); - return; - } - // Oops, need to call into the VM to resolve the klasses at runtime. // Note: This call must not deoptimize, since it is not a real at this bci! kill_dead_locals(); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1785,6 +1785,8 @@ bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, bool must_reason_predicate) { Node *in0 = proj->in(0); if (!in0->is_If()) return false; + // Variation of a dead If node. + if (in0->outcnt() < 2) return false; IfNode* iff = in0->as_If(); // we need "If(Conv2B(Opaque1(...)))" pattern for must_reason_predicate @@ -2086,29 +2088,41 @@ BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl, int scale, Node* offset, Node* init, Node* limit, Node* stride, - Node* range) { + Node* range, bool upper) { + DEBUG_ONLY(ttyLocker ttyl); + if (TraceLoopPredicate) tty->print("rc_predicate "); + Node* max_idx_expr = init; int stride_con = stride->get_int(); - if ((stride_con > 0) == (scale > 0)) { + if ((stride_con > 0) == (scale > 0) == upper) { max_idx_expr = new (C, 3) SubINode(limit, stride); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("(limit - stride) "); + } else { + if (TraceLoopPredicate) tty->print("init "); } if (scale != 1) { ConNode* con_scale = _igvn.intcon(scale); max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("* %d ", scale); } if (offset && (!offset->is_Con() || offset->get_int() != 0)){ max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) + if (offset->is_Con()) tty->print("+ %d ", offset->get_int()); + else tty->print("+ offset "); } CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); register_new_node(cmp, ctrl); BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); register_new_node(bol, ctrl); + + if (TraceLoopPredicate) tty->print_cr("_head->is_Loop()) { + // Could be a simple region when irreducible loops are present. + return false; + } + + CountedLoopNode *cl = NULL; + if (loop->_head->is_CountedLoop()) { + cl = loop->_head->as_CountedLoop(); + // do nothing for iteration-splitted loops + if (!cl->is_normal_loop()) return false; + } + // Too many traps seen? bool tmt = C->too_many_traps(C->method(), 0, Deoptimization::Reason_predicate); int tc = C->trap_count(Deoptimization::Reason_predicate); @@ -2129,13 +2155,6 @@ return false; } - CountedLoopNode *cl = NULL; - if (loop->_head->is_CountedLoop()) { - cl = loop->_head->as_CountedLoop(); - // do nothing for iteration-splitted loops - if(!cl->is_normal_loop()) return false; - } - LoopNode *lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); @@ -2180,7 +2199,6 @@ while (if_proj_list.size() > 0) { // Following are changed to nonnull when a predicate can be hoisted ProjNode* new_predicate_proj = NULL; - BoolNode* new_predicate_bol = NULL; ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); @@ -2211,93 +2229,120 @@ // Invariant test new_predicate_proj = create_new_if_for_predicate(predicate_proj); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); - new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); - if (TraceLoopPredicate) tty->print("invariant"); + BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); + + // Negate test if necessary + bool negated = false; + if (proj->_con != predicate_proj->_con) { + new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); + register_new_node(new_predicate_bol, ctrl); + negated = true; + } + IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); + _igvn.hash_delete(new_predicate_iff); + new_predicate_iff->set_req(1, new_predicate_bol); + if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx); + } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { - // Range check (only for counted loops) - new_predicate_proj = create_new_if_for_predicate(predicate_proj); - Node *ctrl = new_predicate_proj->in(0)->as_If()->in(0); + assert(proj->_con == predicate_proj->_con, "must match"); + + // Range check for counted loops const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); assert(cmp->in(2)->Opcode() == Op_LoadRange, "must be"); - LoadRangeNode* ld_rng = (LoadRangeNode*)cmp->in(2); // LoadRangeNode + Node* ld_rng = cmp->in(2); // LoadRangeNode assert(invar.is_invariant(ld_rng), "load range must be invariant"); - ld_rng = (LoadRangeNode*)invar.clone(ld_rng, ctrl); int scale = 1; Node* offset = zero; bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); assert(ok, "must be index expression"); + + Node* init = cl->init_trip(); + Node* limit = cl->limit(); + Node* stride = cl->stride(); + + // Build if's for the upper and lower bound tests. The + // lower_bound test will dominate the upper bound test and all + // cloned or created nodes will use the lower bound test as + // their declared control. + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj); + assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); + Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); + + // Perform cloning to keep Invariance state correct since the + // late schedule will place invariant things in the loop. + ld_rng = invar.clone(ld_rng, ctrl); if (offset && offset != zero) { assert(invar.is_invariant(offset), "offset must be loop invariant"); offset = invar.clone(offset, ctrl); } - Node* init = cl->init_trip(); - Node* limit = cl->limit(); - Node* stride = cl->stride(); - new_predicate_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng); - if (TraceLoopPredicate) tty->print("range check"); - } + + // Test the lower bound + Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, false); + IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); + _igvn.hash_delete(lower_bound_iff); + lower_bound_iff->set_req(1, lower_bound_bol); + if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); - if (new_predicate_proj == NULL) { + // Test the upper bound + Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, true); + IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); + _igvn.hash_delete(upper_bound_iff); + upper_bound_iff->set_req(1, upper_bound_bol); + if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); + + // Fall through into rest of the clean up code which will move + // any dependent nodes onto the upper bound test. + new_predicate_proj = upper_bound_proj; + } else { // The other proj of the "iff" is a uncommon trap projection, and we can assume // the other proj will not be executed ("executed" means uct raised). continue; - } else { - // Success - attach condition (new_predicate_bol) to predicate if - invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - IfNode* new_iff = new_predicate_proj->in(0)->as_If(); + } - // Negate test if necessary - if (proj->_con != predicate_proj->_con) { - new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); - register_new_node(new_predicate_bol, new_iff->in(0)); - if (TraceLoopPredicate) tty->print_cr(" if negated: %d", iff->_idx); - } else { - if (TraceLoopPredicate) tty->print_cr(" if: %d", iff->_idx); - } + // Success - attach condition (new_predicate_bol) to predicate if + invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - _igvn.hash_delete(new_iff); - new_iff->set_req(1, new_predicate_bol); - - _igvn.hash_delete(iff); - iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); + // Eliminate the old if in the loop body + _igvn.hash_delete(iff); + iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); - Node* ctrl = new_predicate_proj; // new control - ProjNode* dp = proj; // old control - assert(get_loop(dp) == loop, "guarenteed at the time of collecting proj"); - // Find nodes (depends only on the test) off the surviving projection; - // move them outside the loop with the control of proj_clone - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node - if (cd->depends_only_on_test()) { - assert(cd->in(0) == dp, ""); - _igvn.hash_delete(cd); - cd->set_req(0, ctrl); // ctrl, not NULL - set_early_ctrl(cd); - _igvn._worklist.push(cd); - IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if (new_loop != loop) { - if (!loop->_child) loop->_body.yank(cd); - if (!new_loop->_child ) new_loop->_body.push(cd); - } - --i; - --imax; + Node* ctrl = new_predicate_proj; // new control + ProjNode* dp = proj; // old control + assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj"); + // Find nodes (depends only on the test) off the surviving projection; + // move them outside the loop with the control of proj_clone + for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { + Node* cd = dp->fast_out(i); // Control-dependent node + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); + cd->set_req(0, ctrl); // ctrl, not NULL + set_early_ctrl(cd); + _igvn._worklist.push(cd); + IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); + if (new_loop != loop) { + if (!loop->_child) loop->_body.yank(cd); + if (!new_loop->_child ) new_loop->_body.push(cd); } + --i; + --imax; } + } - hoisted = true; - C->set_major_progress(); - } + hoisted = true; + C->set_major_progress(); } // end while #ifndef PRODUCT - // report that the loop predication has been actually performed - // for this loop - if (TraceLoopPredicate && hoisted) { - tty->print("Loop Predication Performed:"); - loop->dump_head(); - } + // report that the loop predication has been actually performed + // for this loop + if (TraceLoopPredicate && hoisted) { + tty->print("Loop Predication Performed:"); + loop->dump_head(); + } #endif return hoisted; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/loopnode.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -821,7 +821,7 @@ BoolNode* rc_predicate(Node* ctrl, int scale, Node* offset, Node* init, Node* limit, Node* stride, - Node* range); + Node* range, bool upper); // Implementation of the loop predication to promote checks outside the loop bool loop_predication_impl(IdealLoopTree *loop); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/matcher.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -373,8 +373,8 @@ // to implement the UseStrictFP mode. static const bool strict_fp_requires_explicit_rounding; - // Do floats take an entire double register or just half? - static const bool float_in_double; + // Are floats conerted to double when stored to stack during deoptimization? + static bool float_in_double(); // Do ints take an entire long register or just half? static const bool int_in_long; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/output.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -678,7 +678,7 @@ #endif //_LP64 else if( (t->base() == Type::FloatBot || t->base() == Type::FloatCon) && OptoReg::is_reg(regnum) ) { - array->append(new_loc_value( _regalloc, regnum, Matcher::float_in_double + array->append(new_loc_value( _regalloc, regnum, Matcher::float_in_double() ? Location::float_in_dbl : Location::normal )); } else if( t->base() == Type::Int && OptoReg::is_reg(regnum) ) { array->append(new_loc_value( _regalloc, regnum, Matcher::int_in_long diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/parse.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -551,9 +551,6 @@ // Also handles exceptions for individual bytecodes. void catch_inline_exceptions(SafePointNode* ex_map); - // Bytecode classifier, helps decide to use uncommon_trap vs. rethrow_C. - bool can_rerun_bytecode(); - // Merge the given map into correct exceptional exit state. // Assumes that there is no applicable local handler. void throw_to_exit(SafePointNode* ex_map); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/parse1.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,6 @@ C->record_method_not_compilable("OSR in empty or breakpointed method"); return; } - MethodLivenessResult raw_live_locals = method()->raw_liveness_at_bci(osr_bci()); // Extract the needed locals from the interpreter frame. Node *locals_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals-1)*wordSize); @@ -306,6 +305,7 @@ SafePointNode* bad_type_exit = clone_map(); bad_type_exit->set_control(new (C, 1) RegionNode(1)); + assert(osr_block->flow()->jsrs()->size() == 0, "should be no jsrs live at osr point"); for (index = 0; index < max_locals; index++) { if (stopped()) break; Node* l = local(index); @@ -317,8 +317,18 @@ continue; } } - if (type->basic_type() == T_ADDRESS && !raw_live_locals.at(index)) { - // Skip type check for dead address locals + if (osr_block->flow()->local_type_at(index)->is_return_address()) { + // In our current system it's illegal for jsr addresses to be + // live into an OSR entry point because the compiler performs + // inlining of jsrs. ciTypeFlow has a bailout that detect this + // case and aborts the compile if addresses are live into an OSR + // entry point. Because of that we can assume that any address + // locals at the OSR entry point are dead. Method liveness + // isn't precise enought to figure out that they are dead in all + // cases so simply skip checking address locals all + // together. Any type check is guaranteed to fail since the + // interpreter type is the result of a load which might have any + // value and the expected type is a constant. continue; } set_local(index, check_interpreter_type(l, type, bad_type_exit)); @@ -788,67 +798,6 @@ initial_gvn()->transform_no_reclaim(exit); } -bool Parse::can_rerun_bytecode() { - switch (bc()) { - case Bytecodes::_ldc: - case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: - case Bytecodes::_getfield: - case Bytecodes::_putfield: - case Bytecodes::_getstatic: - case Bytecodes::_putstatic: - case Bytecodes::_arraylength: - case Bytecodes::_baload: - case Bytecodes::_caload: - case Bytecodes::_iaload: - case Bytecodes::_saload: - case Bytecodes::_faload: - case Bytecodes::_aaload: - case Bytecodes::_laload: - case Bytecodes::_daload: - case Bytecodes::_bastore: - case Bytecodes::_castore: - case Bytecodes::_iastore: - case Bytecodes::_sastore: - case Bytecodes::_fastore: - case Bytecodes::_aastore: - case Bytecodes::_lastore: - case Bytecodes::_dastore: - case Bytecodes::_irem: - case Bytecodes::_idiv: - case Bytecodes::_lrem: - case Bytecodes::_ldiv: - case Bytecodes::_frem: - case Bytecodes::_fdiv: - case Bytecodes::_drem: - case Bytecodes::_ddiv: - case Bytecodes::_checkcast: - case Bytecodes::_instanceof: - case Bytecodes::_anewarray: - case Bytecodes::_newarray: - case Bytecodes::_multianewarray: - case Bytecodes::_new: - case Bytecodes::_monitorenter: // can re-run initial null check, only - case Bytecodes::_return: - return true; - break; - - // Don't rerun athrow since it's part of the exception path. - case Bytecodes::_athrow: - case Bytecodes::_invokestatic: - case Bytecodes::_invokedynamic: - case Bytecodes::_invokespecial: - case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - return false; - break; - - default: - assert(false, "unexpected bytecode produced an exception"); - return true; - } -} - //---------------------------do_exceptions------------------------------------- // Process exceptions arising from the current bytecode. // Send caught exceptions to the proper handler within this method. @@ -862,9 +811,6 @@ return; } - // Make sure we can classify this bytecode if we need to. - debug_only(can_rerun_bytecode()); - PreserveJVMState pjvms(this, false); SafePointNode* ex_map; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/runtime.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -864,7 +864,7 @@ thread->set_exception_handler_pc(handler_address); thread->set_exception_stack_size(0); - // Check if the exception PC is a MethodHandle call. + // Check if the exception PC is a MethodHandle call site. thread->set_is_method_handle_exception(nm->is_method_handle_return(pc)); } @@ -952,7 +952,7 @@ thread->set_vm_result(exception); // Frame not compiled (handles deoptimization blob) - return SharedRuntime::raw_exception_handler_for_return_address(ret_pc); + return SharedRuntime::raw_exception_handler_for_return_address(thread, ret_pc); } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/split_if.cpp --- a/src/share/vm/opto/split_if.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/split_if.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,10 +187,20 @@ } #endif + // ConvI2L may have type information on it which becomes invalid if + // it moves up in the graph so change any clones so widen the type + // to TypeLong::INT when pushing it up. + const Type* rtype = NULL; + if (n->Opcode() == Op_ConvI2L && n->bottom_type() != TypeLong::INT) { + rtype = TypeLong::INT; + } + // Now actually split-up this guy. One copy per control path merging. Node *phi = PhiNode::make_blank(blk1, n); for( uint j = 1; j < blk1->req(); j++ ) { Node *x = n->clone(); + // Widen the type of the ConvI2L when pushing up. + if (rtype != NULL) x->as_Type()->set_type(rtype); if( n->in(0) && n->in(0) == blk1 ) x->set_req( 0, blk1->in(j) ); for( uint i = 1; i < n->req(); i++ ) { diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/opto/type.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -2812,7 +2812,8 @@ // then we can subclass in the Java class hierarchy. if (klass()->equals(ciEnv::current()->Object_klass())) { // that is, tp's array type is a subtype of my klass - return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id); + return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL), + tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id); } } // The other case cannot happen, since I cannot be a subtype of an array. @@ -3418,7 +3419,8 @@ // then we can subclass in the Java class hierarchy. if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) { // that is, my array type is a subtype of 'tp' klass - return make( ptr, _ary, _klass, _klass_is_exact, offset, instance_id ); + return make( ptr, (ptr == Constant ? const_oop() : NULL), + _ary, _klass, _klass_is_exact, offset, instance_id ); } } // The other case cannot happen, since t cannot be a subtype of an array. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/forte.cpp --- a/src/share/vm/prims/forte.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/forte.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -55,12 +55,11 @@ }; -static void is_decipherable_compiled_frame(frame* fr, RegisterMap* map, - bool* is_compiled_p, bool* is_walkable_p); +static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm); static bool is_decipherable_interpreted_frame(JavaThread* thread, - frame* fr, - methodOop* method_p, - int* bci_p); + frame* fr, + methodOop* method_p, + int* bci_p); @@ -122,41 +121,43 @@ // Determine if 'fr' is a decipherable compiled frame. We are already // assured that fr is for a java nmethod. -static bool is_decipherable_compiled_frame(frame* fr) { - - assert(fr->cb() != NULL && fr->cb()->is_nmethod(), "invariant"); - nmethod* nm = (nmethod*) fr->cb(); +static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm) { assert(nm->is_java_method(), "invariant"); - // First try and find an exact PcDesc - - PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); - - // Did we find a useful PcDesc? - if (pc_desc != NULL && - pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { - - address probe_pc = fr->pc() + 1; - pc_desc = nm->pc_desc_near(probe_pc); + if (thread->has_last_Java_frame() && thread->last_Java_pc() == fr->pc()) { + // We're stopped at a call into the JVM so look for a PcDesc with + // the actual pc reported by the frame. + PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); - // Now do we have a useful PcDesc? - + // Did we find a useful PcDesc? if (pc_desc != NULL && - pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { - // No debug information available for this pc - // vframeStream would explode if we try and walk the frames. - return false; + pc_desc->scope_decode_offset() != DebugInformationRecorder::serialized_null) { + return true; } - - // This PcDesc is useful however we must adjust the frame's pc - // so that the vframeStream lookups will use this same pc - - fr->set_pc(pc_desc->real_pc(nm)); } + // We're at some random pc in the nmethod so search for the PcDesc + // whose pc is greater than the current PC. It's done this way + // because the extra PcDescs that are recorded for improved debug + // info record the end of the region covered by the ScopeDesc + // instead of the beginning. + PcDesc* pc_desc = nm->pc_desc_near(fr->pc() + 1); + + // Now do we have a useful PcDesc? + if (pc_desc == NULL || + pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { + // No debug information available for this pc + // vframeStream would explode if we try and walk the frames. + return false; + } + + // This PcDesc is useful however we must adjust the frame's pc + // so that the vframeStream lookups will use this same pc + fr->set_pc(pc_desc->real_pc(nm)); return true; } + // Determine if 'fr' is a walkable interpreted frame. Returns false // if it is not. *method_p, and *bci_p are not set when false is // returned. *method_p is non-NULL if frame was executing a Java @@ -166,9 +167,9 @@ // even if a valid BCI cannot be found. static bool is_decipherable_interpreted_frame(JavaThread* thread, - frame* fr, - methodOop* method_p, - int* bci_p) { + frame* fr, + methodOop* method_p, + int* bci_p) { assert(fr->is_interpreted_frame(), "just checking"); // top frame is an interpreted frame @@ -323,13 +324,15 @@ // have a PCDesc that can get us a bci however we did find // a method - if (!is_decipherable_compiled_frame(&candidate)) { + if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { return false; } // is_decipherable_compiled_frame may modify candidate's pc *initial_frame_p = candidate; + assert(nm->pc_desc_at(candidate.pc()) != NULL, "if it's decipherable then pc must be valid"); + return true; } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/jni.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -3401,12 +3401,16 @@ thread->set_thread_state(_thread_in_vm); // Must do this before initialize_thread_local_storage thread->record_stack_base_and_size(); + thread->initialize_thread_local_storage(); if (!os::create_attached_thread(thread)) { delete thread; return JNI_ERR; } + // Enable stack overflow checks + thread->create_stack_guard_pages(); + thread->initialize_tlab(); // Crucial that we do not have a safepoint check for this thread, since it has @@ -3452,9 +3456,6 @@ // to regrab the threads_lock thread->set_attached(); - // Enable stack overflow checks - thread->create_stack_guard_pages(); - // Set java thread status. java_lang_Thread::set_thread_status(thread->threadObj(), java_lang_Thread::RUNNABLE); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/jvm.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -26,6 +26,10 @@ #include "incls/_jvm.cpp.incl" #include +HS_DTRACE_PROBE_DECL1(hotspot, thread__sleep__begin, long long); +HS_DTRACE_PROBE_DECL1(hotspot, thread__sleep__end, int); +HS_DTRACE_PROBE_DECL0(hotspot, thread__yield); + /* NOTE about use of any ctor or function call that can trigger a safepoint/GC: such ctors and calls MUST NOT come between an oop declaration/init and its @@ -2762,6 +2766,7 @@ JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass)) JVMWrapper("JVM_Yield"); if (os::dont_yield()) return; + HS_DTRACE_PROBE0(hotspot, thread__yield); // When ConvertYieldToSleep is off (default), this matches the classic VM use of yield. // Critical for similar threading behaviour if (ConvertYieldToSleep) { @@ -2787,6 +2792,8 @@ // And set new thread state to SLEEPING. JavaThreadSleepState jtss(thread); + HS_DTRACE_PROBE1(hotspot, thread__sleep__begin, millis); + if (millis == 0) { // When ConvertSleepToYield is on, this matches the classic VM implementation of // JVM_Sleep. Critical for similar threading behaviour (Win32) @@ -2807,6 +2814,7 @@ // An asynchronous exception (e.g., ThreadDeathException) could have been thrown on // us while we were sleeping. We do not overwrite those. if (!HAS_PENDING_EXCEPTION) { + HS_DTRACE_PROBE1(hotspot, thread__sleep__end,1); // TODO-FIXME: THROW_MSG returns which means we will not call set_state() // to properly restore the thread state. That's likely wrong. THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted"); @@ -2814,6 +2822,7 @@ } thread->osthread()->set_state(old_state); } + HS_DTRACE_PROBE1(hotspot, thread__sleep__end,0); JVM_END JVM_ENTRY(jobject, JVM_CurrentThread(JNIEnv* env, jclass threadClass)) diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ NULL }; +// Adapters. +MethodHandlesAdapterBlob* MethodHandles::_adapter_code = NULL; +int MethodHandles::_adapter_code_size = StubRoutines::method_handles_adapters_code_size; + jobject MethodHandles::_raise_exception_method; #ifdef ASSERT @@ -95,6 +99,41 @@ } #endif + +//------------------------------------------------------------------------------ +// MethodHandles::generate_adapters +// +void MethodHandles::generate_adapters() { + if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; + + assert(_adapter_code == NULL, "generate only once"); + + ResourceMark rm; + TraceTime timer("MethodHandles adapters generation", TraceStartupTime); + _adapter_code = MethodHandlesAdapterBlob::create(_adapter_code_size); + if (_adapter_code == NULL) + vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); + CodeBuffer code(_adapter_code->instructions_begin(), _adapter_code->instructions_size()); + + MethodHandlesAdapterGenerator g(&code); + g.generate(); +} + + +//------------------------------------------------------------------------------ +// MethodHandlesAdapterGenerator::generate +// +void MethodHandlesAdapterGenerator::generate() { + // Generate generic method handle adapters. + for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; + ek < MethodHandles::_EK_LIMIT; + ek = MethodHandles::EntryKind(1 + (int)ek)) { + StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); + MethodHandles::generate_method_handle_stub(_masm, ek); + } +} + + void MethodHandles::set_enabled(bool z) { if (_enabled != z) { guarantee(z && EnableMethodHandles, "can only enable once, and only if -XX:+EnableMethodHandles"); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/methodHandles.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,10 @@ static const char* _entry_names[_EK_LIMIT+1]; static jobject _raise_exception_method; + // Adapters. + static MethodHandlesAdapterBlob* _adapter_code; + static int _adapter_code_size; + static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; } static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; } @@ -133,6 +137,43 @@ _entries[ek] = me; } + // Some adapter helper functions. + static void get_ek_bound_mh_info(EntryKind ek, BasicType& arg_type, int& arg_mask, int& arg_slots) { + switch (ek) { + case _bound_int_mh : // fall-thru + case _bound_int_direct_mh : arg_type = T_INT; arg_mask = _INSERT_INT_MASK; break; + case _bound_long_mh : // fall-thru + case _bound_long_direct_mh: arg_type = T_LONG; arg_mask = _INSERT_LONG_MASK; break; + case _bound_ref_mh : // fall-thru + case _bound_ref_direct_mh : arg_type = T_OBJECT; arg_mask = _INSERT_REF_MASK; break; + default: ShouldNotReachHere(); + } + arg_slots = type2size[arg_type]; + } + + static void get_ek_adapter_opt_swap_rot_info(EntryKind ek, int& swap_bytes, int& rotate) { + int swap_slots = 0; + switch (ek) { + case _adapter_opt_swap_1: swap_slots = 1; rotate = 0; break; + case _adapter_opt_swap_2: swap_slots = 2; rotate = 0; break; + case _adapter_opt_rot_1_up: swap_slots = 1; rotate = 1; break; + case _adapter_opt_rot_1_down: swap_slots = 1; rotate = -1; break; + case _adapter_opt_rot_2_up: swap_slots = 2; rotate = 1; break; + case _adapter_opt_rot_2_down: swap_slots = 2; rotate = -1; break; + default: ShouldNotReachHere(); + } + // Return the size of the stack slots to move in bytes. + swap_bytes = swap_slots * Interpreter::stackElementSize(); + } + + static int get_ek_adapter_opt_spread_info(EntryKind ek) { + switch (ek) { + case _adapter_opt_spread_0: return 0; + case _adapter_opt_spread_1: return 1; + default : return -1; + } + } + static methodOop raise_exception_method() { oop rem = JNIHandles::resolve(_raise_exception_method); assert(rem == NULL || rem->is_method(), ""); @@ -230,7 +271,10 @@ // bit values for suppress argument to expand_MemberName: enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; - // called from InterpreterGenerator and StubGenerator + // Generate MethodHandles adapters. + static void generate_adapters(); + + // Called from InterpreterGenerator and MethodHandlesAdapterGenerator. static address generate_method_handle_interpreter_entry(MacroAssembler* _masm); static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek); @@ -385,13 +429,13 @@ static void insert_arg_slots(MacroAssembler* _masm, RegisterOrConstant arg_slots, int arg_mask, - Register rax_argslot, - Register rbx_temp, Register rdx_temp); + Register argslot_reg, + Register temp_reg, Register temp2_reg); static void remove_arg_slots(MacroAssembler* _masm, RegisterOrConstant arg_slots, - Register rax_argslot, - Register rbx_temp, Register rdx_temp); + Register argslot_reg, + Register temp_reg, Register temp2_reg); }; @@ -447,3 +491,14 @@ address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); } address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); } + + +//------------------------------------------------------------------------------ +// MethodHandlesAdapterGenerator +// +class MethodHandlesAdapterGenerator : public StubCodeGenerator { +public: + MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {} + + void generate(); +}; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/prims/unsafe.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -29,6 +29,10 @@ #include "incls/_precompiled.incl" #include "incls/_unsafe.cpp.incl" +HS_DTRACE_PROBE_DECL3(hotspot, thread__park__begin, uintptr_t, int, long long); +HS_DTRACE_PROBE_DECL1(hotspot, thread__park__end, uintptr_t); +HS_DTRACE_PROBE_DECL1(hotspot, thread__unpark, uintptr_t); + #define MAX_OBJECT_SIZE \ ( arrayOopDesc::header_size(T_DOUBLE) * HeapWordSize \ + ((julong)max_jint * sizeof(double)) ) @@ -1083,8 +1087,10 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) UnsafeWrapper("Unsafe_Park"); + HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time); JavaThreadParkedState jtps(thread, time != 0); thread->parker()->park(isAbsolute != 0, time); + HS_DTRACE_PROBE1(hotspot, thread__park__end, thread->parker()); UNSAFE_END UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) @@ -1116,6 +1122,7 @@ } } if (p != NULL) { + HS_DTRACE_PROBE1(hotspot, thread__unpark, p); p->unpark(); } UNSAFE_END diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/arguments.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1203,6 +1203,11 @@ if (!FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim) || !FLAG_IS_DEFAULT(OldPLABWeight)) { CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight); } + if (PrintGCDetails && Verbose) { + tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", + MarkStackSize / K, MarkStackSizeMax / K); + tty->print_cr("ConcGCThreads: %u", ConcGCThreads); + } } #endif // KERNEL @@ -1339,6 +1344,15 @@ if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { FLAG_SET_DEFAULT(MaxGCPauseMillis, 200); } + + if (FLAG_IS_DEFAULT(MarkStackSize)) { + FLAG_SET_DEFAULT(MarkStackSize, 128 * TASKQUEUE_SIZE); + } + if (PrintGCDetails && Verbose) { + tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", + MarkStackSize / K, MarkStackSizeMax / K); + tty->print_cr("ConcGCThreads: %u", ConcGCThreads); + } } void Arguments::set_heap_size() { @@ -1737,6 +1751,11 @@ status = false; } + if (UseG1GC) { + status = status && verify_percentage(InitiatingHeapOccupancyPercent, + "InitiatingHeapOccupancyPercent"); + } + status = status && verify_interval(RefDiscoveryPolicy, ReferenceProcessor::DiscoveryPolicyMin, ReferenceProcessor::DiscoveryPolicyMax, @@ -1795,6 +1814,29 @@ return false; } +bool Arguments::parse_uintx(const char* value, + uintx* uintx_arg, + uintx min_size) { + + // Check the sign first since atomull() parses only unsigned values. + bool value_is_positive = !(*value == '-'); + + if (value_is_positive) { + julong n; + bool good_return = atomull(value, &n); + if (good_return) { + bool above_minimum = n >= min_size; + bool value_is_too_large = n > max_uintx; + + if (above_minimum && !value_is_too_large) { + *uintx_arg = n; + return true; + } + } + } + return false; +} + Arguments::ArgsRange Arguments::parse_memory_size(const char* s, julong* long_arg, julong min_size) { @@ -2453,6 +2495,37 @@ jio_fprintf(defaultStream::error_stream(), "Please use -XX:YoungPLABSize in place of " "-XX:ParallelGCToSpaceAllocBufferSize in the future\n"); + } else if (match_option(option, "-XX:CMSMarkStackSize=", &tail) || + match_option(option, "-XX:G1MarkStackSize=", &tail)) { + julong stack_size = 0; + ArgsRange errcode = parse_memory_size(tail, &stack_size, 1); + if (errcode != arg_in_range) { + jio_fprintf(defaultStream::error_stream(), + "Invalid mark stack size: %s\n", option->optionString); + describe_range_error(errcode); + return JNI_EINVAL; + } + FLAG_SET_CMDLINE(uintx, MarkStackSize, stack_size); + } else if (match_option(option, "-XX:CMSMarkStackSizeMax=", &tail)) { + julong max_stack_size = 0; + ArgsRange errcode = parse_memory_size(tail, &max_stack_size, 1); + if (errcode != arg_in_range) { + jio_fprintf(defaultStream::error_stream(), + "Invalid maximum mark stack size: %s\n", + option->optionString); + describe_range_error(errcode); + return JNI_EINVAL; + } + FLAG_SET_CMDLINE(uintx, MarkStackSizeMax, max_stack_size); + } else if (match_option(option, "-XX:ParallelMarkingThreads=", &tail) || + match_option(option, "-XX:ParallelCMSThreads=", &tail)) { + uintx conc_threads = 0; + if (!parse_uintx(tail, &conc_threads, 1)) { + jio_fprintf(defaultStream::error_stream(), + "Invalid concurrent threads: %s\n", option->optionString); + return JNI_EINVAL; + } + FLAG_SET_CMDLINE(uintx, ConcGCThreads, conc_threads); } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) { @@ -2784,6 +2857,12 @@ } #endif // _LP64 + // MethodHandles code does not support TaggedStackInterpreter. + if (EnableMethodHandles && TaggedStackInterpreter) { + warning("TaggedStackInterpreter is not supported by MethodHandles code. Disabling TaggedStackInterpreter."); + TaggedStackInterpreter = false; + } + // Check the GC selections again. if (!check_gc_consistency()) { return JNI_EINVAL; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/arguments.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -343,6 +343,12 @@ static ArgsRange check_memory_size(julong size, julong min_size); static ArgsRange parse_memory_size(const char* s, julong* long_arg, julong min_size); + // Parse a string for a unsigned integer. Returns true if value + // is an unsigned integer greater than or equal to the minimum + // parameter passed and returns the value in uintx_arg. Returns + // false otherwise, with uintx_arg undefined. + static bool parse_uintx(const char* value, uintx* uintx_arg, + uintx min_size); // methods to build strings from individual args static void build_jvm_args(const char* arg); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/globals.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -1245,9 +1245,6 @@ product(uintx, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ \ - product(uintx, ParallelCMSThreads, 0, \ - "Max number of threads CMS will use for concurrent work") \ - \ develop(bool, ParallelOldGCSplitALot, false, \ "Provoke splitting (copying data from a young gen space to" \ "multiple destination spaces)") \ @@ -1258,8 +1255,8 @@ develop(bool, TraceRegionTasksQueuing, false, \ "Trace the queuing of the region tasks") \ \ - product(uintx, ParallelMarkingThreads, 0, \ - "Number of marking threads concurrent gc will use") \ + product(uintx, ConcGCThreads, 0, \ + "Number of threads concurrent gc will use") \ \ product(uintx, YoungPLABSize, 4096, \ "Size of young gen promotion labs (in HeapWords)") \ @@ -1535,11 +1532,11 @@ develop(bool, CMSOverflowEarlyRestoration, false, \ "Whether preserved marks should be restored early") \ \ - product(uintx, CMSMarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ - "Size of CMS marking stack") \ - \ - product(uintx, CMSMarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \ - "Max size of CMS marking stack") \ + 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") \ \ notproduct(bool, CMSMarkStackOverflowALot, false, \ "Whether we should simulate frequent marking stack / work queue" \ @@ -1724,6 +1721,13 @@ "Percentage CMS generation occupancy to start a CMS collection " \ "cycle. A negative value means that CMSTriggerRatio is used") \ \ + product(uintx, InitiatingHeapOccupancyPercent, 45, \ + "Percentage of the (entire) heap occupancy to start a " \ + "concurrent GC cycle. It us used by GCs that trigger a " \ + "concurrent GC cycle based on the occupancy of the entire heap, " \ + "not just one of the generations (e.g., G1). A value of 0 " \ + "denotes 'do constant GC cycles'.") \ + \ product(intx, CMSInitiatingPermOccupancyFraction, -1, \ "Percentage CMS perm generation occupancy to start a " \ "CMScollection cycle. A negative value means that " \ @@ -1791,6 +1795,10 @@ product(uintx, PreserveMarkStackSize, 1024, \ "Size for stack used in promotion failure handling") \ \ + develop(uintx, ObjArrayMarkingStride, 512, \ + "Number of ObjArray elements to push onto the marking stack" \ + "before pushing a continuation entry") \ + \ product_pd(bool, UseTLAB, "Use thread-local object allocation") \ \ product_pd(bool, ResizeTLAB, \ @@ -2285,6 +2293,10 @@ "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") \ + \ develop(bool, InlineAccessors, true, \ "inline accessor methods (get/set)") \ \ @@ -2490,10 +2502,6 @@ notproduct(bool, TraceSpilling, false, \ "Trace spilling") \ \ - develop(bool, DeutschShiffmanExceptions, true, \ - "Fast check to find exception handler for precisely typed " \ - "exceptions") \ - \ product(bool, SplitIfBlocks, true, \ "Clone compares and control flow through merge points to fold " \ "some branches") \ @@ -2925,7 +2933,7 @@ product(uintx, OldSize, ScaleForWordSize(4*M), \ "Initial tenured generation size (in bytes)") \ \ - product(uintx, NewSize, ScaleForWordSize(4*M), \ + product(uintx, NewSize, ScaleForWordSize(1*M), \ "Initial new generation size (in bytes)") \ \ product(uintx, MaxNewSize, max_uintx, \ diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/init.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,6 +118,9 @@ javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init + // Generate MethodHandles adapters. + MethodHandles::generate_adapters(); + // Although we'd like to, we can't easily do a heap verify // here because the main thread isn't yet a JavaThread, so // its TLAB may not be made parseable from the usual interfaces. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/os.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -218,6 +218,9 @@ static bool guard_memory(char* addr, size_t bytes); static bool unguard_memory(char* addr, size_t bytes); + static bool create_stack_guard_pages(char* addr, size_t bytes); + static bool remove_stack_guard_pages(char* addr, size_t bytes); + static char* map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only = false, bool allow_exec = false); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/safepoint.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -30,8 +30,8 @@ SafepointSynchronize::SynchronizeState volatile SafepointSynchronize::_state = SafepointSynchronize::_not_synchronized; volatile int SafepointSynchronize::_waiting_to_block = 0; -jlong SafepointSynchronize::_last_safepoint = 0; volatile int SafepointSynchronize::_safepoint_counter = 0; +long SafepointSynchronize::_end_of_last_safepoint = 0; static volatile int PageArmed = 0 ; // safepoint polling page is RO|RW vs PROT_NONE static volatile int TryingToBlock = 0 ; // proximate value -- for advisory use only static bool timeout_error_printed = false; @@ -42,7 +42,10 @@ Thread* myThread = Thread::current(); assert(myThread->is_VM_thread(), "Only VM thread may execute a safepoint"); - _last_safepoint = os::javaTimeNanos(); + if (PrintSafepointStatistics || PrintSafepointStatisticsTimeout > 0) { + _safepoint_begin_time = os::javaTimeNanos(); + _ts_of_current_safepoint = tty->time_stamp().seconds(); + } #ifndef SERIALGC if (UseConcMarkSweepGC) { @@ -320,6 +323,11 @@ // Call stuff that needs to be run when a safepoint is just about to be completed do_cleanup_tasks(); + + if (PrintSafepointStatistics) { + // Record how much time spend on the above cleanup tasks + update_statistics_on_cleanup_end(os::javaTimeNanos()); + } } } @@ -411,6 +419,9 @@ ConcurrentGCThread::safepoint_desynchronize(); } #endif // SERIALGC + // record this time so VMThread can keep track how much time has elasped + // since last safepoint. + _end_of_last_safepoint = os::javaTimeMillis(); } bool SafepointSynchronize::is_cleanup_needed() { @@ -445,24 +456,23 @@ // Various cleaning tasks that should be done periodically at safepoints void SafepointSynchronize::do_cleanup_tasks() { - jlong cleanup_time; - - // Update fat-monitor pool, since this is a safepoint. - if (TraceSafepoint) { - cleanup_time = os::javaTimeNanos(); + { + TraceTime t1("deflating idle monitors", TraceSafepointCleanupTime); + ObjectSynchronizer::deflate_idle_monitors(); } - ObjectSynchronizer::deflate_idle_monitors(); - InlineCacheBuffer::update_inline_caches(); + { + TraceTime t2("updating inline caches", TraceSafepointCleanupTime); + InlineCacheBuffer::update_inline_caches(); + } + if(UseCounterDecay && CounterDecay::is_decay_needed()) { + TraceTime t3("decaying counter", TraceSafepointCleanupTime); CounterDecay::decay(); } + + TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime); NMethodSweeper::sweep(); - - if (TraceSafepoint) { - tty->print_cr("do_cleanup_tasks takes "INT64_FORMAT_W(6) "ms", - (os::javaTimeNanos() - cleanup_time) / MICROUNITS); - } } @@ -979,17 +989,32 @@ // Statistics & Instrumentations // SafepointSynchronize::SafepointStats* SafepointSynchronize::_safepoint_stats = NULL; +jlong SafepointSynchronize::_safepoint_begin_time = 0; int SafepointSynchronize::_cur_stat_index = 0; julong SafepointSynchronize::_safepoint_reasons[VM_Operation::VMOp_Terminating]; julong SafepointSynchronize::_coalesced_vmop_count = 0; jlong SafepointSynchronize::_max_sync_time = 0; +jlong SafepointSynchronize::_max_vmop_time = 0; +float SafepointSynchronize::_ts_of_current_safepoint = 0.0f; -// last_safepoint_start_time records the start time of last safepoint. -static jlong last_safepoint_start_time = 0; -static jlong sync_end_time = 0; +static jlong cleanup_end_time = 0; static bool need_to_track_page_armed_status = false; static bool init_done = false; +// Helper method to print the header. +static void print_header() { + tty->print(" vmop " + "[threads: total initially_running wait_to_block] "); + tty->print("[time: spin block sync cleanup vmop] "); + + // no page armed status printed out if it is always armed. + if (need_to_track_page_armed_status) { + tty->print("page_armed "); + } + + tty->print_cr("page_trap_count"); +} + void SafepointSynchronize::deferred_initialize_stat() { if (init_done) return; @@ -1016,19 +1041,6 @@ if (UseCompilerSafepoints && DeferPollingPageLoopCount >= 0) { need_to_track_page_armed_status = true; } - - tty->print(" vmop_name " - "[threads: total initially_running wait_to_block] "); - tty->print("[time: spin block sync] " - "[vmop_time time_elapsed] "); - - // no page armed status printed out if it is always armed. - if (need_to_track_page_armed_status) { - tty->print("page_armed "); - } - - tty->print_cr("page_trap_count"); - init_done = true; } @@ -1036,6 +1048,8 @@ assert(init_done, "safepoint statistics array hasn't been initialized"); SafepointStats *spstat = &_safepoint_stats[_cur_stat_index]; + spstat->_time_stamp = _ts_of_current_safepoint; + VM_Operation *op = VMThread::vm_operation(); spstat->_vmop_type = (op != NULL ? op->type() : -1); if (op != NULL) { @@ -1054,14 +1068,6 @@ } else { spstat->_time_to_spin = 0; } - - if (last_safepoint_start_time == 0) { - spstat->_time_elapsed_since_last_safepoint = 0; - } else { - spstat->_time_elapsed_since_last_safepoint = _last_safepoint - - last_safepoint_start_time; - } - last_safepoint_start_time = _last_safepoint; } void SafepointSynchronize::update_statistics_on_spin_end() { @@ -1097,18 +1103,31 @@ // Records the end time of sync which will be used to calculate the total // vm operation time. Again, the real time spending in syncing will be deducted // from the start of the sync time later when end_statistics is called. - spstat->_time_to_sync = end_time - _last_safepoint; + spstat->_time_to_sync = end_time - _safepoint_begin_time; if (spstat->_time_to_sync > _max_sync_time) { _max_sync_time = spstat->_time_to_sync; } - sync_end_time = end_time; + + spstat->_time_to_do_cleanups = end_time; +} + +void SafepointSynchronize::update_statistics_on_cleanup_end(jlong end_time) { + SafepointStats *spstat = &_safepoint_stats[_cur_stat_index]; + + // Record how long spent in cleanup tasks. + spstat->_time_to_do_cleanups = end_time - spstat->_time_to_do_cleanups; + + cleanup_end_time = end_time; } void SafepointSynchronize::end_statistics(jlong vmop_end_time) { SafepointStats *spstat = &_safepoint_stats[_cur_stat_index]; // Update the vm operation time. - spstat->_time_to_exec_vmop = vmop_end_time - sync_end_time; + spstat->_time_to_exec_vmop = vmop_end_time - cleanup_end_time; + if (spstat->_time_to_exec_vmop > _max_vmop_time) { + _max_vmop_time = spstat->_time_to_exec_vmop; + } // Only the sync time longer than the specified // PrintSafepointStatisticsTimeout will be printed out right away. // By default, it is -1 meaning all samples will be put into the list. @@ -1119,40 +1138,42 @@ } else { // The safepoint statistics will be printed out when the _safepoin_stats // array fills up. - if (_cur_stat_index != PrintSafepointStatisticsCount - 1) { - _cur_stat_index ++; - } else { + if (_cur_stat_index == PrintSafepointStatisticsCount - 1) { print_statistics(); _cur_stat_index = 0; - tty->print_cr(""); + } else { + _cur_stat_index++; } } } void SafepointSynchronize::print_statistics() { - int index; SafepointStats* sstats = _safepoint_stats; - for (index = 0; index <= _cur_stat_index; index++) { + for (int index = 0; index <= _cur_stat_index; index++) { + if (index % 30 == 0) { + print_header(); + } sstats = &_safepoint_stats[index]; - tty->print("%-28s [" + tty->print("%.3f: ", sstats->_time_stamp); + tty->print("%-26s [" INT32_FORMAT_W(8)INT32_FORMAT_W(11)INT32_FORMAT_W(15) - "] ", + " ] ", sstats->_vmop_type == -1 ? "no vm operation" : VM_Operation::name(sstats->_vmop_type), sstats->_nof_total_threads, sstats->_nof_initial_running_threads, sstats->_nof_threads_wait_to_block); // "/ MICROUNITS " is to convert the unit from nanos to millis. - tty->print(" [" - INT64_FORMAT_W(6)INT64_FORMAT_W(6)INT64_FORMAT_W(6) - "] " - "["INT64_FORMAT_W(6)INT64_FORMAT_W(9) "] ", + tty->print(" [" + INT64_FORMAT_W(6)INT64_FORMAT_W(6) + INT64_FORMAT_W(6)INT64_FORMAT_W(6) + INT64_FORMAT_W(6)" ] ", sstats->_time_to_spin / MICROUNITS, sstats->_time_to_wait_to_block / MICROUNITS, sstats->_time_to_sync / MICROUNITS, - sstats->_time_to_exec_vmop / MICROUNITS, - sstats->_time_elapsed_since_last_safepoint / MICROUNITS); + sstats->_time_to_do_cleanups / MICROUNITS, + sstats->_time_to_exec_vmop / MICROUNITS); if (need_to_track_page_armed_status) { tty->print(INT32_FORMAT" ", sstats->_page_armed); @@ -1174,7 +1195,7 @@ // don't print it out. // Approximate the vm op time. _safepoint_stats[_cur_stat_index]._time_to_exec_vmop = - os::javaTimeNanos() - sync_end_time; + os::javaTimeNanos() - cleanup_end_time; if ( PrintSafepointStatisticsTimeout < 0 || spstat->_time_to_sync > PrintSafepointStatisticsTimeout * MICROUNITS) { @@ -1203,6 +1224,9 @@ _coalesced_vmop_count); tty->print_cr("Maximum sync time "INT64_FORMAT_W(5)" ms", _max_sync_time / MICROUNITS); + tty->print_cr("Maximum vm operation time (except for Exit VM operation) " + INT64_FORMAT_W(5)" ms", + _max_vmop_time / MICROUNITS); } // ------------------------------------------------------------------------------------------------ diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/safepoint.hpp --- a/src/share/vm/runtime/safepoint.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/safepoint.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -65,6 +65,7 @@ }; typedef struct { + float _time_stamp; // record when the current safepoint occurs in seconds int _vmop_type; // type of VM operation triggers the safepoint int _nof_total_threads; // total number of Java threads int _nof_initial_running_threads; // total number of initially seen running threads @@ -73,14 +74,14 @@ int _nof_threads_hit_page_trap; // total number of threads hitting the page trap jlong _time_to_spin; // total time in millis spent in spinning jlong _time_to_wait_to_block; // total time in millis spent in waiting for to block + jlong _time_to_do_cleanups; // total time in millis spent in performing cleanups jlong _time_to_sync; // total time in millis spent in getting to _synchronized jlong _time_to_exec_vmop; // total time in millis spent in vm operation itself - jlong _time_elapsed_since_last_safepoint; // time elasped since last safepoint } SafepointStats; private: static volatile SynchronizeState _state; // Threads might read this flag directly, without acquireing the Threads_lock - static volatile int _waiting_to_block; // No. of threads we are waiting for to block. + static volatile int _waiting_to_block; // number of threads we are waiting for to block // This counter is used for fast versions of jni_GetField. // An even value means there is no ongoing safepoint operations. @@ -91,19 +92,22 @@ public: static volatile int _safepoint_counter; private: - - static jlong _last_safepoint; // Time of last safepoint + static long _end_of_last_safepoint; // Time of last safepoint in milliseconds // statistics - static SafepointStats* _safepoint_stats; // array of SafepointStats struct - static int _cur_stat_index; // current index to the above array - static julong _safepoint_reasons[]; // safepoint count for each VM op - static julong _coalesced_vmop_count;// coalesced vmop count - static jlong _max_sync_time; // maximum sync time in nanos + static jlong _safepoint_begin_time; // time when safepoint begins + static SafepointStats* _safepoint_stats; // array of SafepointStats struct + static int _cur_stat_index; // current index to the above array + static julong _safepoint_reasons[]; // safepoint count for each VM op + static julong _coalesced_vmop_count; // coalesced vmop count + static jlong _max_sync_time; // maximum sync time in nanos + static jlong _max_vmop_time; // maximum vm operation time in nanos + static float _ts_of_current_safepoint; // time stamp of current safepoint in seconds static void begin_statistics(int nof_threads, int nof_running); static void update_statistics_on_spin_end(); static void update_statistics_on_sync_end(jlong end_time); + static void update_statistics_on_cleanup_end(jlong end_time); static void end_statistics(jlong end_time); static void print_statistics(); inline static void inc_page_trap_count() { @@ -140,7 +144,9 @@ static void handle_polling_page_exception(JavaThread *thread); // VM Thread interface for determining safepoint rate - static long last_non_safepoint_interval() { return os::javaTimeMillis() - _last_safepoint; } + static long last_non_safepoint_interval() { + return os::javaTimeMillis() - _end_of_last_safepoint; + } static bool is_cleanup_needed(); static void do_cleanup_tasks(); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -256,7 +256,7 @@ // The continuation address is the entry point of the exception handler of the // previous frame depending on the return address. -address SharedRuntime::raw_exception_handler_for_return_address(address return_address) { +address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) { assert(frame::verify_return_pc(return_address), "must be a return pc"); // the fastest case first @@ -264,6 +264,8 @@ if (blob != NULL && blob->is_nmethod()) { nmethod* code = (nmethod*)blob; assert(code != NULL, "nmethod must be present"); + // Check if the return address is a MethodHandle call site. + thread->set_is_method_handle_exception(code->is_method_handle_return(return_address)); // native nmethods don't have exception handlers assert(!code->is_native_method(), "no exception handler"); assert(code->header_begin() != code->exception_begin(), "no exception handler"); @@ -289,6 +291,8 @@ if (blob->is_nmethod()) { nmethod* code = (nmethod*)blob; assert(code != NULL, "nmethod must be present"); + // Check if the return address is a MethodHandle call site. + thread->set_is_method_handle_exception(code->is_method_handle_return(return_address)); assert(code->header_begin() != code->exception_begin(), "no exception handler"); return code->exception_begin(); } @@ -309,10 +313,11 @@ } -JRT_LEAF(address, SharedRuntime::exception_handler_for_return_address(address return_address)) - return raw_exception_handler_for_return_address(return_address); +JRT_LEAF(address, SharedRuntime::exception_handler_for_return_address(JavaThread* thread, address return_address)) + return raw_exception_handler_for_return_address(thread, return_address); JRT_END + address SharedRuntime::get_poll_stub(address pc) { address stub; // Look up the code blob @@ -465,16 +470,6 @@ t = table.entry_for(catch_pco, -1, 0); } -#ifdef COMPILER1 - if (nm->is_compiled_by_c1() && t == NULL && handler_bci == -1) { - // Exception is not handled by this frame so unwind. Note that - // this is not the same as how C2 does this. C2 emits a table - // entry that dispatches to the unwind code in the nmethod. - return NULL; - } -#endif /* COMPILER1 */ - - if (t == NULL) { tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", ret_pc, handler_bci); tty->print_cr(" Exception:"); @@ -587,7 +582,7 @@ // 3. Implict null exception in nmethod if (!cb->is_nmethod()) { - guarantee(cb->is_adapter_blob(), + guarantee(cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(), "exception happened outside interpreter, nmethods and vtable stubs (1)"); // There is no handler here, so we will simply unwind. return StubRoutines::throw_NullPointerException_at_call_entry(); @@ -892,12 +887,13 @@ RegisterMap cbl_map(thread, false); frame caller_frame = thread->last_frame().sender(&cbl_map); - CodeBlob* cb = caller_frame.cb(); - guarantee(cb != NULL && cb->is_nmethod(), "must be called from nmethod"); + CodeBlob* caller_cb = caller_frame.cb(); + guarantee(caller_cb != NULL && caller_cb->is_nmethod(), "must be called from nmethod"); + nmethod* caller_nm = caller_cb->as_nmethod_or_null(); // make sure caller is not getting deoptimized // and removed before we are done with it. // CLEANUP - with lazy deopt shouldn't need this lock - nmethodLocker caller_lock((nmethod*)cb); + nmethodLocker caller_lock(caller_nm); // determine call info & receiver @@ -929,6 +925,13 @@ } #endif + // JSR 292 + // If the resolved method is a MethodHandle invoke target the call + // site must be a MethodHandle call site. + if (callee_method->is_method_handle_invoke()) { + assert(caller_nm->is_method_handle_return(caller_frame.pc()), "must be MH call site"); + } + // Compute entry points. This might require generation of C2I converter // frames, so we cannot be holding any locks here. Furthermore, the // computation of the entry points is independent of patching the call. We @@ -940,13 +943,12 @@ StaticCallInfo static_call_info; CompiledICInfo virtual_call_info; - // Make sure the callee nmethod does not get deoptimized and removed before // we are done patching the code. - nmethod* nm = callee_method->code(); - nmethodLocker nl_callee(nm); + nmethod* callee_nm = callee_method->code(); + nmethodLocker nl_callee(callee_nm); #ifdef ASSERT - address dest_entry_point = nm == NULL ? 0 : nm->entry_point(); // used below + address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below #endif if (is_virtual) { @@ -2077,7 +2079,6 @@ // --------------------------------------------------------------------------- // Implementation of AdapterHandlerLibrary -const char* AdapterHandlerEntry::name = "I2C/C2I adapters"; AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL; AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL; const int AdapterHandlerLibrary_size = 16*K; @@ -2129,7 +2130,7 @@ ResourceMark rm; NOT_PRODUCT(int code_size); - BufferBlob *B = NULL; + AdapterBlob* B = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; { @@ -2179,7 +2180,7 @@ // Create I2C & C2I handlers - BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache + BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); short buffer_locs[20]; @@ -2208,7 +2209,7 @@ } #endif - B = BufferBlob::create(AdapterHandlerEntry::name, &buffer); + B = AdapterBlob::create(&buffer); NOT_PRODUCT(code_size = buffer.code_size()); } if (B == NULL) { @@ -2240,7 +2241,7 @@ jio_snprintf(blob_id, sizeof(blob_id), "%s(%s)@" PTR_FORMAT, - AdapterHandlerEntry::name, + B->name(), fingerprint->as_string(), B->instructions_begin()); VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end()); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/sharedRuntime.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -96,10 +96,9 @@ static jdouble dexp(jdouble x); static jdouble dpow(jdouble x, jdouble y); - // exception handling across interpreter/compiler boundaries - static address raw_exception_handler_for_return_address(address return_address); - static address exception_handler_for_return_address(address return_address); + static address raw_exception_handler_for_return_address(JavaThread* thread, address return_address); + static address exception_handler_for_return_address(JavaThread* thread, address return_address); #ifndef SERIALGC // G1 write barriers @@ -568,9 +567,6 @@ AdapterHandlerEntry(); public: - // The name we give all buffer blobs - static const char* name; - address get_i2c_entry() { return _i2c_entry; } address get_c2i_entry() { return _c2i_entry; } address get_c2i_unverified_entry() { return _c2i_unverified_entry; } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/thread.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1637,6 +1637,9 @@ JNIHandleBlock::release_block(block); } + // These have to be removed while this is still a valid thread. + remove_stack_guard_pages(); + if (UseTLAB) { tlab().make_parsable(true); // retire TLAB, if any } @@ -2134,7 +2137,7 @@ int allocate = os::allocate_stack_guard_pages(); // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); - if (allocate && !os::commit_memory((char *) low_addr, len)) { + if (allocate && !os::create_stack_guard_pages((char *) low_addr, len)) { warning("Attempt to allocate stack guard pages failed."); return; } @@ -2155,7 +2158,7 @@ size_t len = (StackYellowPages + StackRedPages) * os::vm_page_size(); if (os::allocate_stack_guard_pages()) { - if (os::uncommit_memory((char *) low_addr, len)) { + if (os::remove_stack_guard_pages((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { warning("Attempt to deallocate stack guard pages failed."); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/vframeArray.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -223,7 +223,7 @@ break; case Deoptimization::Unpack_exception: // exception is pending - pc = SharedRuntime::raw_exception_handler_for_return_address(pc); + pc = SharedRuntime::raw_exception_handler_for_return_address(thread, pc); // [phh] We're going to end up in some handler or other, so it doesn't // matter what mdp we point to. See exception_handler_for_exception() // in interpreterRuntime.cpp. diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/runtime/vmThread.cpp --- a/src/share/vm/runtime/vmThread.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/runtime/vmThread.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -25,6 +25,10 @@ # include "incls/_precompiled.incl" # include "incls/_vmThread.cpp.incl" +HS_DTRACE_PROBE_DECL3(hotspot, vmops__request, char *, uintptr_t, int); +HS_DTRACE_PROBE_DECL3(hotspot, vmops__begin, char *, uintptr_t, int); +HS_DTRACE_PROBE_DECL3(hotspot, vmops__end, char *, uintptr_t, int); + // Dummy VM operation to act as first element in our circular double-linked list class VM_Dummy: public VM_Operation { VMOp_Type type() const { return VMOp_Dummy; } @@ -132,6 +136,10 @@ //----------------------------------------------------------------- // High-level interface bool VMOperationQueue::add(VM_Operation *op) { + + HS_DTRACE_PROBE3(hotspot, vmops__request, op->name(), strlen(op->name()), + op->evaluation_mode()); + // Encapsulates VM queue policy. Currently, that // only involves putting them on the right list if (op->evaluate_at_safepoint()) { @@ -325,7 +333,11 @@ { PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time()); + HS_DTRACE_PROBE3(hotspot, vmops__begin, op->name(), strlen(op->name()), + op->evaluation_mode()); op->evaluate(); + HS_DTRACE_PROBE3(hotspot, vmops__end, op->name(), strlen(op->name()), + op->evaluation_mode()); } // Last access of info in _cur_vm_operation! diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/services/dtraceAttacher.cpp --- a/src/share/vm/services/dtraceAttacher.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/services/dtraceAttacher.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -135,4 +135,9 @@ } } +void DTrace::set_monitor_dprobes(bool flag) { + // explicit setting of DTraceMonitorProbes flag + set_bool_flag("DTraceMonitorProbes", flag); +} + #endif /* SOLARIS */ diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/services/dtraceAttacher.hpp --- a/src/share/vm/services/dtraceAttacher.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/services/dtraceAttacher.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -41,4 +41,6 @@ static void detach_all_clients(); // set ExtendedDTraceProbes flag static void set_extended_dprobes(bool value); + // set DTraceMonitorProbes flag + static void set_monitor_dprobes(bool value); }; diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/services/management.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -1537,7 +1537,6 @@ global->type = JMM_VMGLOBAL_TYPE_JSTRING; } else { global->type = JMM_VMGLOBAL_TYPE_UNKNOWN; - assert(false, "Unsupported VMGlobal Type"); return false; } diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/utilities/globalDefinitions.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -827,6 +827,8 @@ #define badHeapWord (::badHeapWordVal) #define badJNIHandle ((oop)::badJNIHandleVal) +// Default TaskQueue size is 16K (32-bit) or 128K (64-bit) +#define TASKQUEUE_SIZE (NOT_LP64(1<<14) LP64_ONLY(1<<17)) //---------------------------------------------------------------------------------------------------- // Utility functions for bitfield manipulations diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/utilities/taskqueue.cpp --- a/src/share/vm/utilities/taskqueue.cpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/utilities/taskqueue.cpp Tue Apr 06 22:06:57 2010 -0700 @@ -31,10 +31,6 @@ uint ParallelTaskTerminator::_total_peeks = 0; #endif -bool TaskQueueSuper::peek() { - return _bottom != _age.top(); -} - int TaskQueueSetSuper::randomParkAndMiller(int *seed0) { const int a = 16807; const int m = 2147483647; @@ -180,6 +176,13 @@ } } +#ifdef ASSERT +bool ObjArrayTask::is_valid() const { + return _obj != NULL && _obj->is_objArray() && _index > 0 && + _index < objArrayOop(_obj)->length(); +} +#endif // ASSERT + bool RegionTaskQueueWithOverflow::is_empty() { return (_region_queue.size() == 0) && (_overflow_stack->length() == 0); diff -r 09ac706c2623 -r 895d9ade6111 src/share/vm/utilities/taskqueue.hpp --- a/src/share/vm/utilities/taskqueue.hpp Wed Mar 24 17:16:33 2010 -0700 +++ b/src/share/vm/utilities/taskqueue.hpp Tue Apr 06 22:06:57 2010 -0700 @@ -22,6 +22,7 @@ * */ +template class TaskQueueSuper: public CHeapObj { protected: // Internal type for indexing the queue; also used for the tag. @@ -30,10 +31,7 @@ // The first free element after the last one pushed (mod N). volatile uint _bottom; - enum { - N = 1 << NOT_LP64(14) LP64_ONLY(17), // Queue size: 16K or 128K - MOD_N_MASK = N - 1 // To compute x mod N efficiently. - }; + enum { MOD_N_MASK = N - 1 }; class Age { public: @@ -84,12 +82,12 @@ // Returns a number in the range [0..N). If the result is "N-1", it should be // interpreted as 0. - uint dirty_size(uint bot, uint top) { + uint dirty_size(uint bot, uint top) const { return (bot - top) & MOD_N_MASK; } // Returns the size corresponding to the given "bot" and "top". - uint size(uint bot, uint top) { + uint size(uint bot, uint top) const { uint sz = dirty_size(bot, top); // Has the queue "wrapped", so that bottom is less than top? There's a // complicated special case here. A pair of threads could perform pop_local @@ -111,17 +109,17 @@ public: TaskQueueSuper() : _bottom(0), _age() {} - // Return "true" if the TaskQueue contains any tasks. - bool peek(); + // Return true if the TaskQueue contains any tasks. + bool peek() { return _bottom != _age.top(); } // Return an estimate of the number of elements in the queue. // The "careful" version admits the possibility of pop_local/pop_global // races. - uint size() { + uint size() const { return size(_bottom, _age.top()); } - uint dirty_size() { + uint dirty_size() const { return dirty_size(_bottom, _age.top()); } @@ -132,16 +130,36 @@ // Maximum number of elements allowed in the queue. This is two less // than the actual queue size, for somewhat complicated reasons. - uint max_elems() { return N - 2; } + uint max_elems() const { return N - 2; } + + // Total size of queue. + static const uint total_size() { return N; } }; -template class GenericTaskQueue: public TaskQueueSuper { +template +class GenericTaskQueue: public TaskQueueSuper { +protected: + typedef typename TaskQueueSuper::Age Age; + typedef typename TaskQueueSuper::idx_t idx_t; + + using TaskQueueSuper::_bottom; + using TaskQueueSuper::_age; + using TaskQueueSuper::increment_index; + using TaskQueueSuper::decrement_index; + using TaskQueueSuper::dirty_size; + +public: + using TaskQueueSuper::max_elems; + using TaskQueueSuper::size; + private: // Slow paths for push, pop_local. (pop_global has no fast path.) bool push_slow(E t, uint dirty_n_elems); bool pop_local_slow(uint localBot, Age oldAge); public: + typedef E element_type; + // Initializes the queue to empty. GenericTaskQueue(); @@ -172,19 +190,19 @@ volatile E* _elems; }; -template -GenericTaskQueue::GenericTaskQueue():TaskQueueSuper() { +template +GenericTaskQueue::GenericTaskQueue() { assert(sizeof(Age) == sizeof(size_t), "Depends on this."); } -template -void GenericTaskQueue::initialize() { +template +void GenericTaskQueue::initialize() { _elems = NEW_C_HEAP_ARRAY(E, N); guarantee(_elems != NULL, "Allocation failed."); } -template -void GenericTaskQueue::oops_do(OopClosure* f) { +template +void GenericTaskQueue::oops_do(OopClosure* f) { // tty->print_cr("START OopTaskQueue::oops_do"); uint iters = size(); uint index = _bottom; @@ -200,21 +218,21 @@ // tty->print_cr("END OopTaskQueue::oops_do"); } - -template -bool GenericTaskQueue::push_slow(E t, uint dirty_n_elems) { +template +bool GenericTaskQueue::push_slow(E t, uint dirty_n_elems) { if (dirty_n_elems == N - 1) { // Actually means 0, so do the push. uint localBot = _bottom; - _elems[localBot] = t; + // g++ complains if the volatile result of the assignment is unused. + const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); return true; } return false; } -template -bool GenericTaskQueue:: +template +bool GenericTaskQueue:: pop_local_slow(uint localBot, Age oldAge) { // This queue was observed to contain exactly one element; either this // thread will claim it, or a competing "pop_global". In either case, @@ -246,8 +264,8 @@ return false; } -template -bool GenericTaskQueue::pop_global(E& t) { +template +bool GenericTaskQueue::pop_global(E& t) { Age oldAge = _age.get(); uint localBot = _bottom; uint n_elems = size(localBot, oldAge.top()); @@ -255,7 +273,7 @@ return false; } - t = _elems[oldAge.top()]; + const_cast(t = _elems[oldAge.top()]); Age newAge(oldAge); newAge.increment(); Age resAge = _age.cmpxchg(newAge, oldAge); @@ -266,8 +284,8 @@ return resAge == oldAge; } -template -GenericTaskQueue::~GenericTaskQueue() { +template +GenericTaskQueue::~GenericTaskQueue() { FREE_C_HEAP_ARRAY(E, _elems); } @@ -280,16 +298,18 @@ virtual bool peek() = 0; }; -template class GenericTaskQueueSet: public TaskQueueSetSuper { +template +class GenericTaskQueueSet: public TaskQueueSetSuper { private: uint _n; - GenericTaskQueue** _queues; + T** _queues; public: + typedef typename T::element_type E; + GenericTaskQueueSet(int n) : _n(n) { - typedef GenericTaskQueue* GenericTaskQueuePtr; + typedef T* GenericTaskQueuePtr; _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n); - guarantee(_queues != NULL, "Allocation failure."); for (int i = 0; i < n; i++) { _queues[i] = NULL; } @@ -299,9 +319,9 @@ bool steal_best_of_2(uint queue_num, int* seed, E& t); bool steal_best_of_all(uint queue_num, int* seed, E& t); - void register_queue(uint i, GenericTaskQueue* q); + void register_queue(uint i, T* q); - GenericTaskQueue* queue(uint n); + T* queue(uint n); // The thread with queue number "queue_num" (and whose random number seed // is at "seed") is trying to steal a task from some other queue. (It @@ -313,27 +333,27 @@ bool peek(); }; -template -void GenericTaskQueueSet::register_queue(uint i, GenericTaskQueue* q) { +template void +GenericTaskQueueSet::register_queue(uint i, T* q) { assert(i < _n, "index out of range."); _queues[i] = q; } -template -GenericTaskQueue* GenericTaskQueueSet::queue(uint i) { +template T* +GenericTaskQueueSet::queue(uint i) { return _queues[i]; } -template -bool GenericTaskQueueSet::steal(uint queue_num, int* seed, E& t) { +template bool +GenericTaskQueueSet::steal(uint queue_num, int* seed, E& t) { for (uint i = 0; i < 2 * _n; i++) if (steal_best_of_2(queue_num, seed, t)) return true; return false; } -template -bool GenericTaskQueueSet::steal_best_of_all(uint queue_num, int* seed, E& t) { +template bool +GenericTaskQueueSet::steal_best_of_all(uint queue_num, int* seed, E& t) { if (_n > 2) { int best_k; uint best_sz = 0; @@ -356,8 +376,8 @@ } } -template -bool GenericTaskQueueSet::steal_1_random(uint queue_num, int* seed, E& t) { +template bool +GenericTaskQueueSet::steal_1_random(uint queue_num, int* seed, E& t) { if (_n > 2) { uint k = queue_num; while (k == queue_num) k = randomParkAndMiller(seed) % _n; @@ -372,8 +392,8 @@ } } -template -bool GenericTaskQueueSet::steal_best_of_2(uint queue_num, int* seed, E& t) { +template bool +GenericTaskQueueSet::steal_best_of_2(uint queue_num, int* seed, E& t) { if (_n > 2) { uint k1 = queue_num; while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n; @@ -394,8 +414,8 @@ } } -template -bool GenericTaskQueueSet::peek() { +template +bool GenericTaskQueueSet::peek() { // Try all the queues. for (uint j = 0; j < _n; j++) { if (_queues[j]->peek()) @@ -465,14 +485,16 @@ #endif }; -template inline bool GenericTaskQueue::push(E t) { +template inline bool +GenericTaskQueue::push(E t) { uint localBot = _bottom; assert((localBot >= 0) && (localBot < N), "_bottom out of range."); idx_t top = _age.top(); uint dirty_n_elems = dirty_size(localBot, top); - assert((dirty_n_elems >= 0) && (dirty_n_elems < N), "n_elems out of range."); + assert(dirty_n_elems < N, "n_elems out of range."); if (dirty_n_elems < max_elems()) { - _elems[localBot] = t; + // g++ complains if the volatile result of the assignment is unused. + const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); return true; } else { @@ -480,7 +502,8 @@ } } -template inline bool GenericTaskQueue::pop_local(E& t) { +template inline bool +GenericTaskQueue::pop_local(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 @@ -494,7 +517,7 @@ // This is necessary to prevent any read below from being reordered // before the store just above. OrderAccess::fence(); - t = _elems[localBot]; + const_cast(t = _elems[localBot]); // This is a second read of "age"; the "size()" above is the first. // If there's still at least one element in the queue, based on the // "_bottom" and "age" we've read, then there can be no interference with @@ -511,17 +534,23 @@ } typedef oop Task; -typedef GenericTaskQueue OopTaskQueue; -typedef GenericTaskQueueSet OopTaskQueueSet; +typedef GenericTaskQueue OopTaskQueue; +typedef GenericTaskQueueSet OopTaskQueueSet; - -#define COMPRESSED_OOP_MASK 1 +#ifdef _MSC_VER +#pragma warning(push) +// warning C4522: multiple assignment operators specified +#pragma warning(disable:4522) +#endif // This is a container class for either an oop* or a narrowOop*. // Both are pushed onto a task queue and the consumer will test is_narrow() // to determine which should be processed. class StarTask { void* _holder; // either union oop* or narrowOop* + + enum { COMPRESSED_OOP_MASK = 1 }; + public: StarTask(narrowOop* p) { assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!"); @@ -537,20 +566,61 @@ return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK); } - // Operators to preserve const/volatile in assignments required by gcc - void operator=(const volatile StarTask& t) volatile { _holder = t._holder; } + StarTask& operator=(const StarTask& t) { + _holder = t._holder; + return *this; + } + volatile StarTask& operator=(const volatile StarTask& t) volatile { + _holder = t._holder; + return *this; + } bool is_narrow() const { return (((uintptr_t)_holder & COMPRESSED_OOP_MASK) != 0); } }; -typedef GenericTaskQueue OopStarTaskQueue; -typedef GenericTaskQueueSet OopStarTaskQueueSet; +class ObjArrayTask +{ +public: + ObjArrayTask(oop o = NULL, int idx = 0): _obj(o), _index(idx) { } + ObjArrayTask(oop o, size_t idx): _obj(o), _index(int(idx)) { + assert(idx <= size_t(max_jint), "too big"); + } + ObjArrayTask(const ObjArrayTask& t): _obj(t._obj), _index(t._index) { } + + ObjArrayTask& operator =(const ObjArrayTask& t) { + _obj = t._obj; + _index = t._index; + return *this; + } + volatile ObjArrayTask& + operator =(const volatile ObjArrayTask& t) volatile { + _obj = t._obj; + _index = t._index; + return *this; + } + + inline oop obj() const { return _obj; } + inline int index() const { return _index; } + + DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid. + +private: + oop _obj; + int _index; +}; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +typedef GenericTaskQueue OopStarTaskQueue; +typedef GenericTaskQueueSet OopStarTaskQueueSet; typedef size_t RegionTask; // index for region -typedef GenericTaskQueue RegionTaskQueue; -typedef GenericTaskQueueSet RegionTaskQueueSet; +typedef GenericTaskQueue RegionTaskQueue; +typedef GenericTaskQueueSet RegionTaskQueueSet; class RegionTaskQueueWithOverflow: public CHeapObj { protected: diff -r 09ac706c2623 -r 895d9ade6111 test/compiler/6663854/Test6663854.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6663854/Test6663854.java Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,1521 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6663854 + * @summary assert(n != __null,"Bad immediate dominator info.") in C2 with -Xcomp + * + * @run main/othervm -Xcomp Test6663854 + */ + +// This is a randomly generated test that exposed a crash so don't try +// to make sense of what's it's doing. The output produced is likely +// to be stable but it is not being checked as part of this test. + +final class Test6663854_Class_0 { + final long var_1 = ((byte)1.2510591E38F & - ~ - - - ~3554133935918431232L) << 'g'; + final static long var_2 = 662144491976981504L; + static byte[] var_3; + static byte var_4; + static float var_5; + final short var_6 = 4156; + double var_7; + char var_8 = 'F'; + static long var_9; + char var_10; + + + public Test6663854_Class_0() + { + var_7 = (var_9 = (var_4 = (var_4 = (byte)~ -var_1))); + var_7 = (var_4 = (var_4 = (byte)(var_9 = 690685817))) + ~var_2; + long var_17 = 1755837857030316032L; + var_8 *= (var_7 = var_6); + { + var_4 = (var_4 = (byte)var_6); + } + var_5 = (var_4 = (var_4 = (var_4 = (var_4 = (byte)var_17)))); + if (false) + { + var_5 = var_6; + var_4 = (var_4 = (var_4 = (var_4 = (var_4 = (var_4 = (var_4 = (byte)3.2446162E38F)))))); + } + else + { + var_8 &= false ? var_6 : var_6; + } + ((new Test6663854_Class_0[(byte)+ (var_5 = (var_4 = (byte)'Q'))])[var_4 = (byte)396008820]).var_8++; + var_5 = (var_8 ^= var_6 >>> - (var_4 = (byte)var_6)) >= 360526660 ? var_8 : var_8; + } + + + + protected Object clone() + { + char var_11 = 'E'; + var_7 = 1.2181972357945285E308 + var_6 - + (var_7 = 1269180234) * 6.244754764669101E307; + var_7 = (var_4 = (var_4 = (var_4 = (var_4 = (var_4 = (byte)var_11))))); + { + var_4 = (var_4 = (var_4 = (byte)1016847968)); + (false & true ? "nmot" : "m").charAt((false || !true ? var_6 : var_6) * var_6); + var_8 |= var_8-- == (long)(var_7 = (byte)var_2 & ~var_2) ? (var_4 = (var_4 = (var_4 = (var_4 = (byte)1.5012703E38F)))) : (var_4 = (byte)4795604615834685440L); + ++var_11; + var_5 = (var_9 = (int)var_6 | 302324412 - 1720735728); + "yfkasl".replaceAll("xlvn" + "peedfph", "awfbuujts"); + } + var_9 = false ? var_6 : var_6; + { + final boolean var_12 = false; + } + var_5 = var_2; + { + var_9 = ((new byte[(byte)var_6][(byte)1.3719104187525612E308])[var_4 = (byte)var_1])[var_4 = (var_4 = (var_4 = (var_4 = (byte)2.2549062E38F)))] + 889886326; + } + var_9 = (var_2 | ~var_1) & 848602225; + { + var_4 = (var_4 = (var_4 = (var_4 = (byte)var_6))); + } + var_7 = var_6; + var_9 = var_6; + var_5 = (var_4 = (var_4 = (byte)var_8)); + var_7 = 964691433430251520L ^ var_6; + var_5 = ~2571981928559810560L; + return "yvetn".endsWith("dtgstxcu".toLowerCase()) | true | true ? (4.2416016638902373E307 != -3.1295498440444366E307 ? "p" : "ars") : (new Object[(byte)var_1])[(byte)(var_9 = 7519039949758987264L)]; + } + + public boolean equals(Object obj) + { + var_5 = 1445825238; + { + var_7 = 2.221982E38F; + } + { + var_9 = var_6; + } + var_7 = true ? (var_8 ^= (byte)3588201925057082368L) : (var_7 = var_8); + short var_13 = var_6; + var_4 = (var_4 = (var_4 = (var_4 = (var_4 = (byte)'L')))); + var_13--; + return true | !false; + } + + + protected char[] func_0() + { + if (!true ? !false : false) + { + var_8 %= -(new double[(byte)197311342][(byte)5.6183004E36F])[(byte)(var_5 = (var_9 = 'l'))][(byte)(var_7 = var_6)] * (1.9583867E38F * + (var_4 = (byte)1566742425)); + var_8 >>= ~6333520277515092992L | var_8; + } + else + { + new String(); + } + { + var_7 = (byte)5882830303456225280L % ((var_9 = var_6) << var_1); + } + var_7 = var_6; + float var_14; + var_14 = (var_4 = (var_4 = (byte)1081376784)); + var_8 -= 3.1929636E38F; + var_7 = 1.5931970715760934E308; + var_4 = true | (!false | (var_7 = 2.4773615E37F) < (byte)(short)825088022) ? (var_4 = (byte)4.3114896E37F) : (byte)var_8; + final int var_15 = var_6 >> 1197848918; + var_9 = var_15; + var_14 = 983699379; + var_9 = var_6; + return (new char[var_4 = (byte)3.593425789671245E307][(byte)1.6242754453980546E308])[var_4 = (byte)(var_9 = (var_4 = (byte)var_1))]; + } + + final void func_1(final int arg_0) + { + var_5 = 6370513305314412544L == -5.201821E37F ? 2.5220462E38F : (var_5 = (byte)'f'); + ((new Test6663854_Class_0[(byte)1250580004024059904L][(byte)(short)var_8])[(byte)(var_8 ^= 68680455462355968L)][var_4 = (var_4 = (byte)var_2)]).var_8 *= (char)(byte)(var_6 * var_6) <= - (var_7 = (var_7 = var_6)) ? ~5194741848806877184L : var_8; + var_5 = !"tshhykoap".endsWith("q") ? arg_0 : 'K'; + var_8 *= (var_8 -= (var_5 = - (var_5 = var_8))); + int var_16; + } + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_0.var_8 = "; result += Test6663854.Printer.print(var_8); + result += "\n"; + result += "Test6663854_Class_0.var_10 = "; result += Test6663854.Printer.print(var_10); + result += "\n"; + result += "Test6663854_Class_0.var_3 = "; result += Test6663854.Printer.print(var_3); + result += "\n"; + result += "Test6663854_Class_0.var_1 = "; result += Test6663854.Printer.print(var_1); + result += "\n"; + result += "Test6663854_Class_0.var_2 = "; result += Test6663854.Printer.print(var_2); + result += "\n"; + result += "Test6663854_Class_0.var_9 = "; result += Test6663854.Printer.print(var_9); + result += "\n"; + result += "Test6663854_Class_0.var_7 = "; result += Test6663854.Printer.print(var_7); + result += "\n"; + result += "Test6663854_Class_0.var_5 = "; result += Test6663854.Printer.print(var_5); + result += "\n"; + result += "Test6663854_Class_0.var_6 = "; result += Test6663854.Printer.print(var_6); + result += "\n"; + result += "Test6663854_Class_0.var_4 = "; result += Test6663854.Printer.print(var_4); + result += ""; + result += "\n]"; + return result; + } +} + + +interface Test6663854_Interface_1 { + public boolean func_0(); + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3); +} + + +interface Test6663854_Interface_2 extends Test6663854_Interface_1 { +} + + +final class Test6663854_Class_3 implements Test6663854_Interface_2, Test6663854_Interface_1 { + Object var_18; + long var_19; + static double var_20; + final static float var_21 = 2.0644203E38F; + Test6663854_Class_0 var_22; + final static byte var_23 = 110; + static boolean var_24 = false; + + + public Test6663854_Class_3() + { + Test6663854_Class_0.var_5 = new Test6663854_Class_0().var_6; + var_22 = (var_22 = (new Test6663854_Class_0[var_23])[var_23]); + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23)); + char var_37; + var_19 = var_23; + } + + + public boolean func_0() + { + if (var_24 = var_24) + { + Test6663854_Class_0.var_4 = var_24 ^ (var_24 || (var_24 = false)) ? var_23 : (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23)); + } + else + { + ((Test6663854_Class_0)(var_18 = new Test6663854_Interface_1[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23)][var_23])).var_7 = ((var_22 = (var_22 = (Test6663854_Class_0)(var_18 = "uwt"))).var_8 >>>= (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23))); + var_24 |= !false; + } + var_18 = (var_18 = "ymmk"); + if (var_24) + { + long var_25; + ((Test6663854_Class_0)(var_18 = "wsxqujs")).var_8 >>= 'F'; + var_24 ^= false; + } + else + { + { + (var_22 = (Test6663854_Class_0)(var_18 = (var_18 = (var_18 = "lrgiwpwet")))).var_8++; + } + { + var_18 = new String[Test6663854_Class_0.var_4 = var_23]; + } + { + new String(); + } + ((var_24 |= var_24) | true ^ false ? (var_22 = (Test6663854_Class_0)(var_18 = "rpmudju")) : (var_22 = (new Test6663854_Class_0[var_23])[var_23])).var_8--; + var_24 ^= var_24; + var_19 = 206416809; + var_20 = 1581809112; + Test6663854_Class_0 var_26; + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23); + } + byte var_27 = 29; + short var_28 = 24653; + var_22 = (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = "umagt"))); + return var_24; + } + + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3) + { + { + final Test6663854_Class_0 var_29 = (new Test6663854_Class_0[var_23])[arg_2]; + } + var_18 = (var_18 = (var_22 = (Test6663854_Class_0)(var_18 = arg_0))); + ++(var_22 = (Test6663854_Class_0)(var_18 = (Test6663854_Class_0)(var_18 = (var_18 = new char[var_23])))).var_8; + { + (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = "xcj"))).var_8 |= arg_1 * (short)6.671469496987355E307; + Test6663854_Class_0.var_5 = false ? var_23 : 8012291795221583872L; + (var_24 ? (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = arg_0))) : (var_22 = (Test6663854_Class_0)(var_18 = arg_3))).var_8--; + } + ((new String[var_23][var_23])[var_23][var_23]).compareTo(arg_0); + var_18 = (var_18 = arg_0); + var_24 &= (var_24 ^= true) & ! !false; + { + var_18 = "lok"; + } + float var_30 = 2.0346904E38F; + var_30 += ((Test6663854_Class_0)(var_18 = new float[var_23])).var_6 + 210775691; + final double var_31 = 8.865908414454469E307; + var_20 = 'm'; + var_22 = (Test6663854_Class_0)(var_18 = arg_0); + return arg_0; + } + + + protected Object clone() + { + ((Test6663854_Class_0)(var_18 = new short[var_23])).var_7 = 'M'; + if (var_24) + { + var_24 = false; + String var_32 = "luigad"; + ((Test6663854_Class_0.var_5 = 1.2920056E38F) > (Test6663854_Class_0.var_4 = var_23) ? (Test6663854_Class_0)(var_18 = new Test6663854_Interface_1[var_23][var_23]) : (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = new byte[var_23])))).var_10 = 'A'; + (var_22 = (var_22 = (var_22 = (new Test6663854_Class_0[var_23][var_23])[var_23][var_23]))).var_8 /= ((var_22 = (Test6663854_Class_0)(var_18 = (new short[var_23][var_23][var_23])[var_23])).var_7 = 'h'); + (var_32 = var_32).toString(); + var_32.length(); + var_18 = (var_22 = (var_22 = new Test6663854_Class_0())); + } + else + { + Test6663854_Class_0.var_4 = var_23; + var_22 = (var_22 = (Test6663854_Class_0)(var_18 = "wbeuae")); + float var_33; + --(var_22 = (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = (var_18 = "irl"))))).var_8; + } + Test6663854_Class_0.var_4 = var_23; + Test6663854_Class_0.var_5 = true ? ((Test6663854_Class_0)(var_18 = (var_18 = new boolean[Test6663854_Class_0.var_4 = var_23]))).var_8 : 'n'; + var_24 = (var_24 ^= ((var_22 = (Test6663854_Class_0)(var_18 = "g")).var_6 > ((Test6663854_Class_0)(var_18 = "")).var_6 ? var_24 : true) ? false : (var_24 = var_24)) ? var_24 : false; + var_22 = (var_22 = (var_22 = (Test6663854_Class_0)(var_18 = new Test6663854_Interface_2[var_23]))); + return var_18 = "qrlonljqj"; + } + + public boolean equals(Object obj) + { + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23))); + Test6663854_Class_0.var_5 = var_23 % (var_22 = (var_22 = (Test6663854_Class_0)obj)).var_6; + Test6663854_Class_0.var_5 = (((new Test6663854_Class_0[var_23][var_23][var_23])[var_23])[var_24 | (var_24 &= var_24) ? var_23 : (Test6663854_Class_0.var_4 = var_23)][var_23]).var_8; + var_22 = false ? (var_22 = (var_22 = (Test6663854_Class_0)obj)) : (var_22 = new Test6663854_Class_0()); + Test6663854_Class_0.var_5 = ((new Test6663854_Class_0[var_23])[Test6663854_Class_0.var_4 = var_23]).var_8; + if (! !var_24) + { + var_18 = ""; + (var_22 = (var_22 = (var_22 = (new Test6663854_Class_0[var_23])[Test6663854_Class_0.var_4 = var_23]))).var_8 >>= true ? ~ (Test6663854_Class_0.var_4 = var_23) : (var_22 = (Test6663854_Class_0)obj).var_8++; + (var_24 ? (Test6663854_Class_0)(var_18 = "") : (Test6663854_Class_0)obj).var_8 <<= var_23; + Test6663854_Class_0.var_4 = var_23; + var_20 = (var_22 = (var_22 = (var_22 = (var_22 = (Test6663854_Class_0)obj)))).var_8; + } + else + { + var_19 = ((Test6663854_Class_0)obj).var_6; + } + (var_24 ? "qyukxpui" : (new String[var_23])[Test6663854_Class_0.var_4 = var_23]).substring(612084215); + Test6663854_Class_0.var_5 = 'B'; + if (!false || false) + { + Test6663854_Class_0.var_4 = true & var_24 ? var_23 : var_23; + } + else + { + "eksoig".lastIndexOf('b' > (var_22 = (Test6663854_Class_0)obj).var_8 | 4782397447545636864L >= (short)'[' ? "qusgbf" : "kvmylvct"); + } + Test6663854_Class_0.var_5 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = var_23)) << var_23; + int var_34; + var_24 = (var_24 &= (var_24 &= true)); + var_22 = (var_22 = (var_22 = (var_22 = (Test6663854_Class_0)obj))); + Test6663854_Interface_1 var_35 = var_24 & ((var_24 &= var_24) ^ var_24) ? (new Test6663854_Interface_1[var_23])[var_23] : (new Test6663854_Interface_1[var_23][var_23])[var_23][var_23]; + long var_36 = 1042482863045573632L; + return var_24; + } + + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_3.var_19 = "; result += Test6663854.Printer.print(var_19); + result += "\n"; + result += "Test6663854_Class_3.var_20 = "; result += Test6663854.Printer.print(var_20); + result += "\n"; + result += "Test6663854_Class_3.var_21 = "; result += Test6663854.Printer.print(var_21); + result += "\n"; + result += "Test6663854_Class_3.var_23 = "; result += Test6663854.Printer.print(var_23); + result += "\n"; + result += "Test6663854_Class_3.var_24 = "; result += Test6663854.Printer.print(var_24); + result += "\n"; + result += "Test6663854_Class_3.var_22 = "; result += Test6663854.Printer.print(var_22); + result += "\n"; + result += "Test6663854_Class_3.var_18 = "; result += Test6663854.Printer.print(var_18); + result += ""; + result += "\n]"; + return result; + } +} + + +final class Test6663854_Class_4 implements Test6663854_Interface_1, Test6663854_Interface_2 { + long var_38 = (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_23 < (short)+3417996718812544000L) ? ~543562136204028928L : 1593726438; + char var_39; + static Test6663854_Interface_2 var_40; + Test6663854_Class_3 var_41; + final short var_42 = false ? Test6663854_Class_3.var_23 : (short)~Test6663854_Class_0.var_2; + byte var_43; + static Test6663854_Interface_1[] var_44; + final char var_45 = 4.321821176880639E307 < var_42 ? 'o' : 'v'; + + + public Test6663854_Class_4() + { + Test6663854_Class_0.var_5 = 2137855185; + "nueqthqo".length(); + { + Test6663854_Class_0.var_9 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)); + Object var_61; + } + String var_62 = "rirgfphe"; + ((new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_22 = ((var_41 = (var_41 = new Test6663854_Class_3())).var_22 = new Test6663854_Class_0()); + { + Test6663854_Class_0.var_5 = ((new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_42; + new Test6663854_Class_0(); + var_41 = (var_41 = new Test6663854_Class_3()); + new Test6663854_Class_0().var_8 %= var_38; + (var_41 = ((new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_22 = new Test6663854_Class_0(); + Test6663854_Class_0.var_4 = (Test6663854_Class_3.var_24 |= true) ? (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) : Test6663854_Class_3.var_23; + Test6663854_Interface_1 var_63 = ((new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[var_43 = (var_43 = Test6663854_Class_3.var_23)])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]; + (var_41 = (var_41 = (var_41 = (var_41 = (Test6663854_Class_3)var_63)))).var_18 = var_62; + } + if (Test6663854_Class_3.var_24 ^= false) + { + var_40 = (var_40 = new Test6663854_Class_3()); + } + else + { + var_62 = "agwqc"; + Test6663854_Class_3.var_24 ^= ((Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_24 && Test6663854_Class_3.var_24) & false ? false : !Test6663854_Class_3.var_24) ? false | (Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24) : (Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 |= ! (Test6663854_Class_3.var_24 |= true))); + var_38 *= (Test6663854_Class_3.var_20 = (Test6663854_Class_0.var_5 = var_42 + ((Test6663854_Class_3.var_20 = 5378782303770527744L) <= var_42 ? var_42 : var_42))); + } + var_38 &= ((var_41 = new Test6663854_Class_3()).var_22 = new Test6663854_Class_0()).var_6; + var_62 = var_62; + (var_41 = new Test6663854_Class_3()).var_18 = ((new Object[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (var_43 = Test6663854_Class_3.var_23))]; + final short var_64 = (short)'C'; + ((var_41 = new Test6663854_Class_3()).var_22 = new Test6663854_Class_0()).var_8 /= ((var_41 = new Test6663854_Class_3()).var_22 = new Test6663854_Class_0()).var_6; + } + + + public boolean func_0() + { + final boolean var_46 = false; + return Test6663854_Class_3.var_24; + } + + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3) + { + { + --(false ? new Test6663854_Class_0() : new Test6663854_Class_0()).var_8; + "d".substring(Test6663854_Class_3.var_23 - (arg_2 /= + (Test6663854_Class_3.var_20 = 1483190006) * (Test6663854_Class_3.var_20 = ~Test6663854_Class_3.var_23)), 496015226); + { + var_41 = new Test6663854_Class_3(); + } + var_38 ^= (! ((Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24) && (new boolean[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]) ? arg_1 : (var_39 = var_45)) / var_45; + var_38 -= (Test6663854_Class_3.var_20 = (new short[Test6663854_Class_3.var_23])[arg_2]) != (arg_2 ^= new Test6663854_Class_0().var_6 & - (var_38 /= (Test6663854_Class_0.var_5 = var_38))) ? (Test6663854_Class_0.var_5 = - -Test6663854_Class_3.var_21) : arg_2; + var_41 = new Test6663854_Class_3(); + var_40 = Test6663854_Class_3.var_24 ? new Test6663854_Class_3() : new Test6663854_Class_3(); + } + int var_47; + (var_41 = new Test6663854_Class_3()).var_18 = "qvph"; + { + ++arg_2; + } + final Test6663854_Class_3 var_48 = new Test6663854_Class_3(); + { + var_48.var_22 = (Test6663854_Class_0)((var_41 = var_48).var_18 = (var_48.var_22 = (Test6663854_Class_0)(var_48.var_18 = new String[Test6663854_Class_3.var_23]))); + { + final float[] var_49 = (new float[Test6663854_Class_3.var_23][arg_2])[arg_2]; + } + "lcfxrlilw".replace(var_45, (char)(false ? (short)2998890687978943488L : var_42)); + arg_0.lastIndexOf("mx"); + final Test6663854_Class_0 var_50 = var_48.var_22 = (var_48.var_22 = (Test6663854_Class_0)((var_41 = var_48).var_18 = var_48)); + new String(); + ((Test6663854_Class_3)(var_40 = (var_40 = (var_41 = var_48)))).var_22 = var_50; + var_50.var_8 |= arg_2; + Test6663854_Class_3.var_20 = + - (Test6663854_Class_3.var_20 = var_42) - var_45 * Test6663854_Class_3.var_21; + double var_51 = false ? 1.6389923323715952E308 : (var_39 = var_45); + (((new Test6663854_Class_3[arg_2][arg_2])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_18 = (var_48.var_18 = new Test6663854_Class_0[arg_2 %= 2090054678][arg_2]); + } + { + var_47 = (arg_2 |= (((new Test6663854_Class_4[arg_2][arg_2][arg_2])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_42); + } + ((new Test6663854_Class_4[arg_2][Test6663854_Class_3.var_23])[++arg_2][arg_2 <<= 'c']).var_41 = var_48; + var_41 = var_48; + Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24 & Test6663854_Class_3.var_24; + final boolean var_52 = false; + { + var_40 = (var_41 = (var_41 = var_48)); + (false ? var_48 : var_48).var_18 = ((new Test6663854_Class_0[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23][arg_2])[arg_2])[++arg_2][(byte)203097731]; + var_41 = (var_41 = var_48); + } + var_38 |= (short)Test6663854_Class_3.var_23; + var_40 = var_48; + { + arg_0.indexOf("lnf", var_47 = (((Test6663854_Class_0)(var_48.var_18 = arg_0)).var_8 <<= (var_39 = var_45))); + } + final boolean var_53 = true & 1.4130067467800934E308 < (arg_2 |= 'W'); + var_48.var_18 = (var_41 = var_48); + (var_48.var_22 = new Test6663854_Class_0()).var_7 = Test6663854_Class_3.var_23; + Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 || var_52) ^ ("axg".startsWith(arg_0, var_47 = (var_47 = var_45)) | var_52); + { + Test6663854_Class_0.var_5 = 275192701; + } + Test6663854_Interface_2 var_54; + if (true) + { + var_54 = (var_41 = (var_41 = (var_41 = var_48))); + } + else + { + ((Test6663854_Class_0)((var_41 = var_48).var_18 = (var_41 = var_48))).var_7 = var_42; + } + Test6663854_Class_0.var_5 = --arg_2; + ((new String[Test6663854_Class_3.var_23])[var_53 ? arg_2 : arg_2]).length(); + return arg_0 + "qj"; + } + + + + + final String func_0(byte arg_0, Test6663854_Class_0 arg_1, final Test6663854_Class_0 arg_2, final Object arg_3) + { + arg_2.var_7 = (new long[arg_0][arg_0])[Test6663854_Class_3.var_23][arg_0 >>>= 1960882886] % arg_0; + Object var_55 = (((new Test6663854_Class_4[Test6663854_Class_3.var_23])[--arg_0]).var_41 = new Test6663854_Class_3()).var_18 = (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24 ? (Test6663854_Class_3.var_24 |= (Test6663854_Class_3.var_24 &= true)) : Test6663854_Class_3.var_24 | Test6663854_Class_3.var_24) ? (var_41 = (var_41 = (Test6663854_Class_3)arg_3)) : arg_3; + var_38 >>= ((Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_24)) | (Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_24) ? arg_2.var_6 : (arg_0 -= 1.2264686416488313E308)) != (((new Test6663854_Class_4[arg_0])[arg_0]).var_38 >>>= arg_2.var_8) ? Test6663854_Class_3.var_23 : arg_0; + arg_0 += 1826349110 / (Test6663854_Class_0.var_5 = arg_0) + Test6663854_Class_3.var_21; + (var_41 = !Test6663854_Class_3.var_24 ? (var_41 = (new Test6663854_Class_3[arg_0])[arg_0]) : (new Test6663854_Class_3[--arg_0])[arg_0]).var_22 = ((new Test6663854_Class_0[arg_0][(byte)9.18575257519393E307][Test6663854_Class_3.var_23])[arg_0])[Test6663854_Class_3.var_23][arg_0]; + (var_41 = new Test6663854_Class_3()).var_22 = ((var_41 = (var_41 = (var_41 = (var_41 = (var_41 = (Test6663854_Class_3)arg_3))))).var_22 = (arg_1 = arg_2)); + Test6663854_Class_3.var_20 = Test6663854_Class_3.var_21; + var_40 = (var_41 = (Test6663854_Class_3)(new Test6663854_Interface_2[Test6663854_Class_3.var_23])[arg_0]); + Test6663854_Class_0.var_5 = Test6663854_Class_3.var_24 || (Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 &= true)) ? var_42 : arg_1.var_6; + Test6663854_Class_0.var_5 = arg_0; + { + arg_0 %= (short)var_45; + } + var_55 = arg_1; + var_40 = (var_41 = (Test6663854_Class_3.var_24 = false) ? (Test6663854_Class_3)var_55 : (Test6663854_Class_3)arg_3); + ((Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_20 = arg_0) == 2.2107098E38F) ? (Test6663854_Class_3)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[arg_0] : (Test6663854_Class_3)(var_55 = "unofratwy")).var_18 = var_55; + return ""; + } + + private static String func_1(final String arg_0, char arg_1, final boolean arg_2, Test6663854_Class_3 arg_3) + { + if (!false & Test6663854_Class_3.var_24) + { + char var_56 = 'C'; + } + else + { + var_40 = (var_40 = (var_40 = arg_3)); + } + ((new Test6663854_Class_0[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_7 = 2.4396145E38F + (((new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][(byte)Test6663854_Class_0.var_2]).var_43 = Test6663854_Class_3.var_23); + if (Test6663854_Class_3.var_24) + { + arg_3 = arg_3; + } + else + { + arg_3 = (arg_3 = arg_3); + } + ((new Test6663854_Class_4[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_38 /= '`'; + arg_3 = (arg_3 = arg_3); + new Test6663854_Class_0().var_8++; + return "qd"; + } + + private Object func_2(short[][] arg_0, final Test6663854_Interface_2 arg_1) + { + boolean var_57 = false; + Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + var_40 = arg_1; + ((var_41 = (var_41 = (var_41 = (Test6663854_Class_3)arg_1))).var_22 = (Test6663854_Class_0)(((Test6663854_Class_3)arg_1).var_18 = "dxrwk")).var_7 = 'c'; + if (true) + { + var_40 = (var_40 = arg_1); + } + else + { + var_39 = 'Z'; + } + Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + var_41 = (Test6663854_Class_3)arg_1; + return (var_57 ? (Test6663854_Class_3.var_20 = Test6663854_Class_3.var_23) % 1271549437 : 1.1177259470512304E308) <= 1363316667 ? (new Test6663854_Class_3().var_18 = new String[var_43 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]) : new Test6663854_Class_0(); + } + + private short func_3() + { + int var_58 = true ? var_42 : 1438975079; + float var_59 = Test6663854_Class_3.var_21; + var_43 = Test6663854_Class_3.var_23; + (var_41 = (Test6663854_Class_3)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_22 = (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24) ? new Test6663854_Class_0() : new Test6663854_Class_0(); + var_58++; + return Test6663854_Class_3.var_24 ? var_42 : (var_43 = Test6663854_Class_3.var_23); + } + + protected void func_4(final long arg_0, Test6663854_Class_0 arg_1, long arg_2) + { + ++arg_2; + (arg_1 = (arg_1 = (arg_1 = arg_1))).var_8 /= var_42; + --arg_2; + final Test6663854_Interface_1 var_60 = ((new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[var_43 = Test6663854_Class_3.var_23])[var_43 = Test6663854_Class_3.var_23]; + (true ? (Test6663854_Class_3)var_60 : (Test6663854_Class_3)var_60).var_22 = (Test6663854_Class_0)((var_41 = (Test6663854_Class_3)(var_40 = (Test6663854_Class_3)var_60)).var_18 = (Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_23 == var_38) ? "xo" : "uocm"); + var_38 >>= (((Test6663854_Class_3)(new Test6663854_Interface_2[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_22 = (new Test6663854_Class_0[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)]).var_8++; + } + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_4.var_39 = "; result += Test6663854.Printer.print(var_39); + result += "\n"; + result += "Test6663854_Class_4.var_45 = "; result += Test6663854.Printer.print(var_45); + result += "\n"; + result += "Test6663854_Class_4.var_44 = "; result += Test6663854.Printer.print(var_44); + result += "\n"; + result += "Test6663854_Class_4.var_38 = "; result += Test6663854.Printer.print(var_38); + result += "\n"; + result += "Test6663854_Class_4.var_40 = "; result += Test6663854.Printer.print(var_40); + result += "\n"; + result += "Test6663854_Class_4.var_42 = "; result += Test6663854.Printer.print(var_42); + result += "\n"; + result += "Test6663854_Class_4.var_43 = "; result += Test6663854.Printer.print(var_43); + result += "\n"; + result += "Test6663854_Class_4.var_41 = "; result += Test6663854.Printer.print(var_41); + result += ""; + result += "\n]"; + return result; + } +} + + +class Test6663854_Class_5 implements Test6663854_Interface_1 { + final static char var_65 = 'S'; + static Test6663854_Interface_2 var_66; + static Test6663854_Class_3 var_67; + + + public Test6663854_Class_5() + { + { + ((new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)])[((Test6663854_Class_4)(new Object[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_43 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).func_0(); + } + Test6663854_Class_0.var_5 = 1409421143; + Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 = false); + Test6663854_Class_0.var_5 = 3.1496384E38F / (((new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_45 - (Test6663854_Class_3.var_23 + Test6663854_Class_3.var_23)); + ((new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_18 = (new Object[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + var_66 = (Test6663854_Class_4.var_40 = (Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24)) || false ? new Test6663854_Class_3() : new Test6663854_Class_3()); + } + + + public boolean func_0() + { + { + Test6663854_Class_4.var_40 = (new Test6663854_Class_4[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]; + } + Test6663854_Class_0.var_5 = (new char[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + var_66 = (Test6663854_Class_4.var_40 = new Test6663854_Class_3()); + Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + ((var_67 = (var_67 = new Test6663854_Class_3())).var_22 = (Test6663854_Class_0)(new Test6663854_Class_3().var_18 = (new Test6663854_Class_3().var_22 = (new Test6663854_Class_3().var_22 = new Test6663854_Class_0())))).var_8++; + Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + return (Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24) ? (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24) : (Test6663854_Class_3.var_24 = true); + } + + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3) + { + ((true | (Test6663854_Class_3.var_24 |= true)) ^ false ? (new Test6663854_Class_0[(byte)arg_1])[arg_2--] : new Test6663854_Class_0()).var_8 <<= 2320675830599883776L; + arg_2 -= ~ (Test6663854_Class_3.var_24 ? ~4954934861909065728L : 5155213238651986944L); + ((Test6663854_Class_4)((new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[arg_2 >>>= 1308733456])[Test6663854_Class_3.var_23]).var_43 = arg_2; + Test6663854_Class_0.var_5 = Test6663854_Class_3.var_21; + { + String var_68; + float var_69 = Test6663854_Class_3.var_21 * new Test6663854_Class_0().var_6; + ++arg_2; + Test6663854_Class_0.var_9 = arg_2; + --arg_2; + var_68 = arg_0; + final long[] var_70 = new long[arg_2 /= 8889610108908524544L]; + Test6663854_Class_4 var_71; + } + new Test6663854_Class_4().var_38++; + Test6663854_Class_3 var_72; + (((new Test6663854_Class_4[arg_2 *= var_65][Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[arg_2])[arg_2 ^= arg_2][Test6663854_Class_3.var_23]).var_38--; + new Test6663854_Class_3(); + (((new Test6663854_Class_4[arg_2 /= 7.692983E37F][Test6663854_Class_3.var_23])[arg_2])[Test6663854_Class_3.var_23]).var_38 |= arg_1; + Test6663854_Class_3.var_24 ^= "dlhn".startsWith(true ? "tad" : "bssdfvig", 1125165775) ? Test6663854_Class_3.var_24 : true; + Test6663854_Class_3.var_20 = new Test6663854_Class_0().var_8; + Test6663854_Class_4.var_40 = (Test6663854_Class_4.var_40 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]); + var_72 = (new Test6663854_Class_3[Test6663854_Class_3.var_23][arg_2])[arg_2][arg_2]; + Test6663854_Class_0.var_5 = 8634870161778523136L; + { + Test6663854_Class_0.var_5 = ~4420139622226571264L; + Test6663854_Class_3.var_24 &= (var_72 = (var_67 = (new Test6663854_Class_3[arg_2][Test6663854_Class_3.var_23])[arg_2][arg_2])).func_0(); + arg_2 >>= false ? 'H' : ']'; + } + switch (arg_2) + { + case 72: + String var_73 = arg_0; + break; + + default: + + } + ((Test6663854_Class_0)((var_72 = (Test6663854_Class_3)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[arg_2]).var_18 = (Test6663854_Class_4)(new Test6663854_Interface_2[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])).var_7 = ((new Test6663854_Class_0[arg_2])[arg_2]).var_6 + Test6663854_Class_3.var_23; + var_67 = (var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[(byte)7.184837949183326E307][arg_2 ^= 2188582676874919936L]); + return ((Test6663854_Class_3.var_24 = new Test6663854_Class_0().var_6 >= (short)3.4944631475014644E307) ? Test6663854_Class_3.var_24 : (Test6663854_Class_3.var_24 ? (Test6663854_Class_3.var_24 = false) : !Test6663854_Class_3.var_24)) ? "y" : arg_0; + } + + + + + private final static float func_0(boolean arg_0) + { + { + new String(); + { + new String(); + } + ((Test6663854_Class_3)(new Object[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[(new byte[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_18 = (new Object[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[(byte)1.577204008065932E308][Test6663854_Class_3.var_23]; + int var_74; + new String(); + Test6663854_Class_0.var_5 = ((Test6663854_Class_0)(new Object[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_1; + new String(); + new String(); + new String(); + var_74 = '_'; + new Test6663854_Class_0(); + Test6663854_Class_3 var_75 = var_67 = (((new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_41 = (new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]); + } + if (Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24)) + { + new String(); + arg_0 &= ~ (((new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_38 /= Test6663854_Class_3.var_23) < 2.1129417E38F; + } + else + { + Test6663854_Class_3.var_24 &= false & arg_0 ? false : (Test6663854_Class_3.var_24 &= true); + } + new Test6663854_Class_0().var_8 ^= 682270015; + Test6663854_Class_4.var_40 = (Test6663854_Class_4)(new Test6663854_Interface_2[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + new Test6663854_Class_0(); + new String(); + new Test6663854_Class_0(); + new Test6663854_Class_3().var_22 = new Test6663854_Class_0(); + Test6663854_Class_4.var_40 = (new Test6663854_Class_4[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]; + new Test6663854_Class_0().var_8++; + new Test6663854_Class_0(); + Test6663854_Interface_1 var_76; + return Test6663854_Class_3.var_21; + } + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_5.var_65 = "; result += Test6663854.Printer.print(var_65); + result += "\n"; + result += "Test6663854_Class_5.var_66 = "; result += Test6663854.Printer.print(var_66); + result += "\n"; + result += "Test6663854_Class_5.var_67 = "; result += Test6663854.Printer.print(var_67); + result += ""; + result += "\n]"; + return result; + } +} + + +class Test6663854_Class_6 implements Test6663854_Interface_1, Test6663854_Interface_2 { + static long var_77; + final byte var_78 = Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + long var_79; + static Test6663854_Class_4 var_80; + static long var_81 = 1365276905537306624L; + static Test6663854_Class_3 var_82; + + + public Test6663854_Class_6() + { + Test6663854_Class_0.var_5 = Test6663854_Class_3.var_24 ? "bdouannkn".charAt(373674594) : (char)2612074035904901120L; + if (Test6663854_Class_3.var_24) + { + ++var_81; + Test6663854_Class_0.var_4 = (new byte[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)])[var_78]; + var_81++; + } + else + { + (var_80 = (Test6663854_Class_4)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = var_78]).var_41 = (((Test6663854_Class_4)(new Object[Test6663854_Class_3.var_23])[var_78]).var_41 = new Test6663854_Class_3()); + var_81--; + ((new Test6663854_Class_0[var_78])[var_78]).equals((Test6663854_Class_5.var_67 = (Test6663854_Class_3)(new Test6663854_Interface_2[var_78])[var_78]).var_18 = Test6663854_Class_3.var_23 <= var_78 ? "uvoxke" : new String()); + { + Test6663854_Class_5.var_66 = (new Test6663854_Interface_2[var_78])[((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_78]; + } + "huxqcdmii".compareTo("owtdmma"); + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))); + var_81--; + } + { + Test6663854_Class_5[][] var_85; + } + Test6663854_Class_5.var_66 = (new Test6663854_Interface_2[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + if (Test6663854_Class_3.var_24 || Test6663854_Class_3.var_24) + { + var_82 = (new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[var_78][Test6663854_Class_3.var_23]; + Test6663854_Class_0.var_5 = ++var_81; + Test6663854_Class_0.var_5 = Test6663854_Class_3.var_24 ? 'n' : Test6663854_Class_5.var_65; + } + else + { + new Test6663854_Class_0(); + } + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23); + Test6663854_Class_5.var_66 = new Test6663854_Class_3(); + Test6663854_Class_3 var_86 = (var_80 = (var_80 = (var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]))).var_41 = (var_82 = (Test6663854_Class_5.var_67 = ((new Test6663854_Class_3[Test6663854_Class_3.var_23][var_78][Test6663854_Class_3.var_23])[var_78])[var_78][Test6663854_Class_3.var_23])); + Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24) ? (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24) : (Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24); + var_86.var_22 = (new Test6663854_Class_0[var_78][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][var_78]; + (Test6663854_Class_3.var_24 ? "evayayw" : "ndcq").startsWith("hwlik" + "tnhfsky"); + var_86 = var_86; + } + + + public boolean func_0() + { + Test6663854_Class_4.var_40 = (Test6663854_Class_5.var_67 = (new Test6663854_Class_3[var_78])[Test6663854_Class_3.var_23]); + return Test6663854_Class_0.var_2 != (((new Test6663854_Class_0[var_78])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_7 = Test6663854_Class_3.var_23); + } + + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3) + { + Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24; + Test6663854_Class_0.var_5 = var_78; + char var_83; + (Test6663854_Class_5.var_67 = (Test6663854_Class_5.var_67 = (Test6663854_Class_3)(new Test6663854_Interface_1[var_78])[Test6663854_Class_3.var_23])).var_18 = new Test6663854_Class_0[arg_2]; + Test6663854_Class_4 var_84; + var_81++; + return arg_0; + } + + + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_6.var_77 = "; result += Test6663854.Printer.print(var_77); + result += "\n"; + result += "Test6663854_Class_6.var_79 = "; result += Test6663854.Printer.print(var_79); + result += "\n"; + result += "Test6663854_Class_6.var_81 = "; result += Test6663854.Printer.print(var_81); + result += "\n"; + result += "Test6663854_Class_6.var_78 = "; result += Test6663854.Printer.print(var_78); + result += "\n"; + result += "Test6663854_Class_6.var_80 = "; result += Test6663854.Printer.print(var_80); + result += "\n"; + result += "Test6663854_Class_6.var_82 = "; result += Test6663854.Printer.print(var_82); + result += ""; + result += "\n]"; + return result; + } +} + + +final class Test6663854_Class_7 extends Test6663854_Class_5 implements Test6663854_Interface_2 { + final float var_87 = 1.1671899E38F; + static char var_88 = var_65; + float var_89 = 2.166908E37F; + + + public Test6663854_Class_7() + { + var_88--; + (Test6663854_Class_5.var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).equals(((Test6663854_Class_3)(Test6663854_Class_4.var_40 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])).var_18 = "nycb"); + Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24 ^ false); + Test6663854_Class_3.var_24 ^= true; + var_88--; + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]); + if (false) + { + Test6663854_Class_4.var_40 = (new Test6663854_Interface_2[Test6663854_Class_3.var_23])[((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_78]; + } + else + { + --Test6663854_Class_6.var_81; + } + Test6663854_Class_6.var_81--; + ++Test6663854_Class_6.var_81; + if (Test6663854_Class_3.var_24 = !Test6663854_Class_3.var_24) + { + --var_88; + Test6663854_Class_5.var_66 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]; + Test6663854_Class_6.var_81 &= 1451013276; + var_88--; + } + else + { + var_88 >>= --var_88; + } + Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24; + Test6663854_Class_6.var_81--; + Test6663854_Class_6.var_81++; + --Test6663854_Class_6.var_81; + ((new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_41 = new Test6663854_Class_3(); + } + + + + + public final Test6663854_Class_4 func_0(int arg_0) + { + --arg_0; + { + switch ((char)var_89) + { + case 'R': + + } + ++(Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]))).var_38; + ++var_88; + Test6663854_Class_5.var_66 = ~Test6663854_Class_6.var_81 % Test6663854_Class_6.var_81 != (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) ? (Test6663854_Class_6.var_82 = (var_67 = new Test6663854_Class_3())) : new Test6663854_Class_3(); + } + (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)(new Test6663854_Interface_2[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])).var_38 &= new Test6663854_Class_0().var_6; + Test6663854_Interface_1 var_90 = ((new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]; + (Test6663854_Class_5.var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_22 = new Test6663854_Class_0(); + if (true) + { + ((Test6663854_Class_3)(Test6663854_Interface_2)var_90).var_18 = (((Test6663854_Class_3)var_90).var_22 = new Test6663854_Class_0()); + } + else + { + ++((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)var_90)).var_45 > 7.093005581228189E307 ? (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)var_90)) : (Test6663854_Class_4)(var_90 = (Test6663854_Class_3)var_90)).var_38; + } + var_67 = (Test6663854_Class_3.var_24 ^= true) ^ true ? (Test6663854_Class_6.var_82 = (Test6663854_Class_3)var_90) : (Test6663854_Class_3)var_90; + { + { + var_90 = (var_90 = (Test6663854_Class_5)var_90); + } + Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 ? !false : true) ? (Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24))) : ! !Test6663854_Class_3.var_24 && false); + Test6663854_Class_0 var_91; + Test6663854_Class_4.var_40 = (Test6663854_Class_3.var_24 |= (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24) && (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24) | ! (Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_24)) ? (+Test6663854_Class_3.var_21 != 4.6479454E37F ? (Test6663854_Class_6)(Test6663854_Interface_2)var_90 : (Test6663854_Class_6)var_90) : (new Test6663854_Class_6[Test6663854_Class_3.var_23])[((Test6663854_Class_6)(Test6663854_Class_5.var_66 = (Test6663854_Interface_2)var_90)).var_78]; + } + arg_0 |= ((((Test6663854_Class_6.var_80 = (Test6663854_Class_4)var_90).var_41 = (((Test6663854_Class_4)var_90).var_41 = (Test6663854_Class_3)var_90)).var_22 = new Test6663854_Class_0()).var_8 += (Test6663854_Class_3.var_20 = new Test6663854_Class_0().var_1)); + { + (Test6663854_Class_6.var_82 = (new Test6663854_Class_3[((Test6663854_Class_6)var_90).var_78])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_18 = ((Test6663854_Class_3.var_24 ^ (!false & Test6663854_Class_3.var_24 ? Test6663854_Class_3.var_24 : (Test6663854_Class_3.var_24 ^= true)) ? (Test6663854_Class_3)var_90 : (Test6663854_Class_3)(Test6663854_Interface_2)var_90).var_18 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)var_90)).var_41 = (Test6663854_Class_3)(((Test6663854_Class_3)(Test6663854_Class_5.var_66 = (Test6663854_Class_3)var_90)).var_18 = (((Test6663854_Class_3)(Test6663854_Interface_2)var_90).var_18 = (Test6663854_Class_3)var_90)))); + } + { + arg_0++; + } + Test6663854_Interface_2 var_92; + { + ((Test6663854_Class_5.var_67 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_4)(var_92 = (Test6663854_Class_3)var_90)).var_41 = (Test6663854_Class_5.var_67 = (Test6663854_Class_3)var_90))).var_22 = ((Test6663854_Class_5.var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_22 = ((Test6663854_Class_6.var_82 = (((Test6663854_Class_4)var_90).var_41 = (Test6663854_Class_3)var_90)).var_22 = (Test6663854_Class_0)((Test6663854_Class_5.var_67 = (Test6663854_Class_3)var_90).var_18 = (Test6663854_Class_5)var_90)))).var_7 = Test6663854_Class_3.var_21; + } + arg_0 &= ((var_67 = (var_67 = new Test6663854_Class_3())).var_22 = (new Test6663854_Class_0[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_1 / 2084775982; + Test6663854_Class_3.var_20 = (Test6663854_Class_3.var_24 = false) ^ true ? Test6663854_Class_0.var_2 : var_88; + return Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[((Test6663854_Class_6)var_90).var_78]; + } + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_7.var_65 = "; result += Test6663854.Printer.print(var_65); + result += "\n"; + result += "Test6663854_Class_7.var_88 = "; result += Test6663854.Printer.print(var_88); + result += "\n"; + result += "Test6663854_Class_7.var_87 = "; result += Test6663854.Printer.print(var_87); + result += "\n"; + result += "Test6663854_Class_7.var_89 = "; result += Test6663854.Printer.print(var_89); + result += "\n"; + result += "Test6663854_Class_7.var_66 = "; result += Test6663854.Printer.print(var_66); + result += "\n"; + result += "Test6663854_Class_7.var_67 = "; result += Test6663854.Printer.print(var_67); + result += ""; + result += "\n]"; + return result; + } +} + + +final class Test6663854_Class_8 implements Test6663854_Interface_1 { + long var_93 = ++Test6663854_Class_6.var_81; + short var_94 = (short)'H'; + float var_95; + Test6663854_Interface_1 var_96; + final static float var_97 = 2.43397E38F; + final static long var_98 = 7461452158234510336L; + static Test6663854_Class_7[] var_99; + + + public Test6663854_Class_8() + { + Test6663854_Class_6 var_103; + Test6663854_Class_3.var_20 = (Test6663854_Class_3.var_20 = var_94 / ~Test6663854_Class_3.var_23); + if (false) + { + Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24; + } + else + { + Test6663854_Class_3.var_20 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23); + --Test6663854_Class_7.var_88; + } + final boolean[] var_104 = new boolean[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]; + Test6663854_Class_3.var_24 &= false & (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24); + } + + + public boolean func_0() + { + Test6663854_Class_7.var_88--; + Test6663854_Class_7.var_88--; + (((new Test6663854_Class_0[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_7 = 1.2337083709828518E307; + Test6663854_Class_7.var_88++; + if (Test6663854_Class_3.var_24) + { + byte var_100 = 25; + "lwmbav".toLowerCase(); + Test6663854_Class_3.var_24 |= (Test6663854_Class_3.var_24 |= false) & ((Test6663854_Class_3.var_24 = true) ^ Test6663854_Class_3.var_24 ? (Test6663854_Class_3.var_24 ^= Test6663854_Class_3.var_24) : Test6663854_Class_3.var_24); + } + else + { + long var_101; + new Test6663854_Class_0().var_7 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23); + Test6663854_Class_7.var_88++; + ++Test6663854_Class_6.var_81; + Test6663854_Class_7.var_88 |= 1083041050566936576L; + Test6663854_Class_7.var_88--; + } + var_94 ^= (var_94 = (var_94 *= 1.9072213520938263E307)); + var_94++; + boolean var_102 = true; + ++Test6663854_Class_7.var_88; + Test6663854_Class_7.var_88 += (((new Test6663854_Class_7[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_87; + ((new Test6663854_Class_7[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_89 /= (new double[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23] * var_97; + return (Test6663854_Class_3.var_24 = (var_102 &= Test6663854_Class_3.var_24 & true)) ? false : Test6663854_Class_3.var_24; + } + + public String func_1(final String arg_0, final long arg_1, byte arg_2, char[][] arg_3) + { + Test6663854_Class_7.var_88--; + --Test6663854_Class_7.var_88; + return arg_0; + } + + + + private Test6663854_Class_0 func_0(Test6663854_Class_0 arg_0) + { + if (!Test6663854_Class_3.var_24) + { + Test6663854_Class_7.var_88 ^= (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) << ~Test6663854_Class_0.var_2; + } + else + { + (Test6663854_Class_6.var_82 = (Test6663854_Class_7.var_67 = (Test6663854_Class_3)(new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])).var_22 = (((new Test6663854_Class_3[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_22 = (arg_0 = arg_0)); + } + if ((Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))) < Test6663854_Class_3.var_21) + { + Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 ^= (arg_0.var_6 ^ Test6663854_Class_7.var_88++) != (long)"y".codePointAt((int)var_94)) | false; + } + else + { + ++Test6663854_Class_7.var_88; + } + var_94 >>= (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23); + { + Test6663854_Class_7.var_66 = (Test6663854_Class_6)(var_96 = new Test6663854_Class_3()); + } + arg_0.var_8 = 'u'; + var_94 ^= arg_0.var_8; + ++var_94; + Test6663854_Class_7.var_88++; + var_94 += (Test6663854_Class_3.var_20 = '^'); + return arg_0; + } + + public String toString() + { + String result = "[\n"; + result += "Test6663854_Class_8.var_99 = "; result += Test6663854.Printer.print(var_99); + result += "\n"; + result += "Test6663854_Class_8.var_93 = "; result += Test6663854.Printer.print(var_93); + result += "\n"; + result += "Test6663854_Class_8.var_98 = "; result += Test6663854.Printer.print(var_98); + result += "\n"; + result += "Test6663854_Class_8.var_95 = "; result += Test6663854.Printer.print(var_95); + result += "\n"; + result += "Test6663854_Class_8.var_97 = "; result += Test6663854.Printer.print(var_97); + result += "\n"; + result += "Test6663854_Class_8.var_94 = "; result += Test6663854.Printer.print(var_94); + result += "\n"; + result += "Test6663854_Class_8.var_96 = "; result += Test6663854.Printer.print(var_96); + result += ""; + result += "\n]"; + return result; + } +} + +public class Test6663854 { + static short var_105 = 19709; + static int var_106 = (((Test6663854_Class_3.var_24 = (Test6663854_Class_3.var_24 = false)) | true) & (false || !false) ? ! (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24) : Test6663854_Class_3.var_24 | false) ? (short)5430142769559462912L : Test6663854_Class_3.var_23 << Test6663854_Class_3.var_23; + boolean var_107 = false; + + + private static long func_0(final boolean arg_0) + { + { + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)(new Test6663854_Interface_2[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]); + } + var_105++; + ((new Test6663854_Class_7[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)][((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_78]).func_0(); + byte var_108 = 107; + return Test6663854_Class_8.var_98 << ((new Test6663854_Class_4[var_108][Test6663854_Class_3.var_23])[var_108][Test6663854_Class_3.var_24 ? var_108 : var_108--]).var_42; + } + + protected final long func_1(char[] arg_0, Object arg_1, String arg_2, final int arg_3) + { + (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)))).var_43 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)))))).var_43 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)); + { + Test6663854_Class_6.var_82 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)).var_41 = (((new Test6663854[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_107 ^= var_107) ? (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23] : (Test6663854_Class_3)arg_1); + } + Test6663854_Class_7.var_88 += (Test6663854_Class_6.var_81 >>>= (var_107 &= var_107) | var_107 ? (int)- ~Test6663854_Class_6.var_81 : Test6663854_Class_3.var_23); + short var_109 = 11276; + final Test6663854_Class_8 var_110 = (Test6663854_Class_3.var_24 ^ (Test6663854_Class_3.var_24 = !true) ? 5788412835121658880L : var_109--) * (298795405395535872L << (((Test6663854_Class_0)arg_1).var_1 << (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))) != (var_107 ? var_109 : var_105) ? (Test6663854_Class_8)(arg_1 = arg_1) : ((Test6663854_Class_3.var_24 &= ! !var_107) ? new Test6663854_Class_8() : new Test6663854_Class_8()); + new Test6663854_Class_4().var_43 = Test6663854_Class_3.var_24 ^ Test6663854_Class_3.var_24 ^ Test6663854_Class_3.var_24 ? (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)) : (new byte[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1))); + Test6663854_Class_3.var_20 = (var_105 ^= (var_106 *= ((Test6663854_Class_7)arg_1).var_87 - ~Test6663854_Class_3.var_23)); + Test6663854_Class_5 var_111; + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)); + { + (arg_2 = "eiprceumt").compareTo(arg_2 = (arg_2 = "roae")); + } + if (false) + { + final Test6663854_Class_8 var_112 = var_110; + (true | (false && false) ? (Test6663854_Class_3)arg_1 : ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)).var_41 = (Test6663854_Class_6.var_82 = (Test6663854_Class_3)(var_110.var_96 = var_112)))).var_18 = var_110; + } + else + { + (Test6663854_Class_3.var_24 ? "jpunp" : "giappofq").concat(arg_2 = (arg_2 = arg_2)); + } + { + Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24; + } + var_110.var_96 = (Test6663854_Class_7)(var_110.var_96 = (Test6663854_Class_7)arg_1); + { + ((var_107 ^= !var_107) && (!Test6663854_Class_3.var_24 | (Test6663854_Class_3.var_24 |= true) ? !false : !true) ? (Test6663854_Class_4)arg_1 : (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)).var_41 = (((var_107 &= (var_107 &= (var_107 &= (Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24))))) ? (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1) : (Test6663854_Class_4)(Test6663854_Class_4.var_40 = (Test6663854_Class_7)arg_1)).var_41 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)))).var_41 = false || Test6663854_Class_3.var_24 ? (Test6663854_Class_3)arg_1 : (Test6663854_Class_3)arg_1)); + } + Test6663854_Class_5.var_66 = false ? (new Test6663854_Class_6[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23] : new Test6663854_Class_6(); + var_105++; + arg_1 = (var_111 = new Test6663854_Class_7()); + ((true ? (Test6663854_Class_3)arg_1 : (Test6663854_Class_3)arg_1).var_22 = (new Test6663854_Class_0[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_8 >>= (var_106 /= ((Test6663854_Class_4)arg_1).var_42) - ((Test6663854_Class_3.var_24 ? (Test6663854_Class_4)arg_1 : (Test6663854_Class_4)arg_1).var_43 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1))).var_43 = new Test6663854_Class_6().var_78)); + return 5795172173382514688L | (((var_107 &= (Test6663854_Class_3.var_24 |= false) | Test6663854_Class_3.var_24) ? (Test6663854_Class_4)arg_1 : (Test6663854_Class_6.var_80 = (Test6663854_Class_4)arg_1)).var_43 = Test6663854_Class_3.var_23); + } + + public static String execute() + { + try { + Test6663854 t = new Test6663854(); + try { t.test(); } + catch(Throwable e) { } + try { return t.toString(); } + catch (Throwable e) { return "Error during result conversion to String"; } + } catch (Throwable e) { return "Error during test execution"; } + } + + public static void main(String[] args) + { + try { + Test6663854 t = new Test6663854(); + try { t.test(); } + catch(Throwable e) { } + try { System.out.println(t); } + catch(Throwable e) { } + } catch (Throwable e) { } + } + + private void test() + { + if ((true & (false ? !false : true) || var_107 ? (var_105 <<= Test6663854_Class_5.var_65) / (Test6663854_Class_0.var_5 = var_105) : 2509076152709535744L) >= (true ? new Test6663854_Class_8().var_93 : (Test6663854_Class_3.var_20 = Test6663854_Class_3.var_23))) + { + (true ? (new Test6663854_Class_6[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23] : (Test6663854_Class_7.var_66 = new Test6663854_Class_6())).func_0(); + (var_107 ? (new Test6663854_Class_4().var_41 = new Test6663854_Class_3()) : (Test6663854_Class_3)(new Test6663854_Class_3().var_18 = new Test6663854_Class_8())).var_18 = (new Test6663854_Class_4[new Test6663854_Class_4().var_43 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)])[Test6663854_Class_3.var_23]; + { + ++var_106; + ((new Test6663854_Class_5().func_0() ? (Test6663854_Class_3.var_24 ^= true) : !false) ? (Test6663854_Class_7)new Test6663854_Class_5() : (Test6663854_Class_7)((Test6663854_Class_6.var_82 = new Test6663854_Class_3()).var_18 = (Test6663854_Class_6.var_80 = new Test6663854_Class_4()))).var_89 -= Test6663854_Class_3.var_23; + } + var_105 *= 4.59906108270682E307; + { + Test6663854_Class_0.var_4 = ((Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = new Test6663854_Class_4()))).var_43 = (Test6663854_Class_0.var_4 = false ? (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) : Test6663854_Class_3.var_23)); + } + long var_113 = 0L; + var_106 %= (Test6663854_Class_7.var_88 = 'i'); + for (short var_114 = ((Test6663854_Class_8)(new Test6663854_Interface_1[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))])[Test6663854_Class_3.var_23]).var_94; var_113 < 4 && false; "dmmntw".length()) + { + var_114++; + var_113++; + Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24; + new String("kprvouugy"); + } + { + new Test6663854_Class_8().var_94 /= (long)5.719961906225282E307; + } + double var_115 = 0; + Test6663854_Class_3.var_24 |= var_107; + do + { + Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 |= !Test6663854_Class_3.var_24 && var_107); + var_115++; + var_106++; + } while (var_115 < 29 && (var_107 = (Test6663854_Class_3.var_24 |= Test6663854_Class_3.var_24))); + Test6663854_Class_7.var_66 = new Test6663854_Class_7(); + Test6663854_Class_3.var_20 = (false ? (Test6663854_Class_6.var_80 = new Test6663854_Class_4()) : new Test6663854_Class_4()).var_42; + } + else + { + (((new Test6663854_Class_3[Test6663854_Class_3.var_23])[new Test6663854_Class_6().var_78]).var_22 = (new Test6663854_Class_3().var_22 = (new Test6663854_Class_3().var_22 = new Test6663854_Class_0()))).var_8 >>>= (var_106 &= new Test6663854_Class_0().var_8 << Test6663854_Class_7.var_65); + } + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = new Test6663854_Class_4())); + { + Test6663854_Class_8 var_116; + (!true | (Test6663854_Class_3.var_24 &= true) ? new Test6663854_Class_7() : new Test6663854_Class_7()).var_89 /= Test6663854_Class_7.var_88--; + Test6663854_Class_6.var_81 &= ((new Test6663854_Class_6[Test6663854_Class_3.var_23][Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_78; + } + if (true ? var_107 : (Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 |= false))) + { + Test6663854_Class_3.var_24 |= (Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 ^= (Test6663854_Class_3.var_24 &= !true))); + Test6663854_Class_7.var_66 = (Test6663854_Class_7)new Test6663854_Class_5(); + Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))); + { + Test6663854_Class_7.var_88++; + float var_117 = 0F; + final long var_118 = 1388589135930756096L; + for (var_106++; ((Test6663854_Class_3.var_24 &= false) && (Test6663854_Class_3.var_24 |= true)) ^ true && (var_117 < 1 && Test6663854_Class_3.var_24); new Test6663854_Class_0().var_8 += !false || (new float[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23] <= Test6663854_Class_3.var_23 || Test6663854_Class_3.var_24 ? ((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_78 : Test6663854_Class_3.var_23) + { + Test6663854_Class_6.var_82 = (Test6663854_Class_7.var_67 = new Test6663854_Class_3()); + var_117++; + Test6663854_Class_5.var_66 = Test6663854_Class_3.var_24 & !Test6663854_Class_3.var_24 ^ var_107 ^ new Test6663854_Class_0().var_8 == new Test6663854_Class_0().var_1 ? new Test6663854_Class_6() : new Test6663854_Class_6(); + (Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)]).var_43 = (Test6663854_Class_0.var_4 = ((Test6663854_Class_6)(new Object[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_78); + } + if (false & ((var_107 = true) || ! ((Test6663854_Class_3.var_24 ^= true || !var_107) ? false : Test6663854_Class_3.var_24 ^ var_107) ? (var_107 = Test6663854_Class_3.var_24) && Test6663854_Class_3.var_24 : true)) + { + "yvjk".toString(); + } + else + { + Test6663854_Class_4 var_119 = Test6663854_Class_6.var_80 = ((var_107 = true) ? (Test6663854_Class_6.var_81 |= var_106) : var_118) < (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))) ? (Test6663854_Class_4)(new Test6663854_Class_3().var_18 = new float[Test6663854_Class_3.var_23]) : (new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]; + } + (false | (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) >= var_106 ? new Test6663854_Class_3() : (Test6663854_Class_7.var_67 = new Test6663854_Class_3())).var_18 = ((false ? (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23] : new Test6663854_Class_3()).var_22 = ((Test6663854_Class_7.var_67 = (Test6663854_Class_3)(new Test6663854_Class_3().var_18 = (Test6663854_Class_8)(new Test6663854_Class_8().var_96 = new Test6663854_Class_8()))).var_22 = ((Test6663854_Class_5.var_67 = new Test6663854_Class_3()).var_22 = new Test6663854_Class_0()))); + short var_120; + (Test6663854_Class_6.var_80 = new Test6663854_Class_4()).var_41 = new Test6663854_Class_3(); + ((new Test6663854_Class_8[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_96 = (Test6663854_Class_4.var_40 = !false & var_107 ? (Test6663854_Class_7)new Test6663854_Class_5() : new Test6663854_Class_7()); + } + if ((Test6663854_Class_3.var_24 &= (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24)) || Test6663854_Class_3.var_24) + { + { + var_106--; + Test6663854_Class_6.var_81 -= 2.5265952E38F; + Test6663854_Class_7.var_88++; + Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)(new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])); + Test6663854_Class_6.var_81++; + (((new Test6663854_Class_7[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[(byte)(var_105 &= var_106)])[Test6663854_Class_3.var_23]).equals(((new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_18 = new Test6663854_Class_8()); + } + ((((new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_41 = (Test6663854_Class_7.var_67 = (Test6663854_Class_7.var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]))).var_18 = "mnxktbgv"; + var_105++; + ((Test6663854_Class_3.var_24 &= Test6663854_Class_3.var_24) ? (new Test6663854_Class_3().var_22 = new Test6663854_Class_0()) : new Test6663854_Class_0()).var_7 = new Test6663854_Class_0().var_6; + var_105 = (var_105 >>>= Test6663854_Class_3.var_23); + ++var_105; + { + Test6663854_Class_0.var_4 = ((Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_43 = ((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)]).var_78); + ((Test6663854_Class_8)(new Object[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_96 = (Test6663854_Class_6.var_80 = (Test6663854_Class_4)(Test6663854_Class_5.var_66 = (new Test6663854_Class_6[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])); + } + if (2125632862 >= Test6663854_Class_5.var_65) + { + "nfdjgd".toLowerCase(); + ((new Test6663854_Class_8[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]).var_96 = new Test6663854_Class_8(); + Test6663854_Interface_2 var_121; + new Test6663854_Class_0().var_7 = Test6663854_Class_8.var_97; + --var_105; + --Test6663854_Class_7.var_88; + ((new Test6663854_Class_0[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)])[((Test6663854_Class_6)(Test6663854_Class_4.var_40 = (Test6663854_Class_3)(new Object[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])).var_78]).var_7 = (((new Test6663854_Class_8[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_94 += (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)); + } + else + { + --Test6663854_Class_6.var_81; + } + if (false) + { + Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23; + } + else + { + var_105--; + (true | (Test6663854_Class_3.var_24 |= var_107) ? (Test6663854_Class_7)(new Test6663854_Class_5[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23] : (new Test6663854_Class_7[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]).var_89 *= 2.5396491E38F; + var_107 = Test6663854_Class_3.var_24; + var_105++; + } + Test6663854_Class_6.var_81--; + new Test6663854_Class_5(); + } + else + { + Test6663854_Class_0 var_122; + } + var_107 = false; + (Test6663854_Class_3.var_24 ? new Test6663854_Class_7() : (Test6663854_Class_7)(new Test6663854_Class_3().var_18 = new Test6663854_Class_6())).var_89 *= (var_106 -= (new Test6663854_Class_3().var_22 = new Test6663854_Class_0()).var_6); + new Test6663854_Class_8().var_94 *= Test6663854_Class_7.var_88; + ((new String[new Test6663854_Class_6().var_78])[Test6663854_Class_3.var_23]).codePointAt(135817988); + final double var_123 = 7.395191963488875E307; + --var_105; + Test6663854_Class_7.var_88++; + } + else + { + (Test6663854_Class_6.var_80 = Test6663854_Class_3.var_24 ? (Test6663854_Class_6.var_80 = new Test6663854_Class_4()) : (Test6663854_Class_6.var_80 = new Test6663854_Class_4())).var_38 <<= (Test6663854_Class_7.var_88 <<= (new Test6663854_Class_4().var_43 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))) >>> Test6663854_Class_3.var_23); + } + int var_124 = 0; + Test6663854_Class_7 var_125; + float var_126 = 2.5216562E38F; + int var_127 = 0; + Test6663854_Class_7.var_66 = (Test6663854_Class_5.var_66 = (Test6663854_Class_4)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]); + while (var_127 < 1 && (Test6663854_Class_3.var_24 ? (var_107 |= var_107) : false)) + { + short var_128; + var_127++; + var_125 = (var_125 = (var_125 = (var_125 = (Test6663854_Class_7)(new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]))); + "nkv".indexOf("ptrepiu" + "aljmjttym", var_106 << (new byte[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]); + } + { + Test6663854_Class_7.var_66 = (Test6663854_Class_7.var_67 = (new Test6663854_Class_3[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]); + } + var_125 = (new Test6663854_Class_7[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]; + var_126 += var_106; + while (var_124 < 537 && true) + { + Test6663854_Class_7.var_88 %= var_105; + var_124++; + var_106++; + Test6663854_Class_5.var_66 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])); + final long var_129 = 3230407753980990464L; + new Test6663854_Class_8(); + final Test6663854_Class_3 var_130 = (Test6663854_Class_3)((Test6663854_Class_3.var_24 |= !false) | (var_107 | !var_107) | (new Test6663854_Class_8().var_94++ >= 1015752753 | !true) ? (new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23] : (new Test6663854_Interface_1[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23]); + Test6663854_Class_5.var_66 = (Test6663854_Class_7.var_66 = (Test6663854_Class_7.var_66 = (Test6663854_Class_7.var_67 = var_130))); + } + Test6663854_Class_7.var_66 = var_126 >= (Test6663854_Class_3.var_24 || (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24) ? var_106 : var_126) ? new Test6663854_Class_6() : new Test6663854_Class_6(); + var_107 &= true; + (new Test6663854_Class_8().var_96 = (var_125 = (var_125 = (var_125 = new Test6663854_Class_7())))).func_0(); + float var_131 = 0F; + Test6663854_Class_3 var_132 = new Test6663854_Class_3(); + do + { + long var_133; + var_131++; + Test6663854_Interface_2 var_134 = Test6663854_Class_7.var_66 = var_132; + } while ((Test6663854_Class_3.var_24 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23) == 1.2758309E38F) && (var_131 < 117 && ((new short[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)] == ((var_107 &= ! (Test6663854_Class_3.var_24 ^= false)) ^ ! !false ? new Test6663854_Class_0().var_6 : new Test6663854_Class_4().var_42))); + (var_107 ? var_132 : (Test6663854_Class_3)(Test6663854_Class_7.var_66 = var_132)).var_18 = (Test6663854_Class_0)((Test6663854_Class_5.var_67 = (Test6663854_Class_7.var_67 = (var_132 = var_132))).var_18 = ((new Test6663854_Class_8[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23))])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]); + long var_135 = 0L; + (((new Test6663854_Class_8[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = (byte)+ (Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23)]).var_96 = var_132; + for (((var_107 = ((new Test6663854_Class_0[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).equals(var_132.var_18 = (Test6663854_Class_8)(new Test6663854_Class_8().var_96 = var_132))) ? "oedsntb" : "ouspr").concat("t"); var_135 < 27; (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23]))).var_38 %= (double)func_0(Test6663854_Class_3.var_24 = false ? !var_107 && ! !Test6663854_Class_3.var_24 : Test6663854_Class_3.var_24 ^ ! (Test6663854_Class_3.var_24 = Test6663854_Class_3.var_24))) + { + Test6663854_Class_6.var_80 = (Test6663854_Class_4)(new Test6663854_Class_8().var_96 = new Test6663854_Class_8()); + var_135++; + Test6663854_Class_3.var_24 &= !true; + new Test6663854_Class_0().var_8 += Test6663854_Class_7.var_65; + } + Test6663854_Class_3 var_136 = var_132; + if ((var_107 = ((Test6663854_Class_4)(Test6663854_Class_7.var_66 = (var_125 = (Test6663854_Class_7)(Test6663854_Class_7.var_66 = var_136)))).func_0() ^ true) && (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (Test6663854_Class_6.var_80 = (new Test6663854_Class_4[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]))).var_45 <= ((new Test6663854_Class_6[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23]).var_78) + { + var_126 %= ((var_107 = true) ? (var_105 *= 8272288534835139584L) : (var_105 |= var_105)) % new Test6663854_Class_7().var_89; + ((Test6663854_Class_3)(new Test6663854_Class_8().var_96 = (new Test6663854_Interface_1[Test6663854_Class_3.var_23])[Test6663854_Class_3.var_23])).var_18 = new Test6663854_Class_0(); + var_105 <<= ++((Test6663854_Class_3.var_24 |= false) ? new Test6663854_Class_8() : (Test6663854_Class_8)(new Test6663854_Class_8().var_96 = new Test6663854_Class_4())).var_94 % (Test6663854_Class_0.var_2 - var_106); + Test6663854_Interface_2 var_137; + var_137 = new Test6663854_Class_4(); + int var_138; + } + else + { + final Test6663854_Interface_2 var_139 = Test6663854_Class_4.var_40 = (var_136 = var_136); + new Test6663854_Class_8().var_93 -= new Test6663854_Class_6().var_78; + --((Test6663854_Class_3.var_24 ^= var_126 < Test6663854_Class_3.var_23 | !var_107) ? (new Test6663854_Class_8[Test6663854_Class_3.var_23][Test6663854_Class_3.var_23])[Test6663854_Class_0.var_4 = Test6663854_Class_3.var_23][new Test6663854_Class_6().var_78] : new Test6663854_Class_8()).var_93; + var_105 >>= ! (Test6663854_Class_3.var_24 = true) || ((Test6663854_Class_8)(! (Test6663854_Class_3.var_24 |= var_107) | (false ? Test6663854_Class_3.var_23 : new Test6663854_Class_6().var_78) != new Test6663854_Class_8().var_93 ? (Test6663854_Class_6.var_82 = var_136) : (new Test6663854_Class_8().var_96 = (var_132 = var_136)))).var_94 >= Test6663854_Class_6.var_81++ ? var_124 : '`'; + } + var_126 /= var_105; + var_105 *= var_127; + var_107 ^= (var_107 = true); + { + Test6663854_Class_7.var_66 = (var_125 = (Test6663854_Class_7)(new Test6663854_Class_5[Test6663854_Class_3.var_23])[new Test6663854_Class_6().var_78]); + } + (var_136.var_22 = ((var_136 = var_132).var_22 = new Test6663854_Class_0())).var_7 = ((!false ? var_132 : (Test6663854_Class_7.var_67 = var_132)).var_22 = (((Test6663854_Class_3)(var_136.var_18 = var_136)).var_22 = (Test6663854_Class_0)(var_132.var_18 = "sgybwy"))).var_6; + ((Test6663854_Class_3.var_20 = var_105--) >= ~Test6663854_Class_3.var_23 ? new String() : "lgcfkbsw").replace(new Test6663854_Class_0().var_8 |= 't', false ? (Test6663854_Class_7.var_88 -= var_105) : 'q'); + Test6663854_Class_7.var_88 <<= Test6663854_Class_7.var_88; + } + public String toString() + { + String result = "[\n"; + result += "Test6663854.var_105 = "; result += Printer.print(var_105); + result += "\n"; + result += "Test6663854.var_107 = "; result += Printer.print(var_107); + result += "\n"; + result += "Test6663854.var_106 = "; result += Printer.print(var_106); + result += ""; + result += "\n]"; + return result; + } + static class Printer + { + public static String print(boolean arg) { return String.valueOf(arg); } + public static String print(byte arg) { return String.valueOf(arg); } + public static String print(short arg) { return String.valueOf(arg); } + public static String print(char arg) { return String.valueOf((int)arg); } + public static String print(int arg) { return String.valueOf(arg); } + public static String print(long arg) { return String.valueOf(arg); } + public static String print(float arg) { return String.valueOf(arg); } + public static String print(double arg) { return String.valueOf(arg); } + + + public static String print(Object arg) + { + return print_r(new java.util.Stack(), arg); + } + + private static String print_r(java.util.Stack visitedObjects, Object arg) + { + String result = ""; + if (arg == null) + result += "null"; + else + if (arg.getClass().isArray()) + { + for (int i = 0; i < visitedObjects.size(); i++) + if (visitedObjects.elementAt(i) == arg) return ""; + + visitedObjects.push(arg); + + final String delimiter = ", "; + result += "["; + + if (arg instanceof Object[]) + { + Object[] array = (Object[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print_r(visitedObjects, array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof boolean[]) + { + boolean[] array = (boolean[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof byte[]) + { + byte[] array = (byte[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof short[]) + { + short[] array = (short[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof char[]) + { + char[] array = (char[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof int[]) + { + int[] array = (int[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof long[]) + { + long[] array = (long[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof float[]) + { + float[] array = (float[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + else + if (arg instanceof double[]) + { + double[] array = (double[]) arg; + for (int i = 0; i < array.length; i++) + { + result += print(array[i]); + if (i < array.length - 1) result += delimiter; + } + } + + result += "]"; + visitedObjects.pop(); + + } else + { + result += arg.toString(); + } + + return result; + } + } +} diff -r 09ac706c2623 -r 895d9ade6111 test/compiler/6930043/Test6930043.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6930043/Test6930043.java Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6930043 + * @summary C2: SIGSEGV in javasoft.sqe.tests.lang.arr017.arr01702.arr01702.loop_forw(II)I + * + * @run main Test6930043 + */ + +import java.io.PrintStream; + +public class Test6930043 { + int[] a; + int idx; + + public int loop_back(int i, int i_0_) { + int i_1_ = 0; + int[] is = a; + if (is == null) return 0; + for (int i_2_ = i; i_2_ >= i_0_; i_2_--) + i_1_ += is[idx = i_2_]; + return i_1_; + } + + public int loop_forw(int start, int end) { + int result = 0; + int[] is = a; + if (is == null) return 0; + for (int index = start; index < end; index++) + result += is[index]; + // result += is[idx = index]; + return result; + } + + public static void main(String[] strings) { + Test6930043 var_Test6930043 = new Test6930043(); + var_Test6930043.a = new int[1000000]; + var_Test6930043.loop_forw(10, 999990); + var_Test6930043.loop_forw(10, 999990); + for (int i = 0; i < 3; i++) { + try { + if (var_Test6930043.loop_forw(-1, 999990) != 0) throw new InternalError(); + } catch (ArrayIndexOutOfBoundsException e) { } + } + var_Test6930043.loop_back(999990, 10); + var_Test6930043.loop_back(999990, 10); + for (int i = 0; i < 3; i++) { + try { + if (var_Test6930043.loop_back(999990, -1) != 0) throw new InternalError(); + } catch (ArrayIndexOutOfBoundsException e) { } + } + } +} diff -r 09ac706c2623 -r 895d9ade6111 test/compiler/6932496/Test6932496.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6932496/Test6932496.java Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6932496 + * @summary incorrect deopt of jsr subroutine on 64 bit c1 + * + * @compile -source 1.5 -target 1.5 -XDjsrlimit=0 Test6932496.java + * @run main/othervm -Xcomp -XX:CompileOnly=Test6932496.m Test6932496 + */ + +public class Test6932496 { + static class A { + volatile boolean flag = false; + } + + static void m() { + try { + } finally { + A a = new A(); + a.flag = true; + } + } + + + static public void main(String[] args) { + m(); + } +} diff -r 09ac706c2623 -r 895d9ade6111 test/compiler/6935535/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6935535/Test.java Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6935535 + * @summary String.indexOf() returns incorrect result on x86 with SSE4.2 + * + * @run main/othervm -Xcomp Test + */ + +public class Test { + + static int IndexOfTest(String str) { + return str.indexOf("1111111111111xx1x"); + } + + public static void main(String args[]) { + String str = "1111111111111xx1111111111111xx1x"; + str = str.substring(0, 31); + int idx = IndexOfTest(str); + System.out.println("IndexOf(" + "1111111111111xx1x" + ") = " + idx + " in " + str); + if (idx != -1) { + System.exit(97); + } + } +} + diff -r 09ac706c2623 -r 895d9ade6111 test/runtime/6929067/T.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/6929067/T.java Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,12 @@ +public class T +{ + public static boolean foo(boolean bar) + { + return bar; + } + + public static void printIt() + { + System.out.println("Hello"); + } +} diff -r 09ac706c2623 -r 895d9ade6111 test/runtime/6929067/Test6929067.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/6929067/Test6929067.sh Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,60 @@ +#!/bin/sh + +## +## @test Test6929067.sh +## @bug 6929067 +## @summary Stack guard pages should be removed when thread is detached +## @run shell Test6929067.sh +## + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +BIT_FLAG="" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Linux) + NULL=/dev/null + PS=":" + FS="/" + ;; + SunOS | Windows_* ) + NULL=NUL + PS=";" + FS="\\" + echo "Test passed; only valid for Linux" + exit 0; + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +LD_LIBRARY_PATH=.:${TESTJAVA}/jre/lib/i386/client:/usr/openwin/lib:/usr/dt/lib:/usr/lib:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH + +THIS_DIR=`pwd` + +cp ${TESTSRC}${FS}invoke.c ${THIS_DIR} +cp ${TESTSRC}${FS}T.java ${THIS_DIR} + + +${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -fullversion + +${TESTJAVA}${FS}bin${FS}javac T.java + +gcc -o invoke -I${TESTJAVA}/include -I${TESTJAVA}/include/linux invoke.c ${TESTJAVA}/jre/lib/i386/client/libjvm.so +./invoke +exit $? diff -r 09ac706c2623 -r 895d9ade6111 test/runtime/6929067/invoke.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/6929067/invoke.c Tue Apr 06 22:06:57 2010 -0700 @@ -0,0 +1,90 @@ +#include +#include +#include + +#include + +union env_union +{ + void *void_env; + JNIEnv *jni_env; +}; + +union env_union tmp; +JNIEnv* env; +JavaVM* jvm; +JavaVMInitArgs vm_args; +JavaVMOption options[1]; +jclass class_id; +jmethodID method_id; +jint result; + +long product(unsigned long n, unsigned long m) { + if (m == 1) { + return n; + } else { + int *p = alloca(sizeof (int)); + *p = n; + return product (n, m-1) + *p; + } +} + +void * +floobydust (void *p) +{ + (*jvm)->AttachCurrentThread(jvm, &tmp.void_env, NULL); + env = tmp.jni_env; + + class_id = (*env)->FindClass (env, "T"); + assert (class_id); + + method_id = (*env)->GetStaticMethodID (env, class_id, "printIt", "()V"); + assert (method_id); + + (*env)->CallStaticVoidMethod (env, class_id, method_id, NULL); + + (*jvm)->DetachCurrentThread(jvm); + + printf("%ld\n", product(5000,5000)); + + (*jvm)->AttachCurrentThread(jvm, &tmp.void_env, NULL); + env = tmp.jni_env; + + class_id = (*env)->FindClass (env, "T"); + assert (class_id); + + method_id = (*env)->GetStaticMethodID (env, class_id, "printIt", "()V"); + assert (method_id); + + (*env)->CallStaticVoidMethod (env, class_id, method_id, NULL); + + (*jvm)->DetachCurrentThread(jvm); + + printf("%ld\n", product(5000,5000)); + + return NULL; +} + +int +main (int argc, const char** argv) +{ + options[0].optionString = "-Xss320k"; + + vm_args.version = JNI_VERSION_1_2; + vm_args.ignoreUnrecognized = JNI_TRUE; + vm_args.options = options; + vm_args.nOptions = 1; + + result = JNI_CreateJavaVM (&jvm, &tmp.void_env, &vm_args); + assert (result >= 0); + + env = tmp.jni_env; + + floobydust (NULL); + + pthread_t thr; + pthread_create (&thr, NULL, floobydust, NULL); + pthread_join (thr, NULL); + + return 0; +}