Merge
This commit is contained in:
commit
552f2a578c
.hgtags.hgtags-top-repo
corba
hotspot
.hgtags
agent/src/os/linux
make
src
cpu
sparc/vm
c1_CodeStubs_sparc.cppc1_FrameMap_sparc.hppc1_LIRAssembler_sparc.cppc1_MacroAssembler_sparc.cppc1_Runtime1_sparc.cppc2_globals_sparc.hppglobals_sparc.hppinterp_masm_sparc.cppinterp_masm_sparc.hppsparc.adstubGenerator_sparc.cppstubRoutines_sparc.hpptemplateInterpreter_sparc.cppvm_version_sparc.cpp
x86/vm
assembler_x86.cppc1_CodeStubs_x86.cppc1_FrameMap_x86.hppc1_LIRAssembler_x86.cppc1_MacroAssembler_x86.cppc1_Runtime1_x86.cppc2_globals_x86.hppglobals_x86.hppmethodHandles_x86.cppruntime_x86_32.cppsharedRuntime_x86_64.cppstubGenerator_x86_32.cppstubGenerator_x86_64.cppstubRoutines_x86_32.hppstubRoutines_x86_64.hpptemplateInterpreter_x86_32.cpptemplateInterpreter_x86_64.cpptemplateTable_x86_32.cpptemplateTable_x86_64.cppx86_32.adx86_64.ad
zero/vm
os
linux/vm
solaris
windows/vm
os_cpu/linux_zero/vm
share/vm
4
.hgtags
4
.hgtags
@ -60,3 +60,7 @@ a30062be6d9ca1d48579826f870f85974300004e jdk7-b82
|
||||
34c8199936a1682aa8587857f44cfaf37c2b6381 jdk7-b83
|
||||
b1e55627a6980b9508854ed0c0f21d4f981b4494 jdk7-b84
|
||||
b6f633a93ae0ec4555ff4bf756f5e2150c9bdede jdk7-b85
|
||||
c94d9cc81f495d97817eba9d71b84fc45f7661a5 jdk7-b86
|
||||
b7456c473862048fa70ed8092313a4ef0a55d403 jdk7-b87
|
||||
7077b95d42f6b3942a8751bba033801ff50e5889 jdk7-b88
|
||||
44158f6d3b94c0fa020e33632532473d92d1ea96 jdk7-b89
|
||||
|
@ -60,3 +60,7 @@ e1176f86805fe07fd9fb9da065dc51b47712ce76 jdk7-b82
|
||||
6880a3af9addb41541e80ebe8cde6f79ec402a58 jdk7-b83
|
||||
2f3ea057d1ad56cf3b269cdc4de2741411151982 jdk7-b84
|
||||
cf26288a114be67c39f2758959ce50b60f5ae330 jdk7-b85
|
||||
433a60a9c0bf1b26ee7e65cebaa89c541f497aed jdk7-b86
|
||||
6b1069f53fbc30663ccef49d78c31bb7d6967bde jdk7-b87
|
||||
82135c848d5fcddb065e98ae77b81077c858f593 jdk7-b88
|
||||
7f1ba4459972bf84b8201dc1cc4f62b1fe1c74f4 jdk7-b89
|
||||
|
@ -60,3 +60,7 @@ e08a42a2a94d97ea8eedb187a94dbff822c8fbba jdk7-b81
|
||||
fde0df7a2384f7fe33204a79678989807d9c2b98 jdk7-b83
|
||||
68c8961a82e4a3ad2a67991e5d834192a81eb4cd jdk7-b84
|
||||
c67a9df7bc0ca291f08f9a9cc05cb78ea15d25e6 jdk7-b85
|
||||
6253e28826d16cf1aecc39ce04c8de1f6bf2df5f jdk7-b86
|
||||
09a41111a401d327f65e453384d976a10154d9ea jdk7-b87
|
||||
39e14d2da687c7e592142137517aaf689544820f jdk7-b88
|
||||
bb4424c5e778b842c064a8b1aa902b35f4397654 jdk7-b89
|
||||
|
@ -83,3 +83,9 @@ fafab5d5349c7c066d677538db67a1ee0fb33bd2 hs15-b05
|
||||
ffc8d176b84bcfb5ac21302b4feb3b0c0d69b97c jdk7-b84
|
||||
6c9796468b91dcbb39e09dfa1baf9779ac45eb66 jdk7-b85
|
||||
418bc80ce13995149eadc9eecbba21d7a9fa02ae hs17-b10
|
||||
bf823ef06b4f211e66988d76a2e2669be5c0820e jdk7-b86
|
||||
07226e9eab8f74b37346b32715f829a2ef2c3188 hs18-b01
|
||||
e7e7e36ccdb5d56edd47e5744351202d38f3b7ad jdk7-b87
|
||||
4b60f23c42231f7ecd62ad1fcb6a9ca26fa57d1b jdk7-b88
|
||||
15836273ac2494f36ef62088bc1cb6f3f011f565 jdk7-b89
|
||||
4b60f23c42231f7ecd62ad1fcb6a9ca26fa57d1b hs18-b02
|
||||
|
@ -174,7 +174,7 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
|
||||
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);
|
||||
}
|
||||
|
@ -53,8 +53,274 @@ typedef struct symtab {
|
||||
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 @@ struct symtab* build_symtab(int fd) {
|
||||
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 @@ struct symtab* build_symtab(int fd) {
|
||||
|
||||
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 @@ struct symtab* build_symtab(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ quit:
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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=03
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
5
hotspot/make/linux/makefiles/build_vm_def.sh
Normal file
5
hotspot/make/linux/makefiles/build_vm_def.sh
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
nm --defined-only $* | awk '
|
||||
{ if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" }
|
||||
'
|
@ -290,6 +290,9 @@ SUNWprivate_1.1 {
|
||||
|
||||
# This is for Forte Analyzer profiling support.
|
||||
AsyncGetCallTrace;
|
||||
|
||||
# INSERT VTABLE SYMBOLS HERE
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
@ -285,6 +285,9 @@ SUNWprivate_1.1 {
|
||||
|
||||
# This is for Forte Analyzer profiling support.
|
||||
AsyncGetCallTrace;
|
||||
|
||||
# INSERT VTABLE SYMBOLS HERE
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
@ -121,14 +121,21 @@ JVM_OBJ_FILES = $(Obj_Files)
|
||||
|
||||
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
|
||||
|
@ -28,6 +28,9 @@ REM
|
||||
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 not "%7" == "" goto usage
|
||||
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 @@ if "%2" == "adlc" goto build_adlc
|
||||
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 @@ goto end
|
||||
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 where:
|
||||
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%
|
||||
|
@ -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 @@ develop: checks $(variantDir) $(variantDir)\local.make sanity
|
||||
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)
|
||||
|
@ -36,6 +36,9 @@ REM
|
||||
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
|
||||
|
@ -22,6 +22,8 @@
|
||||
#
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# This shell script echoes "MSC_VER=<munged version of cl>"
|
||||
# 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 @@ fi
|
||||
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`
|
||||
|
@ -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 PatchingStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -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; }
|
||||
|
@ -378,12 +378,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
|
||||
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::align_call(LIR_Code) {
|
||||
}
|
||||
|
||||
|
||||
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::vtable_call(int vtable_offset, CodeEmitInfo* info) {
|
||||
}
|
||||
|
||||
|
||||
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 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
|
||||
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 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi
|
||||
}
|
||||
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 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
|
||||
|
||||
switch (c->type()) {
|
||||
case T_INT:
|
||||
case T_ADDRESS:
|
||||
{
|
||||
jint con = c->as_jint();
|
||||
if (to_reg->is_single_cpu()) {
|
||||
@ -1720,9 +1728,13 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
} else if (code == lir_cmp_l2i) {
|
||||
#ifdef _LP64
|
||||
__ lcmp(left->as_register_lo(), right->as_register_lo(), dst->as_register());
|
||||
#else
|
||||
__ lcmp(left->as_register_hi(), left->as_register_lo(),
|
||||
right->as_register_hi(), right->as_register_lo(),
|
||||
dst->as_register());
|
||||
#endif
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -2841,7 +2853,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
|
||||
|
||||
|
||||
void LIR_Assembler::align_backward_branch_target() {
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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::inline_cache_check(Register receiver, Register iCache) {
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -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 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ 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 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
|
||||
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 @@ void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_map
|
||||
// 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 @@ void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_map
|
||||
__ 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);
|
||||
}
|
||||
|
||||
|
@ -60,9 +60,6 @@ define_pd_global(intx, FreqInlineSize, 175);
|
||||
define_pd_global(intx, INTPRESSURE, 48); // large register set
|
||||
define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment
|
||||
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
|
||||
// The default setting 16/16 seems to work best.
|
||||
// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
|
||||
define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize
|
||||
define_pd_global(intx, RegisterCostAreaRatio, 12000);
|
||||
define_pd_global(bool, UseTLAB, true);
|
||||
define_pd_global(bool, ResizeTLAB, true);
|
||||
|
@ -40,6 +40,9 @@ define_pd_global(bool, ImplicitNullChecks, true); // Generate code for
|
||||
define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
|
||||
|
||||
define_pd_global(intx, CodeEntryAlignment, 32);
|
||||
// The default setting 16/16 seems to work best.
|
||||
// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
|
||||
define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize
|
||||
define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC
|
||||
define_pd_global(intx, InlineSmallCode, 1500);
|
||||
#ifdef _LP64
|
||||
|
@ -244,9 +244,10 @@ void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg)
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -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 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
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.
|
||||
|
@ -471,6 +471,9 @@ extern bool can_branch_register( Node *bol, Node *cmp );
|
||||
source %{
|
||||
#define __ _masm.
|
||||
|
||||
// Block initializing store
|
||||
#define ASI_BLK_INIT_QUAD_LDD_P 0xE2
|
||||
|
||||
// tertiary op of a LoadP or StoreP encoding
|
||||
#define REGP_OP true
|
||||
|
||||
@ -1803,8 +1806,9 @@ void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
|
||||
// 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.
|
||||
@ -6146,6 +6150,7 @@ instruct prefetchr( memory mem ) %{
|
||||
%}
|
||||
|
||||
instruct prefetchw( memory mem ) %{
|
||||
predicate(AllocatePrefetchStyle != 3 );
|
||||
match( PrefetchWrite mem );
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
|
||||
@ -6155,6 +6160,23 @@ instruct prefetchw( memory mem ) %{
|
||||
ins_pipe(iload_mem);
|
||||
%}
|
||||
|
||||
// Use BIS instruction to prefetch.
|
||||
instruct prefetchw_bis( memory mem ) %{
|
||||
predicate(AllocatePrefetchStyle == 3);
|
||||
match( PrefetchWrite mem );
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
|
||||
format %{ "STXA G0,$mem\t! // Block initializing store" %}
|
||||
ins_encode %{
|
||||
Register base = as_Register($mem$$base);
|
||||
int disp = $mem$$disp;
|
||||
if (disp != 0) {
|
||||
__ add(base, AllocatePrefetchStepSize, base);
|
||||
}
|
||||
__ stxa(G0, base, G0, ASI_BLK_INIT_QUAD_LDD_P);
|
||||
%}
|
||||
ins_pipe(istore_mem_reg);
|
||||
%}
|
||||
|
||||
//----------Store Instructions-------------------------------------------------
|
||||
// Store Byte
|
||||
|
@ -379,7 +379,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ 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
|
||||
|
||||
@ -1148,7 +1148,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ andn(from, 7, from); // Align address
|
||||
__ ldx(from, 0, O3);
|
||||
__ inc(from, 8);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_loop);
|
||||
__ ldx(from, 0, O4);
|
||||
__ deccc(count, count_dec); // Can we do next iteration after this one?
|
||||
@ -1220,7 +1220,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
__ andn(end_from, 7, end_from); // Align address
|
||||
__ ldx(end_from, 0, O3);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_loop);
|
||||
__ ldx(end_from, -8, O4);
|
||||
__ deccc(count, count_dec); // Can we do next iteration after this one?
|
||||
@ -1349,7 +1349,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ BIND(L_copy_byte);
|
||||
__ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit);
|
||||
__ delayed()->nop();
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_byte_loop);
|
||||
__ ldub(from, offset, O3);
|
||||
__ deccc(count);
|
||||
@ -1445,7 +1445,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
L_aligned_copy, L_copy_byte);
|
||||
}
|
||||
// copy 4 elements (16 bytes) at a time
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_aligned_copy);
|
||||
__ dec(end_from, 16);
|
||||
__ ldx(end_from, 8, O3);
|
||||
@ -1461,7 +1461,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ BIND(L_copy_byte);
|
||||
__ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit);
|
||||
__ delayed()->nop();
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_byte_loop);
|
||||
__ dec(end_from);
|
||||
__ dec(end_to);
|
||||
@ -1577,7 +1577,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ BIND(L_copy_2_bytes);
|
||||
__ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit);
|
||||
__ delayed()->nop();
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_2_bytes_loop);
|
||||
__ lduh(from, offset, O3);
|
||||
__ deccc(count);
|
||||
@ -1684,7 +1684,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
L_aligned_copy, L_copy_2_bytes);
|
||||
}
|
||||
// copy 4 elements (16 bytes) at a time
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_aligned_copy);
|
||||
__ dec(end_from, 16);
|
||||
__ ldx(end_from, 8, O3);
|
||||
@ -1781,7 +1781,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// copy with shift 4 elements (16 bytes) at a time
|
||||
__ dec(count, 4); // The cmp at the beginning guaranty count >= 4
|
||||
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_16_bytes);
|
||||
__ ldx(from, 4, O4);
|
||||
__ deccc(count, 4); // Can we do next iteration after this one?
|
||||
@ -1907,7 +1907,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// to form 2 aligned 8-bytes chunks to store.
|
||||
//
|
||||
__ ldx(end_from, -4, O3);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_16_bytes);
|
||||
__ ldx(end_from, -12, O4);
|
||||
__ deccc(count, 4);
|
||||
@ -1929,7 +1929,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ delayed()->inc(count, 4);
|
||||
|
||||
// copy 4 elements (16 bytes) at a time
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_aligned_copy);
|
||||
__ dec(end_from, 16);
|
||||
__ ldx(end_from, 8, O3);
|
||||
@ -2000,6 +2000,27 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// to: O1
|
||||
// count: O2 treated as signed
|
||||
//
|
||||
// count -= 2;
|
||||
// if ( count >= 0 ) { // >= 2 elements
|
||||
// if ( count > 6) { // >= 8 elements
|
||||
// count -= 6; // original count - 8
|
||||
// do {
|
||||
// copy_8_elements;
|
||||
// count -= 8;
|
||||
// } while ( count >= 0 );
|
||||
// count += 6;
|
||||
// }
|
||||
// if ( count >= 0 ) { // >= 2 elements
|
||||
// do {
|
||||
// copy_2_elements;
|
||||
// } while ( (count=count-2) >= 0 );
|
||||
// }
|
||||
// }
|
||||
// count += 2;
|
||||
// if ( count != 0 ) { // 1 element left
|
||||
// copy_1_element;
|
||||
// }
|
||||
//
|
||||
void generate_disjoint_long_copy_core(bool aligned) {
|
||||
Label L_copy_8_bytes, L_copy_16_bytes, L_exit;
|
||||
const Register from = O0; // source array address
|
||||
@ -2012,7 +2033,39 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ mov(G0, offset0); // offset from start of arrays (0)
|
||||
__ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
|
||||
__ delayed()->add(offset0, 8, offset8);
|
||||
__ align(16);
|
||||
|
||||
// Copy by 64 bytes chunks
|
||||
Label L_copy_64_bytes;
|
||||
const Register from64 = O3; // source address
|
||||
const Register to64 = G3; // destination address
|
||||
__ subcc(count, 6, O3);
|
||||
__ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes );
|
||||
__ delayed()->mov(to, to64);
|
||||
// Now we can use O4(offset0), O5(offset8) as temps
|
||||
__ mov(O3, count);
|
||||
__ mov(from, from64);
|
||||
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_64_bytes);
|
||||
for( int off = 0; off < 64; off += 16 ) {
|
||||
__ ldx(from64, off+0, O4);
|
||||
__ ldx(from64, off+8, O5);
|
||||
__ stx(O4, to64, off+0);
|
||||
__ stx(O5, to64, off+8);
|
||||
}
|
||||
__ deccc(count, 8);
|
||||
__ inc(from64, 64);
|
||||
__ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_64_bytes);
|
||||
__ delayed()->inc(to64, 64);
|
||||
|
||||
// Restore O4(offset0), O5(offset8)
|
||||
__ sub(from64, from, offset0);
|
||||
__ inccc(count, 6);
|
||||
__ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
|
||||
__ delayed()->add(offset0, 8, offset8);
|
||||
|
||||
// Copy by 16 bytes chunks
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_16_bytes);
|
||||
__ ldx(from, offset0, O3);
|
||||
__ ldx(from, offset8, G3);
|
||||
@ -2023,6 +2076,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes);
|
||||
__ delayed()->inc(offset8, 16);
|
||||
|
||||
// Copy last 8 bytes
|
||||
__ BIND(L_copy_8_bytes);
|
||||
__ inccc(count, 2);
|
||||
__ brx(Assembler::zero, true, Assembler::pn, L_exit );
|
||||
@ -2085,7 +2139,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_8_bytes );
|
||||
__ delayed()->sllx(count, LogBytesPerLong, offset8);
|
||||
__ sub(offset8, 8, offset0);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_16_bytes);
|
||||
__ ldx(from, offset8, O2);
|
||||
__ ldx(from, offset0, O3);
|
||||
@ -2351,7 +2405,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// (O5 = 0; ; O5 += wordSize) --- offset from src, dest arrays
|
||||
// (O2 = len; O2 != 0; O2--) --- number of oops *remaining*
|
||||
// G3, G4, G5 --- current oop, oop.klass, oop.klass.super
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
|
||||
__ BIND(store_element);
|
||||
__ deccc(G1_remain); // decrement the count
|
||||
|
@ -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 @@ static bool returns_to_call_stub(address return_pc) {
|
||||
|
||||
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 {
|
||||
|
@ -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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
__ 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.
|
||||
|
@ -86,14 +86,24 @@ void VM_Version::initialize() {
|
||||
if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) {
|
||||
FLAG_SET_DEFAULT(InteriorEntryAlignment, 4);
|
||||
}
|
||||
if (is_niagara1_plus()) {
|
||||
if (AllocatePrefetchStyle > 0 && FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
|
||||
// Use BIS instruction for allocation prefetch.
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
|
||||
// Use smaller prefetch distance on N2 with BIS
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64);
|
||||
}
|
||||
}
|
||||
if (AllocatePrefetchStyle != 3 && FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
|
||||
// Use different prefetch distance without BIS
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (FLAG_IS_DEFAULT(OptoLoopAlignment)) {
|
||||
FLAG_SET_DEFAULT(OptoLoopAlignment, 4);
|
||||
}
|
||||
if (is_niagara1_plus() && FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
|
||||
// Use smaller prefetch distance on N2
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Use hardware population count instruction if available.
|
||||
|
@ -3365,6 +3365,13 @@ void Assembler::shrdl(Register dst, Register src) {
|
||||
|
||||
#else // LP64
|
||||
|
||||
void Assembler::set_byte_if_not_zero(Register dst) {
|
||||
int enc = prefix_and_encode(dst->encoding(), true);
|
||||
emit_byte(0x0F);
|
||||
emit_byte(0x95);
|
||||
emit_byte(0xE0 | enc);
|
||||
}
|
||||
|
||||
// 64bit only pieces of the assembler
|
||||
// This should only be used by 64bit instructions that can use rip-relative
|
||||
// it cannot be used by instructions that want an immediate value.
|
||||
@ -8460,6 +8467,7 @@ void MacroAssembler::string_indexof(Register str1, Register str2,
|
||||
subptr(str1, result); // Restore counter
|
||||
shrl(str1, 1);
|
||||
addl(cnt1, str1);
|
||||
decrementl(cnt1);
|
||||
lea(str1, Address(result, 2)); // Reload string
|
||||
|
||||
// Load substr
|
||||
|
@ -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 PatchingStub::emit_code(LIR_Assembler* ce) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -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; }
|
||||
|
@ -436,40 +436,18 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
|
||||
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);
|
||||
}
|
||||
// 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");
|
||||
|
||||
// unwind activation and forward exception to caller
|
||||
// rax,: exception
|
||||
__ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
|
||||
assert(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
@ -495,8 +473,10 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
|
||||
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 @@ void LIR_Assembler::return_op(LIR_Opr result) {
|
||||
}
|
||||
|
||||
// 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 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
|
||||
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 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
|
||||
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 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi
|
||||
switch (type) {
|
||||
case T_INT: // fall through
|
||||
case T_FLOAT:
|
||||
case T_ADDRESS:
|
||||
__ movl(as_Address(addr), c->as_jint_bits());
|
||||
break;
|
||||
|
||||
@ -2707,19 +2690,14 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op
|
||||
} else {
|
||||
assert(code == lir_cmp_l2i, "check");
|
||||
#ifdef _LP64
|
||||
Register dest = dst->as_register();
|
||||
__ xorptr(dest, dest);
|
||||
Label high, done;
|
||||
__ cmpptr(left->as_register_lo(), right->as_register_lo());
|
||||
__ jcc(Assembler::equal, done);
|
||||
__ jcc(Assembler::greater, high);
|
||||
__ decrement(dest);
|
||||
__ jmp(done);
|
||||
__ bind(high);
|
||||
__ increment(dest);
|
||||
|
||||
__ bind(done);
|
||||
|
||||
Label done;
|
||||
Register dest = dst->as_register();
|
||||
__ cmpptr(left->as_register_lo(), right->as_register_lo());
|
||||
__ movl(dest, -1);
|
||||
__ jccb(Assembler::less, done);
|
||||
__ set_byte_if_not_zero(dest);
|
||||
__ movzbl(dest, dest);
|
||||
__ bind(done);
|
||||
#else
|
||||
__ lcmp2int(left->as_register_hi(),
|
||||
left->as_register_lo(),
|
||||
@ -2738,6 +2716,7 @@ void LIR_Assembler::align_call(LIR_Code code) {
|
||||
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 +2732,41 @@ void LIR_Assembler::align_call(LIR_Code code) {
|
||||
}
|
||||
|
||||
|
||||
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 +2819,12 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
|
||||
} 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();
|
||||
|
@ -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::inline_cache_check(Register receiver, Register iCache) {
|
||||
}
|
||||
|
||||
|
||||
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 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes) {
|
||||
// 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::build_frame(int frame_size_in_bytes) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -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 @@ void Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_map
|
||||
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 @@ void Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_map
|
||||
__ 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 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
|
||||
// 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), exception_pc);
|
||||
// rax,: exception handler address of the caller
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, 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_return_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 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,6 @@ define_pd_global(intx, CodeCacheExpansionSize, 32*K);
|
||||
// Ergonomics related flags
|
||||
define_pd_global(uint64_t,MaxRAM, 4ULL*G);
|
||||
#endif // AMD64
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, RegisterCostAreaRatio, 16000);
|
||||
|
||||
// Peephole and CISC spilling both break the graph, and so makes the
|
||||
|
@ -45,6 +45,7 @@ define_pd_global(intx, CodeEntryAlignment, 32);
|
||||
#else
|
||||
define_pd_global(intx, CodeEntryAlignment, 16);
|
||||
#endif // COMPILER2
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, InlineFrequencyCount, 100);
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
|
||||
|
@ -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 @@ MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _mas
|
||||
}
|
||||
|
||||
#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 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
||||
|
||||
// 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 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
(!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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
// 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
}
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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,19 +732,8 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
if (ek == _adapter_opt_f2d) {
|
||||
__ fld_s(vmarg); // load float to ST0
|
||||
__ fstp_s(vmarg); // store single
|
||||
} else if (!TaggedStackInterpreter) {
|
||||
__ 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
|
||||
// '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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
|
||||
// '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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ 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 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,8 +115,8 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
// rax: exception handler for given <exception oop/exception pc>
|
||||
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call.
|
||||
__ cmpl(Address(rcx, JavaThread::is_method_handle_exception_offset()), 0);
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call site.
|
||||
__ cmpl(Address(rcx, JavaThread::is_method_handle_return_offset()), 0);
|
||||
__ cmovptr(Assembler::notEqual, rsp, rbp);
|
||||
|
||||
// We have a handler in rax, (could be deopt blob)
|
||||
|
@ -3328,8 +3328,8 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
// rax: exception handler
|
||||
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call.
|
||||
__ cmpl(Address(r15_thread, JavaThread::is_method_handle_exception_offset()), 0);
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call site.
|
||||
__ cmpl(Address(r15_thread, JavaThread::is_method_handle_return_offset()), 0);
|
||||
__ cmovptr(Assembler::notEqual, rsp, rbp);
|
||||
|
||||
// We have a handler in rax (could be deopt blob).
|
||||
|
@ -369,7 +369,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// 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 @@ class StubGenerator: public StubCodeGenerator {
|
||||
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 @@ class StubGenerator: public StubCodeGenerator {
|
||||
#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 @@ class StubGenerator: public StubCodeGenerator {
|
||||
#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_return_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;
|
||||
}
|
||||
@ -799,7 +812,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit;
|
||||
// Copy 64-byte chunks
|
||||
__ jmpb(L_copy_64_bytes);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_64_bytes_loop);
|
||||
|
||||
if(UseUnalignedLoadStores) {
|
||||
@ -861,7 +874,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit;
|
||||
// Copy 64-byte chunks
|
||||
__ jmpb(L_copy_64_bytes);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_64_bytes_loop);
|
||||
__ movq(mmx0, Address(from, 0));
|
||||
__ movq(mmx1, Address(from, 8));
|
||||
@ -1131,7 +1144,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ movl(Address(to, count, sf, 0), rdx);
|
||||
__ jmpb(L_copy_8_bytes);
|
||||
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
// Move 8 bytes
|
||||
__ BIND(L_copy_8_bytes_loop);
|
||||
if (UseXMMForArrayCopy) {
|
||||
@ -1222,7 +1235,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
} else {
|
||||
__ jmpb(L_copy_8_bytes);
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_8_bytes_loop);
|
||||
__ fild_d(Address(from, 0));
|
||||
__ fistp_d(Address(from, to_from, Address::times_1));
|
||||
@ -1269,7 +1282,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
__ jmpb(L_copy_8_bytes);
|
||||
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_copy_8_bytes_loop);
|
||||
if (VM_Version::supports_mmx()) {
|
||||
if (UseXMMForArrayCopy) {
|
||||
@ -1441,7 +1454,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Loop control:
|
||||
// for (count = -count; count != 0; count++)
|
||||
// Base pointers src, dst are biased by 8*count,to last element.
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
|
||||
__ BIND(L_store_element);
|
||||
__ movptr(to_element_addr, elem); // store the oop
|
||||
@ -2263,16 +2276,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -466,7 +466,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
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
|
||||
@ -871,9 +871,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
|
||||
address generate_fp_mask(const char *stub_name, int64_t mask) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", stub_name);
|
||||
|
||||
__ align(16);
|
||||
address start = __ pc();
|
||||
|
||||
__ emit_data64( mask, relocInfo::none );
|
||||
@ -1268,7 +1267,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label& L_copy_32_bytes, Label& L_copy_8_bytes) {
|
||||
DEBUG_ONLY(__ stop("enter at entry label, not here"));
|
||||
Label L_loop;
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_loop);
|
||||
if(UseUnalignedLoadStores) {
|
||||
__ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24));
|
||||
@ -1309,7 +1308,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label& L_copy_32_bytes, Label& L_copy_8_bytes) {
|
||||
DEBUG_ONLY(__ stop("enter at entry label, not here"));
|
||||
Label L_loop;
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
__ BIND(L_loop);
|
||||
if(UseUnalignedLoadStores) {
|
||||
__ movdqu(xmm0, Address(from, qword_count, Address::times_8, 16));
|
||||
@ -2229,7 +2228,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Loop control:
|
||||
// for (count = -count; count != 0; count++)
|
||||
// Base pointers src, dst are biased by 8*(count-1),to last element.
|
||||
__ align(16);
|
||||
__ align(OptoLoopAlignment);
|
||||
|
||||
__ BIND(L_store_element);
|
||||
__ store_heap_oop(to_element_addr, rax_oop); // store the oop
|
||||
@ -3009,16 +3008,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -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 @@ enum platform_dependent_constants {
|
||||
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;
|
||||
|
@ -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 {
|
||||
|
@ -1550,6 +1550,7 @@ int AbstractInterpreter::layout_activation(methodOop method,
|
||||
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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
// 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
__ 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
/* 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
// 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
}
|
||||
|
||||
// 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
|
||||
// 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 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
//
|
||||
address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
|
||||
address entry = __ pc();
|
||||
const Register thread = rcx;
|
||||
|
||||
__ restore_bcp();
|
||||
__ restore_locals();
|
||||
@ -1735,8 +1737,8 @@ address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state
|
||||
__ 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
|
||||
|
@ -1741,7 +1741,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
__ 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
|
||||
|
@ -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 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no)
|
||||
__ 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
|
||||
|
@ -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 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no)
|
||||
__ 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
|
||||
|
@ -1444,8 +1444,10 @@ void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
|
||||
// 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;
|
||||
|
||||
|
@ -2074,8 +2074,10 @@ void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {}
|
||||
// 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;
|
||||
|
||||
|
@ -206,7 +206,6 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
|
||||
// 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 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
if (HAS_PENDING_EXCEPTION)
|
||||
goto unwind_and_return;
|
||||
}
|
||||
thread->clr_do_not_unlock();
|
||||
}
|
||||
|
||||
// Lock if necessary
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -192,7 +192,8 @@ int LinuxAttachListener::init() {
|
||||
res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
|
||||
}
|
||||
if (res == -1) {
|
||||
sprintf(path, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id());
|
||||
snprintf(path, PATH_MAX+1, "%s/.java_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
strcpy(addr.sun_path, path);
|
||||
::unlink(path);
|
||||
res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
|
||||
@ -460,13 +461,14 @@ bool AttachListener::is_init_trigger() {
|
||||
if (init_at_startup() || is_initialized()) {
|
||||
return false; // initialized at startup or already initialized
|
||||
}
|
||||
char fn[32];
|
||||
char fn[128];
|
||||
sprintf(fn, ".attach_pid%d", os::current_process_id());
|
||||
int ret;
|
||||
struct stat64 st;
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
if (ret == -1) {
|
||||
sprintf(fn, "/tmp/.attach_pid%d", os::current_process_id());
|
||||
snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
}
|
||||
if (ret == 0) {
|
||||
|
@ -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 <sys/ipc.h>
|
||||
# include <sys/shm.h>
|
||||
# include <link.h>
|
||||
# include <stdint.h>
|
||||
# include <inttypes.h>
|
||||
|
||||
#define MAX_PATH (2 * K)
|
||||
|
||||
@ -1518,7 +1522,10 @@ int os::current_process_id() {
|
||||
|
||||
const char* os::dll_file_extension() { return ".so"; }
|
||||
|
||||
const char* os::get_temp_directory() { return "/tmp/"; }
|
||||
const char* os::get_temp_directory() {
|
||||
const char *prop = Arguments::get_property("java.io.tmpdir");
|
||||
return prop == NULL ? "/tmp" : prop;
|
||||
}
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
@ -2301,7 +2308,8 @@ void linux_wrap_code(char* base, size_t size) {
|
||||
char buf[40];
|
||||
int num = Atomic::add(1, &cnt);
|
||||
|
||||
sprintf(buf, "/tmp/hs-vm-%d-%d", os::current_process_id(), num);
|
||||
snprintf(buf, sizeof(buf), "%s/hs-vm-%d-%d",
|
||||
os::get_temp_directory(), os::current_process_id(), num);
|
||||
unlink(buf);
|
||||
|
||||
int fd = open(buf, O_CREAT | O_RDWR, S_IRWXU);
|
||||
@ -2492,6 +2500,91 @@ bool os::uncommit_memory(char* addr, size_t size) {
|
||||
!= 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
|
||||
|
@ -145,11 +145,11 @@ static char* get_user_tmp_dir(const char* user) {
|
||||
|
||||
const char* tmpdir = os::get_temp_directory();
|
||||
const char* perfdir = PERFDATA_NAME;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 2;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
|
||||
char* dirname = NEW_C_HEAP_ARRAY(char, nbytes);
|
||||
|
||||
// construct the path name to user specific tmp directory
|
||||
snprintf(dirname, nbytes, "%s%s_%s", tmpdir, perfdir, user);
|
||||
snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user);
|
||||
|
||||
return dirname;
|
||||
}
|
||||
@ -331,8 +331,9 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
||||
}
|
||||
|
||||
char* usrdir_name = NEW_C_HEAP_ARRAY(char,
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 1);
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 2);
|
||||
strcpy(usrdir_name, tmpdirname);
|
||||
strcat(usrdir_name, "/");
|
||||
strcat(usrdir_name, dentry->d_name);
|
||||
|
||||
DIR* subdirp = os::opendir(usrdir_name);
|
||||
|
@ -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 @@ provider hotspot {
|
||||
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(
|
||||
|
@ -375,7 +375,8 @@ int SolarisAttachListener::create_door() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(door_path, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id());
|
||||
snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
RESTARTABLE(::creat(door_path, S_IRUSR | S_IWUSR), fd);
|
||||
|
||||
if (fd == -1) {
|
||||
@ -591,13 +592,14 @@ bool AttachListener::is_init_trigger() {
|
||||
if (init_at_startup() || is_initialized()) {
|
||||
return false; // initialized at startup or already initialized
|
||||
}
|
||||
char fn[32];
|
||||
char fn[128];
|
||||
sprintf(fn, ".attach_pid%d", os::current_process_id());
|
||||
int ret;
|
||||
struct stat64 st;
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
if (ret == -1) {
|
||||
sprintf(fn, "/tmp/.attach_pid%d", os::current_process_id());
|
||||
snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
}
|
||||
if (ret == 0) {
|
||||
@ -668,13 +670,18 @@ jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -676,15 +676,6 @@ bool os::have_special_privileges() {
|
||||
}
|
||||
|
||||
|
||||
static char* get_property(char* name, char* buffer, int buffer_size) {
|
||||
if (os::getenv(name, buffer, buffer_size)) {
|
||||
return buffer;
|
||||
}
|
||||
static char empty[] = "";
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
void os::init_system_properties_values() {
|
||||
char arch[12];
|
||||
sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
|
||||
@ -1826,7 +1817,10 @@ void os::set_error_file(const char *logfile) {}
|
||||
|
||||
const char* os::dll_file_extension() { return ".so"; }
|
||||
|
||||
const char* os::get_temp_directory() { return "/tmp/"; }
|
||||
const char* os::get_temp_directory() {
|
||||
const char *prop = Arguments::get_property("java.io.tmpdir");
|
||||
return prop == NULL ? "/tmp" : prop;
|
||||
}
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
@ -2698,6 +2692,14 @@ void os::free_memory(char* addr, size_t bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
|
@ -147,11 +147,11 @@ static char* get_user_tmp_dir(const char* user) {
|
||||
|
||||
const char* tmpdir = os::get_temp_directory();
|
||||
const char* perfdir = PERFDATA_NAME;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 2;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
|
||||
char* dirname = NEW_C_HEAP_ARRAY(char, nbytes);
|
||||
|
||||
// construct the path name to user specific tmp directory
|
||||
snprintf(dirname, nbytes, "%s%s_%s", tmpdir, perfdir, user);
|
||||
snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user);
|
||||
|
||||
return dirname;
|
||||
}
|
||||
@ -322,8 +322,9 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
||||
}
|
||||
|
||||
char* usrdir_name = NEW_C_HEAP_ARRAY(char,
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 1);
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 2);
|
||||
strcpy(usrdir_name, tmpdirname);
|
||||
strcat(usrdir_name, "/");
|
||||
strcat(usrdir_name, dentry->d_name);
|
||||
|
||||
DIR* subdirp = os::opendir(usrdir_name);
|
||||
|
@ -998,15 +998,16 @@ os::closedir(DIR *dirp)
|
||||
|
||||
const char* os::dll_file_extension() { return ".dll"; }
|
||||
|
||||
const char * os::get_temp_directory()
|
||||
{
|
||||
static char path_buf[MAX_PATH];
|
||||
if (GetTempPath(MAX_PATH, path_buf)>0)
|
||||
return path_buf;
|
||||
else{
|
||||
path_buf[0]='\0';
|
||||
return path_buf;
|
||||
}
|
||||
const char* os::get_temp_directory() {
|
||||
const char *prop = Arguments::get_property("java.io.tmpdir");
|
||||
if (prop != 0) return prop;
|
||||
static char path_buf[MAX_PATH];
|
||||
if (GetTempPath(MAX_PATH, path_buf)>0)
|
||||
return path_buf;
|
||||
else{
|
||||
path_buf[0]='\0';
|
||||
return path_buf;
|
||||
}
|
||||
}
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
@ -2803,6 +2804,14 @@ bool os::release_memory(char* addr, size_t bytes) {
|
||||
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) {
|
||||
|
@ -149,11 +149,11 @@ static char* get_user_tmp_dir(const char* user) {
|
||||
|
||||
const char* tmpdir = os::get_temp_directory();
|
||||
const char* perfdir = PERFDATA_NAME;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 2;
|
||||
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
|
||||
char* dirname = NEW_C_HEAP_ARRAY(char, nbytes);
|
||||
|
||||
// construct the path name to user specific tmp directory
|
||||
_snprintf(dirname, nbytes, "%s%s_%s", tmpdir, perfdir, user);
|
||||
_snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user);
|
||||
|
||||
return dirname;
|
||||
}
|
||||
@ -318,8 +318,9 @@ static char* get_user_name_slow(int vmid) {
|
||||
}
|
||||
|
||||
char* usrdir_name = NEW_C_HEAP_ARRAY(char,
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 1);
|
||||
strlen(tmpdirname) + strlen(dentry->d_name) + 2);
|
||||
strcpy(usrdir_name, tmpdirname);
|
||||
strcat(usrdir_name, "\\");
|
||||
strcat(usrdir_name, dentry->d_name);
|
||||
|
||||
DIR* subdirp = os::opendir(usrdir_name);
|
||||
|
@ -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);
|
||||
#ifdef _LP64
|
||||
define_pd_global(intx, ThreadStackSize, 1536);
|
||||
#ifdef _LP64
|
||||
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);
|
||||
|
@ -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 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) {
|
||||
}
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ class PatchingStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
@ -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 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
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 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
CHECK_BAILOUT();
|
||||
|
||||
// inlining not successful => standard invoke
|
||||
bool is_static = code == Bytecodes::_invokestatic;
|
||||
ValueType* result_type = as_ValueType(target->return_type());
|
||||
Values* args = state()->pop_arguments(target->arg_size_no_receiver());
|
||||
Value recv = is_static ? NULL : apop();
|
||||
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 = has_receiver ? apop() : NULL;
|
||||
int vtable_index = methodOopDesc::invalid_vtable_index;
|
||||
|
||||
#ifdef SPARC
|
||||
@ -1723,7 +1728,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
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 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||
_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);
|
||||
// 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();
|
||||
}
|
||||
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();
|
||||
|
@ -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 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, bool lock_stack_only)
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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 @@ class IRScopeDebugInfo: public CompilationResourceObj {
|
||||
//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 @@ class IRScopeDebugInfo: public CompilationResourceObj {
|
||||
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 @@ class CodeEmitInfo: public CompilationResourceObj {
|
||||
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; }
|
||||
|
@ -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 @@ void Intrinsic::state_values_do(void f(Value*)) {
|
||||
|
||||
|
||||
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 @@ Invoke::Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values*
|
||||
_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 @@ Invoke::Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values*
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -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 @@ BASE(StateSplit, Instruction)
|
||||
|
||||
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 @@ LEAF(Invoke, StateSplit)
|
||||
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 @@ LEAF(Invoke, StateSplit)
|
||||
// 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 @@ LEAF(Invoke, StateSplit)
|
||||
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*));
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 @@ LIR_Opr LIR_OprFact::value_type(ValueType* type) {
|
||||
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::value_type(ValueType* type) {
|
||||
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 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
|
||||
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 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
|
||||
}
|
||||
|
||||
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 @@ void LIR_OprDesc::print(outputStream* out) const {
|
||||
// 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 @@ const char * LIR_Op::name() const {
|
||||
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
|
||||
|
@ -85,9 +85,10 @@ class LIR_Const: public LIR_OprPtr {
|
||||
|
||||
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 @@ class LIR_Const: public LIR_OprPtr {
|
||||
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 @@ class LIR_Const: public LIR_OprPtr {
|
||||
#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 @@ class LIR_OprFact: public AllStatic {
|
||||
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 @@ enum LIR_Code {
|
||||
, lir_optvirtual_call
|
||||
, lir_icvirtual_call
|
||||
, lir_virtual_call
|
||||
, lir_dynamic_call
|
||||
, end_opJavaCall
|
||||
, begin_opArrayCopy
|
||||
, lir_arraycopy
|
||||
@ -1052,6 +1055,16 @@ class LIR_OpJavaCall: public LIR_OpCall {
|
||||
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 @@ class LIR_List: public CompilationResourceObj {
|
||||
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)); }
|
||||
|
@ -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_debug_info_for_branch(CodeEmitInfo* info) {
|
||||
}
|
||||
|
||||
|
||||
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_rtcall(LIR_OpRTCall* op) {
|
||||
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 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
|
||||
|
||||
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) {
|
||||
|
@ -82,7 +82,7 @@ class LIR_Assembler: public CompilationResourceObj {
|
||||
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 @@ class LIR_Assembler: public CompilationResourceObj {
|
||||
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();
|
||||
|
||||
|
@ -2284,7 +2284,7 @@ void LIRGenerator::do_OsrEntry(OsrEntry* x) {
|
||||
|
||||
|
||||
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 @@ LIRItemList* LIRGenerator::invoke_visit_arguments(Invoke* x) {
|
||||
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 @@ void LIRGenerator::do_Invoke(Invoke* x) {
|
||||
|
||||
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 @@ void LIRGenerator::do_Invoke(Invoke* x) {
|
||||
__ 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;
|
||||
|
@ -2479,6 +2479,15 @@ int LinearScan::append_scope_value_for_constant(LIR_Opr opr, GrowableArray<Scope
|
||||
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;
|
||||
@ -2599,12 +2608,17 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArray<ScopeV
|
||||
} else if (opr->is_double_xmm()) {
|
||||
assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation");
|
||||
VMReg rname_first = opr->as_xmm_double_reg()->as_VMReg();
|
||||
# ifdef _LP64
|
||||
first = new LocationValue(Location::new_reg_loc(Location::dbl, rname_first));
|
||||
second = &_int_0_scope_value;
|
||||
# else
|
||||
first = new LocationValue(Location::new_reg_loc(Location::normal, rname_first));
|
||||
// %%% This is probably a waste but we'll keep things as they were for now
|
||||
if (true) {
|
||||
VMReg rname_second = rname_first->next();
|
||||
second = new LocationValue(Location::new_reg_loc(Location::normal, rname_second));
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
} else if (opr->is_double_fpu()) {
|
||||
@ -2630,13 +2644,17 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArray<ScopeV
|
||||
#endif
|
||||
|
||||
VMReg rname_first = frame_map()->fpu_regname(opr->fpu_regnrHi());
|
||||
|
||||
#ifdef _LP64
|
||||
first = new LocationValue(Location::new_reg_loc(Location::dbl, rname_first));
|
||||
second = &_int_0_scope_value;
|
||||
#else
|
||||
first = new LocationValue(Location::new_reg_loc(Location::normal, rname_first));
|
||||
// %%% This is probably a waste but we'll keep things as they were for now
|
||||
if (true) {
|
||||
VMReg rname_second = rname_first->next();
|
||||
second = new LocationValue(Location::new_reg_loc(Location::normal, rname_second));
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
|
@ -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 @@ class C1_MacroAssembler: public MacroAssembler {
|
||||
|
||||
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();
|
||||
|
@ -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
|
||||
@ -40,6 +40,16 @@ size_t ciCPCache::get_f1_offset(int index) {
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 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
|
||||
//
|
||||
|
@ -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 @@ public:
|
||||
// requested entry.
|
||||
size_t get_f1_offset(int index);
|
||||
|
||||
bool is_f1_null_at(int index);
|
||||
|
||||
void print();
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ void ciConstant::print() {
|
||||
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:
|
||||
|
@ -385,11 +385,6 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||
KILL_COMPILE_ON_FATAL_(fail_type));
|
||||
}
|
||||
|
||||
if (found_klass != NULL) {
|
||||
// Found it. Build a CI handle.
|
||||
return get_object(found_klass)->as_klass();
|
||||
}
|
||||
|
||||
// If we fail to find an array klass, look again for its element type.
|
||||
// The element type may be available either locally or via constraints.
|
||||
// In either case, if we can find the element type in the system dictionary,
|
||||
@ -414,6 +409,11 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||
}
|
||||
}
|
||||
|
||||
if (found_klass != NULL) {
|
||||
// Found it. Build a CI handle.
|
||||
return get_object(found_klass)->as_klass();
|
||||
}
|
||||
|
||||
if (require_local) return NULL;
|
||||
// Not yet loaded into the VM, or not governed by loader constraints.
|
||||
// Make a CI representative for it.
|
||||
|
@ -2956,8 +2956,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
#endif
|
||||
bool compact_fields = CompactFields;
|
||||
int allocation_style = FieldsAllocationStyle;
|
||||
if( allocation_style < 0 || allocation_style > 1 ) { // Out of range?
|
||||
assert(false, "0 <= FieldsAllocationStyle <= 1");
|
||||
if( allocation_style < 0 || allocation_style > 2 ) { // Out of range?
|
||||
assert(false, "0 <= FieldsAllocationStyle <= 2");
|
||||
allocation_style = 1; // Optimistic
|
||||
}
|
||||
|
||||
@ -2993,6 +2993,25 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
} else if( allocation_style == 1 ) {
|
||||
// Fields order: longs/doubles, ints, shorts/chars, bytes, oops
|
||||
next_nonstatic_double_offset = next_nonstatic_field_offset;
|
||||
} else if( allocation_style == 2 ) {
|
||||
// Fields allocation: oops fields in super and sub classes are together.
|
||||
if( nonstatic_field_size > 0 && super_klass() != NULL &&
|
||||
super_klass->nonstatic_oop_map_size() > 0 ) {
|
||||
int map_size = super_klass->nonstatic_oop_map_size();
|
||||
OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps();
|
||||
OopMapBlock* last_map = first_map + map_size - 1;
|
||||
int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
|
||||
if (next_offset == next_nonstatic_field_offset) {
|
||||
allocation_style = 0; // allocate oops first
|
||||
next_nonstatic_oop_offset = next_nonstatic_field_offset;
|
||||
next_nonstatic_double_offset = next_nonstatic_oop_offset +
|
||||
(nonstatic_oop_count * heapOopSize);
|
||||
}
|
||||
}
|
||||
if( allocation_style == 2 ) {
|
||||
allocation_style = 1; // allocate oops last
|
||||
next_nonstatic_double_offset = next_nonstatic_field_offset;
|
||||
}
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
@ -334,33 +334,6 @@ klassOop LoaderConstraintTable::find_constrained_klass(symbolHandle name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
klassOop LoaderConstraintTable::find_constrained_elem_klass(symbolHandle name,
|
||||
symbolHandle elem_name,
|
||||
Handle loader,
|
||||
TRAPS) {
|
||||
LoaderConstraintEntry *p = *(find_loader_constraint(name, loader));
|
||||
if (p != NULL) {
|
||||
assert(p->klass() == NULL, "Expecting null array klass");
|
||||
|
||||
// The array name has a constraint, but it will not have a class. Check
|
||||
// each loader for an associated elem
|
||||
for (int i = 0; i < p->num_loaders(); i++) {
|
||||
Handle no_protection_domain;
|
||||
|
||||
klassOop k = SystemDictionary::find(elem_name, p->loader(i), no_protection_domain, THREAD);
|
||||
if (k != NULL) {
|
||||
// Return the first elem klass found.
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No constraints, or else no klass loaded yet.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void LoaderConstraintTable::ensure_loader_constraint_capacity(
|
||||
LoaderConstraintEntry *p,
|
||||
int nfree) {
|
||||
|
@ -66,9 +66,6 @@ public:
|
||||
// bool is_method, TRAPS)
|
||||
|
||||
klassOop find_constrained_klass(symbolHandle name, Handle loader);
|
||||
klassOop find_constrained_elem_klass(symbolHandle name, symbolHandle elem_name,
|
||||
Handle loader, TRAPS);
|
||||
|
||||
|
||||
// Class loader constraints
|
||||
|
||||
|
@ -2178,9 +2178,8 @@ klassOop SystemDictionary::find_constrained_instance_or_array_klass(
|
||||
// a loader constraint that would require this loader to return the
|
||||
// klass that is already loaded.
|
||||
if (FieldType::is_array(class_name())) {
|
||||
// Array classes are hard because their klassOops are not kept in the
|
||||
// constraint table. The array klass may be constrained, but the elem class
|
||||
// may not be.
|
||||
// For array classes, their klassOops are not kept in the
|
||||
// constraint table. The element klassOops are.
|
||||
jint dimension;
|
||||
symbolOop object_key;
|
||||
BasicType t = FieldType::get_array_info(class_name(), &dimension,
|
||||
@ -2190,8 +2189,9 @@ klassOop SystemDictionary::find_constrained_instance_or_array_klass(
|
||||
} else {
|
||||
symbolHandle elem_name(THREAD, object_key);
|
||||
MutexLocker mu(SystemDictionary_lock, THREAD);
|
||||
klass = constraints()->find_constrained_elem_klass(class_name, elem_name, class_loader, THREAD);
|
||||
klass = constraints()->find_constrained_klass(elem_name, class_loader);
|
||||
}
|
||||
// If element class already loaded, allocate array klass
|
||||
if (klass != NULL) {
|
||||
klass = Klass::cast(klass)->array_klass_or_null(dimension);
|
||||
}
|
||||
@ -2209,22 +2209,38 @@ bool SystemDictionary::add_loader_constraint(symbolHandle class_name,
|
||||
Handle class_loader1,
|
||||
Handle class_loader2,
|
||||
Thread* THREAD) {
|
||||
unsigned int d_hash1 = dictionary()->compute_hash(class_name, class_loader1);
|
||||
symbolHandle constraint_name;
|
||||
if (!FieldType::is_array(class_name())) {
|
||||
constraint_name = class_name;
|
||||
} else {
|
||||
// For array classes, their klassOops are not kept in the
|
||||
// constraint table. The element classes are.
|
||||
jint dimension;
|
||||
symbolOop object_key;
|
||||
BasicType t = FieldType::get_array_info(class_name(), &dimension,
|
||||
&object_key, CHECK_(false));
|
||||
// primitive types always pass
|
||||
if (t != T_OBJECT) {
|
||||
return true;
|
||||
} else {
|
||||
constraint_name = symbolHandle(THREAD, object_key);
|
||||
}
|
||||
}
|
||||
unsigned int d_hash1 = dictionary()->compute_hash(constraint_name, class_loader1);
|
||||
int d_index1 = dictionary()->hash_to_index(d_hash1);
|
||||
|
||||
unsigned int d_hash2 = dictionary()->compute_hash(class_name, class_loader2);
|
||||
unsigned int d_hash2 = dictionary()->compute_hash(constraint_name, class_loader2);
|
||||
int d_index2 = dictionary()->hash_to_index(d_hash2);
|
||||
|
||||
{
|
||||
MutexLocker mu_s(SystemDictionary_lock, THREAD);
|
||||
MutexLocker mu_s(SystemDictionary_lock, THREAD);
|
||||
|
||||
// Better never do a GC while we're holding these oops
|
||||
No_Safepoint_Verifier nosafepoint;
|
||||
// Better never do a GC while we're holding these oops
|
||||
No_Safepoint_Verifier nosafepoint;
|
||||
|
||||
klassOop klass1 = find_class(d_index1, d_hash1, class_name, class_loader1);
|
||||
klassOop klass2 = find_class(d_index2, d_hash2, class_name, class_loader2);
|
||||
return constraints()->add_entry(class_name, klass1, class_loader1,
|
||||
klass2, class_loader2);
|
||||
klassOop klass1 = find_class(d_index1, d_hash1, constraint_name, class_loader1);
|
||||
klassOop klass2 = find_class(d_index2, d_hash2, constraint_name, class_loader2);
|
||||
return constraints()->add_entry(constraint_name, klass1, class_loader1,
|
||||
klass2, class_loader2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2301,6 +2317,7 @@ symbolOop SystemDictionary::find_resolution_error(constantPoolHandle pool, int w
|
||||
// Returns the name of the type that failed a loader constraint check, or
|
||||
// NULL if no constraint failed. The returned C string needs cleaning up
|
||||
// with a ResourceMark in the caller. No exception except OOME is thrown.
|
||||
// Arrays are not added to the loader constraint table, their elements are.
|
||||
char* SystemDictionary::check_signature_loaders(symbolHandle signature,
|
||||
Handle loader1, Handle loader2,
|
||||
bool is_method, TRAPS) {
|
||||
|
@ -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 @@ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
|
||||
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 @@ BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
|
||||
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 @@ void BufferBlob::free( BufferBlob *blob ) {
|
||||
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
|
||||
|
||||
|
@ -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 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
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 CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
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 @@ class BufferBlob: public CodeBlob {
|
||||
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 */ }
|
||||
@ -254,6 +257,40 @@ class BufferBlob: public CodeBlob {
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// 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
|
||||
|
||||
|
@ -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
|
||||
@ -284,9 +284,11 @@ void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) {
|
||||
cur->print_on(tty, is_live ? "scavenge root" : "dead scavenge root"); tty->cr();
|
||||
}
|
||||
#endif //PRODUCT
|
||||
if (is_live)
|
||||
if (is_live) {
|
||||
// Perform cur->oops_do(f), maybe just once per nmethod.
|
||||
f->do_code_blob(cur);
|
||||
cur->fix_oop_relocations();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for stray marks.
|
||||
|
@ -988,10 +988,12 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
|
||||
}
|
||||
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 {
|
||||
@ -1412,9 +1414,14 @@ void CompileBroker::init_compiler_thread_log() {
|
||||
intx thread_id = os::current_thread_id();
|
||||
for (int try_temp_dir = 1; try_temp_dir >= 0; try_temp_dir--) {
|
||||
const char* dir = (try_temp_dir ? os::get_temp_directory() : NULL);
|
||||
if (dir == NULL) dir = "";
|
||||
sprintf(fileBuf, "%shs_c" UINTX_FORMAT "_pid%u.log",
|
||||
dir, thread_id, os::current_process_id());
|
||||
if (dir == NULL) {
|
||||
jio_snprintf(fileBuf, sizeof(fileBuf), "hs_c" UINTX_FORMAT "_pid%u.log",
|
||||
thread_id, os::current_process_id());
|
||||
} else {
|
||||
jio_snprintf(fileBuf, sizeof(fileBuf),
|
||||
"%s%shs_c" UINTX_FORMAT "_pid%u.log", dir,
|
||||
os::file_separator(), thread_id, os::current_process_id());
|
||||
}
|
||||
fp = fopen(fileBuf, "at");
|
||||
if (fp != NULL) {
|
||||
file = NEW_C_HEAP_ARRAY(char, strlen(fileBuf)+1);
|
||||
|
@ -46,9 +46,9 @@ CMSAdaptiveSizePolicy::CMSAdaptiveSizePolicy(size_t init_eden_size,
|
||||
|
||||
_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;
|
||||
|
@ -606,7 +606,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
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 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
|
||||
// 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);
|
||||
FLAG_SET_DEFAULT(ConcGCThreads, (ParallelGCThreads + 3)/4);
|
||||
}
|
||||
if (ParallelCMSThreads > 1) {
|
||||
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 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
}
|
||||
}
|
||||
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 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
// 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 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
|
||||
// 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 @@ bool CMSCollector::markFromRootsWork(bool asynch) {
|
||||
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 @@ void CMSConcMarkingTask::coordinator_yield() {
|
||||
}
|
||||
|
||||
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 @@ bool CMSMarkStack::allocate(size_t size) {
|
||||
// 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 @@ void CMSMarkStack::expand() {
|
||||
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(
|
||||
|
@ -44,20 +44,20 @@ ConcurrentG1Refine::ConcurrentG1Refine() :
|
||||
{
|
||||
|
||||
// Ergomonically select initial concurrent refinement parameters
|
||||
if (FLAG_IS_DEFAULT(G1ConcRefineGreenZone)) {
|
||||
FLAG_SET_DEFAULT(G1ConcRefineGreenZone, MAX2<int>(ParallelGCThreads, 1));
|
||||
if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
|
||||
FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, MAX2<int>(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<int>(G1ConcRefineYellowZone, green_zone()));
|
||||
set_yellow_zone(MAX2<int>(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<int>(G1ConcRefineRedZone, yellow_zone()));
|
||||
set_red_zone(MAX2<int>(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 @@ ConcurrentG1Refine::ConcurrentG1Refine() :
|
||||
}
|
||||
|
||||
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<int>((G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads, 1);
|
||||
return MAX2<int>((G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads : ParallelGCThreads, 1);
|
||||
}
|
||||
|
||||
void ConcurrentG1Refine::init() {
|
||||
|
@ -39,7 +39,8 @@ class ConcurrentG1Refine: public CHeapObj {
|
||||
* 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.
|
||||
|
@ -107,7 +107,7 @@ void ConcurrentG1RefineThread::run_young_rs_sampling() {
|
||||
if (_should_terminate) {
|
||||
break;
|
||||
}
|
||||
_monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefineServiceInterval);
|
||||
_monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ bool ConcurrentG1RefineThread::is_active() {
|
||||
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::activate() {
|
||||
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::run() {
|
||||
|
||||
|
||||
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 @@ void ConcurrentG1RefineThread::stop() {
|
||||
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 {
|
||||
|
@ -297,6 +297,11 @@ void CMRegionStack::push(MemRegion mr) {
|
||||
}
|
||||
}
|
||||
|
||||
// Currently we do not call this at all. Normally we would call it
|
||||
// during the concurrent marking / remark phases but we now call
|
||||
// the lock-based version instead. But we might want to resurrect this
|
||||
// code in the future. So, we'll leave it here commented out.
|
||||
#if 0
|
||||
MemRegion CMRegionStack::pop() {
|
||||
while (true) {
|
||||
// Otherwise...
|
||||
@ -321,6 +326,41 @@ MemRegion CMRegionStack::pop() {
|
||||
// Otherwise, we need to try again.
|
||||
}
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
void CMRegionStack::push_with_lock(MemRegion mr) {
|
||||
assert(mr.word_size() > 0, "Precondition");
|
||||
MutexLockerEx x(CMRegionStack_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (isFull()) {
|
||||
_overflow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_base[_index] = mr;
|
||||
_index += 1;
|
||||
}
|
||||
|
||||
MemRegion CMRegionStack::pop_with_lock() {
|
||||
MutexLockerEx x(CMRegionStack_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
while (true) {
|
||||
if (_index == 0) {
|
||||
return MemRegion();
|
||||
}
|
||||
_index -= 1;
|
||||
|
||||
MemRegion mr = _base[_index];
|
||||
if (mr.start() != NULL) {
|
||||
assert(mr.end() != NULL, "invariant");
|
||||
assert(mr.word_size() > 0, "invariant");
|
||||
return mr;
|
||||
} else {
|
||||
// that entry was invalidated... let's skip it
|
||||
assert(mr.end() == NULL, "invariant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CMRegionStack::invalidate_entries_into_cset() {
|
||||
bool result = false;
|
||||
@ -447,7 +487,7 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs,
|
||||
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 +501,7 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs,
|
||||
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 +523,8 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs,
|
||||
_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 +534,11 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs,
|
||||
_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) {
|
||||
@ -668,24 +708,46 @@ ConcurrentMark::~ConcurrentMark() {
|
||||
//
|
||||
|
||||
void ConcurrentMark::clearNextBitmap() {
|
||||
guarantee(!G1CollectedHeap::heap()->mark_in_progress(), "Precondition.");
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
G1CollectorPolicy* g1p = g1h->g1_policy();
|
||||
|
||||
// clear the mark bitmap (no grey objects to start with).
|
||||
// We need to do this in chunks and offer to yield in between
|
||||
// each chunk.
|
||||
HeapWord* start = _nextMarkBitMap->startWord();
|
||||
HeapWord* end = _nextMarkBitMap->endWord();
|
||||
HeapWord* cur = start;
|
||||
size_t chunkSize = M;
|
||||
while (cur < end) {
|
||||
HeapWord* next = cur + chunkSize;
|
||||
if (next > end)
|
||||
next = end;
|
||||
MemRegion mr(cur,next);
|
||||
_nextMarkBitMap->clearRange(mr);
|
||||
cur = next;
|
||||
do_yield_check();
|
||||
}
|
||||
// Make sure that the concurrent mark thread looks to still be in
|
||||
// the current cycle.
|
||||
guarantee(cmThread()->during_cycle(), "invariant");
|
||||
|
||||
// We are finishing up the current cycle by clearing the next
|
||||
// marking bitmap and getting it ready for the next cycle. During
|
||||
// this time no other cycle can start. So, let's make sure that this
|
||||
// is the case.
|
||||
guarantee(!g1h->mark_in_progress(), "invariant");
|
||||
|
||||
// clear the mark bitmap (no grey objects to start with).
|
||||
// We need to do this in chunks and offer to yield in between
|
||||
// each chunk.
|
||||
HeapWord* start = _nextMarkBitMap->startWord();
|
||||
HeapWord* end = _nextMarkBitMap->endWord();
|
||||
HeapWord* cur = start;
|
||||
size_t chunkSize = M;
|
||||
while (cur < end) {
|
||||
HeapWord* next = cur + chunkSize;
|
||||
if (next > end)
|
||||
next = end;
|
||||
MemRegion mr(cur,next);
|
||||
_nextMarkBitMap->clearRange(mr);
|
||||
cur = next;
|
||||
do_yield_check();
|
||||
|
||||
// Repeat the asserts from above. We'll do them as asserts here to
|
||||
// minimize their overhead on the product. However, we'll have
|
||||
// them as guarantees at the beginning / end of the bitmap
|
||||
// clearing to get some checking in the product.
|
||||
assert(cmThread()->during_cycle(), "invariant");
|
||||
assert(!g1h->mark_in_progress(), "invariant");
|
||||
}
|
||||
|
||||
// Repeat the asserts from above.
|
||||
guarantee(cmThread()->during_cycle(), "invariant");
|
||||
guarantee(!g1h->mark_in_progress(), "invariant");
|
||||
}
|
||||
|
||||
class NoteStartOfMarkHRClosure: public HeapRegionClosure {
|
||||
@ -760,7 +822,10 @@ void ConcurrentMark::checkpointRootsInitialPost() {
|
||||
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 +1144,11 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
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 +2655,11 @@ void ConcurrentMark::abort() {
|
||||
|
||||
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,
|
||||
@ -3352,7 +3425,7 @@ void CMTask::drain_region_stack(BitMapClosure* bc) {
|
||||
gclog_or_tty->print_cr("[%d] draining region stack, size = %d",
|
||||
_task_id, _cm->region_stack_size());
|
||||
|
||||
MemRegion mr = _cm->region_stack_pop();
|
||||
MemRegion mr = _cm->region_stack_pop_with_lock();
|
||||
// it returns MemRegion() if the pop fails
|
||||
statsOnly(if (mr.start() != NULL) ++_region_stack_pops );
|
||||
|
||||
@ -3373,7 +3446,7 @@ void CMTask::drain_region_stack(BitMapClosure* bc) {
|
||||
if (has_aborted())
|
||||
mr = MemRegion();
|
||||
else {
|
||||
mr = _cm->region_stack_pop();
|
||||
mr = _cm->region_stack_pop_with_lock();
|
||||
// it returns MemRegion() if the pop fails
|
||||
statsOnly(if (mr.start() != NULL) ++_region_stack_pops );
|
||||
}
|
||||
@ -3406,7 +3479,7 @@ void CMTask::drain_region_stack(BitMapClosure* bc) {
|
||||
}
|
||||
// Now push the part of the region we didn't scan on the
|
||||
// region stack to make sure a task scans it later.
|
||||
_cm->region_stack_push(newRegion);
|
||||
_cm->region_stack_push_with_lock(newRegion);
|
||||
}
|
||||
// break from while
|
||||
mr = MemRegion();
|
||||
@ -3704,7 +3777,14 @@ void CMTask::do_marking_step(double time_target_ms) {
|
||||
// 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
|
||||
|
@ -24,8 +24,8 @@
|
||||
|
||||
class G1CollectedHeap;
|
||||
class CMTask;
|
||||
typedef GenericTaskQueue<oop> CMTaskQueue;
|
||||
typedef GenericTaskQueueSet<oop> CMTaskQueueSet;
|
||||
typedef GenericTaskQueue<oop> CMTaskQueue;
|
||||
typedef GenericTaskQueueSet<CMTaskQueue> CMTaskQueueSet;
|
||||
|
||||
// A generic CM bit map. This is essentially a wrapper around the BitMap
|
||||
// class, with one bit per (1<<_shifter) HeapWords.
|
||||
@ -252,9 +252,19 @@ public:
|
||||
// with other "push" operations (no pops).
|
||||
void push(MemRegion mr);
|
||||
|
||||
#if 0
|
||||
// This is currently not used. See the comment in the .cpp file.
|
||||
|
||||
// Lock-free; assumes that it will only be called in parallel
|
||||
// with other "pop" operations (no pushes).
|
||||
MemRegion pop();
|
||||
#endif // 0
|
||||
|
||||
// These two are the implementations that use a lock. They can be
|
||||
// called concurrently with each other but they should not be called
|
||||
// concurrently with the lock-free versions (push() / pop()).
|
||||
void push_with_lock(MemRegion mr);
|
||||
MemRegion pop_with_lock();
|
||||
|
||||
bool isEmpty() { return _index == 0; }
|
||||
bool isFull() { return _index == _capacity; }
|
||||
@ -540,6 +550,10 @@ public:
|
||||
|
||||
// Manipulation of the region stack
|
||||
bool region_stack_push(MemRegion mr) {
|
||||
// Currently we only call the lock-free version during evacuation
|
||||
// pauses.
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped");
|
||||
|
||||
_regionStack.push(mr);
|
||||
if (_regionStack.overflow()) {
|
||||
set_has_overflown();
|
||||
@ -547,7 +561,33 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
MemRegion region_stack_pop() { return _regionStack.pop(); }
|
||||
#if 0
|
||||
// Currently this is not used. See the comment in the .cpp file.
|
||||
MemRegion region_stack_pop() { return _regionStack.pop(); }
|
||||
#endif // 0
|
||||
|
||||
bool region_stack_push_with_lock(MemRegion mr) {
|
||||
// Currently we only call the lock-based version during either
|
||||
// concurrent marking or remark.
|
||||
assert(!SafepointSynchronize::is_at_safepoint() || !concurrent(),
|
||||
"if we are at a safepoint it should be the remark safepoint");
|
||||
|
||||
_regionStack.push_with_lock(mr);
|
||||
if (_regionStack.overflow()) {
|
||||
set_has_overflown();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
MemRegion region_stack_pop_with_lock() {
|
||||
// Currently we only call the lock-based version during either
|
||||
// concurrent marking or remark.
|
||||
assert(!SafepointSynchronize::is_at_safepoint() || !concurrent(),
|
||||
"if we are at a safepoint it should be the remark safepoint");
|
||||
|
||||
return _regionStack.pop_with_lock();
|
||||
}
|
||||
|
||||
int region_stack_size() { return _regionStack.size(); }
|
||||
bool region_stack_overflow() { return _regionStack.overflow(); }
|
||||
bool region_stack_empty() { return _regionStack.isEmpty(); }
|
||||
|
@ -42,8 +42,8 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
|
||||
private:
|
||||
ConcurrentMark* _cm;
|
||||
bool _started;
|
||||
bool _in_progress;
|
||||
volatile bool _started;
|
||||
volatile bool _in_progress;
|
||||
|
||||
void sleepBeforeNextCycle();
|
||||
|
||||
@ -67,15 +67,25 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
// Counting virtual time so far.
|
||||
double vtime_count_accum() { return _vtime_count_accum; }
|
||||
|
||||
ConcurrentMark* cm() { return _cm; }
|
||||
ConcurrentMark* cm() { return _cm; }
|
||||
|
||||
void set_started() { _started = true; }
|
||||
void clear_started() { _started = false; }
|
||||
bool started() { return _started; }
|
||||
void set_started() { _started = true; }
|
||||
void clear_started() { _started = false; }
|
||||
bool started() { return _started; }
|
||||
|
||||
void set_in_progress() { _in_progress = true; }
|
||||
void clear_in_progress() { _in_progress = false; }
|
||||
bool in_progress() { return _in_progress; }
|
||||
void set_in_progress() { _in_progress = true; }
|
||||
void clear_in_progress() { _in_progress = false; }
|
||||
bool in_progress() { return _in_progress; }
|
||||
|
||||
// This flag returns true from the moment a marking cycle is
|
||||
// initiated (during the initial-mark pause when started() is set)
|
||||
// to the moment when the cycle completes (just after the next
|
||||
// marking bitmap has been cleared and in_progress() is
|
||||
// cleared). While this flag is true we will not start another cycle
|
||||
// so that cycles do not overlap. We cannot use just in_progress()
|
||||
// as the CM thread might take some time to wake up before noticing
|
||||
// that started() is set and set in_progress().
|
||||
bool during_cycle() { return started() || in_progress(); }
|
||||
|
||||
// Yield for GC
|
||||
void yield();
|
||||
|
@ -583,7 +583,7 @@ HeapRegion* G1CollectedHeap::newAllocRegion_work(size_t word_size,
|
||||
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,
|
||||
@ -902,6 +902,10 @@ public:
|
||||
|
||||
void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
|
||||
size_t word_size) {
|
||||
if (GC_locker::check_active_before_gc()) {
|
||||
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
|
||||
if (PrintHeapAtGC) {
|
||||
@ -916,10 +920,6 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
|
||||
assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread");
|
||||
|
||||
if (GC_locker::is_active()) {
|
||||
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
|
||||
}
|
||||
|
||||
{
|
||||
IsGCActiveMark x;
|
||||
|
||||
@ -2102,18 +2102,21 @@ size_t G1CollectedHeap::tlab_capacity(Thread* ignored) const {
|
||||
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 @@ void G1CollectedHeap::print_tracing_info() const {
|
||||
if (G1SummarizeRSetStats) {
|
||||
g1_rem_set()->print_summary_info();
|
||||
}
|
||||
if (G1SummarizeConcurrentMark) {
|
||||
if (G1SummarizeConcMark) {
|
||||
concurrent_mark()->print_summary_info();
|
||||
}
|
||||
if (G1SummarizeZFStats) {
|
||||
@ -2655,6 +2658,10 @@ struct PrepareForRSScanningClosure : public HeapRegionClosure {
|
||||
|
||||
void
|
||||
G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
if (GC_locker::check_active_before_gc()) {
|
||||
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
|
||||
}
|
||||
|
||||
if (PrintHeapAtGC) {
|
||||
Universe::print_heap_before_gc();
|
||||
}
|
||||
@ -2662,6 +2669,11 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
{
|
||||
ResourceMark rm;
|
||||
|
||||
// This call will decide whether this pause is an initial-mark
|
||||
// pause. If it is, during_initial_mark_pause() will return true
|
||||
// for the duration of this pause.
|
||||
g1_policy()->decide_on_conc_mark_initiation();
|
||||
|
||||
char verbose_str[128];
|
||||
sprintf(verbose_str, "GC pause ");
|
||||
if (g1_policy()->in_young_gc_mode()) {
|
||||
@ -2670,7 +2682,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
else
|
||||
strcat(verbose_str, "(partial)");
|
||||
}
|
||||
if (g1_policy()->should_initiate_conc_mark())
|
||||
if (g1_policy()->during_initial_mark_pause())
|
||||
strcat(verbose_str, " (initial-mark)");
|
||||
|
||||
// if PrintGCDetails is on, we'll print long statistics information
|
||||
@ -2694,10 +2706,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
"young list should be well formed");
|
||||
}
|
||||
|
||||
if (GC_locker::is_active()) {
|
||||
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
|
||||
}
|
||||
|
||||
bool abandoned = false;
|
||||
{ // Call to jvmpi::post_class_unload_events must occur outside of active GC
|
||||
IsGCActiveMark x;
|
||||
@ -2753,7 +2761,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
_young_list->print();
|
||||
#endif // SCAN_ONLY_VERBOSE
|
||||
|
||||
if (g1_policy()->should_initiate_conc_mark()) {
|
||||
if (g1_policy()->during_initial_mark_pause()) {
|
||||
concurrent_mark()->checkpointRootsInitialPre();
|
||||
}
|
||||
save_marks();
|
||||
@ -2855,7 +2863,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
|
||||
}
|
||||
|
||||
if (g1_policy()->in_young_gc_mode() &&
|
||||
g1_policy()->should_initiate_conc_mark()) {
|
||||
g1_policy()->during_initial_mark_pause()) {
|
||||
concurrent_mark()->checkpointRootsInitialPost();
|
||||
set_marking_started();
|
||||
// CAUTION: after the doConcurrentMark() call below,
|
||||
@ -2934,6 +2942,9 @@ void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) {
|
||||
// the same region
|
||||
assert(r == NULL || !r->is_gc_alloc_region(),
|
||||
"shouldn't already be a GC alloc region");
|
||||
assert(r == NULL || !r->isHumongous(),
|
||||
"humongous regions shouldn't be used as GC alloc regions");
|
||||
|
||||
HeapWord* original_top = NULL;
|
||||
if (r != NULL)
|
||||
original_top = r->top();
|
||||
@ -3076,12 +3087,17 @@ void G1CollectedHeap::get_gc_alloc_regions() {
|
||||
|
||||
if (alloc_region->in_collection_set() ||
|
||||
alloc_region->top() == alloc_region->end() ||
|
||||
alloc_region->top() == alloc_region->bottom()) {
|
||||
// we will discard the current GC alloc region if it's in the
|
||||
// collection set (it can happen!), if it's already full (no
|
||||
// point in using it), or if it's empty (this means that it
|
||||
// was emptied during a cleanup and it should be on the free
|
||||
// list now).
|
||||
alloc_region->top() == alloc_region->bottom() ||
|
||||
alloc_region->isHumongous()) {
|
||||
// we will discard the current GC alloc region if
|
||||
// * it's in the collection set (it can happen!),
|
||||
// * it's already full (no point in using it),
|
||||
// * it's empty (this means that it was emptied during
|
||||
// a cleanup and it should be on the free list now), or
|
||||
// * it's humongous (this means that it was emptied
|
||||
// during a cleanup and was added to the free list, but
|
||||
// has been subseqently used to allocate a humongous
|
||||
// object that may be less than the region size).
|
||||
|
||||
alloc_region = NULL;
|
||||
}
|
||||
@ -3480,7 +3496,7 @@ void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) {
|
||||
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());
|
||||
@ -3974,7 +3990,7 @@ public:
|
||||
OopsInHeapRegionClosure *scan_perm_cl;
|
||||
OopsInHeapRegionClosure *scan_so_cl;
|
||||
|
||||
if (_g1h->g1_policy()->should_initiate_conc_mark()) {
|
||||
if (_g1h->g1_policy()->during_initial_mark_pause()) {
|
||||
scan_root_cl = &scan_mark_root_cl;
|
||||
scan_perm_cl = &scan_mark_perm_cl;
|
||||
scan_so_cl = &scan_mark_heap_rs_cl;
|
||||
@ -4002,9 +4018,7 @@ public:
|
||||
_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.
|
||||
@ -4139,7 +4153,7 @@ G1CollectedHeap::scan_scan_only_set(OopsInHeapRegionClosure* oc,
|
||||
FilterAndMarkInHeapRegionAndIntoCSClosure scan_and_mark(this, &boc, concurrent_mark());
|
||||
|
||||
OopsInHeapRegionClosure *foc;
|
||||
if (g1_policy()->should_initiate_conc_mark())
|
||||
if (g1_policy()->during_initial_mark_pause())
|
||||
foc = &scan_and_mark;
|
||||
else
|
||||
foc = &scan_only;
|
||||
|
@ -56,8 +56,8 @@ class ConcurrentZFThread;
|
||||
# define IF_G1_DETAILED_STATS(code)
|
||||
#endif
|
||||
|
||||
typedef GenericTaskQueue<StarTask> RefToScanQueue;
|
||||
typedef GenericTaskQueueSet<StarTask> RefToScanQueueSet;
|
||||
typedef GenericTaskQueue<StarTask> RefToScanQueue;
|
||||
typedef GenericTaskQueueSet<RefToScanQueue> RefToScanQueueSet;
|
||||
|
||||
typedef int RegionIdx_t; // needs to hold [ 0..max_regions() )
|
||||
typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion )
|
||||
@ -1055,7 +1055,12 @@ public:
|
||||
|
||||
// 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.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user