# HG changeset patch # User twisti # Date 1268919403 25200 # Node ID 97fe2cc98b1daab3d19cafa4e69d6df01e9570f8 # Parent 12d91eb0f579964f435764ce3c35f926ac425c17# Parent 76c1d7d13ec5c76822f8ddb16aabb47756cb0391 Merge diff -r 12d91eb0f579 -r 97fe2cc98b1d agent/src/os/linux/libproc_impl.c --- a/agent/src/os/linux/libproc_impl.c Thu Mar 11 14:41:29 2010 -0500 +++ b/agent/src/os/linux/libproc_impl.c Thu Mar 18 06:36:43 2010 -0700 @@ -174,7 +174,7 @@ return NULL; } - newlib->symtab = build_symtab(newlib->fd); + newlib->symtab = build_symtab(newlib->fd, libname); if (newlib->symtab == NULL) { print_debug("symbol table build failed for %s\n", newlib->name); } diff -r 12d91eb0f579 -r 97fe2cc98b1d agent/src/os/linux/symtab.c --- a/agent/src/os/linux/symtab.c Thu Mar 11 14:41:29 2010 -0500 +++ b/agent/src/os/linux/symtab.c Thu Mar 18 06:36:43 2010 -0700 @@ -53,8 +53,274 @@ struct hsearch_data *hash_table; } symtab_t; -// read symbol table from given fd. -struct symtab* build_symtab(int fd) { + +// Directory that contains global debuginfo files. In theory it +// should be possible to change this, but in a Java environment there +// is no obvious place to put a user interface to do it. Maybe this +// could be set with an environment variable. +static const char debug_file_directory[] = "/usr/lib/debug"; + +/* The CRC used in gnu_debuglink, retrieved from + http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ +unsigned int gnu_debuglink_crc32 (unsigned int crc, + unsigned char *buf, size_t len) +{ + static const unsigned int crc32_table[256] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + unsigned char *end; + + crc = ~crc & 0xffffffff; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc & 0xffffffff; +} + +/* Open a debuginfo file and check its CRC. If it exists and the CRC + matches return its fd. */ +static int +open_debug_file (const char *pathname, unsigned int crc) +{ + unsigned int file_crc = 0; + unsigned char buffer[8 * 1024]; + + int fd = pathmap_open(pathname); + + if (fd < 0) + return -1; + + lseek(fd, 0, SEEK_SET); + + for (;;) { + int len = read(fd, buffer, sizeof buffer); + if (len <= 0) + break; + file_crc = gnu_debuglink_crc32(file_crc, buffer, len); + } + + if (crc == file_crc) + return fd; + else { + close(fd); + return -1; + } +} + +/* Find an ELF section. */ +static struct elf_section *find_section_by_name(char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + ELF_SHDR* cursct = NULL; + char *strtab; + int cnt; + + if (scn_cache[ehdr->e_shstrndx].c_data == NULL) { + if ((scn_cache[ehdr->e_shstrndx].c_data + = read_section_data(fd, ehdr, cursct)) == NULL) { + return NULL; + } + } + + strtab = scn_cache[ehdr->e_shstrndx].c_data; + + for (cursct = shbuf, cnt = 0; + cnt < ehdr->e_shnum; + cnt++, cursct++) { + if (strcmp(cursct->sh_name + strtab, name) == 0) { + scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct); + return &scn_cache[cnt]; + } + } + + return NULL; +} + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file. */ +static int open_file_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + int debug_fd; + struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, + shbuf, scn_cache); + if (debug_link == NULL) + return -1; + char *debug_filename = debug_link->c_data; + int offset = (strlen(debug_filename) + 4) >> 2; + static unsigned int crc; + crc = ((unsigned int*)debug_link->c_data)[offset]; + char *debug_pathname = malloc(strlen(debug_filename) + + strlen(name) + + strlen(".debug/") + + strlen(debug_file_directory) + + 2); + strcpy(debug_pathname, name); + char *last_slash = strrchr(debug_pathname, '/'); + if (last_slash == NULL) + return -1; + + /* Look in the same directory as the object. */ + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in a subdirectory named ".debug". */ + strcpy(last_slash+1, ".debug/"); + strcat(last_slash, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in /usr/lib/debug + the full pathname. */ + strcpy(debug_pathname, debug_file_directory); + strcat(debug_pathname, name); + last_slash = strrchr(debug_pathname, '/'); + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + free(debug_pathname); + return -1; +} + +static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo); + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file and read a symbol table from it. */ +static struct symtab *build_symtab_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + ELF_SHDR *shbuf, + struct elf_section *scn_cache) +{ + fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache); + + if (fd >= 0) { + struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); + close(fd); + return symtab; + } + + return NULL; +} + +// Given a build_id, find the associated debuginfo file +static char * +build_id_to_debug_filename (size_t size, unsigned char *data) +{ + char *filename, *s; + + filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * size + (sizeof ".debug" - 1) + 1); + s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); + if (size > 0) + { + size--; + s += sprintf (s, "%02x", *data++); + } + if (size > 0) + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", *data++); + strcpy (s, ".debug"); + + return filename; +} + +// Read a build ID note. Try to open any associated debuginfo file +// and return its symtab +static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note) +{ + int fd; + struct symtab *symtab = NULL; + + unsigned char *bytes + = (unsigned char*)(note+1) + note->n_namesz; + unsigned char *filename + = (build_id_to_debug_filename (note->n_descsz, bytes)); + + fd = pathmap_open(filename); + if (fd >= 0) { + symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); + close(fd); + } + free(filename); + + return symtab; +} + +// read symbol table from given fd. If try_debuginfo) is true, also +// try to open an associated debuginfo file +static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) { ELF_EHDR ehdr; char *names = NULL; struct symtab* symtab = NULL; @@ -66,6 +332,7 @@ ELF_SHDR* cursct = NULL; ELF_PHDR* phbuf = NULL; ELF_PHDR* phdr = NULL; + int sym_section = SHT_DYNSYM; uintptr_t baseaddr = (uintptr_t)-1; @@ -90,18 +357,23 @@ for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) { scn_cache[cnt].c_shdr = cursct; - if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB) { + if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB + || cursct->sh_type == SHT_NOTE || cursct->sh_type == SHT_DYNSYM) { if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) { goto quit; } } + if (cursct->sh_type == SHT_SYMTAB) { + // Full symbol table available so use that + sym_section = cursct->sh_type; + } cursct++; } for (cnt = 1; cnt < ehdr.e_shnum; cnt++) { ELF_SHDR *shdr = scn_cache[cnt].c_shdr; - if (shdr->sh_type == SHT_SYMTAB) { + if (shdr->sh_type == sym_section) { ELF_SYM *syms; int j, n, rslt; size_t size; @@ -163,6 +435,45 @@ } } + // Look for a separate debuginfo file. + if (try_debuginfo) { + + // We prefer a debug symtab to an object's own symtab, so look in + // the debuginfo file. We stash a copy of the old symtab in case + // there is no debuginfo. + struct symtab* prev_symtab = symtab; + symtab = NULL; + +#ifdef NT_GNU_BUILD_ID + // First we look for a Build ID + for (cursct = shbuf, cnt = 0; + symtab == NULL && cnt < ehdr.e_shnum; + cnt++) { + if (cursct->sh_type == SHT_NOTE) { + Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; + if (note->n_type == NT_GNU_BUILD_ID) { + symtab = build_symtab_from_build_id(note); + } + } + cursct++; + } +#endif + + // Then, if that doesn't work, the debug link + if (symtab == NULL) { + symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf, + scn_cache); + } + + // If we still haven't found a symtab, use the object's own symtab. + if (symtab != NULL) { + if (prev_symtab != NULL) + destroy_symtab(prev_symtab); + } else { + symtab = prev_symtab; + } + } + quit: if (shbuf) free(shbuf); if (phbuf) free(phbuf); @@ -177,6 +488,11 @@ return symtab; } +struct symtab* build_symtab(int fd, const char *filename) { + return build_symtab_internal(fd, filename, /* try_debuginfo */ true); +} + + void destroy_symtab(struct symtab* symtab) { if (!symtab) return; if (symtab->strs) free(symtab->strs); diff -r 12d91eb0f579 -r 97fe2cc98b1d agent/src/os/linux/symtab.h --- a/agent/src/os/linux/symtab.h Thu Mar 11 14:41:29 2010 -0500 +++ b/agent/src/os/linux/symtab.h Thu Mar 18 06:36:43 2010 -0700 @@ -32,7 +32,7 @@ struct symtab; // build symbol table for a given ELF file descriptor -struct symtab* build_symtab(int fd); +struct symtab* build_symtab(int fd, const char *filename); // destroy the symbol table void destroy_symtab(struct symtab* symtab); diff -r 12d91eb0f579 -r 97fe2cc98b1d make/linux/makefiles/build_vm_def.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/linux/makefiles/build_vm_def.sh Thu Mar 18 06:36:43 2010 -0700 @@ -0,0 +1,5 @@ +#!/bin/sh + +nm --defined-only $* | awk ' + { if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" } + ' diff -r 12d91eb0f579 -r 97fe2cc98b1d make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Thu Mar 11 14:41:29 2010 -0500 +++ b/make/linux/makefiles/mapfile-vers-debug Thu Mar 18 06:36:43 2010 -0700 @@ -290,6 +290,9 @@ # This is for Forte Analyzer profiling support. AsyncGetCallTrace; + + # INSERT VTABLE SYMBOLS HERE + local: *; }; diff -r 12d91eb0f579 -r 97fe2cc98b1d make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Thu Mar 11 14:41:29 2010 -0500 +++ b/make/linux/makefiles/mapfile-vers-product Thu Mar 18 06:36:43 2010 -0700 @@ -285,6 +285,9 @@ # This is for Forte Analyzer profiling support. AsyncGetCallTrace; + + # INSERT VTABLE SYMBOLS HERE + local: *; }; diff -r 12d91eb0f579 -r 97fe2cc98b1d make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Thu Mar 11 14:41:29 2010 -0500 +++ b/make/linux/makefiles/vm.make Thu Mar 18 06:36:43 2010 -0700 @@ -121,14 +121,21 @@ vm_version.o: $(filter-out vm_version.o,$(JVM_OBJ_FILES)) -mapfile : $(MAPFILE) +mapfile : $(MAPFILE) vm.def rm -f $@ - cat $^ > $@ + awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE") \ + { system ("cat vm.def"); } \ + else \ + { print $$0 } \ + }' > $@ < $(MAPFILE) mapfile_reorder : mapfile $(REORDERFILE) rm -f $@ cat $^ > $@ +vm.def: $(Res_Files) $(Obj_Files) + sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@ + ifeq ($(ZERO_LIBARCH), ppc64) STATIC_CXX = false else diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -377,6 +377,16 @@ } + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + __ call(SharedRuntime::deopt_blob()->unpack_with_reexecution()); + __ delayed()->nop(); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + + void ArrayCopyStub::emit_code(LIR_Assembler* ce) { //---------------slow case: call to native----------------- __ bind(_entry); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/c1_FrameMap_sparc.hpp --- a/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,3 +143,6 @@ static bool is_caller_save_register (LIR_Opr reg); static bool is_caller_save_register (Register r); + + // JSR 292 + static LIR_Opr& method_handle_invoke_SP_save_opr() { return L7_opr; } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -378,12 +378,7 @@ int offset = code_offset(); - if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) { - __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - } - - __ call(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type); + __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type); __ delayed()->nop(); debug_only(__ stop("should have gone to the caller");) assert(code_offset() - offset <= exception_handler_size, "overflow"); @@ -685,29 +680,29 @@ } -void LIR_Assembler::call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info) { - __ call(entry, rtype); +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + __ call(op->addr(), rtype); // the peephole pass fills the delay slot } -void LIR_Assembler::ic_call(address entry, CodeEmitInfo* info) { +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { RelocationHolder rspec = virtual_call_Relocation::spec(pc()); __ set_oop((jobject)Universe::non_oop_word(), G5_inline_cache_reg); __ relocate(rspec); - __ call(entry, relocInfo::none); + __ call(op->addr(), relocInfo::none); // the peephole pass fills the delay slot } -void LIR_Assembler::vtable_call(int vtable_offset, CodeEmitInfo* info) { - add_debug_info_for_null_check_here(info); +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { + add_debug_info_for_null_check_here(op->info()); __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), G3_scratch); - if (__ is_simm13(vtable_offset) ) { - __ ld_ptr(G3_scratch, vtable_offset, G5_method); + if (__ is_simm13(op->vtable_offset())) { + __ ld_ptr(G3_scratch, op->vtable_offset(), G5_method); } else { // This will generate 2 instructions - __ set(vtable_offset, G5_method); + __ set(op->vtable_offset(), G5_method); // ld_ptr, set_hi, set __ ld_ptr(G3_scratch, G5_method, G5_method); } @@ -717,6 +712,16 @@ } +void LIR_Assembler::preserve_SP(LIR_OpJavaCall* op) { + Unimplemented(); +} + + +void LIR_Assembler::restore_SP(LIR_OpJavaCall* op) { + Unimplemented(); +} + + // load with 32-bit displacement int LIR_Assembler::load(Register s, int disp, Register d, BasicType ld_type, CodeEmitInfo *info) { int load_offset = code_offset(); @@ -1067,7 +1072,8 @@ LIR_Const* c = src->as_constant_ptr(); switch (c->type()) { case T_INT: - case T_FLOAT: { + case T_FLOAT: + case T_ADDRESS: { Register src_reg = O7; int value = c->as_jint_bits(); if (value == 0) { @@ -1123,7 +1129,8 @@ } switch (c->type()) { case T_INT: - case T_FLOAT: { + case T_FLOAT: + case T_ADDRESS: { LIR_Opr tmp = FrameMap::O7_opr; int value = c->as_jint_bits(); if (value == 0) { @@ -1195,6 +1202,7 @@ switch (c->type()) { case T_INT: + case T_ADDRESS: { jint con = c->as_jint(); if (to_reg->is_single_cpu()) { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,17 +42,6 @@ } -void C1_MacroAssembler::method_exit(bool restore_frame) { - // this code must be structured this way so that the return - // instruction can be a safepoint. - if (restore_frame) { - restore(); - } - retl(); - delayed()->nop(); -} - - void C1_MacroAssembler::explicit_null_check(Register base) { Unimplemented(); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -677,7 +677,7 @@ __ add(I7, frame::pc_return_offset, Oissuing_pc->after_save()); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - Oissuing_pc->after_save()); + G2_thread, Oissuing_pc->after_save()); __ verify_not_null_oop(Oexception->after_save()); __ jmp(O0, 0); __ delayed()->restore(); @@ -985,7 +985,6 @@ void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_maps, OopMap* oop_map, bool) { Label no_deopt; - Label no_handler; __ verify_not_null_oop(Oexception); @@ -1003,9 +1002,14 @@ // whether it had a handler or not we will deoptimize // by entering the deopt blob with a pending exception. +#ifdef ASSERT + Label done; __ tst(O0); - __ br(Assembler::zero, false, Assembler::pn, no_handler); + __ br(Assembler::notZero, false, Assembler::pn, done); __ delayed()->nop(); + __ stop("should have found address"); + __ bind(done); +#endif // restore the registers that were saved at the beginning and jump to the exception handler. restore_live_registers(sasm); @@ -1013,20 +1017,6 @@ __ jmp(O0, 0); __ delayed()->restore(); - __ bind(no_handler); - __ mov(L0, I7); // restore return address - - // restore exception oop - __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), Oexception->after_save()); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset())); - - __ restore(); - - AddressLiteral exc(Runtime1::entry_for(Runtime1::unwind_exception_id)); - __ jump_to(exc, G4); - __ delayed()->nop(); - - oop_maps->add_gc_map(call_offset, oop_map); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -244,9 +244,10 @@ } -void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) { +void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) { mov(arg_1, O0); - MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 1); + mov(arg_2, O1); + MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 2); } #endif /* CC_INTERP */ diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ bool check_exception = true); #ifndef CC_INTERP - void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1); + void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2); // Generate a subtype check: branch to ok_is_subtype if sub_klass is // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3. diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -379,7 +379,7 @@ __ save_frame(0); // compensates for compiler weakness __ add(O7->after_save(), frame::pc_return_offset, Lscratch); // save the issuing PC BLOCK_COMMENT("call exception_handler_for_return_address"); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), Lscratch); + __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), G2_thread, Lscratch); __ mov(O0, handler_reg); __ restore(); // compensates for compiler weakness diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/stubRoutines_sparc.hpp --- a/src/cpu/sparc/vm/stubRoutines_sparc.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/stubRoutines_sparc.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,13 @@ enum /* platform_dependent_constants */ { // %%%%%%%% May be able to shrink this a lot - code_size1 = 20000, // simply increase if too small (assembler will crash if too small) - code_size2 = 20000 // simply increase if too small (assembler will crash if too small) + code_size1 = 20000, // simply increase if too small (assembler will crash if too small) + code_size2 = 20000 // simply increase if too small (assembler will crash if too small) +}; + +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 5000 }; class Sparc { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1822,7 +1822,7 @@ __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller __ super_call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - Oissuing_pc->after_save()); + G2_thread, Oissuing_pc->after_save()); // The caller's SP was adjusted upon method entry to accomodate // the callee's non-argument locals. Undo that adjustment. diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -8460,6 +8460,7 @@ subptr(str1, result); // Restore counter shrl(str1, 1); addl(cnt1, str1); + decrementl(cnt1); lea(str1, Address(result, 2)); // Reload string // Load substr diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -373,6 +373,14 @@ } +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + __ call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack_with_reexecution())); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + + void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); __ bind(_entry); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/c1_FrameMap_x86.hpp --- a/src/cpu/x86/vm/c1_FrameMap_x86.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/c1_FrameMap_x86.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,3 +126,6 @@ assert(i >= 0 && i < nof_caller_save_xmm_regs, "out of bounds"); return _caller_save_xmm_regs[i]; } + + // JSR 292 + static LIR_Opr& method_handle_invoke_SP_save_opr() { return rbp_opr; } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -436,40 +436,18 @@ int offset = code_offset(); - // if the method does not have an exception handler, then there is - // no reason to search for one - if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) { - // the exception oop and pc are in rax, and rdx - // no other registers need to be preserved, so invalidate them - __ invalidate_registers(false, true, true, false, true, true); - - // check that there is really an exception - __ verify_not_null_oop(rax); - - // search an exception handler (rax: exception oop, rdx: throwing pc) - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_nofpu_id))); - - // if the call returns here, then the exception handler for particular - // exception doesn't exist -> unwind activation and forward exception to caller - } - - // the exception oop is in rax, + // the exception oop and pc are in rax, and rdx // no other registers need to be preserved, so invalidate them - __ invalidate_registers(false, true, true, true, true, true); + __ invalidate_registers(false, true, true, false, true, true); // check that there is really an exception __ verify_not_null_oop(rax); - // unlock the receiver/klass if necessary - // rax,: exception - ciMethod* method = compilation()->method(); - if (method->is_synchronized() && GenerateSynchronizationCode) { - monitorexit(FrameMap::rbx_oop_opr, FrameMap::rcx_opr, SYNC_header, 0, rax); - } - - // unwind activation and forward exception to caller - // rax,: exception - __ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); + // search an exception handler (rax: exception oop, rdx: throwing pc) + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_nofpu_id))); + + __ stop("should not reach here"); + assert(code_offset() - offset <= exception_handler_size, "overflow"); __ end_a_stub(); @@ -495,8 +473,10 @@ int offset = code_offset(); InternalAddress here(__ pc()); + __ pushptr(here.addr()); __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + assert(code_offset() - offset <= deopt_handler_size, "overflow"); __ end_a_stub(); @@ -593,7 +573,7 @@ } // Pop the stack before the safepoint code - __ leave(); + __ remove_frame(initial_frame_size_in_bytes()); bool result_is_oop = result->is_valid() ? result->is_oop() : false; @@ -648,7 +628,8 @@ LIR_Const* c = src->as_constant_ptr(); switch (c->type()) { - case T_INT: { + case T_INT: + case T_ADDRESS: { assert(patch_code == lir_patch_none, "no patching handled here"); __ movl(dest->as_register(), c->as_jint()); break; @@ -731,6 +712,7 @@ switch (c->type()) { case T_INT: // fall through case T_FLOAT: + case T_ADDRESS: __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jint_bits()); break; @@ -766,6 +748,7 @@ switch (type) { case T_INT: // fall through case T_FLOAT: + case T_ADDRESS: __ movl(as_Address(addr), c->as_jint_bits()); break; @@ -2738,6 +2721,7 @@ switch (code) { case lir_static_call: case lir_optvirtual_call: + case lir_dynamic_call: offset += NativeCall::displacement_offset; break; case lir_icvirtual_call: @@ -2753,30 +2737,41 @@ } -void LIR_Assembler::call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info) { +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0, "must be aligned"); - __ call(AddressLiteral(entry, rtype)); - add_call_info(code_offset(), info); + __ call(AddressLiteral(op->addr(), rtype)); + add_call_info(code_offset(), op->info(), op->is_method_handle_invoke()); } -void LIR_Assembler::ic_call(address entry, CodeEmitInfo* info) { +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { RelocationHolder rh = virtual_call_Relocation::spec(pc()); __ movoop(IC_Klass, (jobject)Universe::non_oop_word()); assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0, "must be aligned"); - __ call(AddressLiteral(entry, rh)); - add_call_info(code_offset(), info); + __ call(AddressLiteral(op->addr(), rh)); + add_call_info(code_offset(), op->info(), op->is_method_handle_invoke()); } /* Currently, vtable-dispatch is only enabled for sparc platforms */ -void LIR_Assembler::vtable_call(int vtable_offset, CodeEmitInfo* info) { +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { ShouldNotReachHere(); } + +void LIR_Assembler::preserve_SP(LIR_OpJavaCall* op) { + __ movptr(FrameMap::method_handle_invoke_SP_save_opr()->as_register(), rsp); +} + + +void LIR_Assembler::restore_SP(LIR_OpJavaCall* op) { + __ movptr(rsp, FrameMap::method_handle_invoke_SP_save_opr()->as_register()); +} + + void LIR_Assembler::emit_static_call_stub() { address call_pc = __ pc(); address stub = __ start_a_stub(call_stub_size); @@ -2829,10 +2824,12 @@ } else { unwind_id = Runtime1::handle_exception_nofpu_id; } + __ call(RuntimeAddress(Runtime1::entry_for(unwind_id))); } else { - unwind_id = Runtime1::unwind_exception_id; + // remove the activation + __ remove_frame(initial_frame_size_in_bytes()); + __ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); } - __ call(RuntimeAddress(Runtime1::entry_for(unwind_id))); // enough room for two byte trap __ nop(); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/c1_MacroAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -317,14 +317,6 @@ } -void C1_MacroAssembler::method_exit(bool restore_frame) { - if (restore_frame) { - leave(); - } - ret(0); -} - - void C1_MacroAssembler::build_frame(int frame_size_in_bytes) { // Make sure there is enough stack space for this method's activation. // Note that we do this before doing an enter(). This matches the @@ -333,7 +325,7 @@ // between the two compilers. generate_stack_overflow_check(frame_size_in_bytes); - enter(); + push(rbp); #ifdef TIERED // c2 leaves fpu stack dirty. Clean it on entry if (UseSSE < 2 ) { @@ -344,6 +336,12 @@ } +void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) { + increment(rsp, frame_size_in_bytes); // Does not emit code for frame_size == 0 + pop(rbp); +} + + void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) { if (C1Breakpoint) int3(); inline_cache_check(receiver, ic_klass); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -688,18 +688,21 @@ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); oop_maps->add_gc_map(call_offset, oop_map); - // rax,: handler address or NULL if no handler exists + // rax,: handler address // will be the deopt blob if nmethod was deoptimized while we looked up // handler regardless of whether handler existed in the nmethod. // only rax, is valid at this time, all other registers have been destroyed by the runtime call __ invalidate_registers(false, true, true, true, true, true); +#ifdef ASSERT // Do we have an exception handler in the nmethod? - Label no_handler; Label done; __ testptr(rax, rax); - __ jcc(Assembler::zero, no_handler); + __ jcc(Assembler::notZero, done); + __ stop("no handler found"); + __ bind(done); +#endif // exception handler found // patch the return address -> the stub will directly return to the exception handler @@ -712,36 +715,14 @@ __ leave(); __ ret(0); - __ bind(no_handler); - // no exception handler found in this method, so the exception is - // forwarded to the caller (using the unwind code of the nmethod) - // there is no need to restore the registers - - // restore the real return address that was saved before the RT-call - __ movptr(real_return_addr, Address(rsp, temp_1_off * VMRegImpl::stack_slot_size)); - __ movptr(Address(rbp, 1*BytesPerWord), real_return_addr); - - // load address of JavaThread object for thread-local data - NOT_LP64(__ get_thread(thread);) - // restore exception oop into rax, (convention for unwind code) - __ movptr(exception_oop, Address(thread, JavaThread::exception_oop_offset())); - - // clear exception fields in JavaThread because they are no longer needed - // (fields must be cleared because they are processed by GC otherwise) - __ movptr(Address(thread, JavaThread::exception_oop_offset()), NULL_WORD); - __ movptr(Address(thread, JavaThread::exception_pc_offset()), NULL_WORD); - - // pop the stub frame off - __ leave(); - - generate_unwind_exception(sasm); - __ stop("should not reach here"); } void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // incoming parameters const Register exception_oop = rax; + // callee-saved copy of exception_oop during runtime call + const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14); // other registers used in this stub const Register exception_pc = rdx; const Register handler_addr = rbx; @@ -769,38 +750,39 @@ // clear the FPU stack in case any FPU results are left behind __ empty_FPU_stack(); - // leave activation of nmethod - __ leave(); - // store return address (is on top of stack after leave) + // save exception_oop in callee-saved register to preserve it during runtime calls + __ verify_not_null_oop(exception_oop); + __ movptr(exception_oop_callee_saved, exception_oop); + + NOT_LP64(__ get_thread(thread);) + // Get return address (is on top of stack after leave). __ movptr(exception_pc, Address(rsp, 0)); - __ verify_oop(exception_oop); - - // save exception oop from rax, to stack before call - __ push(exception_oop); + // search the exception handler address of the caller (using the return address) + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); + // rax: exception handler address of the caller - // search the exception handler address of the caller (using the return address) - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), exception_pc); - // rax,: exception handler address of the caller - - // only rax, is valid at this time, all other registers have been destroyed by the call - __ invalidate_registers(false, true, true, true, true, true); + // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call. + __ invalidate_registers(false, true, true, true, false, true); // move result of call into correct register __ movptr(handler_addr, rax); - // restore exception oop in rax, (required convention of exception handler) - __ pop(exception_oop); + // Restore exception oop to RAX (required convention of exception handler). + __ movptr(exception_oop, exception_oop_callee_saved); - __ verify_oop(exception_oop); + // verify that there is really a valid exception in rax + __ verify_not_null_oop(exception_oop); // get throwing pc (= return address). // rdx has been destroyed by the call, so it must be set again // the pop is also necessary to simulate the effect of a ret(0) __ pop(exception_pc); - // verify that that there is really a valid exception in rax, - __ verify_not_null_oop(exception_oop); + // Restore SP from BP if the exception PC is a MethodHandle call site. + NOT_LP64(__ get_thread(thread);) + __ cmpl(Address(thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); // continue at exception handler (return address removed) // note: do *not* remove arguments when unwinding the @@ -808,9 +790,9 @@ // all arguments on the stack when entering the // runtime to determine the exception handler // (GC happens at call site with arguments!) - // rax,: exception oop + // rax: exception oop // rdx: throwing pc - // rbx,: exception handler + // rbx: exception handler __ jmp(handler_addr); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,13 +60,13 @@ } #ifdef ASSERT -static void verify_argslot(MacroAssembler* _masm, Register rax_argslot, +static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, const char* error_message) { // Verify that argslot lies within (rsp, rbp]. Label L_ok, L_bad; - __ cmpptr(rax_argslot, rbp); + __ cmpptr(argslot_reg, rbp); __ jccb(Assembler::above, L_bad); - __ cmpptr(rsp, rax_argslot); + __ cmpptr(rsp, argslot_reg); __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop(error_message); @@ -178,22 +178,6 @@ // Now move the argslot down, to point to the opened-up space. __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); - - if (TaggedStackInterpreter && arg_mask != _INSERT_NO_MASK) { - // The caller has specified a bitmask of tags to put into the opened space. - // This only works when the arg_slots value is an assembly-time constant. - int constant_arg_slots = arg_slots.as_constant() / stack_move_unit(); - int tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes(); - for (int slot = 0; slot < constant_arg_slots; slot++) { - BasicType slot_type = ((arg_mask & (1 << slot)) == 0 ? T_OBJECT : T_INT); - int slot_offset = Interpreter::stackElementSize() * slot; - Address tag_addr(rax_argslot, slot_offset + tag_offset); - __ movptr(tag_addr, frame::tag_for_basic_type(slot_type)); - } - // Note that the new argument slots are tagged properly but contain - // garbage at this point. The value portions must be initialized - // by the caller. (Especially references!) - } } // Helper to remove argument slots from the stack. @@ -206,18 +190,9 @@ (!arg_slots.is_register() ? rsp : arg_slots.as_register())); #ifdef ASSERT - { - // Verify that [argslot..argslot+size) lies within (rsp, rbp). - Label L_ok, L_bad; - __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); - __ cmpptr(rbx_temp, rbp); - __ jccb(Assembler::above, L_bad); - __ cmpptr(rsp, rax_argslot); - __ jccb(Assembler::below, L_ok); - __ bind(L_bad); - __ stop("deleted argument(s) must fall within current frame"); - __ bind(L_ok); - } + // Verify that [argslot..argslot+size) lies within (rsp, rbp). + __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); + verify_argslot(_masm, rbx_temp, "deleted argument(s) must fall within current frame"); if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); @@ -321,12 +296,6 @@ Address rcx_amh_conversion( rcx_recv, sun_dyn_AdapterMethodHandle::conversion_offset_in_bytes() ); Address vmarg; // __ argument_address(vmargslot) - int tag_offset = -1; - if (TaggedStackInterpreter) { - tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes(); - assert(tag_offset = wordSize, "stack grows as expected"); - } - const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes(); if (have_entry(ek)) { @@ -372,11 +341,8 @@ __ mov(rsp, rsi); // cut the stack back to where the caller started // Repush the arguments as if coming from the interpreter. - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_INT)); __ push(rdx_code); - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT)); __ push(rcx_fail); - if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT)); __ push(rax_want); Register rbx_method = rbx_temp; @@ -397,7 +363,6 @@ // Do something that is at least causes a valid throw from the interpreter. __ bind(no_method); __ pop(rax_want); - if (TaggedStackInterpreter) __ pop(rcx_fail); __ pop(rcx_fail); __ push(rax_want); __ push(rcx_fail); @@ -510,18 +475,10 @@ case _bound_long_direct_mh: { bool direct_to_method = (ek >= _bound_ref_direct_mh); - BasicType arg_type = T_ILLEGAL; - if (ek == _bound_long_mh || ek == _bound_long_direct_mh) { - arg_type = T_LONG; - } else if (ek == _bound_int_mh || ek == _bound_int_direct_mh) { - arg_type = T_INT; - } else { - assert(ek == _bound_ref_mh || ek == _bound_ref_direct_mh, "must be ref"); - arg_type = T_OBJECT; - } - int arg_slots = type2size[arg_type]; - int arg_mask = (arg_type == T_OBJECT ? _INSERT_REF_MASK : - arg_slots == 1 ? _INSERT_INT_MASK : _INSERT_LONG_MASK); + BasicType arg_type = T_ILLEGAL; + int arg_mask = _INSERT_NO_MASK; + int arg_slots = -1; + get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots); // make room for the new argument: __ movl(rax_argslot, rcx_bmh_vmargslot); @@ -660,13 +617,10 @@ } break; default: - assert(false, ""); + ShouldNotReachHere(); } - goto finish_int_conversion; - } - finish_int_conversion: - { + // Do the requested conversion and store the value. Register rbx_vminfo = rbx_temp; __ movl(rbx_vminfo, rcx_amh_conversion); assert(CONV_VMINFO_SHIFT == 0, "preshifted"); @@ -692,7 +646,7 @@ __ shrl(rdx_temp /*, rcx*/); __ bind(done); - __ movl(vmarg, rdx_temp); + __ movl(vmarg, rdx_temp); // Store the value. __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv __ jump_to_method_handle_entry(rcx_recv, rdx_temp); @@ -715,9 +669,14 @@ switch (ek) { case _adapter_opt_i2l: { +#ifdef _LP64 + __ movslq(rdx_temp, vmarg1); // Load sign-extended + __ movq(vmarg1, rdx_temp); // Store into first slot +#else __ movl(rdx_temp, vmarg1); - __ sarl(rdx_temp, 31); // __ extend_sign() + __ sarl(rdx_temp, BitsPerInt - 1); // __ extend_sign() __ movl(vmarg2, rdx_temp); // store second word +#endif } break; case _adapter_opt_unboxl: @@ -727,14 +686,19 @@ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG); assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), ""); __ null_check(rdx_temp, value_offset); +#ifdef _LP64 + __ movq(rbx_temp, Address(rdx_temp, value_offset)); + __ movq(vmarg1, rbx_temp); +#else __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt)); __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt)); __ movl(vmarg1, rbx_temp); __ movl(vmarg2, rdx_temp); +#endif } break; default: - assert(false, ""); + ShouldNotReachHere(); } __ movptr(rcx_recv, rcx_mh_vmtarget); @@ -768,20 +732,9 @@ if (ek == _adapter_opt_f2d) { __ fld_s(vmarg); // load float to ST0 __ fstp_s(vmarg); // store single - } else if (!TaggedStackInterpreter) { + } else { __ fld_d(vmarg); // load double to ST0 __ fstp_s(vmarg); // store single - } else { - Address vmarg_tag = vmarg.plus_disp(tag_offset); - Address vmarg2 = vmarg.plus_disp(Interpreter::stackElementSize()); - // vmarg2_tag does not participate in this code - Register rbx_tag = rbx_temp; - __ movl(rbx_tag, vmarg_tag); // preserve tag - __ movl(rdx_temp, vmarg2); // get second word of double - __ movl(vmarg_tag, rdx_temp); // align with first word - __ fld_d(vmarg); // load double to ST0 - __ movl(vmarg_tag, rbx_tag); // restore tag - __ fstp_s(vmarg); // store single } #endif //_LP64 @@ -812,19 +765,8 @@ case _adapter_opt_rot_2_up: case _adapter_opt_rot_2_down: { - int rotate = 0, swap_slots = 0; - switch ((int)ek) { - case _adapter_opt_swap_1: swap_slots = 1; break; - case _adapter_opt_swap_2: swap_slots = 2; break; - case _adapter_opt_rot_1_up: swap_slots = 1; rotate++; break; - case _adapter_opt_rot_1_down: swap_slots = 1; rotate--; break; - case _adapter_opt_rot_2_up: swap_slots = 2; rotate++; break; - case _adapter_opt_rot_2_down: swap_slots = 2; rotate--; break; - default: assert(false, ""); - } - - // the real size of the move must be doubled if TaggedStackInterpreter: - int swap_bytes = (int)( swap_slots * Interpreter::stackElementWords() * wordSize ); + int swap_bytes = 0, rotate = 0; + get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate); // 'argslot' is the position of the first argument to swap __ movl(rax_argslot, rcx_amh_vmargslot); @@ -925,8 +867,8 @@ // 'stack_move' is negative number of words to duplicate Register rdx_stack_move = rdx_temp; - __ movl(rdx_stack_move, rcx_amh_conversion); - __ sarl(rdx_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdx_stack_move, rcx_amh_conversion); + __ sarptr(rdx_stack_move, CONV_STACK_MOVE_SHIFT); int argslot0_num = 0; Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num)); @@ -988,8 +930,8 @@ // 'stack_move' is number of words to drop Register rdi_stack_move = rdi; - __ movl(rdi_stack_move, rcx_amh_conversion); - __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdi_stack_move, rcx_amh_conversion); + __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); remove_arg_slots(_masm, rdi_stack_move, rax_argslot, rbx_temp, rdx_temp); @@ -1014,11 +956,7 @@ case _adapter_opt_spread_more: { // spread an array out into a group of arguments - int length_constant = -1; - switch (ek) { - case _adapter_opt_spread_0: length_constant = 0; break; - case _adapter_opt_spread_1: length_constant = 1; break; - } + int length_constant = get_ek_adapter_opt_spread_info(ek); // find the address of the array argument __ movl(rax_argslot, rcx_amh_vmargslot); @@ -1079,8 +1017,8 @@ __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize())); // 'stack_move' is negative number of words to insert Register rdi_stack_move = rdi; - __ movl(rdi_stack_move, rcx_amh_conversion); - __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT); + __ movl2ptr(rdi_stack_move, rcx_amh_conversion); + __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); Register rsi_temp = rsi_array; // spill this insert_arg_slots(_masm, rdi_stack_move, -1, rax_argslot, rbx_temp, rsi_temp); @@ -1114,10 +1052,6 @@ __ movptr(rbx_temp, Address(rsi_source, 0)); __ movptr(Address(rax_argslot, 0), rbx_temp); __ addptr(rsi_source, type2aelembytes(elem_type)); - if (TaggedStackInterpreter) { - __ movptr(Address(rax_argslot, tag_offset), - frame::tag_for_basic_type(elem_type)); - } __ addptr(rax_argslot, Interpreter::stackElementSize()); __ cmpptr(rax_argslot, rdx_argslot_limit); __ jccb(Assembler::less, loop); @@ -1131,10 +1065,6 @@ __ 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(); } } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -369,7 +369,7 @@ // The pending exception in Thread is converted into a Java-level exception. // // Contract with Java-level exception handlers: - // rax,: exception + // rax: exception // rdx: throwing pc // // NOTE: At entry of this stub, exception-pc must be on stack !! @@ -377,6 +377,12 @@ address generate_forward_exception() { StubCodeMark mark(this, "StubRoutines", "forward exception"); address start = __ pc(); + const Register thread = rcx; + + // other registers used in this stub + const Register exception_oop = rax; + const Register handler_addr = rbx; + const Register exception_pc = rdx; // Upon entry, the sp points to the return address returning into Java // (interpreted or compiled) code; i.e., the return address becomes the @@ -389,8 +395,8 @@ #ifdef ASSERT // make sure this code is only executed if there is a pending exception { Label L; - __ get_thread(rcx); - __ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD); + __ get_thread(thread); + __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (1)"); __ bind(L); @@ -398,33 +404,40 @@ #endif // compute exception handler into rbx, - __ movptr(rax, Address(rsp, 0)); + __ get_thread(thread); + __ movptr(exception_pc, Address(rsp, 0)); BLOCK_COMMENT("call exception_handler_for_return_address"); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rax); - __ mov(rbx, rax); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); + __ mov(handler_addr, rax); - // setup rax, & rdx, remove return address & clear pending exception - __ get_thread(rcx); - __ pop(rdx); - __ movptr(rax, Address(rcx, Thread::pending_exception_offset())); - __ movptr(Address(rcx, Thread::pending_exception_offset()), NULL_WORD); + // setup rax & rdx, remove return address & clear pending exception + __ get_thread(thread); + __ pop(exception_pc); + __ movptr(exception_oop, Address(thread, Thread::pending_exception_offset())); + __ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); #ifdef ASSERT // make sure exception is set { Label L; - __ testptr(rax, rax); + __ testptr(exception_oop, exception_oop); __ jcc(Assembler::notEqual, L); __ stop("StubRoutines::forward exception: no pending exception (2)"); __ bind(L); } #endif + // Verify that there is really a valid exception in RAX. + __ verify_oop(exception_oop); + + // Restore SP from BP if the exception PC is a MethodHandle call site. + __ cmpl(Address(thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); + // continue at exception handler (return address removed) - // rax,: exception - // rbx,: exception handler + // rax: exception + // rbx: exception handler // rdx: throwing pc - __ verify_oop(rax); - __ jmp(rbx); + __ jmp(handler_addr); return start; } @@ -2263,16 +2276,6 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // generic method handle stubs - if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) { - for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; - ek < MethodHandles::_EK_LIMIT; - ek = MethodHandles::EntryKind(1 + (int)ek)) { - StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek); - } - } - generate_math_stubs(); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -466,7 +466,7 @@ BLOCK_COMMENT("call exception_handler_for_return_address"); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - c_rarg0); + r15_thread, c_rarg0); __ mov(rbx, rax); // setup rax & rdx, remove return address & clear pending exception @@ -3009,16 +3009,6 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // generic method handle stubs - if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) { - for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; - ek < MethodHandles::_EK_LIMIT; - ek = MethodHandles::EntryKind(1 + (int)ek)) { - StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek); - } - } - generate_math_stubs(); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/stubRoutines_x86_32.hpp --- a/src/cpu/x86/vm/stubRoutines_x86_32.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/stubRoutines_x86_32.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,11 @@ code_size2 = 22000 // simply increase if too small (assembler will crash if too small) }; +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 5000 +}; + class x86 { friend class StubGenerator; friend class VMStructs; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/stubRoutines_x86_64.hpp --- a/src/cpu/x86/vm/stubRoutines_x86_64.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/stubRoutines_x86_64.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,14 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _call_stub_return_address; } -enum platform_dependent_constants -{ - code_size1 = 19000, // simply increase if too small (assembler will - // crash if too small) - code_size2 = 22000 // simply increase if too small (assembler will - // crash if too small) +enum platform_dependent_constants { + code_size1 = 19000, // simply increase if too small (assembler will crash if too small) + code_size2 = 22000 // simply increase if too small (assembler will crash if too small) +}; + +// MethodHandles adapters +enum method_handles_platform_dependent_constants { + method_handles_adapters_code_size = 13000 }; class x86 { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1550,6 +1550,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // Entry point in previous activation (i.e., if the caller was interpreted) Interpreter::_rethrow_exception_entry = __ pc(); + const Register thread = rcx; // Restore sp to interpreter_frame_last_sp even though we are going // to empty the expression stack for the exception processing. @@ -1598,10 +1599,10 @@ // Set the popframe_processing bit in pending_popframe_condition indicating that we are // currently handling popframe, so that call_VMs that may happen later do not trigger new // popframe handling cycles. - __ get_thread(rcx); - __ movl(rdx, Address(rcx, JavaThread::popframe_condition_offset())); + __ get_thread(thread); + __ movl(rdx, Address(thread, JavaThread::popframe_condition_offset())); __ orl(rdx, JavaThread::popframe_processing_bit); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), rdx); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), rdx); { // Check to see whether we are returning to a deoptimized frame. @@ -1629,8 +1630,8 @@ __ subptr(rdi, rax); __ addptr(rdi, wordSize); // Save these arguments - __ get_thread(rcx); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), rcx, rax, rdi); + __ get_thread(thread); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), thread, rax, rdi); __ remove_activation(vtos, rdx, /* throw_monitor_exception */ false, @@ -1638,8 +1639,8 @@ /* notify_jvmdi */ false); // Inform deoptimization that it is responsible for restoring these arguments - __ get_thread(rcx); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), JavaThread::popframe_force_deopt_reexecution_bit); + __ get_thread(thread); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_force_deopt_reexecution_bit); // Continue in deoptimization handler __ jmp(rdx); @@ -1665,12 +1666,12 @@ // expression stack if necessary. __ mov(rax, rsp); __ movptr(rbx, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize)); - __ get_thread(rcx); + __ get_thread(thread); // PC must point into interpreter here - __ set_last_Java_frame(rcx, noreg, rbp, __ pc()); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), rcx, rax, rbx); - __ get_thread(rcx); - __ reset_last_Java_frame(rcx, true, true); + __ set_last_Java_frame(thread, noreg, rbp, __ pc()); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), thread, rax, rbx); + __ get_thread(thread); + __ reset_last_Java_frame(thread, true, true); // Restore the last_sp and null it out __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize)); __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); @@ -1684,8 +1685,8 @@ } // Clear the popframe condition flag - __ get_thread(rcx); - __ movl(Address(rcx, JavaThread::popframe_condition_offset()), JavaThread::popframe_inactive); + __ get_thread(thread); + __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_inactive); __ dispatch_next(vtos); // end of PopFrame support @@ -1694,27 +1695,27 @@ // preserve exception over this code sequence __ pop_ptr(rax); - __ get_thread(rcx); - __ movptr(Address(rcx, JavaThread::vm_result_offset()), rax); + __ get_thread(thread); + __ movptr(Address(thread, JavaThread::vm_result_offset()), rax); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, rdx, false, true, false); // restore exception - __ get_thread(rcx); - __ movptr(rax, Address(rcx, JavaThread::vm_result_offset())); - __ movptr(Address(rcx, JavaThread::vm_result_offset()), NULL_WORD); + __ get_thread(thread); + __ movptr(rax, Address(thread, JavaThread::vm_result_offset())); + __ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD); __ verify_oop(rax); // Inbetween activations - previous activation type unknown yet // compute continuation point - the continuation point expects // the following registers set up: // - // rax,: exception + // rax: exception // rdx: return address/pc that threw exception // rsp: expression stack of caller - // rbp,: rbp, of caller + // rbp: rbp, of caller __ push(rax); // save exception __ push(rdx); // save return address - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rdx); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, rdx); __ mov(rbx, rax); // save exception handler __ pop(rdx); // restore return address __ pop(rax); // restore exception @@ -1728,6 +1729,7 @@ // address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { address entry = __ pc(); + const Register thread = rcx; __ restore_bcp(); __ restore_locals(); @@ -1735,8 +1737,8 @@ __ empty_FPU_stack(); __ load_earlyret_value(state); - __ get_thread(rcx); - __ movptr(rcx, Address(rcx, JavaThread::jvmti_thread_state_offset())); + __ get_thread(thread); + __ movptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset())); const Address cond_addr(rcx, JvmtiThreadState::earlyret_state_offset()); // Clear the earlyret state diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1741,7 +1741,7 @@ __ push(rdx); // save return address __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - rdx); + r15_thread, rdx); __ mov(rbx, rax); // save exception handler __ pop(rdx); // restore return address __ pop(rax); // restore exception diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2915,12 +2915,8 @@ __ andl(recv, 0xFF); // recv count is 0 based? Address recv_addr(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)); - if (is_invokedynamic) { - __ lea(recv, recv_addr); - } else { - __ movptr(recv, recv_addr); - __ verify_oop(recv); - } + __ movptr(recv, recv_addr); + __ verify_oop(recv); } // do null check if needed diff -r 12d91eb0f579 -r 97fe2cc98b1d src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2860,12 +2860,8 @@ __ andl(recv, 0xFF); if (TaggedStackInterpreter) __ shll(recv, 1); // index*2 Address recv_addr(rsp, recv, Address::times_8, -Interpreter::expr_offset_in_bytes(1)); - if (is_invokedynamic) { - __ lea(recv, recv_addr); - } else { - __ movptr(recv, recv_addr); - __ verify_oop(recv); - } + __ movptr(recv, recv_addr); + __ verify_oop(recv); } // do null check if needed diff -r 12d91eb0f579 -r 97fe2cc98b1d src/os_cpu/linux_zero/vm/globals_linux_zero.hpp --- a/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,6 +1,6 @@ /* * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,10 @@ // define_pd_global(bool, DontYieldALot, false); +define_pd_global(intx, ThreadStackSize, 1536); #ifdef _LP64 -define_pd_global(intx, ThreadStackSize, 1536); define_pd_global(intx, VMThreadStackSize, 1024); #else -define_pd_global(intx, ThreadStackSize, 1024); define_pd_global(intx, VMThreadStackSize, 512); #endif // _LP64 define_pd_global(intx, SurvivorRatio, 8); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,11 +222,15 @@ } } else { LoadField* lf = x->array()->as_LoadField(); - if (lf != NULL && lf->field()->is_constant()) { - ciObject* c = lf->field()->constant_value().as_object(); - if (c->is_array()) { - ciArray* array = (ciArray*) c; - set_constant(array->length()); + if (lf != NULL) { + ciField* field = lf->field(); + if (field->is_constant() && field->is_static()) { + // final static field + ciObject* c = field->constant_value().as_object(); + if (c->is_array()) { + ciArray* array = (ciArray*) c; + set_constant(array->length()); + } } } } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -415,6 +415,28 @@ }; +//------------------------------------------------------------------------------ +// DeoptimizeStub +// +class DeoptimizeStub : public CodeStub { +private: + CodeEmitInfo* _info; + +public: + DeoptimizeStub(CodeEmitInfo* info) : _info(new CodeEmitInfo(info)) {} + + virtual void emit_code(LIR_Assembler* e); + virtual CodeEmitInfo* info() const { return _info; } + virtual bool is_exception_throw_stub() const { return true; } + virtual void visit(LIR_OpVisitState* visitor) { + visitor->do_slow_case(_info); + } +#ifndef PRODUCT + virtual void print_name(outputStream* out) const { out->print("DeoptimizeStub"); } +#endif // PRODUCT +}; + + class SimpleExceptionStub: public CodeStub { private: LIR_Opr _obj; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1524,18 +1524,14 @@ code = Bytecodes::_invokespecial; } - if (code == Bytecodes::_invokedynamic) { - BAILOUT("invokedynamic NYI"); // FIXME - return; - } - // NEEDS_CLEANUP // I've added the target-is_loaded() test below but I don't really understand // how klass->is_loaded() can be true and yet target->is_loaded() is false. // this happened while running the JCK invokevirtual tests under doit. TKR ciMethod* cha_monomorphic_target = NULL; ciMethod* exact_target = NULL; - if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded()) { + if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() && + !target->is_method_handle_invoke()) { Value receiver = NULL; ciInstanceKlass* receiver_klass = NULL; bool type_is_exact = false; @@ -1681,11 +1677,20 @@ CHECK_BAILOUT(); // inlining not successful => standard invoke - bool is_static = code == Bytecodes::_invokestatic; + bool is_loaded = target->is_loaded(); + bool has_receiver = + code == Bytecodes::_invokespecial || + code == Bytecodes::_invokevirtual || + code == Bytecodes::_invokeinterface; + bool is_invokedynamic = code == Bytecodes::_invokedynamic; ValueType* result_type = as_ValueType(target->return_type()); + + // We require the debug info to be the "state before" because + // invokedynamics may deoptimize. + ValueStack* state_before = is_invokedynamic ? state()->copy() : NULL; + Values* args = state()->pop_arguments(target->arg_size_no_receiver()); - Value recv = is_static ? NULL : apop(); - bool is_loaded = target->is_loaded(); + Value recv = has_receiver ? apop() : NULL; int vtable_index = methodOopDesc::invalid_vtable_index; #ifdef SPARC @@ -1723,7 +1728,7 @@ profile_call(recv, target_klass); } - Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target); + Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before); // push result append_split(result); @@ -2862,20 +2867,18 @@ _initial_state = state_at_entry(); start_block->merge(_initial_state); - BlockBegin* sync_handler = NULL; - if (method()->is_synchronized() || _compilation->env()->dtrace_method_probes()) { - // setup an exception handler to do the unlocking and/or notification - sync_handler = new BlockBegin(-1); - sync_handler->set(BlockBegin::exception_entry_flag); - sync_handler->set(BlockBegin::is_on_work_list_flag); - sync_handler->set(BlockBegin::default_exception_handler_flag); - - ciExceptionHandler* desc = new ciExceptionHandler(method()->holder(), 0, method()->code_size(), -1, 0); - XHandler* h = new XHandler(desc); - h->set_entry_block(sync_handler); - scope_data()->xhandlers()->append(h); - scope_data()->set_has_handler(); - } + // setup an exception handler to do the unlocking and/or + // notification and unwind the frame. + BlockBegin* sync_handler = new BlockBegin(-1); + sync_handler->set(BlockBegin::exception_entry_flag); + sync_handler->set(BlockBegin::is_on_work_list_flag); + sync_handler->set(BlockBegin::default_exception_handler_flag); + + ciExceptionHandler* desc = new ciExceptionHandler(method()->holder(), 0, method()->code_size(), -1, 0); + XHandler* h = new XHandler(desc); + h->set_entry_block(sync_handler); + scope_data()->xhandlers()->append(h); + scope_data()->set_has_handler(); // complete graph _vmap = new ValueMap(); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_IR.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,10 +259,10 @@ } -void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset) { +void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool is_method_handle_invoke) { // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); - _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/); + _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/, is_method_handle_invoke); recorder->end_safepoint(pc_offset); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_IR.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,7 +242,7 @@ //Whether we should reexecute this bytecode for deopt bool should_reexecute(); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost) { + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost, bool is_method_handle_invoke = false) { if (caller() != NULL) { // Order is significant: Must record caller first. caller()->record_debug_info(recorder, pc_offset, false/*topmost*/); @@ -252,7 +252,6 @@ DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; - bool is_method_handle_invoke = false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } @@ -303,7 +302,7 @@ int bci() const { return _bci; } void add_register_oop(LIR_Opr opr); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool is_method_handle_invoke = false); CodeEmitInfo* next() const { return _next; } void set_next(CodeEmitInfo* next) { _next = next; } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_Instruction.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -334,13 +334,14 @@ Invoke::Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args, - int vtable_index, ciMethod* target) + int vtable_index, ciMethod* target, ValueStack* state_before) : StateSplit(result_type) , _code(code) , _recv(recv) , _args(args) , _vtable_index(vtable_index) , _target(target) + , _state_before(state_before) { set_flag(TargetIsLoadedFlag, target->is_loaded()); set_flag(TargetIsFinalFlag, target_is_loaded() && target->is_final_method()); @@ -355,6 +356,9 @@ _signature = new BasicTypeList(number_of_arguments() + (has_receiver() ? 1 : 0)); if (has_receiver()) { _signature->append(as_BasicType(receiver()->type())); + } else if (is_invokedynamic()) { + // Add the synthetic MethodHandle argument to the signature. + _signature->append(T_OBJECT); } for (int i = 0; i < number_of_arguments(); i++) { ValueType* t = argument_at(i)->type(); @@ -364,6 +368,13 @@ } +void Invoke::state_values_do(void f(Value*)) { + StateSplit::state_values_do(f); + if (state_before() != NULL) state_before()->values_do(f); + if (state() != NULL) state()->values_do(f); +} + + // Implementation of Contant intx Constant::hash() const { if (_state == NULL) { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_Instruction.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1134,17 +1134,18 @@ LEAF(Invoke, StateSplit) private: - Bytecodes::Code _code; - Value _recv; - Values* _args; - BasicTypeList* _signature; - int _vtable_index; - ciMethod* _target; + Bytecodes::Code _code; + Value _recv; + Values* _args; + BasicTypeList* _signature; + int _vtable_index; + ciMethod* _target; + ValueStack* _state_before; // Required for deoptimization. public: // creation Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args, - int vtable_index, ciMethod* target); + int vtable_index, ciMethod* target, ValueStack* state_before); // accessors Bytecodes::Code code() const { return _code; } @@ -1155,6 +1156,7 @@ int vtable_index() const { return _vtable_index; } BasicTypeList* signature() const { return _signature; } ciMethod* target() const { return _target; } + ValueStack* state_before() const { return _state_before; } // Returns false if target is not loaded bool target_is_final() const { return check_flag(TargetIsFinalFlag); } @@ -1162,6 +1164,9 @@ // Returns false if target is not loaded bool target_is_strictfp() const { return check_flag(TargetIsStrictfpFlag); } + // JSR 292 support + bool is_invokedynamic() const { return code() == Bytecodes::_invokedynamic; } + // generic virtual bool can_trap() const { return true; } virtual void input_values_do(void f(Value*)) { @@ -1169,6 +1174,7 @@ if (has_receiver()) f(&_recv); for (int i = 0; i < _args->length(); i++) f(_args->adr_at(i)); } + virtual void state_values_do(void f(Value*)); }; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LIR.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ return LIR_OprFact::oopConst(type->as_ObjectType()->encoding()); } } - case addressTag: return LIR_OprFact::intConst(type->as_AddressConstant()->value()); + case addressTag: return LIR_OprFact::addressConst(type->as_AddressConstant()->value()); case intTag : return LIR_OprFact::intConst(type->as_IntConstant()->value()); case floatTag : return LIR_OprFact::floatConst(type->as_FloatConstant()->value()); case longTag : return LIR_OprFact::longConst(type->as_LongConstant()->value()); @@ -89,7 +89,7 @@ LIR_Opr LIR_OprFact::dummy_value_type(ValueType* type) { switch (type->tag()) { case objectTag: return LIR_OprFact::oopConst(NULL); - case addressTag: + case addressTag:return LIR_OprFact::addressConst(0); case intTag: return LIR_OprFact::intConst(0); case floatTag: return LIR_OprFact::floatConst(0.0); case longTag: return LIR_OprFact::longConst(0); @@ -689,9 +689,10 @@ case lir_static_call: case lir_optvirtual_call: case lir_icvirtual_call: - case lir_virtual_call: { - assert(op->as_OpJavaCall() != NULL, "must be"); - LIR_OpJavaCall* opJavaCall = (LIR_OpJavaCall*)op; + case lir_virtual_call: + case lir_dynamic_call: { + LIR_OpJavaCall* opJavaCall = op->as_OpJavaCall(); + assert(opJavaCall != NULL, "must be"); if (opJavaCall->_receiver->is_valid()) do_input(opJavaCall->_receiver); @@ -704,6 +705,7 @@ } if (opJavaCall->_info) do_info(opJavaCall->_info); + if (opJavaCall->is_method_handle_invoke()) do_temp(FrameMap::method_handle_invoke_SP_save_opr()); do_call(); if (opJavaCall->_result->is_valid()) do_output(opJavaCall->_result); @@ -1410,6 +1412,7 @@ // LIR_Address void LIR_Const::print_value_on(outputStream* out) const { switch (type()) { + case T_ADDRESS:out->print("address:%d",as_jint()); break; case T_INT: out->print("int:%d", as_jint()); break; case T_LONG: out->print("lng:%lld", as_jlong()); break; case T_FLOAT: out->print("flt:%f", as_jfloat()); break; @@ -1590,6 +1593,7 @@ case lir_optvirtual_call: s = "optvirtual"; break; case lir_icvirtual_call: s = "icvirtual"; break; case lir_virtual_call: s = "virtual"; break; + case lir_dynamic_call: s = "dynamic"; break; // LIR_OpArrayCopy case lir_arraycopy: s = "arraycopy"; break; // LIR_OpLock diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LIR.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -85,9 +85,10 @@ void type_check(BasicType t) const { assert(type() == t, "type check"); } void type_check(BasicType t1, BasicType t2) const { assert(type() == t1 || type() == t2, "type check"); } + void type_check(BasicType t1, BasicType t2, BasicType t3) const { assert(type() == t1 || type() == t2 || type() == t3, "type check"); } public: - LIR_Const(jint i) { _value.set_type(T_INT); _value.set_jint(i); } + LIR_Const(jint i, bool is_address=false) { _value.set_type(is_address?T_ADDRESS:T_INT); _value.set_jint(i); } LIR_Const(jlong l) { _value.set_type(T_LONG); _value.set_jlong(l); } LIR_Const(jfloat f) { _value.set_type(T_FLOAT); _value.set_jfloat(f); } LIR_Const(jdouble d) { _value.set_type(T_DOUBLE); _value.set_jdouble(d); } @@ -105,7 +106,7 @@ virtual BasicType type() const { return _value.get_type(); } virtual LIR_Const* as_constant() { return this; } - jint as_jint() const { type_check(T_INT ); return _value.get_jint(); } + jint as_jint() const { type_check(T_INT, T_ADDRESS); return _value.get_jint(); } jlong as_jlong() const { type_check(T_LONG ); return _value.get_jlong(); } jfloat as_jfloat() const { type_check(T_FLOAT ); return _value.get_jfloat(); } jdouble as_jdouble() const { type_check(T_DOUBLE); return _value.get_jdouble(); } @@ -120,7 +121,7 @@ #endif - jint as_jint_bits() const { type_check(T_FLOAT, T_INT); return _value.get_jint(); } + jint as_jint_bits() const { type_check(T_FLOAT, T_INT, T_ADDRESS); return _value.get_jint(); } jint as_jint_lo_bits() const { if (type() == T_DOUBLE) { return low(jlong_cast(_value.get_jdouble())); @@ -718,6 +719,7 @@ static LIR_Opr intptrConst(void* p) { return (LIR_Opr)(new LIR_Const(p)); } static LIR_Opr intptrConst(intptr_t v) { return (LIR_Opr)(new LIR_Const((void*)v)); } static LIR_Opr illegal() { return (LIR_Opr)-1; } + static LIR_Opr addressConst(jint i) { return (LIR_Opr)(new LIR_Const(i, true)); } static LIR_Opr value_type(ValueType* type); static LIR_Opr dummy_value_type(ValueType* type); @@ -840,6 +842,7 @@ , lir_optvirtual_call , lir_icvirtual_call , lir_virtual_call + , lir_dynamic_call , end_opJavaCall , begin_opArrayCopy , lir_arraycopy @@ -1052,6 +1055,16 @@ LIR_Opr receiver() const { return _receiver; } ciMethod* method() const { return _method; } + // JSR 292 support. + bool is_invokedynamic() const { return code() == lir_dynamic_call; } + bool is_method_handle_invoke() const { + return + is_invokedynamic() // An invokedynamic is always a MethodHandle call site. + || + (method()->holder()->name() == ciSymbol::java_dyn_MethodHandle() && + method()->name() == ciSymbol::invoke_name()); + } + intptr_t vtable_offset() const { assert(_code == lir_virtual_call, "only have vtable for real vcall"); return (intptr_t) addr(); @@ -1766,6 +1779,10 @@ intptr_t vtable_offset, LIR_OprList* arguments, CodeEmitInfo* info) { append(new LIR_OpJavaCall(lir_virtual_call, method, receiver, result, vtable_offset, arguments, info)); } + void call_dynamic(ciMethod* method, LIR_Opr receiver, LIR_Opr result, + address dest, LIR_OprList* arguments, CodeEmitInfo* info) { + append(new LIR_OpJavaCall(lir_dynamic_call, method, receiver, result, dest, arguments, info)); + } void get_thread(LIR_Opr result) { append(new LIR_Op0(lir_get_thread, result)); } void word_align() { append(new LIR_Op0(lir_word_align)); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -301,9 +301,9 @@ } -void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo) { +void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo, bool is_method_handle_invoke) { flush_debug_info(pc_offset); - cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset); + cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset, is_method_handle_invoke); if (cinfo->exception_handlers() != NULL) { compilation()->add_exception_handlers_for_pco(pc_offset, cinfo->exception_handlers()); } @@ -413,6 +413,12 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { verify_oop_map(op->info()); + // JSR 292 + // Preserve the SP over MethodHandle call sites. + if (op->is_method_handle_invoke()) { + preserve_SP(op); + } + if (os::is_MP()) { // must align calls sites, otherwise they can't be updated atomically on MP hardware align_call(op->code()); @@ -423,19 +429,25 @@ switch (op->code()) { case lir_static_call: - call(op->addr(), relocInfo::static_call_type, op->info()); + call(op, relocInfo::static_call_type); break; case lir_optvirtual_call: - call(op->addr(), relocInfo::opt_virtual_call_type, op->info()); + case lir_dynamic_call: + call(op, relocInfo::opt_virtual_call_type); break; case lir_icvirtual_call: - ic_call(op->addr(), op->info()); + ic_call(op); break; case lir_virtual_call: - vtable_call(op->vtable_offset(), op->info()); + vtable_call(op); break; default: ShouldNotReachHere(); } + + if (op->is_method_handle_invoke()) { + restore_SP(op); + } + #if defined(X86) && defined(TIERED) // C2 leave fpu stack dirty clean it if (UseSSE < 2) { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -82,7 +82,7 @@ Address as_Address_hi(LIR_Address* addr); // debug information - void add_call_info(int pc_offset, CodeEmitInfo* cinfo); + void add_call_info(int pc_offset, CodeEmitInfo* cinfo, bool is_method_handle_invoke = false); void add_debug_info_for_branch(CodeEmitInfo* info); void add_debug_info_for_div0(int pc_offset, CodeEmitInfo* cinfo); void add_debug_info_for_div0_here(CodeEmitInfo* info); @@ -205,9 +205,13 @@ void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op); void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result); - void ic_call(address destination, CodeEmitInfo* info); - void vtable_call(int vtable_offset, CodeEmitInfo* info); - void call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info); + void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); + void ic_call( LIR_OpJavaCall* op); + void vtable_call( LIR_OpJavaCall* op); + + // JSR 292 + void preserve_SP(LIR_OpJavaCall* op); + void restore_SP( LIR_OpJavaCall* op); void osr_entry(); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -2284,7 +2284,7 @@ void LIRGenerator::invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list) { - int i = x->has_receiver() ? 1 : 0; + int i = (x->has_receiver() || x->is_invokedynamic()) ? 1 : 0; for (; i < args->length(); i++) { LIRItem* param = args->at(i); LIR_Opr loc = arg_list->at(i); @@ -2322,6 +2322,10 @@ LIRItem* receiver = new LIRItem(x->receiver(), this); argument_items->append(receiver); } + if (x->is_invokedynamic()) { + // Insert a dummy for the synthetic MethodHandle argument. + argument_items->append(NULL); + } int idx = x->has_receiver() ? 1 : 0; for (int i = 0; i < x->number_of_arguments(); i++) { LIRItem* param = new LIRItem(x->argument_at(i), this); @@ -2371,6 +2375,9 @@ CodeEmitInfo* info = state_for(x, x->state()); + // invokedynamics can deoptimize. + CodeEmitInfo* deopt_info = x->is_invokedynamic() ? state_for(x, x->state_before()) : NULL; + invoke_load_arguments(x, args, arg_list); if (x->has_receiver()) { @@ -2407,6 +2414,47 @@ __ call_virtual(x->target(), receiver, result_register, vtable_offset, arg_list, info); } break; + case Bytecodes::_invokedynamic: { + ciBytecodeStream bcs(x->scope()->method()); + bcs.force_bci(x->bci()); + assert(bcs.cur_bc() == Bytecodes::_invokedynamic, "wrong stream"); + ciCPCache* cpcache = bcs.get_cpcache(); + + // Get CallSite offset from constant pool cache pointer. + int index = bcs.get_method_index(); + size_t call_site_offset = cpcache->get_f1_offset(index); + + // If this invokedynamic call site hasn't been executed yet in + // the interpreter, the CallSite object in the constant pool + // cache is still null and we need to deoptimize. + if (cpcache->is_f1_null_at(index)) { + // Cannot re-use same xhandlers for multiple CodeEmitInfos, so + // clone all handlers. This is handled transparently in other + // places by the CodeEmitInfo cloning logic but is handled + // specially here because a stub isn't being used. + x->set_exception_handlers(new XHandlers(x->exception_handlers())); + + DeoptimizeStub* deopt_stub = new DeoptimizeStub(deopt_info); + __ jump(deopt_stub); + } + + // Use the receiver register for the synthetic MethodHandle + // argument. + receiver = LIR_Assembler::receiverOpr(); + LIR_Opr tmp = new_register(objectType); + + // Load CallSite object from constant pool cache. + __ oop2reg(cpcache->constant_encoding(), tmp); + __ load(new LIR_Address(tmp, call_site_offset, T_OBJECT), tmp); + + // Load target MethodHandle from CallSite object. + __ load(new LIR_Address(tmp, java_dyn_CallSite::target_offset_in_bytes(), T_OBJECT), receiver); + + __ call_dynamic(x->target(), receiver, result_register, + SharedRuntime::get_resolve_opt_virtual_call_stub(), + arg_list, info); + break; + } default: ShouldNotReachHere(); break; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_LinearScan.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -2479,6 +2479,15 @@ return 2; } + case T_ADDRESS: { +#ifdef _LP64 + scope_values->append(new ConstantLongValue(c->as_jint())); +#else + scope_values->append(new ConstantIntValue(c->as_jint())); +#endif + return 1; + } + default: ShouldNotReachHere(); return -1; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/c1/c1_MacroAssembler.hpp --- a/src/share/vm/c1/c1_MacroAssembler.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/c1/c1_MacroAssembler.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ void inline_cache_check(Register receiver, Register iCache); void build_frame(int frame_size_in_bytes); - void method_exit(bool restore_frame); + void remove_frame(int frame_size_in_bytes); void unverified_entry(Register receiver, Register ic_klass); void verified_entry(); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/ci/ciCPCache.cpp --- a/src/share/vm/ci/ciCPCache.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/ci/ciCPCache.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,16 @@ // ------------------------------------------------------------------ +// ciCPCache::is_f1_null_at +bool ciCPCache::is_f1_null_at(int index) { + VM_ENTRY_MARK; + constantPoolCacheOop cpcache = (constantPoolCacheOop) get_oop(); + oop f1 = cpcache->secondary_entry_at(index)->f1(); + return (f1 == NULL); +} + + +// ------------------------------------------------------------------ // ciCPCache::print // // Print debugging information about the cache. diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/ci/ciCPCache.hpp --- a/src/share/vm/ci/ciCPCache.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/ci/ciCPCache.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,5 +39,7 @@ // requested entry. size_t get_f1_offset(int index); + bool is_f1_null_at(int index); + void print(); }; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/code/codeBlob.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,7 +249,6 @@ size += round_to(buffer_size, oopSize); assert(name != NULL, "must provide a name"); { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) BufferBlob(name, size); } @@ -271,7 +270,6 @@ unsigned int size = allocation_size(cb, sizeof(BufferBlob)); assert(name != NULL, "must provide a name"); { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) BufferBlob(name, size, cb); } @@ -298,10 +296,48 @@ MemoryService::track_code_cache_memory_usage(); } -bool BufferBlob::is_adapter_blob() const { - return (strcmp(AdapterHandlerEntry::name, name()) == 0); + +//---------------------------------------------------------------------------------------------------- +// Implementation of AdapterBlob + +AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + AdapterBlob* blob = NULL; + unsigned int size = allocation_size(cb, sizeof(AdapterBlob)); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) AdapterBlob(size, cb); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; } + +//---------------------------------------------------------------------------------------------------- +// Implementation of MethodHandlesAdapterBlob + +MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + MethodHandlesAdapterBlob* blob = NULL; + unsigned int size = sizeof(MethodHandlesAdapterBlob); + // align the size to CodeEntryAlignment + size = align_code_offset(size); + size += round_to(buffer_size, oopSize); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) MethodHandlesAdapterBlob(size); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; +} + + //---------------------------------------------------------------------------------------------------- // Implementation of RuntimeStub diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/code/codeBlob.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,14 +90,15 @@ void flush(); // Typing - virtual bool is_buffer_blob() const { return false; } - virtual bool is_nmethod() const { return false; } - virtual bool is_runtime_stub() const { return false; } - virtual bool is_deoptimization_stub() const { return false; } - virtual bool is_uncommon_trap_stub() const { return false; } - virtual bool is_exception_stub() const { return false; } - virtual bool is_safepoint_stub() const { return false; } - virtual bool is_adapter_blob() const { return false; } + virtual bool is_buffer_blob() const { return false; } + virtual bool is_nmethod() const { return false; } + virtual bool is_runtime_stub() const { return false; } + virtual bool is_deoptimization_stub() const { return false; } + virtual bool is_uncommon_trap_stub() const { return false; } + virtual bool is_exception_stub() const { return false; } + virtual bool is_safepoint_stub() const { return false; } + virtual bool is_adapter_blob() const { return false; } + virtual bool is_method_handles_adapter_blob() const { return false; } virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } @@ -221,6 +222,9 @@ class BufferBlob: public CodeBlob { friend class VMStructs; + friend class AdapterBlob; + friend class MethodHandlesAdapterBlob; + private: // Creation support BufferBlob(const char* name, int size); @@ -236,8 +240,7 @@ static void free(BufferBlob* buf); // Typing - bool is_buffer_blob() const { return true; } - bool is_adapter_blob() const; + virtual bool is_buffer_blob() const { return true; } // GC/Verification support void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } @@ -255,6 +258,40 @@ //---------------------------------------------------------------------------------------------------- +// AdapterBlob: used to hold C2I/I2C adapters + +class AdapterBlob: public BufferBlob { +private: + AdapterBlob(int size) : BufferBlob("I2C/C2I adapters", size) {} + AdapterBlob(int size, CodeBuffer* cb) : BufferBlob("I2C/C2I adapters", size, cb) {} + +public: + // Creation + static AdapterBlob* create(CodeBuffer* cb); + + // Typing + virtual bool is_adapter_blob() const { return true; } +}; + + +//---------------------------------------------------------------------------------------------------- +// MethodHandlesAdapterBlob: used to hold MethodHandles adapters + +class MethodHandlesAdapterBlob: public BufferBlob { +private: + MethodHandlesAdapterBlob(int size) : BufferBlob("MethodHandles adapters", size) {} + MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {} + +public: + // Creation + static MethodHandlesAdapterBlob* create(int buffer_size); + + // Typing + virtual bool is_method_handles_adapter_blob() const { return true; } +}; + + +//---------------------------------------------------------------------------------------------------- // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine class RuntimeStub: public CodeBlob { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -988,10 +988,12 @@ } if (method->is_not_compilable(comp_level)) return NULL; - nmethod* saved = CodeCache::find_and_remove_saved_code(method()); - if (saved != NULL) { - method->set_code(method, saved); - return saved; + if (UseCodeCacheFlushing) { + nmethod* saved = CodeCache::find_and_remove_saved_code(method()); + if (saved != NULL) { + method->set_code(method, saved); + return saved; + } } } else { diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/includeDB_compiler1 --- a/src/share/vm/includeDB_compiler1 Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/includeDB_compiler1 Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ // -// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -246,6 +246,7 @@ c1_LIRGenerator.cpp c1_LIRGenerator.hpp c1_LIRGenerator.cpp c1_ValueStack.hpp c1_LIRGenerator.cpp ciArrayKlass.hpp +c1_LIRGenerator.cpp ciCPCache.hpp c1_LIRGenerator.cpp ciInstance.hpp c1_LIRGenerator.cpp heapRegion.hpp c1_LIRGenerator.cpp sharedRuntime.hpp diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/includeDB_core --- a/src/share/vm/includeDB_core Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/includeDB_core Thu Mar 18 06:36:43 2010 -0700 @@ -541,6 +541,7 @@ ciCPCache.cpp cpCacheOop.hpp ciCPCache.cpp ciCPCache.hpp +ciCPCache.cpp ciUtilities.hpp ciCPCache.hpp ciClassList.hpp ciCPCache.hpp ciObject.hpp @@ -2016,6 +2017,7 @@ init.cpp icBuffer.hpp init.cpp icache.hpp init.cpp init.hpp +init.cpp methodHandles.hpp init.cpp safepoint.hpp init.cpp sharedRuntime.hpp init.cpp universe.hpp @@ -2870,6 +2872,7 @@ methodHandles.cpp oopFactory.hpp methodHandles.cpp reflection.hpp methodHandles.cpp signature.hpp +methodHandles.cpp stubRoutines.hpp methodHandles.cpp symbolTable.hpp methodHandles_.cpp allocation.inline.hpp diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/opto/loopTransform.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2088,29 +2088,41 @@ BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl, int scale, Node* offset, Node* init, Node* limit, Node* stride, - Node* range) { + Node* range, bool upper) { + DEBUG_ONLY(ttyLocker ttyl); + if (TraceLoopPredicate) tty->print("rc_predicate "); + Node* max_idx_expr = init; int stride_con = stride->get_int(); - if ((stride_con > 0) == (scale > 0)) { + if ((stride_con > 0) == (scale > 0) == upper) { max_idx_expr = new (C, 3) SubINode(limit, stride); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("(limit - stride) "); + } else { + if (TraceLoopPredicate) tty->print("init "); } if (scale != 1) { ConNode* con_scale = _igvn.intcon(scale); max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("* %d ", scale); } if (offset && (!offset->is_Con() || offset->get_int() != 0)){ max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) + if (offset->is_Con()) tty->print("+ %d ", offset->get_int()); + else tty->print("+ offset "); } CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); register_new_node(cmp, ctrl); BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); register_new_node(bol, ctrl); + + if (TraceLoopPredicate) tty->print_cr(" 0) { // Following are changed to nonnull when a predicate can be hoisted ProjNode* new_predicate_proj = NULL; - BoolNode* new_predicate_bol = NULL; ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); @@ -2218,93 +2229,120 @@ // Invariant test new_predicate_proj = create_new_if_for_predicate(predicate_proj); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); - new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); - if (TraceLoopPredicate) tty->print("invariant"); + BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); + + // Negate test if necessary + bool negated = false; + if (proj->_con != predicate_proj->_con) { + new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); + register_new_node(new_predicate_bol, ctrl); + negated = true; + } + IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); + _igvn.hash_delete(new_predicate_iff); + new_predicate_iff->set_req(1, new_predicate_bol); + if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx); + } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { - // Range check (only for counted loops) - new_predicate_proj = create_new_if_for_predicate(predicate_proj); - Node *ctrl = new_predicate_proj->in(0)->as_If()->in(0); + assert(proj->_con == predicate_proj->_con, "must match"); + + // Range check for counted loops const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); assert(cmp->in(2)->Opcode() == Op_LoadRange, "must be"); - LoadRangeNode* ld_rng = (LoadRangeNode*)cmp->in(2); // LoadRangeNode + Node* ld_rng = cmp->in(2); // LoadRangeNode assert(invar.is_invariant(ld_rng), "load range must be invariant"); - ld_rng = (LoadRangeNode*)invar.clone(ld_rng, ctrl); int scale = 1; Node* offset = zero; bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); assert(ok, "must be index expression"); + + Node* init = cl->init_trip(); + Node* limit = cl->limit(); + Node* stride = cl->stride(); + + // Build if's for the upper and lower bound tests. The + // lower_bound test will dominate the upper bound test and all + // cloned or created nodes will use the lower bound test as + // their declared control. + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj); + assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); + Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); + + // Perform cloning to keep Invariance state correct since the + // late schedule will place invariant things in the loop. + ld_rng = invar.clone(ld_rng, ctrl); if (offset && offset != zero) { assert(invar.is_invariant(offset), "offset must be loop invariant"); offset = invar.clone(offset, ctrl); } - Node* init = cl->init_trip(); - Node* limit = cl->limit(); - Node* stride = cl->stride(); - new_predicate_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng); - if (TraceLoopPredicate) tty->print("range check"); - } + + // Test the lower bound + Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, false); + IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); + _igvn.hash_delete(lower_bound_iff); + lower_bound_iff->set_req(1, lower_bound_bol); + if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); - if (new_predicate_proj == NULL) { + // Test the upper bound + Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, true); + IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); + _igvn.hash_delete(upper_bound_iff); + upper_bound_iff->set_req(1, upper_bound_bol); + if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); + + // Fall through into rest of the clean up code which will move + // any dependent nodes onto the upper bound test. + new_predicate_proj = upper_bound_proj; + } else { // The other proj of the "iff" is a uncommon trap projection, and we can assume // the other proj will not be executed ("executed" means uct raised). continue; - } else { - // Success - attach condition (new_predicate_bol) to predicate if - invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - IfNode* new_iff = new_predicate_proj->in(0)->as_If(); + } - // Negate test if necessary - if (proj->_con != predicate_proj->_con) { - new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); - register_new_node(new_predicate_bol, new_iff->in(0)); - if (TraceLoopPredicate) tty->print_cr(" if negated: %d", iff->_idx); - } else { - if (TraceLoopPredicate) tty->print_cr(" if: %d", iff->_idx); - } + // Success - attach condition (new_predicate_bol) to predicate if + invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - _igvn.hash_delete(new_iff); - new_iff->set_req(1, new_predicate_bol); - - _igvn.hash_delete(iff); - iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); + // Eliminate the old if in the loop body + _igvn.hash_delete(iff); + iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); - Node* ctrl = new_predicate_proj; // new control - ProjNode* dp = proj; // old control - assert(get_loop(dp) == loop, "guarenteed at the time of collecting proj"); - // Find nodes (depends only on the test) off the surviving projection; - // move them outside the loop with the control of proj_clone - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node - if (cd->depends_only_on_test()) { - assert(cd->in(0) == dp, ""); - _igvn.hash_delete(cd); - cd->set_req(0, ctrl); // ctrl, not NULL - set_early_ctrl(cd); - _igvn._worklist.push(cd); - IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if (new_loop != loop) { - if (!loop->_child) loop->_body.yank(cd); - if (!new_loop->_child ) new_loop->_body.push(cd); - } - --i; - --imax; + Node* ctrl = new_predicate_proj; // new control + ProjNode* dp = proj; // old control + assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj"); + // Find nodes (depends only on the test) off the surviving projection; + // move them outside the loop with the control of proj_clone + for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { + Node* cd = dp->fast_out(i); // Control-dependent node + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); + cd->set_req(0, ctrl); // ctrl, not NULL + set_early_ctrl(cd); + _igvn._worklist.push(cd); + IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); + if (new_loop != loop) { + if (!loop->_child) loop->_body.yank(cd); + if (!new_loop->_child ) new_loop->_body.push(cd); } + --i; + --imax; } + } - hoisted = true; - C->set_major_progress(); - } + hoisted = true; + C->set_major_progress(); } // end while #ifndef PRODUCT - // report that the loop predication has been actually performed - // for this loop - if (TraceLoopPredicate && hoisted) { - tty->print("Loop Predication Performed:"); - loop->dump_head(); - } + // report that the loop predication has been actually performed + // for this loop + if (TraceLoopPredicate && hoisted) { + tty->print("Loop Predication Performed:"); + loop->dump_head(); + } #endif return hoisted; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/opto/loopnode.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -821,7 +821,7 @@ BoolNode* rc_predicate(Node* ctrl, int scale, Node* offset, Node* init, Node* limit, Node* stride, - Node* range); + Node* range, bool upper); // Implementation of the loop predication to promote checks outside the loop bool loop_predication_impl(IdealLoopTree *loop); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/opto/runtime.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -864,7 +864,7 @@ thread->set_exception_handler_pc(handler_address); thread->set_exception_stack_size(0); - // Check if the exception PC is a MethodHandle call. + // Check if the exception PC is a MethodHandle call site. thread->set_is_method_handle_exception(nm->is_method_handle_return(pc)); } @@ -952,7 +952,7 @@ thread->set_vm_result(exception); // Frame not compiled (handles deoptimization blob) - return SharedRuntime::raw_exception_handler_for_return_address(ret_pc); + return SharedRuntime::raw_exception_handler_for_return_address(thread, ret_pc); } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/prims/methodHandles.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ NULL }; +// Adapters. +MethodHandlesAdapterBlob* MethodHandles::_adapter_code = NULL; +int MethodHandles::_adapter_code_size = StubRoutines::method_handles_adapters_code_size; + jobject MethodHandles::_raise_exception_method; #ifdef ASSERT @@ -95,6 +99,41 @@ } #endif + +//------------------------------------------------------------------------------ +// MethodHandles::generate_adapters +// +void MethodHandles::generate_adapters() { + if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; + + assert(_adapter_code == NULL, "generate only once"); + + ResourceMark rm; + TraceTime timer("MethodHandles adapters generation", TraceStartupTime); + _adapter_code = MethodHandlesAdapterBlob::create(_adapter_code_size); + if (_adapter_code == NULL) + vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); + CodeBuffer code(_adapter_code->instructions_begin(), _adapter_code->instructions_size()); + + MethodHandlesAdapterGenerator g(&code); + g.generate(); +} + + +//------------------------------------------------------------------------------ +// MethodHandlesAdapterGenerator::generate +// +void MethodHandlesAdapterGenerator::generate() { + // Generate generic method handle adapters. + for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; + ek < MethodHandles::_EK_LIMIT; + ek = MethodHandles::EntryKind(1 + (int)ek)) { + StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); + MethodHandles::generate_method_handle_stub(_masm, ek); + } +} + + void MethodHandles::set_enabled(bool z) { if (_enabled != z) { guarantee(z && EnableMethodHandles, "can only enable once, and only if -XX:+EnableMethodHandles"); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/prims/methodHandles.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,10 @@ static const char* _entry_names[_EK_LIMIT+1]; static jobject _raise_exception_method; + // Adapters. + static MethodHandlesAdapterBlob* _adapter_code; + static int _adapter_code_size; + static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; } static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; } @@ -133,6 +137,43 @@ _entries[ek] = me; } + // Some adapter helper functions. + static void get_ek_bound_mh_info(EntryKind ek, BasicType& arg_type, int& arg_mask, int& arg_slots) { + switch (ek) { + case _bound_int_mh : // fall-thru + case _bound_int_direct_mh : arg_type = T_INT; arg_mask = _INSERT_INT_MASK; break; + case _bound_long_mh : // fall-thru + case _bound_long_direct_mh: arg_type = T_LONG; arg_mask = _INSERT_LONG_MASK; break; + case _bound_ref_mh : // fall-thru + case _bound_ref_direct_mh : arg_type = T_OBJECT; arg_mask = _INSERT_REF_MASK; break; + default: ShouldNotReachHere(); + } + arg_slots = type2size[arg_type]; + } + + static void get_ek_adapter_opt_swap_rot_info(EntryKind ek, int& swap_bytes, int& rotate) { + int swap_slots = 0; + switch (ek) { + case _adapter_opt_swap_1: swap_slots = 1; rotate = 0; break; + case _adapter_opt_swap_2: swap_slots = 2; rotate = 0; break; + case _adapter_opt_rot_1_up: swap_slots = 1; rotate = 1; break; + case _adapter_opt_rot_1_down: swap_slots = 1; rotate = -1; break; + case _adapter_opt_rot_2_up: swap_slots = 2; rotate = 1; break; + case _adapter_opt_rot_2_down: swap_slots = 2; rotate = -1; break; + default: ShouldNotReachHere(); + } + // Return the size of the stack slots to move in bytes. + swap_bytes = swap_slots * Interpreter::stackElementSize(); + } + + static int get_ek_adapter_opt_spread_info(EntryKind ek) { + switch (ek) { + case _adapter_opt_spread_0: return 0; + case _adapter_opt_spread_1: return 1; + default : return -1; + } + } + static methodOop raise_exception_method() { oop rem = JNIHandles::resolve(_raise_exception_method); assert(rem == NULL || rem->is_method(), ""); @@ -230,7 +271,10 @@ // bit values for suppress argument to expand_MemberName: enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; - // called from InterpreterGenerator and StubGenerator + // Generate MethodHandles adapters. + static void generate_adapters(); + + // Called from InterpreterGenerator and MethodHandlesAdapterGenerator. static address generate_method_handle_interpreter_entry(MacroAssembler* _masm); static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek); @@ -385,13 +429,13 @@ static void insert_arg_slots(MacroAssembler* _masm, RegisterOrConstant arg_slots, int arg_mask, - Register rax_argslot, - Register rbx_temp, Register rdx_temp); + Register argslot_reg, + Register temp_reg, Register temp2_reg); static void remove_arg_slots(MacroAssembler* _masm, RegisterOrConstant arg_slots, - Register rax_argslot, - Register rbx_temp, Register rdx_temp); + Register argslot_reg, + Register temp_reg, Register temp2_reg); }; @@ -447,3 +491,14 @@ address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); } address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); } + + +//------------------------------------------------------------------------------ +// MethodHandlesAdapterGenerator +// +class MethodHandlesAdapterGenerator : public StubCodeGenerator { +public: + MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {} + + void generate(); +}; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/runtime/arguments.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -2859,6 +2859,12 @@ } #endif // _LP64 + // MethodHandles code does not support TaggedStackInterpreter. + if (EnableMethodHandles && TaggedStackInterpreter) { + warning("TaggedStackInterpreter is not supported by MethodHandles code. Disabling TaggedStackInterpreter."); + TaggedStackInterpreter = false; + } + // Check the GC selections again. if (!check_gc_consistency()) { return JNI_EINVAL; diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/runtime/init.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,6 +118,9 @@ javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init + // Generate MethodHandles adapters. + MethodHandles::generate_adapters(); + // Although we'd like to, we can't easily do a heap verify // here because the main thread isn't yet a JavaThread, so // its TLAB may not be made parseable from the usual interfaces. diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -256,7 +256,7 @@ // The continuation address is the entry point of the exception handler of the // previous frame depending on the return address. -address SharedRuntime::raw_exception_handler_for_return_address(address return_address) { +address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) { assert(frame::verify_return_pc(return_address), "must be a return pc"); // the fastest case first @@ -264,6 +264,8 @@ if (blob != NULL && blob->is_nmethod()) { nmethod* code = (nmethod*)blob; assert(code != NULL, "nmethod must be present"); + // Check if the return address is a MethodHandle call site. + thread->set_is_method_handle_exception(code->is_method_handle_return(return_address)); // native nmethods don't have exception handlers assert(!code->is_native_method(), "no exception handler"); assert(code->header_begin() != code->exception_begin(), "no exception handler"); @@ -289,6 +291,8 @@ if (blob->is_nmethod()) { nmethod* code = (nmethod*)blob; assert(code != NULL, "nmethod must be present"); + // Check if the return address is a MethodHandle call site. + thread->set_is_method_handle_exception(code->is_method_handle_return(return_address)); assert(code->header_begin() != code->exception_begin(), "no exception handler"); return code->exception_begin(); } @@ -309,10 +313,11 @@ } -JRT_LEAF(address, SharedRuntime::exception_handler_for_return_address(address return_address)) - return raw_exception_handler_for_return_address(return_address); +JRT_LEAF(address, SharedRuntime::exception_handler_for_return_address(JavaThread* thread, address return_address)) + return raw_exception_handler_for_return_address(thread, return_address); JRT_END + address SharedRuntime::get_poll_stub(address pc) { address stub; // Look up the code blob @@ -465,16 +470,6 @@ t = table.entry_for(catch_pco, -1, 0); } -#ifdef COMPILER1 - if (nm->is_compiled_by_c1() && t == NULL && handler_bci == -1) { - // Exception is not handled by this frame so unwind. Note that - // this is not the same as how C2 does this. C2 emits a table - // entry that dispatches to the unwind code in the nmethod. - return NULL; - } -#endif /* COMPILER1 */ - - if (t == NULL) { tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", ret_pc, handler_bci); tty->print_cr(" Exception:"); @@ -587,7 +582,7 @@ // 3. Implict null exception in nmethod if (!cb->is_nmethod()) { - guarantee(cb->is_adapter_blob(), + guarantee(cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(), "exception happened outside interpreter, nmethods and vtable stubs (1)"); // There is no handler here, so we will simply unwind. return StubRoutines::throw_NullPointerException_at_call_entry(); @@ -892,12 +887,13 @@ RegisterMap cbl_map(thread, false); frame caller_frame = thread->last_frame().sender(&cbl_map); - CodeBlob* cb = caller_frame.cb(); - guarantee(cb != NULL && cb->is_nmethod(), "must be called from nmethod"); + CodeBlob* caller_cb = caller_frame.cb(); + guarantee(caller_cb != NULL && caller_cb->is_nmethod(), "must be called from nmethod"); + nmethod* caller_nm = caller_cb->as_nmethod_or_null(); // make sure caller is not getting deoptimized // and removed before we are done with it. // CLEANUP - with lazy deopt shouldn't need this lock - nmethodLocker caller_lock((nmethod*)cb); + nmethodLocker caller_lock(caller_nm); // determine call info & receiver @@ -929,6 +925,13 @@ } #endif + // JSR 292 + // If the resolved method is a MethodHandle invoke target the call + // site must be a MethodHandle call site. + if (callee_method->is_method_handle_invoke()) { + assert(caller_nm->is_method_handle_return(caller_frame.pc()), "must be MH call site"); + } + // Compute entry points. This might require generation of C2I converter // frames, so we cannot be holding any locks here. Furthermore, the // computation of the entry points is independent of patching the call. We @@ -940,13 +943,12 @@ StaticCallInfo static_call_info; CompiledICInfo virtual_call_info; - // Make sure the callee nmethod does not get deoptimized and removed before // we are done patching the code. - nmethod* nm = callee_method->code(); - nmethodLocker nl_callee(nm); + nmethod* callee_nm = callee_method->code(); + nmethodLocker nl_callee(callee_nm); #ifdef ASSERT - address dest_entry_point = nm == NULL ? 0 : nm->entry_point(); // used below + address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below #endif if (is_virtual) { @@ -2077,7 +2079,6 @@ // --------------------------------------------------------------------------- // Implementation of AdapterHandlerLibrary -const char* AdapterHandlerEntry::name = "I2C/C2I adapters"; AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL; AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL; const int AdapterHandlerLibrary_size = 16*K; @@ -2129,7 +2130,7 @@ ResourceMark rm; NOT_PRODUCT(int code_size); - BufferBlob *B = NULL; + AdapterBlob* B = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; { @@ -2179,7 +2180,7 @@ // Create I2C & C2I handlers - BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache + BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); short buffer_locs[20]; @@ -2208,7 +2209,7 @@ } #endif - B = BufferBlob::create(AdapterHandlerEntry::name, &buffer); + B = AdapterBlob::create(&buffer); NOT_PRODUCT(code_size = buffer.code_size()); } if (B == NULL) { @@ -2240,7 +2241,7 @@ jio_snprintf(blob_id, sizeof(blob_id), "%s(%s)@" PTR_FORMAT, - AdapterHandlerEntry::name, + B->name(), fingerprint->as_string(), B->instructions_begin()); VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end()); diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 18 06:36:43 2010 -0700 @@ -96,10 +96,9 @@ static jdouble dexp(jdouble x); static jdouble dpow(jdouble x, jdouble y); - // exception handling across interpreter/compiler boundaries - static address raw_exception_handler_for_return_address(address return_address); - static address exception_handler_for_return_address(address return_address); + static address raw_exception_handler_for_return_address(JavaThread* thread, address return_address); + static address exception_handler_for_return_address(JavaThread* thread, address return_address); #ifndef SERIALGC // G1 write barriers @@ -568,9 +567,6 @@ AdapterHandlerEntry(); public: - // The name we give all buffer blobs - static const char* name; - address get_i2c_entry() { return _i2c_entry; } address get_c2i_entry() { return _c2i_entry; } address get_c2i_unverified_entry() { return _c2i_unverified_entry; } diff -r 12d91eb0f579 -r 97fe2cc98b1d src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Thu Mar 11 14:41:29 2010 -0500 +++ b/src/share/vm/runtime/vframeArray.cpp Thu Mar 18 06:36:43 2010 -0700 @@ -223,7 +223,7 @@ break; case Deoptimization::Unpack_exception: // exception is pending - pc = SharedRuntime::raw_exception_handler_for_return_address(pc); + pc = SharedRuntime::raw_exception_handler_for_return_address(thread, pc); // [phh] We're going to end up in some handler or other, so it doesn't // matter what mdp we point to. See exception_handler_for_exception() // in interpreterRuntime.cpp. diff -r 12d91eb0f579 -r 97fe2cc98b1d test/compiler/6930043/Test6930043.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6930043/Test6930043.java Thu Mar 18 06:36:43 2010 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6930043 + * @summary C2: SIGSEGV in javasoft.sqe.tests.lang.arr017.arr01702.arr01702.loop_forw(II)I + * + * @run main Test6930043 + */ + +import java.io.PrintStream; + +public class Test6930043 { + int[] a; + int idx; + + public int loop_back(int i, int i_0_) { + int i_1_ = 0; + int[] is = a; + if (is == null) return 0; + for (int i_2_ = i; i_2_ >= i_0_; i_2_--) + i_1_ += is[idx = i_2_]; + return i_1_; + } + + public int loop_forw(int start, int end) { + int result = 0; + int[] is = a; + if (is == null) return 0; + for (int index = start; index < end; index++) + result += is[index]; + // result += is[idx = index]; + return result; + } + + public static void main(String[] strings) { + Test6930043 var_Test6930043 = new Test6930043(); + var_Test6930043.a = new int[1000000]; + var_Test6930043.loop_forw(10, 999990); + var_Test6930043.loop_forw(10, 999990); + for (int i = 0; i < 3; i++) { + try { + if (var_Test6930043.loop_forw(-1, 999990) != 0) throw new InternalError(); + } catch (ArrayIndexOutOfBoundsException e) { } + } + var_Test6930043.loop_back(999990, 10); + var_Test6930043.loop_back(999990, 10); + for (int i = 0; i < 3; i++) { + try { + if (var_Test6930043.loop_back(999990, -1) != 0) throw new InternalError(); + } catch (ArrayIndexOutOfBoundsException e) { } + } + } +} diff -r 12d91eb0f579 -r 97fe2cc98b1d test/compiler/6932496/Test6932496.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6932496/Test6932496.java Thu Mar 18 06:36:43 2010 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6932496 + * @summary incorrect deopt of jsr subroutine on 64 bit c1 + * + * @compile -source 1.5 -target 1.5 -XDjsrlimit=0 Test6932496.java + * @run main/othervm -Xcomp -XX:CompileOnly=Test6932496.m Test6932496 + */ + +public class Test6932496 { + static class A { + volatile boolean flag = false; + } + + static void m() { + try { + } finally { + A a = new A(); + a.flag = true; + } + } + + + static public void main(String[] args) { + m(); + } +} diff -r 12d91eb0f579 -r 97fe2cc98b1d test/compiler/6935535/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6935535/Test.java Thu Mar 18 06:36:43 2010 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6935535 + * @summary String.indexOf() returns incorrect result on x86 with SSE4.2 + * + * @run main/othervm -Xcomp Test + */ + +public class Test { + + static int IndexOfTest(String str) { + return str.indexOf("1111111111111xx1x"); + } + + public static void main(String args[]) { + String str = "1111111111111xx1111111111111xx1x"; + str = str.substring(0, 31); + int idx = IndexOfTest(str); + System.out.println("IndexOf(" + "1111111111111xx1x" + ") = " + idx + " in " + str); + if (idx != -1) { + System.exit(97); + } + } +} +