diff --git a/.hgtags b/.hgtags index 74ffa4a5911..df602413e65 100644 --- a/.hgtags +++ b/.hgtags @@ -16,3 +16,4 @@ a2879b2837f5a4c87e9542efe69ef138194af8ff jdk7-b38 126f365cec6c3c2c72de934fa1c64b5f082b55b5 jdk7-b39 3c53424bbe3bb77e01b468b4b0140deec33e11fc jdk7-b40 3cb2a607c347934f8e7e86f840a094c28b08d9ea jdk7-b41 +caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index db14d6be8bb..0ba997a6a9e 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -16,3 +16,4 @@ cc47a76899ed33a2c513cb688348244c9b5a1288 jdk7-b38 ab523b49de1fc73fefe6855ce1e0349bdbd7af29 jdk7-b39 44be42de6693063fb191989bf0e188de2fa51e7c jdk7-b40 541bdc5ad32fc33255944d0a044ad992f3d915e8 jdk7-b41 +94052b87287303527125026fe4b2698cf867ea83 jdk7-b42 diff --git a/corba/.hgtags b/corba/.hgtags index ef73173d9d2..d10fcea0a24 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -16,3 +16,4 @@ ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31 55078b6661e286e90387d1d9950bd865f5cc436e jdk7-b39 184e21992f47a8d730df1adc5b21a108f3125489 jdk7-b40 c90eeda9594ed2983403e2049aed8d503126c62e jdk7-b41 +ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 90191ff65d0..2769cf0f79a 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -16,3 +16,4 @@ d9bc824aa078573829bb66572af847e26e1bd12e jdk7-b38 49ca90d77f34571b0757ebfcb8a7848ef2696b88 jdk7-b39 81a0cbe3b28460ce836109934ece03db7afaf9cc jdk7-b40 f9d938ede1960d18cb7cf23c645b026519c1a678 jdk7-b41 +ad8c8ca4ab0f4c86e74c061958f44a8f4a930f2c jdk7-b42 diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index a932f652954..4454f180b5b 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2008 HS_MAJOR_VER=14 HS_MINOR_VER=0 -HS_BUILD_NUMBER=09 +HS_BUILD_NUMBER=10 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/linux/adlc_updater b/hotspot/make/linux/adlc_updater index 6a97b79931d..b54f783d6ee 100644 --- a/hotspot/make/linux/adlc_updater +++ b/hotspot/make/linux/adlc_updater @@ -7,5 +7,13 @@ # # adlc-updater # -[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ -( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) +fix_lines() { + # repair bare #line directives in $1 to refer to $2 + awk < $1 > $1+ ' + /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} + {print} + ' F2=$2 + mv $1+ $1 +} +[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \ +( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/linux/makefiles/adlc.make b/hotspot/make/linux/makefiles/adlc.make index 5349f5bd323..5e48fed1567 100644 --- a/hotspot/make/linux/makefiles/adlc.make +++ b/hotspot/make/linux/makefiles/adlc.make @@ -54,10 +54,12 @@ VPATH += $(Src_Dirs_V:%=%:) Src_Dirs_I = ${Src_Dirs} $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) -# Force assertions on. -SYSDEFS += -DASSERT +# set flags for adlc compilation CPPFLAGS = $(SYSDEFS) $(INCLUDES) +# Force assertions on. +CPPFLAGS += -DASSERT + # CFLAGS_WARN holds compiler options to suppress/enable warnings. # Suppress warnings (for now) CFLAGS_WARN = -w @@ -125,7 +127,15 @@ $(GENERATEDFILES): refresh_adfiles # Note that product files are updated via "mv", which is atomic. TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$) -ADLCFLAGS = -q -T +# Pass -D flags into ADLC. +ADLCFLAGS += $(SYSDEFS) + +# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. +ADLCFLAGS += -q -T + +# Normally, debugging is done directly on the ad_*.cpp files. +# But -g will put #line directives in those files pointing back to .ad. +#ADLCFLAGS += -g ifdef LP64 ADLCFLAGS += -D_LP64 @@ -140,6 +150,8 @@ endif # ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS) ADLC_UPDATER = adlc_updater +$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) + $(QUIETLY) cp $< $@; chmod +x $@ # This action refreshes all generated adlc files simultaneously. # The way it works is this: @@ -149,9 +161,8 @@ ADLC_UPDATER = adlc_updater # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files. # 5) If we actually updated any files, echo a notice. # -refresh_adfiles: $(EXEC) $(SOURCE.AD) +refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER) @rm -rf $(TEMPDIR); mkdir $(TEMPDIR) - $(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) ) $(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \ -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \ || { rm -rf $(TEMPDIR); exit 1; } @@ -174,7 +185,15 @@ refresh_adfiles: $(EXEC) $(SOURCE.AD) # ######################################################################### $(SOURCE.AD): $(SOURCES.AD) - $(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD) + $(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD) + +#PROCESS_AD_FILES = cat +# Pass through #line directives, in case user enables -g option above: +PROCESS_AD_FILES = awk '{ \ + if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \ + print }' $(OUTDIR)/%.o: %.cpp @echo Compiling $< diff --git a/hotspot/make/solaris/adlc_updater b/hotspot/make/solaris/adlc_updater index 6a97b79931d..b54f783d6ee 100644 --- a/hotspot/make/solaris/adlc_updater +++ b/hotspot/make/solaris/adlc_updater @@ -7,5 +7,13 @@ # # adlc-updater # -[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ -( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) +fix_lines() { + # repair bare #line directives in $1 to refer to $2 + awk < $1 > $1+ ' + /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} + {print} + ' F2=$2 + mv $1+ $1 +} +[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \ +( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) diff --git a/hotspot/make/solaris/makefiles/adlc.make b/hotspot/make/solaris/makefiles/adlc.make index f746d77494d..2d1a87a20b4 100644 --- a/hotspot/make/solaris/makefiles/adlc.make +++ b/hotspot/make/solaris/makefiles/adlc.make @@ -54,10 +54,12 @@ VPATH += $(Src_Dirs_V:%=%:) Src_Dirs_I = ${Src_Dirs} $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) -# Force assertions on. -SYSDEFS += -DASSERT +# set flags for adlc compilation CPPFLAGS = $(SYSDEFS) $(INCLUDES) +# Force assertions on. +CPPFLAGS += -DASSERT + ifndef USE_GCC # We need libCstd.so for adlc CFLAGS += -library=Cstd -g @@ -141,7 +143,15 @@ $(GENERATEDFILES): refresh_adfiles # Note that product files are updated via "mv", which is atomic. TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$) -ADLCFLAGS = -q -T +# Pass -D flags into ADLC. +ADLCFLAGS += $(SYSDEFS) + +# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. +ADLCFLAGS += -q -T + +# Normally, debugging is done directly on the ad_*.cpp files. +# But -g will put #line directives in those files pointing back to .ad. +#ADLCFLAGS += -g ifdef LP64 ADLCFLAGS += -D_LP64 @@ -156,6 +166,8 @@ endif # ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS) ADLC_UPDATER = adlc_updater +$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) + $(QUIETLY) cp $< $@; chmod +x $@ # This action refreshes all generated adlc files simultaneously. # The way it works is this: @@ -165,9 +177,8 @@ ADLC_UPDATER = adlc_updater # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files. # 5) If we actually updated any files, echo a notice. # -refresh_adfiles: $(EXEC) $(SOURCE.AD) +refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER) @rm -rf $(TEMPDIR); mkdir $(TEMPDIR) - $(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) ) $(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \ -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \ || { rm -rf $(TEMPDIR); exit 1; } @@ -190,7 +201,15 @@ refresh_adfiles: $(EXEC) $(SOURCE.AD) # ######################################################################### $(SOURCE.AD): $(SOURCES.AD) - $(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD) + $(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD) + +#PROCESS_AD_FILES = cat +# Pass through #line directives, in case user enables -g option above: +PROCESS_AD_FILES = awk '{ \ + if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \ + print }' $(OUTDIR)/%.o: %.cpp @echo Compiling $< diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 6331bf4aca5..3b8c0b4dc03 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2500,7 +2500,7 @@ bool os::guard_memory(char* addr, size_t size) { } bool os::unguard_memory(char* addr, size_t size) { - return linux_mprotect(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC); + return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } // Large page support diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 7225f3be425..f74967ab079 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1638,16 +1638,24 @@ inline hrtime_t oldgetTimeNanos() { // getTimeNanos is guaranteed to not move backward on Solaris inline hrtime_t getTimeNanos() { if (VM_Version::supports_cx8()) { - bool retry = false; - hrtime_t newtime = gethrtime(); - hrtime_t oldmaxtime = max_hrtime; - hrtime_t retmaxtime = oldmaxtime; - while ((newtime > retmaxtime) && (retry == false || retmaxtime != oldmaxtime)) { - oldmaxtime = retmaxtime; - retmaxtime = Atomic::cmpxchg(newtime, (volatile jlong *)&max_hrtime, oldmaxtime); - retry = true; - } - return (newtime > retmaxtime) ? newtime : retmaxtime; + const hrtime_t now = gethrtime(); + const hrtime_t prev = max_hrtime; + if (now <= prev) return prev; // same or retrograde time; + const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); + assert(obsv >= prev, "invariant"); // Monotonicity + // If the CAS succeeded then we're done and return "now". + // If the CAS failed and the observed value "obs" is >= now then + // we should return "obs". If the CAS failed and now > obs > prv then + // some other thread raced this thread and installed a new value, in which case + // we could either (a) retry the entire operation, (b) retry trying to install now + // or (c) just return obs. We use (c). No loop is required although in some cases + // we might discard a higher "now" value in deference to a slightly lower but freshly + // installed obs value. That's entirely benign -- it admits no new orderings compared + // to (a) or (b) -- and greatly reduces coherence traffic. + // We might also condition (c) on the magnitude of the delta between obs and now. + // Avoiding excessive CAS operations to hot RW locations is critical. + // See http://blogs.sun.com/dave/entry/cas_and_cache_trivia_invalidate + return (prev == obsv) ? now : obsv ; } else { return oldgetTimeNanos(); } @@ -3026,6 +3034,8 @@ static bool solaris_mprotect(char* addr, size_t bytes, int prot) { // Protect memory (Used to pass readonly pages through // JNI GetArrayElements with empty arrays.) +// Also, used for serialization page and for compressed oops null pointer +// checking. bool os::protect_memory(char* addr, size_t bytes, ProtType prot, bool is_committed) { unsigned int p = 0; @@ -3049,7 +3059,7 @@ bool os::guard_memory(char* addr, size_t bytes) { } bool os::unguard_memory(char* addr, size_t bytes) { - return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE|PROT_EXEC); + return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE); } // Large page support diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 97228370b9f..d674d434b90 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2020,10 +2020,11 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (UnguardOnExecutionViolation > 0 && addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Set memory to RWX and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256]; @@ -2755,12 +2756,12 @@ bool os::protect_memory(char* addr, size_t bytes, ProtType prot, bool os::guard_memory(char* addr, size_t bytes) { DWORD old_status; - return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_status) != 0; + return VirtualProtect(addr, bytes, PAGE_READWRITE | PAGE_GUARD, &old_status) != 0; } bool os::unguard_memory(char* addr, size_t bytes) { DWORD old_status; - return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &old_status) != 0; + return VirtualProtect(addr, bytes, PAGE_READWRITE, &old_status) != 0; } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 174c1df492e..90e1921f8a0 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -422,10 +422,11 @@ JVM_handle_linux_signal(int sig, if (addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Set memory to RWX and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256]; diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index b21206dd227..c37370b572b 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -203,10 +203,10 @@ frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } -extern "C" intptr_t *_get_previous_fp(); // in .il file. +extern "C" intptr_t *_get_current_fp(); // in .il file frame os::current_frame() { - intptr_t* fp = _get_previous_fp(); + intptr_t* fp = _get_current_fp(); // it's inlined so want current fp frame myframe((intptr_t*)os::current_stack_pointer(), (intptr_t*)fp, CAST_FROM_FN_PTR(address, os::current_frame)); @@ -576,10 +576,11 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_ if (addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Make memory rwx and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256]; diff --git a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il index 49ae97729fe..9e1d6ce8ed3 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il @@ -37,10 +37,10 @@ movl %gs:0, %eax .end - // Get callers fp - .inline _get_previous_fp,0 + // Get current fp + .inline _get_current_fp,0 + .volatile movl %ebp, %eax - movl %eax, %eax .end // Support for jint Atomic::add(jint inc, volatile jint* dest) diff --git a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il index 89ed2c87b68..169bebc9984 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_64.il @@ -30,10 +30,10 @@ movq %fs:0, %rax .end - // Get the frame pointer from previous frame. - .inline _get_previous_fp,0 + // Get the frame pointer from current frame. + .inline _get_current_fp,0 + .volatile movq %rbp, %rax - movq %rax, %rax .end // Support for jint Atomic::add(jint add_value, volatile jint* dest) diff --git a/hotspot/src/share/vm/adlc/adlparse.cpp b/hotspot/src/share/vm/adlc/adlparse.cpp index 097684acdde..81a95e861ab 100644 --- a/hotspot/src/share/vm/adlc/adlparse.cpp +++ b/hotspot/src/share/vm/adlc/adlparse.cpp @@ -108,6 +108,7 @@ void ADLParser::parse() { else if (!strcmp(ident, "pipeline")) pipe_parse(); else if (!strcmp(ident, "definitions")) definitions_parse(); else if (!strcmp(ident, "peephole")) peep_parse(); + else if (!strcmp(ident, "#line")) preproc_line(); else if (!strcmp(ident, "#define")) preproc_define(); else if (!strcmp(ident, "#undef")) preproc_undef(); else { @@ -786,9 +787,11 @@ void ADLParser::reg_parse(void) { parse_err(SYNERR, "missing identifier inside register block.\n"); return; } - if (strcmp(token,"reg_def")==0) { reg_def_parse(); } - if (strcmp(token,"reg_class")==0) { reg_class_parse(); } - if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } + if (strcmp(token,"reg_def")==0) { reg_def_parse(); } + else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } + else if (strcmp(token,"#define")==0) { preproc_define(); } + else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } skipws(); } } @@ -903,11 +906,7 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) { skipws_no_preproc(); // Skip leading whitespace // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block if (_AD._adlocation_debug) { - const char* file = _AD._ADL_file._name; - int line = linenum(); - char* location = (char *)malloc(strlen(file) + 100); - sprintf(location, "#line %d \"%s\"\n", line, file); - encoding->add_code(location); + encoding->add_code(get_line_string()); } // Collect the parts of the encode description @@ -948,6 +947,10 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) { skipws(); + if (_AD._adlocation_debug) { + encoding->add_code(end_line_marker()); + } + // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name); } @@ -2349,7 +2352,11 @@ void ADLParser::reg_class_parse(void) { return; } RegDef *regDef = _AD._register->getRegDef(rname); - reg_class->addReg(regDef); // add regDef to regClass + if (!regDef) { + parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname); + } else { + reg_class->addReg(regDef); // add regDef to regClass + } // Check for ',' and position to next token. skipws(); @@ -2746,7 +2753,8 @@ Predicate *ADLParser::pred_parse(void) { char *rule = NULL; // String representation of predicate skipws(); // Skip leading whitespace - if ( (rule = get_paren_expr("pred expression")) == NULL ) { + int line = linenum(); + if ( (rule = get_paren_expr("pred expression", true)) == NULL ) { parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n"); return NULL; } @@ -3407,7 +3415,12 @@ FormatRule* ADLParser::format_parse(void) { // Check if there is a string to pass through to output char *start = _ptr; // Record start of the next string while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { - if (_curchar == '\\') next_char(); // superquote + if (_curchar == '\\') { + next_char(); // superquote + if ((_curchar == '$') || (_curchar == '%')) + // hack to avoid % escapes and warnings about undefined \ escapes + *(_ptr-1) = _curchar; + } if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! next_char(); } @@ -3942,8 +3955,7 @@ char* ADLParser::find_cpp_block(const char* description) { next_char(); // Skip block delimiter skipws_no_preproc(); // Skip leading whitespace cppBlock = _ptr; // Point to start of expression - const char* file = _AD._ADL_file._name; - int line = linenum(); + int line = linenum(); next = _ptr + 1; while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { next_char_or_line(); @@ -3958,15 +3970,16 @@ char* ADLParser::find_cpp_block(const char* description) { _curchar = *_ptr; // Maintain invariant // Prepend location descriptor, for debugging. - char* location = (char *)malloc(strlen(file) + 100); - *location = '\0'; - if (_AD._adlocation_debug) - sprintf(location, "#line %d \"%s\"\n", line, file); - char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + 1); - strcpy(result, location); - strcat(result, cppBlock); - cppBlock = result; - free(location); + if (_AD._adlocation_debug) { + char* location = get_line_string(line); + char* end_loc = end_line_marker(); + char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); + strcpy(result, location); + strcat(result, cppBlock); + strcat(result, end_loc); + cppBlock = result; + free(location); + } } return cppBlock; @@ -4036,13 +4049,26 @@ char* ADLParser::get_expr(const char *desc, const char *stop_chars) { // Helper function around get_expr // Sets _curchar to '(' so that get_paren_expr will search for a matching ')' -char *ADLParser::get_paren_expr(const char *description) { +char *ADLParser::get_paren_expr(const char *description, bool include_location) { + int line = linenum(); if (_curchar != '(') // Escape if not valid starting position return NULL; next_char(); // Skip the required initial paren. char *token2 = get_expr(description, ")"); if (_curchar == ')') next_char(); // Skip required final paren. + int junk = 0; + if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) { + // Prepend location descriptor, for debugging. + char* location = get_line_string(line); + char* end_loc = end_line_marker(); + char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1); + strcpy(result, location); + strcat(result, token2); + strcat(result, end_loc); + token2 = result; + free(location); + } return token2; } @@ -4082,10 +4108,16 @@ char *ADLParser::get_ident_common(bool do_preproc) { if (do_preproc && start != NULL) { const char* def = _AD.get_preproc_def(start); if (def != NULL && strcmp(def, start)) { - const char* def2 = _AD.get_preproc_def(def); - if (def2 != NULL && strcmp(def2, def)) { - parse_err(SYNERR, "unimplemented: using %s defined as %s => %s", - start, def, def2); + const char* def1 = def; + const char* def2 = _AD.get_preproc_def(def1); + // implement up to 2 levels of #define + if (def2 != NULL && strcmp(def2, def1)) { + def = def2; + const char* def3 = _AD.get_preproc_def(def2); + if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) { + parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s", + start, def1, def2, def3); + } } start = strdup(def); } @@ -4431,6 +4463,35 @@ void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) { } +//-------------------------------preproc_line---------------------------------- +// A "#line" keyword has been seen, so parse the rest of the line. +void ADLParser::preproc_line(void) { + int line = get_int(); + skipws_no_preproc(); + const char* file = NULL; + if (_curchar == '"') { + next_char(); // Move past the initial '"' + file = _ptr; + while (true) { + if (_curchar == '\n') { + parse_err(SYNERR, "missing '\"' at end of #line directive"); + return; + } + if (_curchar == '"') { + *_ptr = '\0'; // Terminate the string + next_char(); + skipws_no_preproc(); + break; + } + next_char(); + } + } + ensure_end_of_line(); + if (file != NULL) + _AD._ADL_file._name = file; + _buf.set_linenum(line); +} + //------------------------------preproc_define--------------------------------- // A "#define" keyword has been seen, so parse the rest of the line. void ADLParser::preproc_define(void) { @@ -4494,6 +4555,7 @@ void ADLParser::parse_err(int flag, const char *fmt, ...) { // A preprocessor directive has been encountered. Be sure it has fallen at // the begining of a line, or else report an error. void ADLParser::ensure_start_of_line(void) { + if (_curchar == '\n') { next_line(); return; } assert( _ptr >= _curline && _ptr < _curline+strlen(_curline), "Must be able to find which line we are in" ); @@ -4662,6 +4724,7 @@ char ADLParser::cur_char() { //---------------------------next_char----------------------------------------- void ADLParser::next_char() { + if (_curchar == '\n') parse_err(WARN, "must call next_line!"); _curchar = *++_ptr; // if ( _curchar == '\n' ) { // next_line(); @@ -4682,6 +4745,18 @@ void ADLParser::next_char_or_line() { //---------------------------next_line----------------------------------------- void ADLParser::next_line() { _curline = _buf.get_line(); + _curchar = ' '; +} + +//------------------------get_line_string-------------------------------------- +// Prepended location descriptor, for debugging. +// Must return a malloced string (that can be freed if desired). +char* ADLParser::get_line_string(int linenum) { + const char* file = _AD._ADL_file._name; + int line = linenum ? linenum : this->linenum(); + char* location = (char *)malloc(strlen(file) + 100); + sprintf(location, "\n#line %d \"%s\"\n", line, file); + return location; } //-------------------------is_literal_constant--------------------------------- @@ -4722,6 +4797,66 @@ bool ADLParser::is_int_token(const char* token, int& intval) { return true; } +static const char* skip_expr_ws(const char* str) { + const char * cp = str; + while (cp[0]) { + if (cp[0] <= ' ') { + ++cp; + } else if (cp[0] == '#') { + ++cp; + while (cp[0] == ' ') ++cp; + assert(0 == strncmp(cp, "line", 4), "must be a #line directive"); + const char* eol = strchr(cp, '\n'); + assert(eol != NULL, "must find end of line"); + if (eol == NULL) eol = cp + strlen(cp); + cp = eol; + } else { + break; + } + } + return cp; +} + +//-----------------------equivalent_expressions-------------------------------- +bool ADLParser::equivalent_expressions(const char* str1, const char* str2) { + if (str1 == str2) + return true; + else if (str1 == NULL || str2 == NULL) + return false; + const char* cp1 = str1; + const char* cp2 = str2; + char in_quote = '\0'; + while (cp1[0] && cp2[0]) { + if (!in_quote) { + // skip spaces and/or cpp directives + const char* cp1a = skip_expr_ws(cp1); + const char* cp2a = skip_expr_ws(cp2); + if (cp1a > cp1 && cp2a > cp2) { + cp1 = cp1a; cp2 = cp2a; + continue; + } + if (cp1a > cp1 || cp2a > cp2) break; // fail + } + // match one non-space char + if (cp1[0] != cp2[0]) break; // fail + char ch = cp1[0]; + cp1++; cp2++; + // watch for quotes + if (in_quote && ch == '\\') { + if (cp1[0] != cp2[0]) break; // fail + if (!cp1[0]) break; + cp1++; cp2++; + } + if (in_quote && ch == in_quote) { + in_quote = '\0'; + } else if (!in_quote && (ch == '"' || ch == '\'')) { + in_quote = ch; + } + } + return (!cp1[0] && !cp2[0]); +} + + //-------------------------------trim------------------------------------------ void ADLParser::trim(char* &token) { while (*token <= ' ') token++; diff --git a/hotspot/src/share/vm/adlc/adlparse.hpp b/hotspot/src/share/vm/adlc/adlparse.hpp index d3e26886558..0840bfc758b 100644 --- a/hotspot/src/share/vm/adlc/adlparse.hpp +++ b/hotspot/src/share/vm/adlc/adlparse.hpp @@ -93,6 +93,7 @@ protected: void pipe_parse(void); // Parse pipeline section void definitions_parse(void); // Parse definitions section void peep_parse(void); // Parse peephole rule definitions + void preproc_line(void); // Parse a #line statement void preproc_define(void); // Parse a #define statement void preproc_undef(void); // Parse an #undef statement @@ -226,7 +227,7 @@ protected: void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs // Return the contents of a parenthesized expression. // Requires initial '(' and consumes final ')', which is replaced by '\0'. - char *get_paren_expr(const char *description); + char *get_paren_expr(const char *description, bool include_location = false); // Return expression up to next stop-char, which terminator replaces. // Does not require initial '('. Does not consume final stop-char. // Final stop-char is left in _curchar, but is also is replaced by '\0'. @@ -234,6 +235,11 @@ protected: char *find_cpp_block(const char *description); // Parse a C++ code block // Issue parser error message & go to EOL void parse_err(int flag, const char *fmt, ...); + // Create a location marker for this file and line. + char *get_line_string(int linenum = 0); + // Return a location marker which tells the C preprocessor to + // forget the previous location marker. (Requires awk postprocessing.) + char *end_line_marker() { return (char*)"\n#line 999999\n"; } // Return pointer to current character inline char cur_char(void); @@ -268,5 +274,6 @@ public: static bool is_literal_constant(const char *hex_string); static bool is_hex_digit(char digit); static bool is_int_token(const char* token, int& intval); + static bool equivalent_expressions(const char* str1, const char* str2); static void trim(char* &token); // trim leading & trailing spaces }; diff --git a/hotspot/src/share/vm/adlc/archDesc.cpp b/hotspot/src/share/vm/adlc/archDesc.cpp index 9702fb47730..a73ad76da23 100644 --- a/hotspot/src/share/vm/adlc/archDesc.cpp +++ b/hotspot/src/share/vm/adlc/archDesc.cpp @@ -140,7 +140,7 @@ bool MatchList::search(const char *opc, const char *res, const char *lch, if ((rch == _rchild) || (rch && _rchild && !strcmp(rch, _rchild))) { char * predStr = get_pred(); char * prStr = pr?pr->_pred:NULL; - if ((prStr == predStr) || (prStr && predStr && !strcmp(prStr, predStr))) { + if (ADLParser::equivalent_expressions(prStr, predStr)) { return true; } } diff --git a/hotspot/src/share/vm/adlc/dfa.cpp b/hotspot/src/share/vm/adlc/dfa.cpp index 36d56062cfd..1075c9da774 100644 --- a/hotspot/src/share/vm/adlc/dfa.cpp +++ b/hotspot/src/share/vm/adlc/dfa.cpp @@ -458,7 +458,7 @@ void ArchDesc::buildDFA(FILE* fp) { class dfa_shared_preds { - enum { count = 2 }; + enum { count = 4 }; static bool _found[count]; static const char* _type [count]; @@ -479,12 +479,15 @@ class dfa_shared_preds { char c = *prev; switch( c ) { case ' ': + case '\n': return dfa_shared_preds::valid_loc(pred, prev); case '!': case '(': case '<': case '=': return true; + case '"': // such as: #line 10 "myfile.ad"\n mypredicate + return true; case '|': if( prev != pred && *(prev-1) == '|' ) return true; case '&': @@ -564,10 +567,14 @@ public: } }; // shared predicates, _var and _pred entry should be the same length -bool dfa_shared_preds::_found[dfa_shared_preds::count] = { false, false }; -const char* dfa_shared_preds::_type[dfa_shared_preds::count] = { "int", "bool" }; -const char* dfa_shared_preds::_var [dfa_shared_preds::count] = { "_n_get_int__", "Compile__current____select_24_bit_instr__" }; -const char* dfa_shared_preds::_pred[dfa_shared_preds::count] = { "n->get_int()", "Compile::current()->select_24_bit_instr()" }; +bool dfa_shared_preds::_found[dfa_shared_preds::count] + = { false, false, false, false }; +const char* dfa_shared_preds::_type[dfa_shared_preds::count] + = { "int", "jlong", "intptr_t", "bool" }; +const char* dfa_shared_preds::_var [dfa_shared_preds::count] + = { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__", "Compile__current____select_24_bit_instr__" }; +const char* dfa_shared_preds::_pred[dfa_shared_preds::count] + = { "n->get_int()", "n->get_long()", "n->get_intptr_t()", "Compile::current()->select_24_bit_instr()" }; void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) { diff --git a/hotspot/src/share/vm/adlc/filebuff.hpp b/hotspot/src/share/vm/adlc/filebuff.hpp index 10bb68fcb4f..8f12f9262d9 100644 --- a/hotspot/src/share/vm/adlc/filebuff.hpp +++ b/hotspot/src/share/vm/adlc/filebuff.hpp @@ -68,6 +68,7 @@ class FileBuff { // and increments bufeol and filepos to point at the end of that line. char *get_line(void); int linenum() const { return _linenum; } + void set_linenum(int line) { _linenum = line; } // This converts a pointer into the buffer to a file offset. It only works // when the pointer is valid (i.e. just obtained from getline()). diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index fb91d83d2f6..65b511bcdb1 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -1102,10 +1102,7 @@ bool equivalent_predicates( const InstructForm *instr1, const InstructForm *inst } if( pred1 != NULL && pred2 != NULL ) { // compare the predicates - const char *str1 = pred1->_pred; - const char *str2 = pred2->_pred; - if( (str1 == NULL && str2 == NULL) - || (str1 != NULL && str2 != NULL && strcmp(str1,str2) == 0) ) { + if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) { return true; } } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 16552a7e5d3..9b718a3d28f 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1210,8 +1210,8 @@ LIR_Opr LIRGenerator::load_constant(LIR_Const* c) { break; case T_LONG: case T_DOUBLE: - if (c->as_jint_hi_bits() != other->as_jint_lo_bits()) continue; - if (c->as_jint_lo_bits() != other->as_jint_hi_bits()) continue; + if (c->as_jint_hi_bits() != other->as_jint_hi_bits()) continue; + if (c->as_jint_lo_bits() != other->as_jint_lo_bits()) continue; break; case T_OBJECT: if (c->as_jobject() != other->as_jobject()) continue; diff --git a/hotspot/src/share/vm/c1/c1_Optimizer.cpp b/hotspot/src/share/vm/c1/c1_Optimizer.cpp index ea4b3a576db..1b9f77aeef2 100644 --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp @@ -327,8 +327,6 @@ class BlockMerger: public BlockClosure { BlockBegin* fsux = if_->fsux(); if (swapped) { cond = Instruction::mirror(cond); - tsux = if_->fsux(); - fsux = if_->tsux(); } BlockBegin* tblock = tval->compare(cond, con, tsux, fsux); diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 04750308db3..dcd0f282ab9 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -842,6 +842,13 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i if (TracePatching) { tty->print_cr("Deoptimizing for patching volatile field reference"); } + // It's possible the nmethod was invalidated in the last + // safepoint, but if it's still alive then make it not_entrant. + nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); + if (nm != NULL) { + nm->make_not_entrant(); + } + VM_DeoptimizeFrame deopt(thread, caller_frame.id()); VMThread::execute(&deopt); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 45d0147fa7d..703217f9255 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -581,7 +581,8 @@ objArrayHandle ClassFileParser::parse_interfaces(constantPoolHandle cp, interf = KlassHandle(THREAD, k); vmtimer->resume(); - cp->klass_at_put(interface_index, interf()); // eagerly resolve + if (LinkWellKnownClasses) // my super type is well known to me + cp->klass_at_put(interface_index, interf()); // eagerly resolve } if (!Klass::cast(interf())->is_interface()) { @@ -2699,7 +2700,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, CHECK_(nullHandle)); KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); - cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve + if (LinkWellKnownClasses) // my super class is well known to me + cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve } if (super_klass.not_null()) { if (super_klass->is_interface()) { @@ -3128,7 +3130,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, this_klass->set_method_ordering(method_ordering()); this_klass->set_initial_method_idnum(methods->length()); this_klass->set_name(cp->klass_name_at(this_class_index)); - cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve + if (LinkWellKnownClasses) // I am well known to myself + cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve this_klass->set_protection_domain(protection_domain()); this_klass->set_fields_annotations(fields_annotations()); this_klass->set_methods_annotations(methods_annotations()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index daf31a0e8f5..3aa19ccb85d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2954,7 +2954,7 @@ public: // The object has been either evacuated or is dead. Fill it with a // dummy object. MemRegion mr((HeapWord*)obj, obj->size()); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); _cm->clearRangeBothMaps(mr); } } @@ -3225,7 +3225,7 @@ void G1CollectedHeap::par_allocate_remaining_space(HeapRegion* r) { // Otherwise, try to claim it. block = r->par_allocate(free_words); } while (block == NULL); - SharedHeap::fill_region_with_object(MemRegion(block, free_words)); + fill_with_object(block, free_words); } #define use_local_bitmaps 1 @@ -3619,9 +3619,8 @@ public: guarantee(alloc_buffer(purpose)->contains(obj + word_sz - 1), "should contain whole object"); alloc_buffer(purpose)->undo_allocation(obj, word_sz); - } - else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + } else { + CollectedHeap::fill_with_object(obj, word_sz); add_to_undo_waste(word_sz); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index f2d262ebfb5..e2b15ca37c9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -181,7 +181,7 @@ public: void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) { HeapWord* hr_bot = hr()->bottom(); - int hr_first_card_index = ctbs->index_for(hr_bot); + size_t hr_first_card_index = ctbs->index_for(hr_bot); bm()->set_intersection_at_offset(*card_bm, hr_first_card_index); #if PRT_COUNT_OCCUPIED recount_occupied(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index 89cd9e45f88..5eeb42fbf6c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -102,7 +102,7 @@ HeapRegionSeq::alloc_obj_from_region_index(int ind, size_t word_size) { HeapWord* tmp = hr->allocate(sz); assert(tmp != NULL, "Humongous allocation failure"); MemRegion mr = MemRegion(tmp, sz); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); hr->declare_filled_region_to_BOT(mr); if (i == first) { first_hr->set_startsHumongous(); diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp index d4c641bf028..e2d0ebd701f 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp @@ -51,14 +51,14 @@ void ParGCAllocBuffer::retire(bool end_of_gc, bool retain) { if (_retained) { // If the buffer had been retained shorten the previous filler object. assert(_retained_filler.end() <= _top, "INVARIANT"); - SharedHeap::fill_region_with_object(_retained_filler); + CollectedHeap::fill_with_object(_retained_filler); // Wasted space book-keeping, otherwise (normally) done in invalidate() _wasted += _retained_filler.word_size(); _retained = false; } assert(!end_of_gc || !_retained, "At this point, end_of_gc ==> !_retained."); if (_top < _hard_end) { - SharedHeap::fill_region_with_object(MemRegion(_top, _hard_end)); + CollectedHeap::fill_with_object(_top, _hard_end); if (!retain) { invalidate(); } else { @@ -155,7 +155,7 @@ ParGCAllocBufferWithBOT::ParGCAllocBufferWithBOT(size_t word_sz, // modifying the _next_threshold state in the BOT. void ParGCAllocBufferWithBOT::fill_region_with_block(MemRegion mr, bool contig) { - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); if (contig) { _bt.alloc_block(mr.start(), mr.end()); } else { @@ -171,7 +171,7 @@ HeapWord* ParGCAllocBufferWithBOT::allocate_slow(size_t word_sz) { "or else _true_end should be equal to _hard_end"); assert(_retained, "or else _true_end should be equal to _hard_end"); assert(_retained_filler.end() <= _top, "INVARIANT"); - SharedHeap::fill_region_with_object(_retained_filler); + CollectedHeap::fill_with_object(_retained_filler); if (_top < _hard_end) { fill_region_with_block(MemRegion(_top, _hard_end), true); } @@ -316,11 +316,9 @@ void ParGCAllocBufferWithBOT::retire(bool end_of_gc, bool retain) { while (_top <= chunk_boundary) { assert(pointer_delta(_hard_end, chunk_boundary) >= AlignmentReserve, "Consequence of last card handling above."); - MemRegion chunk_portion(chunk_boundary, _hard_end); - _bt.BlockOffsetArray::alloc_block(chunk_portion.start(), - chunk_portion.end()); - SharedHeap::fill_region_with_object(chunk_portion); - _hard_end = chunk_portion.start(); + _bt.BlockOffsetArray::alloc_block(chunk_boundary, _hard_end); + CollectedHeap::fill_with_object(chunk_boundary, _hard_end); + _hard_end = chunk_boundary; chunk_boundary -= ChunkSizeInWords; } _end = _hard_end - AlignmentReserve; diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index 72907679905..a2b7607bb79 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -201,7 +201,7 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, "Should contain whole object."); to_space_alloc_buffer()->undo_allocation(obj, word_sz); } else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + CollectedHeap::fill_with_object(obj, word_sz); } } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index ea0c20b0148..829403f5128 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -389,7 +389,7 @@ bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy, // full GC. const size_t alignment = old_gen->virtual_space()->alignment(); const size_t eden_used = eden_space->used_in_bytes(); - const size_t promoted = (size_t)(size_policy->avg_promoted()->padded_average()); + const size_t promoted = (size_t)size_policy->avg_promoted()->padded_average(); const size_t absorb_size = align_size_up(eden_used + promoted, alignment); const size_t eden_capacity = eden_space->capacity_in_bytes(); @@ -416,16 +416,14 @@ bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy, // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); - MemRegion old_gen_unused(old_space->top(), old_space->end()); + HeapWord* const unused_start = old_space->top(); + size_t const unused_words = pointer_delta(old_space->end(), unused_start); - // If the unused part of the old gen cannot be filled, skip - // absorbing eden. - if (old_gen_unused.word_size() < SharedHeap::min_fill_size()) { - return false; - } - - if (!old_gen_unused.is_empty()) { - SharedHeap::fill_region_with_object(old_gen_unused); + if (unused_words > 0) { + if (unused_words < CollectedHeap::min_fill_size()) { + return false; // If the old gen cannot be filled, must give up. + } + CollectedHeap::fill_with_objects(unused_start, unused_words); } // Take the live data from eden and set both top and end in the old gen to @@ -441,9 +439,8 @@ bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy, // Update the object start array for the filler object and the data from eden. ObjectStartArray* const start_array = old_gen->start_array(); - HeapWord* const start = old_gen_unused.start(); - for (HeapWord* addr = start; addr < new_top; addr += oop(addr)->size()) { - start_array->allocate_block(addr); + for (HeapWord* p = unused_start; p < new_top; p += oop(p)->size()) { + start_array->allocate_block(p); } // Could update the promoted average here, but it is not typically updated at diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp index 310ad40d1b7..4cc90cd2de2 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp @@ -275,22 +275,9 @@ bool PSMarkSweepDecorator::insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q, size_t deadlength) { if (allowed_deadspace_words >= deadlength) { allowed_deadspace_words -= deadlength; - oop(q)->set_mark(markOopDesc::prototype()->set_marked()); - const size_t aligned_min_int_array_size = - align_object_size(typeArrayOopDesc::header_size(T_INT)); - if (deadlength >= aligned_min_int_array_size) { - oop(q)->set_klass(Universe::intArrayKlassObj()); - assert(((deadlength - aligned_min_int_array_size) * (HeapWordSize/sizeof(jint))) < (size_t)max_jint, - "deadspace too big for Arrayoop"); - typeArrayOop(q)->set_length((int)((deadlength - aligned_min_int_array_size) - * (HeapWordSize/sizeof(jint)))); - } else { - assert((int) deadlength == instanceOopDesc::header_size(), - "size for smallest fake dead object doesn't match"); - oop(q)->set_klass(SystemDictionary::object_klass()); - } - assert((int) deadlength == oop(q)->size(), - "make sure size for fake dead object match"); + CollectedHeap::fill_with_object(q, deadlength); + oop(q)->set_mark(oop(q)->mark()->set_marked()); + assert((int) deadlength == oop(q)->size(), "bad filler object size"); // Recall that we required "q == compaction_top". return true; } else { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 1ad78f84c56..5d693905c98 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -88,6 +88,72 @@ GrowableArray* PSParallelCompact::_last_gc_live_oops_moved_to = NULL; GrowableArray * PSParallelCompact::_last_gc_live_oops_size = NULL; #endif +void SplitInfo::record(size_t src_region_idx, size_t partial_obj_size, + HeapWord* destination) +{ + assert(src_region_idx != 0, "invalid src_region_idx"); + assert(partial_obj_size != 0, "invalid partial_obj_size argument"); + assert(destination != NULL, "invalid destination argument"); + + _src_region_idx = src_region_idx; + _partial_obj_size = partial_obj_size; + _destination = destination; + + // These fields may not be updated below, so make sure they're clear. + assert(_dest_region_addr == NULL, "should have been cleared"); + assert(_first_src_addr == NULL, "should have been cleared"); + + // Determine the number of destination regions for the partial object. + HeapWord* const last_word = destination + partial_obj_size - 1; + const ParallelCompactData& sd = PSParallelCompact::summary_data(); + HeapWord* const beg_region_addr = sd.region_align_down(destination); + HeapWord* const end_region_addr = sd.region_align_down(last_word); + + if (beg_region_addr == end_region_addr) { + // One destination region. + _destination_count = 1; + if (end_region_addr == destination) { + // The destination falls on a region boundary, thus the first word of the + // partial object will be the first word copied to the destination region. + _dest_region_addr = end_region_addr; + _first_src_addr = sd.region_to_addr(src_region_idx); + } + } else { + // Two destination regions. When copied, the partial object will cross a + // destination region boundary, so a word somewhere within the partial + // object will be the first word copied to the second destination region. + _destination_count = 2; + _dest_region_addr = end_region_addr; + const size_t ofs = pointer_delta(end_region_addr, destination); + assert(ofs < _partial_obj_size, "sanity"); + _first_src_addr = sd.region_to_addr(src_region_idx) + ofs; + } +} + +void SplitInfo::clear() +{ + _src_region_idx = 0; + _partial_obj_size = 0; + _destination = NULL; + _destination_count = 0; + _dest_region_addr = NULL; + _first_src_addr = NULL; + assert(!is_valid(), "sanity"); +} + +#ifdef ASSERT +void SplitInfo::verify_clear() +{ + assert(_src_region_idx == 0, "not clear"); + assert(_partial_obj_size == 0, "not clear"); + assert(_destination == NULL, "not clear"); + assert(_destination_count == 0, "not clear"); + assert(_dest_region_addr == NULL, "not clear"); + assert(_first_src_addr == NULL, "not clear"); +} +#endif // #ifdef ASSERT + + #ifndef PRODUCT const char* PSParallelCompact::space_names[] = { "perm", "old ", "eden", "from", "to " @@ -416,21 +482,134 @@ ParallelCompactData::summarize_dense_prefix(HeapWord* beg, HeapWord* end) } } -bool ParallelCompactData::summarize(HeapWord* target_beg, HeapWord* target_end, - HeapWord* source_beg, HeapWord* source_end, - HeapWord** target_next, - HeapWord** source_next) { - // This is too strict. - // assert(region_offset(source_beg) == 0, "not RegionSize aligned"); +// Find the point at which a space can be split and, if necessary, record the +// split point. +// +// If the current src region (which overflowed the destination space) doesn't +// have a partial object, the split point is at the beginning of the current src +// region (an "easy" split, no extra bookkeeping required). +// +// If the current src region has a partial object, the split point is in the +// region where that partial object starts (call it the split_region). If +// split_region has a partial object, then the split point is just after that +// partial object (a "hard" split where we have to record the split data and +// zero the partial_obj_size field). With a "hard" split, we know that the +// partial_obj ends within split_region because the partial object that caused +// the overflow starts in split_region. If split_region doesn't have a partial +// obj, then the split is at the beginning of split_region (another "easy" +// split). +HeapWord* +ParallelCompactData::summarize_split_space(size_t src_region, + SplitInfo& split_info, + HeapWord* destination, + HeapWord* target_end, + HeapWord** target_next) +{ + assert(destination <= target_end, "sanity"); + assert(destination + _region_data[src_region].data_size() > target_end, + "region should not fit into target space"); + + size_t split_region = src_region; + HeapWord* split_destination = destination; + size_t partial_obj_size = _region_data[src_region].partial_obj_size(); + + if (destination + partial_obj_size > target_end) { + // The split point is just after the partial object (if any) in the + // src_region that contains the start of the object that overflowed the + // destination space. + // + // Find the start of the "overflow" object and set split_region to the + // region containing it. + HeapWord* const overflow_obj = _region_data[src_region].partial_obj_addr(); + split_region = addr_to_region_idx(overflow_obj); + + // Clear the source_region field of all destination regions whose first word + // came from data after the split point (a non-null source_region field + // implies a region must be filled). + // + // An alternative to the simple loop below: clear during post_compact(), + // which uses memcpy instead of individual stores, and is easy to + // parallelize. (The downside is that it clears the entire RegionData + // object as opposed to just one field.) + // + // post_compact() would have to clear the summary data up to the highest + // address that was written during the summary phase, which would be + // + // max(top, max(new_top, clear_top)) + // + // where clear_top is a new field in SpaceInfo. Would have to set clear_top + // to destination + partial_obj_size, where both have the values passed to + // this routine. + const RegionData* const sr = region(split_region); + const size_t beg_idx = + addr_to_region_idx(region_align_up(sr->destination() + + sr->partial_obj_size())); + const size_t end_idx = + addr_to_region_idx(region_align_up(destination + partial_obj_size)); + + if (TraceParallelOldGCSummaryPhase) { + gclog_or_tty->print_cr("split: clearing source_region field in [" + SIZE_FORMAT ", " SIZE_FORMAT ")", + beg_idx, end_idx); + } + for (size_t idx = beg_idx; idx < end_idx; ++idx) { + _region_data[idx].set_source_region(0); + } + + // Set split_destination and partial_obj_size to reflect the split region. + split_destination = sr->destination(); + partial_obj_size = sr->partial_obj_size(); + } + + // The split is recorded only if a partial object extends onto the region. + if (partial_obj_size != 0) { + _region_data[split_region].set_partial_obj_size(0); + split_info.record(split_region, partial_obj_size, split_destination); + } + + // Setup the continuation addresses. + *target_next = split_destination + partial_obj_size; + HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size; if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("tb=" PTR_FORMAT " te=" PTR_FORMAT " " - "sb=" PTR_FORMAT " se=" PTR_FORMAT " " - "tn=" PTR_FORMAT " sn=" PTR_FORMAT, - target_beg, target_end, - source_beg, source_end, - target_next != 0 ? *target_next : (HeapWord*) 0, - source_next != 0 ? *source_next : (HeapWord*) 0); + const char * split_type = partial_obj_size == 0 ? "easy" : "hard"; + gclog_or_tty->print_cr("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT + " pos=" SIZE_FORMAT, + split_type, source_next, split_region, + partial_obj_size); + gclog_or_tty->print_cr("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT + " tn=" PTR_FORMAT, + split_type, split_destination, + addr_to_region_idx(split_destination), + *target_next); + + if (partial_obj_size != 0) { + HeapWord* const po_beg = split_info.destination(); + HeapWord* const po_end = po_beg + split_info.partial_obj_size(); + gclog_or_tty->print_cr("%s split: " + "po_beg=" PTR_FORMAT " " SIZE_FORMAT " " + "po_end=" PTR_FORMAT " " SIZE_FORMAT, + split_type, + po_beg, addr_to_region_idx(po_beg), + po_end, addr_to_region_idx(po_end)); + } + } + + return source_next; +} + +bool ParallelCompactData::summarize(SplitInfo& split_info, + HeapWord* source_beg, HeapWord* source_end, + HeapWord** source_next, + HeapWord* target_beg, HeapWord* target_end, + HeapWord** target_next) +{ + if (TraceParallelOldGCSummaryPhase) { + HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next; + tty->print_cr("sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT + "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, + source_beg, source_end, source_next_val, + target_beg, target_end, *target_next); } size_t cur_region = addr_to_region_idx(source_beg); @@ -438,45 +617,53 @@ bool ParallelCompactData::summarize(HeapWord* target_beg, HeapWord* target_end, HeapWord *dest_addr = target_beg; while (cur_region < end_region) { - size_t words = _region_data[cur_region].data_size(); - -#if 1 - assert(pointer_delta(target_end, dest_addr) >= words, - "source region does not fit into target region"); -#else - // XXX - need some work on the corner cases here. If the region does not - // fit, then must either make sure any partial_obj from the region fits, or - // "undo" the initial part of the partial_obj that is in the previous - // region. - if (dest_addr + words >= target_end) { - // Let the caller know where to continue. - *target_next = dest_addr; - *source_next = region_to_addr(cur_region); - return false; - } -#endif // #if 1 - + // The destination must be set even if the region has no data. _region_data[cur_region].set_destination(dest_addr); - // Set the destination_count for cur_region, and if necessary, update - // source_region for a destination region. The source_region field is - // updated if cur_region is the first (left-most) region to be copied to a - // destination region. - // - // The destination_count calculation is a bit subtle. A region that has - // data that compacts into itself does not count itself as a destination. - // This maintains the invariant that a zero count means the region is - // available and can be claimed and then filled. + size_t words = _region_data[cur_region].data_size(); if (words > 0) { + // If cur_region does not fit entirely into the target space, find a point + // at which the source space can be 'split' so that part is copied to the + // target space and the rest is copied elsewhere. + if (dest_addr + words > target_end) { + assert(source_next != NULL, "source_next is NULL when splitting"); + *source_next = summarize_split_space(cur_region, split_info, dest_addr, + target_end, target_next); + return false; + } + + // Compute the destination_count for cur_region, and if necessary, update + // source_region for a destination region. The source_region field is + // updated if cur_region is the first (left-most) region to be copied to a + // destination region. + // + // The destination_count calculation is a bit subtle. A region that has + // data that compacts into itself does not count itself as a destination. + // This maintains the invariant that a zero count means the region is + // available and can be claimed and then filled. + uint destination_count = 0; + if (split_info.is_split(cur_region)) { + // The current region has been split: the partial object will be copied + // to one destination space and the remaining data will be copied to + // another destination space. Adjust the initial destination_count and, + // if necessary, set the source_region field if the partial object will + // cross a destination region boundary. + destination_count = split_info.destination_count(); + if (destination_count == 2) { + size_t dest_idx = addr_to_region_idx(split_info.dest_region_addr()); + _region_data[dest_idx].set_source_region(cur_region); + } + } + HeapWord* const last_addr = dest_addr + words - 1; const size_t dest_region_1 = addr_to_region_idx(dest_addr); const size_t dest_region_2 = addr_to_region_idx(last_addr); -#if 0 + // Initially assume that the destination regions will be the same and // adjust the value below if necessary. Under this assumption, if // cur_region == dest_region_2, then cur_region will be compacted // completely into itself. - uint destination_count = cur_region == dest_region_2 ? 0 : 1; + destination_count += cur_region == dest_region_2 ? 0 : 1; if (dest_region_1 != dest_region_2) { // Destination regions differ; adjust destination_count. destination_count += 1; @@ -487,25 +674,6 @@ bool ParallelCompactData::summarize(HeapWord* target_beg, HeapWord* target_end, // region. _region_data[dest_region_1].set_source_region(cur_region); } -#else - // Initially assume that the destination regions will be different and - // adjust the value below if necessary. Under this assumption, if - // cur_region == dest_region2, then cur_region will be compacted partially - // into dest_region_1 and partially into itself. - uint destination_count = cur_region == dest_region_2 ? 1 : 2; - if (dest_region_1 != dest_region_2) { - // Data from cur_region will be copied to the start of dest_region_2. - _region_data[dest_region_2].set_source_region(cur_region); - } else { - // Destination regions are the same; adjust destination_count. - destination_count -= 1; - if (region_offset(dest_addr) == 0) { - // Data from cur_region will be copied to the start of the destination - // region. - _region_data[dest_region_1].set_source_region(cur_region); - } - } -#endif // #if 0 _region_data[cur_region].set_destination_count(destination_count); _region_data[cur_region].set_data_location(region_to_addr(cur_region)); @@ -558,7 +726,7 @@ HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr) { size_t live_to_left = bitmap->live_words_in_range(search_start, oop(addr)); result += partial_obj_size + live_to_left; - assert(result <= addr, "object cannot move to the right"); + DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result);) return result; } @@ -749,6 +917,13 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) const size_t end_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(max_top)); _summary_data.clear_range(beg_region, end_region); + + // Clear the data used to 'split' regions. + SplitInfo& split_info = _space_info[id].split_info(); + if (split_info.is_valid()) { + split_info.clear(); + } + DEBUG_ONLY(split_info.verify_clear();) } void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) @@ -807,10 +982,11 @@ void PSParallelCompact::post_compact() { TraceTime tm("post compact", print_phases(), true, gclog_or_tty); - // Clear the marking bitmap and summary data and update top() in each space. for (unsigned int id = perm_space_id; id < last_space_id; ++id) { + // Clear the marking bitmap, summary data and split info. clear_data_covering_space(SpaceId(id)); - _space_info[id].space()->set_top(_space_info[id].new_top()); + // Update top(). Must be done after clearing the bitmap and summary data. + _space_info[id].publish_new_top(); } MutableSpace* const eden_space = _space_info[eden_space_id].space(); @@ -1151,6 +1327,13 @@ HeapWord* PSParallelCompact::compute_dense_prefix(const SpaceId id, bool maximum_compaction) { + if (ParallelOldGCSplitALot) { + if (_space_info[id].dense_prefix() != _space_info[id].space()->bottom()) { + // The value was chosen to provoke splitting a young gen space; use it. + return _space_info[id].dense_prefix(); + } + } + const size_t region_size = ParallelCompactData::RegionSize; const ParallelCompactData& sd = summary_data(); @@ -1239,16 +1422,221 @@ PSParallelCompact::compute_dense_prefix(const SpaceId id, return sd.region_to_addr(best_cp); } +#ifndef PRODUCT +void +PSParallelCompact::fill_with_live_objects(SpaceId id, HeapWord* const start, + size_t words) +{ + if (TraceParallelOldGCSummaryPhase) { + tty->print_cr("fill_with_live_objects [" PTR_FORMAT " " PTR_FORMAT ") " + SIZE_FORMAT, start, start + words, words); + } + + ObjectStartArray* const start_array = _space_info[id].start_array(); + CollectedHeap::fill_with_objects(start, words); + for (HeapWord* p = start; p < start + words; p += oop(p)->size()) { + _mark_bitmap.mark_obj(p, words); + _summary_data.add_obj(p, words); + start_array->allocate_block(p); + } +} + +void +PSParallelCompact::summarize_new_objects(SpaceId id, HeapWord* start) +{ + ParallelCompactData& sd = summary_data(); + MutableSpace* space = _space_info[id].space(); + + // Find the source and destination start addresses. + HeapWord* const src_addr = sd.region_align_down(start); + HeapWord* dst_addr; + if (src_addr < start) { + dst_addr = sd.addr_to_region_ptr(src_addr)->destination(); + } else if (src_addr > space->bottom()) { + // The start (the original top() value) is aligned to a region boundary so + // the associated region does not have a destination. Compute the + // destination from the previous region. + RegionData* const cp = sd.addr_to_region_ptr(src_addr) - 1; + dst_addr = cp->destination() + cp->data_size(); + } else { + // Filling the entire space. + dst_addr = space->bottom(); + } + assert(dst_addr != NULL, "sanity"); + + // Update the summary data. + bool result = _summary_data.summarize(_space_info[id].split_info(), + src_addr, space->top(), NULL, + dst_addr, space->end(), + _space_info[id].new_top_addr()); + assert(result, "should not fail: bad filler object size"); +} + +void +PSParallelCompact::provoke_split_fill_survivor(SpaceId id) +{ + if (total_invocations() % (ParallelOldGCSplitInterval * 3) != 0) { + return; + } + + MutableSpace* const space = _space_info[id].space(); + if (space->is_empty()) { + HeapWord* b = space->bottom(); + HeapWord* t = b + space->capacity_in_words() / 2; + space->set_top(t); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + + size_t obj_len = 8; + while (b + obj_len <= t) { + CollectedHeap::fill_with_object(b, obj_len); + mark_bitmap()->mark_obj(b, obj_len); + summary_data().add_obj(b, obj_len); + b += obj_len; + obj_len = (obj_len & 0x18) + 8; // 8 16 24 32 8 16 24 32 ... + } + if (b < t) { + // The loop didn't completely fill to t (top); adjust top downward. + space->set_top(b); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + } + + HeapWord** nta = _space_info[id].new_top_addr(); + bool result = summary_data().summarize(_space_info[id].split_info(), + space->bottom(), space->top(), NULL, + space->bottom(), space->end(), nta); + assert(result, "space must fit into itself"); + } +} + +void +PSParallelCompact::provoke_split(bool & max_compaction) +{ + if (total_invocations() % ParallelOldGCSplitInterval != 0) { + return; + } + + const size_t region_size = ParallelCompactData::RegionSize; + ParallelCompactData& sd = summary_data(); + + MutableSpace* const eden_space = _space_info[eden_space_id].space(); + MutableSpace* const from_space = _space_info[from_space_id].space(); + const size_t eden_live = pointer_delta(eden_space->top(), + _space_info[eden_space_id].new_top()); + const size_t from_live = pointer_delta(from_space->top(), + _space_info[from_space_id].new_top()); + + const size_t min_fill_size = CollectedHeap::min_fill_size(); + const size_t eden_free = pointer_delta(eden_space->end(), eden_space->top()); + const size_t eden_fillable = eden_free >= min_fill_size ? eden_free : 0; + const size_t from_free = pointer_delta(from_space->end(), from_space->top()); + const size_t from_fillable = from_free >= min_fill_size ? from_free : 0; + + // Choose the space to split; need at least 2 regions live (or fillable). + SpaceId id; + MutableSpace* space; + size_t live_words; + size_t fill_words; + if (eden_live + eden_fillable >= region_size * 2) { + id = eden_space_id; + space = eden_space; + live_words = eden_live; + fill_words = eden_fillable; + } else if (from_live + from_fillable >= region_size * 2) { + id = from_space_id; + space = from_space; + live_words = from_live; + fill_words = from_fillable; + } else { + return; // Give up. + } + assert(fill_words == 0 || fill_words >= min_fill_size, "sanity"); + + if (live_words < region_size * 2) { + // Fill from top() to end() w/live objects of mixed sizes. + HeapWord* const fill_start = space->top(); + live_words += fill_words; + + space->set_top(fill_start + fill_words); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + + HeapWord* cur_addr = fill_start; + while (fill_words > 0) { + const size_t r = (size_t)os::random() % (region_size / 2) + min_fill_size; + size_t cur_size = MIN2(align_object_size_(r), fill_words); + if (fill_words - cur_size < min_fill_size) { + cur_size = fill_words; // Avoid leaving a fragment too small to fill. + } + + CollectedHeap::fill_with_object(cur_addr, cur_size); + mark_bitmap()->mark_obj(cur_addr, cur_size); + sd.add_obj(cur_addr, cur_size); + + cur_addr += cur_size; + fill_words -= cur_size; + } + + summarize_new_objects(id, fill_start); + } + + max_compaction = false; + + // Manipulate the old gen so that it has room for about half of the live data + // in the target young gen space (live_words / 2). + id = old_space_id; + space = _space_info[id].space(); + const size_t free_at_end = space->free_in_words(); + const size_t free_target = align_object_size(live_words / 2); + const size_t dead = pointer_delta(space->top(), _space_info[id].new_top()); + + if (free_at_end >= free_target + min_fill_size) { + // Fill space above top() and set the dense prefix so everything survives. + HeapWord* const fill_start = space->top(); + const size_t fill_size = free_at_end - free_target; + space->set_top(space->top() + fill_size); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + fill_with_live_objects(id, fill_start, fill_size); + summarize_new_objects(id, fill_start); + _space_info[id].set_dense_prefix(sd.region_align_down(space->top())); + } else if (dead + free_at_end > free_target) { + // Find a dense prefix that makes the right amount of space available. + HeapWord* cur = sd.region_align_down(space->top()); + HeapWord* cur_destination = sd.addr_to_region_ptr(cur)->destination(); + size_t dead_to_right = pointer_delta(space->end(), cur_destination); + while (dead_to_right < free_target) { + cur -= region_size; + cur_destination = sd.addr_to_region_ptr(cur)->destination(); + dead_to_right = pointer_delta(space->end(), cur_destination); + } + _space_info[id].set_dense_prefix(cur); + } +} +#endif // #ifndef PRODUCT + void PSParallelCompact::summarize_spaces_quick() { for (unsigned int i = 0; i < last_space_id; ++i) { const MutableSpace* space = _space_info[i].space(); - bool result = _summary_data.summarize(space->bottom(), space->end(), - space->bottom(), space->top(), - _space_info[i].new_top_addr()); - assert(result, "should never fail"); + HeapWord** nta = _space_info[i].new_top_addr(); + bool result = _summary_data.summarize(_space_info[i].split_info(), + space->bottom(), space->top(), NULL, + space->bottom(), space->end(), nta); + assert(result, "space must fit into itself"); _space_info[i].set_dense_prefix(space->bottom()); } + +#ifndef PRODUCT + if (ParallelOldGCSplitALot) { + provoke_split_fill_survivor(to_space_id); + } +#endif // #ifndef PRODUCT } void PSParallelCompact::fill_dense_prefix_end(SpaceId id) @@ -1308,8 +1696,7 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) } #endif // #ifdef _LP64 - MemRegion region(obj_beg, obj_len); - SharedHeap::fill_region_with_object(region); + CollectedHeap::fill_with_object(obj_beg, obj_len); _mark_bitmap.mark_obj(obj_beg, obj_len); _summary_data.add_obj(obj_beg, obj_len); assert(start_array(id) != NULL, "sanity"); @@ -1317,12 +1704,24 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) } } +void +PSParallelCompact::clear_source_region(HeapWord* beg_addr, HeapWord* end_addr) +{ + RegionData* const beg_ptr = _summary_data.addr_to_region_ptr(beg_addr); + HeapWord* const end_aligned_up = _summary_data.region_align_up(end_addr); + RegionData* const end_ptr = _summary_data.addr_to_region_ptr(end_aligned_up); + for (RegionData* cur = beg_ptr; cur < end_ptr; ++cur) { + cur->set_source_region(0); + } +} + void PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) { assert(id < last_space_id, "id out of range"); - assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom(), - "should have been set in summarize_spaces_quick()"); + assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom() || + ParallelOldGCSplitALot && id == old_space_id, + "should have been reset in summarize_spaces_quick()"); const MutableSpace* space = _space_info[id].space(); if (_space_info[id].new_top() != space->bottom()) { @@ -1338,20 +1737,24 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) } #endif // #ifndef PRODUCT - // If dead space crosses the dense prefix boundary, it is (at least - // partially) filled with a dummy object, marked live and added to the - // summary data. This simplifies the copy/update phase and must be done - // before the final locations of objects are determined, to prevent leaving - // a fragment of dead space that is too small to fill with an object. + // Recompute the summary data, taking into account the dense prefix. If + // every last byte will be reclaimed, then the existing summary data which + // compacts everything can be left in place. if (!maximum_compaction && dense_prefix_end != space->bottom()) { + // If dead space crosses the dense prefix boundary, it is (at least + // partially) filled with a dummy object, marked live and added to the + // summary data. This simplifies the copy/update phase and must be done + // before the final locations of objects are determined, to prevent + // leaving a fragment of dead space that is too small to fill. fill_dense_prefix_end(id); - } - // Compute the destination of each Region, and thus each object. - _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end); - _summary_data.summarize(dense_prefix_end, space->end(), - dense_prefix_end, space->top(), - _space_info[id].new_top_addr()); + // Compute the destination of each Region, and thus each object. + _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end); + _summary_data.summarize(_space_info[id].split_info(), + dense_prefix_end, space->top(), NULL, + dense_prefix_end, space->end(), + _space_info[id].new_top_addr()); + } } if (TraceParallelOldGCSummaryPhase) { @@ -1371,6 +1774,30 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) } } +#ifndef PRODUCT +void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, + HeapWord* dst_beg, HeapWord* dst_end, + SpaceId src_space_id, + HeapWord* src_beg, HeapWord* src_end) +{ + if (TraceParallelOldGCSummaryPhase) { + tty->print_cr("summarizing %d [%s] into %d [%s]: " + "src=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT " " + "dst=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT, + src_space_id, space_names[src_space_id], + dst_space_id, space_names[dst_space_id], + src_beg, src_end, + _summary_data.addr_to_region_idx(src_beg), + _summary_data.addr_to_region_idx(src_end), + dst_beg, dst_end, + _summary_data.addr_to_region_idx(dst_beg), + _summary_data.addr_to_region_idx(dst_end)); + } +} +#endif // #ifndef PRODUCT + void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { @@ -1403,57 +1830,80 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, // The amount of live data that will end up in old space (assuming it fits). size_t old_space_total_live = 0; - unsigned int id; - for (id = old_space_id; id < last_space_id; ++id) { + assert(perm_space_id < old_space_id, "should not count perm data here"); + for (unsigned int id = old_space_id; id < last_space_id; ++id) { old_space_total_live += pointer_delta(_space_info[id].new_top(), _space_info[id].space()->bottom()); } - const MutableSpace* old_space = _space_info[old_space_id].space(); - if (old_space_total_live > old_space->capacity_in_words()) { + MutableSpace* const old_space = _space_info[old_space_id].space(); + const size_t old_capacity = old_space->capacity_in_words(); + if (old_space_total_live > old_capacity) { // XXX - should also try to expand maximum_compaction = true; - } else if (!UseParallelOldGCDensePrefix) { - maximum_compaction = true; } +#ifndef PRODUCT + if (ParallelOldGCSplitALot && old_space_total_live < old_capacity) { + provoke_split(maximum_compaction); + } +#endif // #ifndef PRODUCT // Permanent and Old generations. summarize_space(perm_space_id, maximum_compaction); summarize_space(old_space_id, maximum_compaction); - // Summarize the remaining spaces (those in the young gen) into old space. If - // the live data from a space doesn't fit, the existing summarization is left - // intact, so the data is compacted down within the space itself. - HeapWord** new_top_addr = _space_info[old_space_id].new_top_addr(); - HeapWord* const target_space_end = old_space->end(); - for (id = eden_space_id; id < last_space_id; ++id) { + // Summarize the remaining spaces in the young gen. The initial target space + // is the old gen. If a space does not fit entirely into the target, then the + // remainder is compacted into the space itself and that space becomes the new + // target. + SpaceId dst_space_id = old_space_id; + HeapWord* dst_space_end = old_space->end(); + HeapWord** new_top_addr = _space_info[dst_space_id].new_top_addr(); + for (unsigned int id = eden_space_id; id < last_space_id; ++id) { const MutableSpace* space = _space_info[id].space(); const size_t live = pointer_delta(_space_info[id].new_top(), space->bottom()); - const size_t available = pointer_delta(target_space_end, *new_top_addr); + const size_t available = pointer_delta(dst_space_end, *new_top_addr); + + NOT_PRODUCT(summary_phase_msg(dst_space_id, *new_top_addr, dst_space_end, + SpaceId(id), space->bottom(), space->top());) if (live > 0 && live <= available) { // All the live data will fit. - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("summarizing %d into old_space @ " PTR_FORMAT, - id, *new_top_addr); - } - _summary_data.summarize(*new_top_addr, target_space_end, - space->bottom(), space->top(), - new_top_addr); - - // Clear the source_region field for each region in the space. - HeapWord* const new_top = _space_info[id].new_top(); - HeapWord* const clear_end = _summary_data.region_align_up(new_top); - RegionData* beg_region = - _summary_data.addr_to_region_ptr(space->bottom()); - RegionData* end_region = _summary_data.addr_to_region_ptr(clear_end); - while (beg_region < end_region) { - beg_region->set_source_region(0); - ++beg_region; - } + bool done = _summary_data.summarize(_space_info[id].split_info(), + space->bottom(), space->top(), + NULL, + *new_top_addr, dst_space_end, + new_top_addr); + assert(done, "space must fit into old gen"); // Reset the new_top value for the space. _space_info[id].set_new_top(space->bottom()); + } else if (live > 0) { + // Attempt to fit part of the source space into the target space. + HeapWord* next_src_addr = NULL; + bool done = _summary_data.summarize(_space_info[id].split_info(), + space->bottom(), space->top(), + &next_src_addr, + *new_top_addr, dst_space_end, + new_top_addr); + assert(!done, "space should not fit into old gen"); + assert(next_src_addr != NULL, "sanity"); + + // The source space becomes the new target, so the remainder is compacted + // within the space itself. + dst_space_id = SpaceId(id); + dst_space_end = space->end(); + new_top_addr = _space_info[id].new_top_addr(); + NOT_PRODUCT(summary_phase_msg(dst_space_id, + space->bottom(), dst_space_end, + SpaceId(id), next_src_addr, space->top());) + done = _summary_data.summarize(_space_info[id].split_info(), + next_src_addr, space->top(), + NULL, + space->bottom(), dst_space_end, + new_top_addr); + assert(done, "space must fit when compacted into itself"); + assert(*new_top_addr <= space->top(), "usage should not grow"); } } @@ -1807,9 +2257,14 @@ bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_po // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); - MemRegion old_gen_unused(old_space->top(), old_space->end()); - if (!old_gen_unused.is_empty()) { - SharedHeap::fill_region_with_object(old_gen_unused); + HeapWord* const unused_start = old_space->top(); + size_t const unused_words = pointer_delta(old_space->end(), unused_start); + + if (unused_words > 0) { + if (unused_words < CollectedHeap::min_fill_size()) { + return false; // If the old gen cannot be filled, must give up. + } + CollectedHeap::fill_with_objects(unused_start, unused_words); } // Take the live data from eden and set both top and end in the old gen to @@ -1825,9 +2280,8 @@ bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_po // Update the object start array for the filler object and the data from eden. ObjectStartArray* const start_array = old_gen->start_array(); - HeapWord* const start = old_gen_unused.start(); - for (HeapWord* addr = start; addr < new_top; addr += oop(addr)->size()) { - start_array->allocate_block(addr); + for (HeapWord* p = unused_start; p < new_top; p += oop(p)->size()) { + start_array->allocate_block(p); } // Could update the promoted average here, but it is not typically updated at @@ -2048,14 +2502,13 @@ void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, // regions in the dense prefix. Assume that 1 gc thread // will work on opening the gaps and the remaining gc threads // will work on the dense prefix. - SpaceId space_id = old_space_id; - while (space_id != last_space_id) { + unsigned int space_id; + for (space_id = old_space_id; space_id < last_space_id; ++ space_id) { HeapWord* const dense_prefix_end = _space_info[space_id].dense_prefix(); const MutableSpace* const space = _space_info[space_id].space(); if (dense_prefix_end == space->bottom()) { // There is no dense prefix for this space. - space_id = next_compaction_space_id(space_id); continue; } @@ -2105,23 +2558,20 @@ void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, // region_index_end is not processed size_t region_index_end = MIN2(region_index_start + regions_per_thread, region_index_end_dense_prefix); - q->enqueue(new UpdateDensePrefixTask( - space_id, - region_index_start, - region_index_end)); + q->enqueue(new UpdateDensePrefixTask(SpaceId(space_id), + region_index_start, + region_index_end)); region_index_start = region_index_end; } } // This gets any part of the dense prefix that did not // fit evenly. if (region_index_start < region_index_end_dense_prefix) { - q->enqueue(new UpdateDensePrefixTask( - space_id, - region_index_start, - region_index_end_dense_prefix)); + q->enqueue(new UpdateDensePrefixTask(SpaceId(space_id), + region_index_start, + region_index_end_dense_prefix)); } - space_id = next_compaction_space_id(space_id); - } // End tasks for dense prefix + } } void PSParallelCompact::enqueue_region_stealing_tasks( @@ -2567,16 +3017,24 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count) return m->bit_to_addr(cur_beg); } -HeapWord* -PSParallelCompact::first_src_addr(HeapWord* const dest_addr, - size_t src_region_idx) +HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, + SpaceId src_space_id, + size_t src_region_idx) { - ParMarkBitMap* const bitmap = mark_bitmap(); + assert(summary_data().is_region_aligned(dest_addr), "not aligned"); + + const SplitInfo& split_info = _space_info[src_space_id].split_info(); + if (split_info.dest_region_addr() == dest_addr) { + // The partial object ending at the split point contains the first word to + // be copied to dest_addr. + return split_info.first_src_addr(); + } + const ParallelCompactData& sd = summary_data(); + ParMarkBitMap* const bitmap = mark_bitmap(); const size_t RegionSize = ParallelCompactData::RegionSize; assert(sd.is_region_aligned(dest_addr), "not aligned"); - const RegionData* const src_region_ptr = sd.region(src_region_idx); const size_t partial_obj_size = src_region_ptr->partial_obj_size(); HeapWord* const src_region_destination = src_region_ptr->destination(); @@ -2625,19 +3083,34 @@ PSParallelCompact::first_src_addr(HeapWord* const dest_addr, } void PSParallelCompact::decrement_destination_counts(ParCompactionManager* cm, + SpaceId src_space_id, size_t beg_region, HeapWord* end_addr) { ParallelCompactData& sd = summary_data(); + +#ifdef ASSERT + MutableSpace* const src_space = _space_info[src_space_id].space(); + HeapWord* const beg_addr = sd.region_to_addr(beg_region); + assert(src_space->contains(beg_addr) || beg_addr == src_space->end(), + "src_space_id does not match beg_addr"); + assert(src_space->contains(end_addr) || end_addr == src_space->end(), + "src_space_id does not match end_addr"); +#endif // #ifdef ASSERT + RegionData* const beg = sd.region(beg_region); - HeapWord* const end_addr_aligned_up = sd.region_align_up(end_addr); - RegionData* const end = sd.addr_to_region_ptr(end_addr_aligned_up); - size_t cur_idx = beg_region; - for (RegionData* cur = beg; cur < end; ++cur, ++cur_idx) { + RegionData* const end = sd.addr_to_region_ptr(sd.region_align_up(end_addr)); + + // Regions up to new_top() are enqueued if they become available. + HeapWord* const new_top = _space_info[src_space_id].new_top(); + RegionData* const enqueue_end = + sd.addr_to_region_ptr(sd.region_align_up(new_top)); + + for (RegionData* cur = beg; cur < end; ++cur) { assert(cur->data_size() > 0, "region must have live data"); cur->decrement_destination_count(); - if (cur_idx <= cur->source_region() && cur->available() && cur->claim()) { - cm->save_for_processing(cur_idx); + if (cur < enqueue_end && cur->available() && cur->claim()) { + cm->save_for_processing(sd.region(cur)); } } } @@ -2737,7 +3210,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, size_t region_idx) HeapWord* src_space_top = _space_info[src_space_id].space()->top(); MoveAndUpdateClosure closure(bitmap, cm, start_array, dest_addr, words); - closure.set_source(first_src_addr(dest_addr, src_region_idx)); + closure.set_source(first_src_addr(dest_addr, src_space_id, src_region_idx)); // Adjust src_region_idx to prepare for decrementing destination counts (the // destination count is not decremented when a region is copied to itself). @@ -2752,7 +3225,8 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, size_t region_idx) HeapWord* const old_src_addr = closure.source(); closure.copy_partial_obj(); if (closure.is_full()) { - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_deferred_obj_addr(NULL); region_ptr->set_completed(); return; @@ -2761,7 +3235,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, size_t region_idx) HeapWord* const end_addr = sd.region_align_down(closure.source()); if (sd.region_align_down(old_src_addr) != end_addr) { // The partial object was copied from more than one source region. - decrement_destination_counts(cm, src_region_idx, end_addr); + decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr); // Move to the next source region, possibly switching spaces as well. All // args except end_addr may be modified. @@ -2801,19 +3275,21 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, size_t region_idx) region_ptr->set_deferred_obj_addr(closure.destination()); status = closure.copy_until_full(); // copies from closure.source() - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_completed(); return; } if (status == ParMarkBitMap::full) { - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_deferred_obj_addr(NULL); region_ptr->set_completed(); return; } - decrement_destination_counts(cm, src_region_idx, end_addr); + decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr); // Move to the next source region, possibly switching spaces as well. All // args except end_addr may be modified. @@ -2892,7 +3368,7 @@ void PSParallelCompact::reset_millis_since_last_gc() { ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full() { if (source() != destination()) { - assert(source() > destination(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words_remaining()); } update_state(words_remaining()); @@ -2913,7 +3389,7 @@ void MoveAndUpdateClosure::copy_partial_obj() // This test is necessary; if omitted, the pointer updates to a partial object // that crosses the dense prefix boundary could be overwritten. if (source() != destination()) { - assert(source() > destination(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words); } update_state(words); @@ -2938,7 +3414,7 @@ MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { } if (destination() != source()) { - assert(destination() < source(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words); } @@ -3008,34 +3484,3 @@ void PSParallelCompact::compact_prologue() { summary_data().calc_new_pointer(Universe::intArrayKlassObj()); } -// The initial implementation of this method created a field -// _next_compaction_space_id in SpaceInfo and initialized -// that field in SpaceInfo::initialize_space_info(). That -// required that _next_compaction_space_id be declared a -// SpaceId in SpaceInfo and that would have required that -// either SpaceId be declared in a separate class or that -// it be declared in SpaceInfo. It didn't seem consistent -// to declare it in SpaceInfo (didn't really fit logically). -// Alternatively, defining a separate class to define SpaceId -// seem excessive. This implementation is simple and localizes -// the knowledge. - -PSParallelCompact::SpaceId -PSParallelCompact::next_compaction_space_id(SpaceId id) { - assert(id < last_space_id, "id out of range"); - switch (id) { - case perm_space_id : - return last_space_id; - case old_space_id : - return eden_space_id; - case eden_space_id : - return from_space_id; - case from_space_id : - return to_space_id; - case to_space_id : - return last_space_id; - default: - assert(false, "Bad space id"); - return last_space_id; - } -} diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp index 7ca899956f4..eb9ed0fc86b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp @@ -36,6 +36,123 @@ class PreGCValues; class MoveAndUpdateClosure; class RefProcTaskExecutor; +// The SplitInfo class holds the information needed to 'split' a source region +// so that the live data can be copied to two destination *spaces*. Normally, +// all the live data in a region is copied to a single destination space (e.g., +// everything live in a region in eden is copied entirely into the old gen). +// However, when the heap is nearly full, all the live data in eden may not fit +// into the old gen. Copying only some of the regions from eden to old gen +// requires finding a region that does not contain a partial object (i.e., no +// live object crosses the region boundary) somewhere near the last object that +// does fit into the old gen. Since it's not always possible to find such a +// region, splitting is necessary for predictable behavior. +// +// A region is always split at the end of the partial object. This avoids +// additional tests when calculating the new location of a pointer, which is a +// very hot code path. The partial object and everything to its left will be +// copied to another space (call it dest_space_1). The live data to the right +// of the partial object will be copied either within the space itself, or to a +// different destination space (distinct from dest_space_1). +// +// Split points are identified during the summary phase, when region +// destinations are computed: data about the split, including the +// partial_object_size, is recorded in a SplitInfo record and the +// partial_object_size field in the summary data is set to zero. The zeroing is +// possible (and necessary) since the partial object will move to a different +// destination space than anything to its right, thus the partial object should +// not affect the locations of any objects to its right. +// +// The recorded data is used during the compaction phase, but only rarely: when +// the partial object on the split region will be copied across a destination +// region boundary. This test is made once each time a region is filled, and is +// a simple address comparison, so the overhead is negligible (see +// PSParallelCompact::first_src_addr()). +// +// Notes: +// +// Only regions with partial objects are split; a region without a partial +// object does not need any extra bookkeeping. +// +// At most one region is split per space, so the amount of data required is +// constant. +// +// A region is split only when the destination space would overflow. Once that +// happens, the destination space is abandoned and no other data (even from +// other source spaces) is targeted to that destination space. Abandoning the +// destination space may leave a somewhat large unused area at the end, if a +// large object caused the overflow. +// +// Future work: +// +// More bookkeeping would be required to continue to use the destination space. +// The most general solution would allow data from regions in two different +// source spaces to be "joined" in a single destination region. At the very +// least, additional code would be required in next_src_region() to detect the +// join and skip to an out-of-order source region. If the join region was also +// the last destination region to which a split region was copied (the most +// likely case), then additional work would be needed to get fill_region() to +// stop iteration and switch to a new source region at the right point. Basic +// idea would be to use a fake value for the top of the source space. It is +// doable, if a bit tricky. +// +// A simpler (but less general) solution would fill the remainder of the +// destination region with a dummy object and continue filling the next +// destination region. + +class SplitInfo +{ +public: + // Return true if this split info is valid (i.e., if a split has been + // recorded). The very first region cannot have a partial object and thus is + // never split, so 0 is the 'invalid' value. + bool is_valid() const { return _src_region_idx > 0; } + + // Return true if this split holds data for the specified source region. + inline bool is_split(size_t source_region) const; + + // The index of the split region, the size of the partial object on that + // region and the destination of the partial object. + size_t src_region_idx() const { return _src_region_idx; } + size_t partial_obj_size() const { return _partial_obj_size; } + HeapWord* destination() const { return _destination; } + + // The destination count of the partial object referenced by this split + // (either 1 or 2). This must be added to the destination count of the + // remainder of the source region. + unsigned int destination_count() const { return _destination_count; } + + // If a word within the partial object will be written to the first word of a + // destination region, this is the address of the destination region; + // otherwise this is NULL. + HeapWord* dest_region_addr() const { return _dest_region_addr; } + + // If a word within the partial object will be written to the first word of a + // destination region, this is the address of that word within the partial + // object; otherwise this is NULL. + HeapWord* first_src_addr() const { return _first_src_addr; } + + // Record the data necessary to split the region src_region_idx. + void record(size_t src_region_idx, size_t partial_obj_size, + HeapWord* destination); + + void clear(); + + DEBUG_ONLY(void verify_clear();) + +private: + size_t _src_region_idx; + size_t _partial_obj_size; + HeapWord* _destination; + unsigned int _destination_count; + HeapWord* _dest_region_addr; + HeapWord* _first_src_addr; +}; + +inline bool SplitInfo::is_split(size_t region_idx) const +{ + return _src_region_idx == region_idx && is_valid(); +} + class SpaceInfo { public: @@ -58,18 +175,23 @@ class SpaceInfo // is no start array. ObjectStartArray* start_array() const { return _start_array; } + SplitInfo& split_info() { return _split_info; } + void set_space(MutableSpace* s) { _space = s; } void set_new_top(HeapWord* addr) { _new_top = addr; } void set_min_dense_prefix(HeapWord* addr) { _min_dense_prefix = addr; } void set_dense_prefix(HeapWord* addr) { _dense_prefix = addr; } void set_start_array(ObjectStartArray* s) { _start_array = s; } + void publish_new_top() const { _space->set_top(_new_top); } + private: MutableSpace* _space; HeapWord* _new_top; HeapWord* _min_dense_prefix; HeapWord* _dense_prefix; ObjectStartArray* _start_array; + SplitInfo _split_info; }; class ParallelCompactData @@ -230,9 +352,14 @@ public: // must be region-aligned; end need not be. void summarize_dense_prefix(HeapWord* beg, HeapWord* end); - bool summarize(HeapWord* target_beg, HeapWord* target_end, + HeapWord* summarize_split_space(size_t src_region, SplitInfo& split_info, + HeapWord* destination, HeapWord* target_end, + HeapWord** target_next); + bool summarize(SplitInfo& split_info, HeapWord* source_beg, HeapWord* source_end, - HeapWord** target_next, HeapWord** source_next = 0); + HeapWord** source_next, + HeapWord* target_beg, HeapWord* target_end, + HeapWord** target_next); void clear(); void clear_range(size_t beg_region, size_t end_region); @@ -838,13 +965,31 @@ class PSParallelCompact : AllStatic { // non-empty. static void fill_dense_prefix_end(SpaceId id); + // Clear the summary data source_region field for the specified addresses. + static void clear_source_region(HeapWord* beg_addr, HeapWord* end_addr); + +#ifndef PRODUCT + // Routines to provoke splitting a young gen space (ParallelOldGCSplitALot). + + // Fill the region [start, start + words) with live object(s). Only usable + // for the old and permanent generations. + static void fill_with_live_objects(SpaceId id, HeapWord* const start, + size_t words); + // Include the new objects in the summary data. + static void summarize_new_objects(SpaceId id, HeapWord* start); + + // Add live objects to a survivor space since it's rare that both survivors + // are non-empty. + static void provoke_split_fill_survivor(SpaceId id); + + // Add live objects and/or choose the dense prefix to provoke splitting. + static void provoke_split(bool & maximum_compaction); +#endif + static void summarize_spaces_quick(); static void summarize_space(SpaceId id, bool maximum_compaction); static void summary_phase(ParCompactionManager* cm, bool maximum_compaction); - // The space that is compacted after space_id. - static SpaceId next_compaction_space_id(SpaceId space_id); - // Adjust addresses in roots. Does not adjust addresses in heap. static void adjust_roots(); @@ -999,6 +1144,7 @@ class PSParallelCompact : AllStatic { // Return the address of the word to be copied to dest_addr, which must be // aligned to a region boundary. static HeapWord* first_src_addr(HeapWord* const dest_addr, + SpaceId src_space_id, size_t src_region_idx); // Determine the next source region, set closure.source() to the start of the @@ -1012,8 +1158,10 @@ class PSParallelCompact : AllStatic { HeapWord* end_addr); // Decrement the destination count for each non-empty source region in the - // range [beg_region, region(region_align_up(end_addr))). + // range [beg_region, region(region_align_up(end_addr))). If the destination + // count for a region goes to 0 and it needs to be filled, enqueue it. static void decrement_destination_counts(ParCompactionManager* cm, + SpaceId src_space_id, size_t beg_region, HeapWord* end_addr); @@ -1081,9 +1229,15 @@ class PSParallelCompact : AllStatic { const SpaceId id, const bool maximum_compaction, HeapWord* const addr); + static void summary_phase_msg(SpaceId dst_space_id, + HeapWord* dst_beg, HeapWord* dst_end, + SpaceId src_space_id, + HeapWord* src_beg, HeapWord* src_end); #endif // #ifndef PRODUCT #ifdef ASSERT + // Sanity check the new location of a word in the heap. + static inline void check_new_location(HeapWord* old_addr, HeapWord* new_addr); // Verify that all the regions have been emptied. static void verify_complete(SpaceId space_id); #endif // #ifdef ASSERT @@ -1251,6 +1405,15 @@ inline void PSParallelCompact::adjust_pointer(T* p, } } +#ifdef ASSERT +inline void +PSParallelCompact::check_new_location(HeapWord* old_addr, HeapWord* new_addr) +{ + assert(old_addr >= new_addr || space_id(old_addr) != space_id(new_addr), + "must move left or to a different space"); +} +#endif // ASSERT + class MoveAndUpdateClosure: public ParMarkBitMapClosure { public: inline MoveAndUpdateClosure(ParMarkBitMap* bitmap, ParCompactionManager* cm, @@ -1324,31 +1487,28 @@ inline void UpdateOnlyClosure::do_addr(HeapWord* addr) oop(addr)->update_contents(compaction_manager()); } -class FillClosure: public ParMarkBitMapClosure { - public: +class FillClosure: public ParMarkBitMapClosure +{ +public: FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id) : ParMarkBitMapClosure(PSParallelCompact::mark_bitmap(), cm), - _space_id(space_id), - _start_array(PSParallelCompact::start_array(space_id)) { - assert(_space_id == PSParallelCompact::perm_space_id || - _space_id == PSParallelCompact::old_space_id, + _start_array(PSParallelCompact::start_array(space_id)) + { + assert(space_id == PSParallelCompact::perm_space_id || + space_id == PSParallelCompact::old_space_id, "cannot use FillClosure in the young gen"); - assert(bitmap() != NULL, "need a bitmap"); - assert(_start_array != NULL, "need a start array"); - } - - void fill_region(HeapWord* addr, size_t size) { - MemRegion region(addr, size); - SharedHeap::fill_region_with_object(region); - _start_array->allocate_block(addr); } virtual IterationStatus do_addr(HeapWord* addr, size_t size) { - fill_region(addr, size); + CollectedHeap::fill_with_objects(addr, size); + HeapWord* const end = addr + size; + do { + _start_array->allocate_block(addr); + addr += oop(addr)->size(); + } while (addr < end); return ParMarkBitMap::incomplete; } private: - const PSParallelCompact::SpaceId _space_id; - ObjectStartArray* const _start_array; + ObjectStartArray* const _start_array; }; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp index dd74617ebb3..11b6118322b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp @@ -499,26 +499,15 @@ oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) { // We lost, someone else "owns" this object guarantee(o->is_forwarded(), "Object must be forwarded if the cas failed."); - // Unallocate the space used. NOTE! We may have directly allocated - // the object. If so, we cannot deallocate it, so we have to test! + // Try to deallocate the space. If it was directly allocated we cannot + // deallocate it, so we have to test. If the deallocation fails, + // overwrite with a filler object. if (new_obj_is_tenured) { if (!_old_lab.unallocate_object(new_obj)) { - // The promotion lab failed to unallocate the object. - // We need to overwrite the object with a filler that - // contains no interior pointers. - MemRegion mr((HeapWord*)new_obj, new_obj_size); - // Clean this up and move to oopFactory (see bug 4718422) - SharedHeap::fill_region_with_object(mr); - } - } else { - if (!_young_lab.unallocate_object(new_obj)) { - // The promotion lab failed to unallocate the object. - // We need to overwrite the object with a filler that - // contains no interior pointers. - MemRegion mr((HeapWord*)new_obj, new_obj_size); - // Clean this up and move to oopFactory (see bug 4718422) - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size); } + } else if (!_young_lab.unallocate_object(new_obj)) { + CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size); } // don't update this before the unallocation! diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp index 0f38b70ee69..c639bbf3f96 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp @@ -76,8 +76,8 @@ void MutableNUMASpace::ensure_parsability() { MutableSpace *s = ls->space(); if (s->top() < top()) { // For all spaces preceeding the one containing top() if (s->free_in_words() > 0) { - SharedHeap::fill_region_with_object(MemRegion(s->top(), s->end())); size_t area_touched_words = pointer_delta(s->end(), s->top()); + CollectedHeap::fill_with_object(s->top(), area_touched_words); #ifndef ASSERT if (!ZapUnusedHeapArea) { area_touched_words = MIN2((size_t)align_object_size(typeArrayOopDesc::header_size(T_INT)), @@ -686,11 +686,11 @@ void MutableNUMASpace::set_top(HeapWord* value) { // a minimal object; assuming that's not the last chunk in which case we don't care. if (i < lgrp_spaces()->length() - 1) { size_t remainder = pointer_delta(s->end(), value); - const size_t minimal_object_size = oopDesc::header_size(); - if (remainder < minimal_object_size && remainder > 0) { - // Add a filler object of a minimal size, it will cross the chunk boundary. - SharedHeap::fill_region_with_object(MemRegion(value, minimal_object_size)); - value += minimal_object_size; + const size_t min_fill_size = CollectedHeap::min_fill_size(); + if (remainder < min_fill_size && remainder > 0) { + // Add a minimum size filler object; it will cross the chunk boundary. + CollectedHeap::fill_with_object(value, min_fill_size); + value += min_fill_size; assert(!s->contains(value), "Should be in the next chunk"); // Restart the loop from the same chunk, since the value has moved // to the next one. diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index df8ef081632..3e5cf87c1d4 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -30,12 +30,21 @@ int CollectedHeap::_fire_out_of_memory_count = 0; #endif +size_t CollectedHeap::_filler_array_max_size = 0; + // Memory state functions. -CollectedHeap::CollectedHeap() : - _reserved(), _barrier_set(NULL), _is_gc_active(false), - _total_collections(0), _total_full_collections(0), - _gc_cause(GCCause::_no_gc), _gc_lastcause(GCCause::_no_gc) { +CollectedHeap::CollectedHeap() +{ + const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT)); + const size_t elements_per_word = HeapWordSize / sizeof(jint); + _filler_array_max_size = align_object_size(filler_array_hdr_size() + + max_len * elements_per_word); + + _barrier_set = NULL; + _is_gc_active = false; + _total_collections = _total_full_collections = 0; + _gc_cause = _gc_lastcause = GCCause::_no_gc; NOT_PRODUCT(_promotion_failure_alot_count = 0;) NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;) @@ -128,6 +137,94 @@ HeapWord* CollectedHeap::allocate_from_tlab_slow(Thread* thread, size_t size) { return obj; } +size_t CollectedHeap::filler_array_hdr_size() { + return size_t(arrayOopDesc::header_size(T_INT)); +} + +size_t CollectedHeap::filler_array_min_size() { + return align_object_size(filler_array_hdr_size()); +} + +size_t CollectedHeap::filler_array_max_size() { + return _filler_array_max_size; +} + +#ifdef ASSERT +void CollectedHeap::fill_args_check(HeapWord* start, size_t words) +{ + assert(words >= min_fill_size(), "too small to fill"); + assert(words % MinObjAlignment == 0, "unaligned size"); + assert(Universe::heap()->is_in_reserved(start), "not in heap"); + assert(Universe::heap()->is_in_reserved(start + words - 1), "not in heap"); +} + +void CollectedHeap::zap_filler_array(HeapWord* start, size_t words) +{ + if (ZapFillerObjects) { + Copy::fill_to_words(start + filler_array_hdr_size(), + words - filler_array_hdr_size(), 0XDEAFBABE); + } +} +#endif // ASSERT + +void +CollectedHeap::fill_with_array(HeapWord* start, size_t words) +{ + assert(words >= filler_array_min_size(), "too small for an array"); + assert(words <= filler_array_max_size(), "too big for a single object"); + + const size_t payload_size = words - filler_array_hdr_size(); + const size_t len = payload_size * HeapWordSize / sizeof(jint); + + // Set the length first for concurrent GC. + ((arrayOop)start)->set_length((int)len); + post_allocation_setup_common(Universe::intArrayKlassObj(), start, words); + DEBUG_ONLY(zap_filler_array(start, words);) +} + +void +CollectedHeap::fill_with_object_impl(HeapWord* start, size_t words) +{ + assert(words <= filler_array_max_size(), "too big for a single object"); + + if (words >= filler_array_min_size()) { + fill_with_array(start, words); + } else if (words > 0) { + assert(words == min_fill_size(), "unaligned size"); + post_allocation_setup_common(SystemDictionary::object_klass(), start, + words); + } +} + +void CollectedHeap::fill_with_object(HeapWord* start, size_t words) +{ + DEBUG_ONLY(fill_args_check(start, words);) + HandleMark hm; // Free handles before leaving. + fill_with_object_impl(start, words); +} + +void CollectedHeap::fill_with_objects(HeapWord* start, size_t words) +{ + DEBUG_ONLY(fill_args_check(start, words);) + HandleMark hm; // Free handles before leaving. + +#ifdef LP64 + // A single array can fill ~8G, so multiple objects are needed only in 64-bit. + // First fill with arrays, ensuring that any remaining space is big enough to + // fill. The remainder is filled with a single object. + const size_t min = min_fill_size(); + const size_t max = filler_array_max_size(); + while (words > max) { + const size_t cur = words - max >= min ? max : max - min; + fill_with_array(start, cur); + start += cur; + words -= cur; + } +#endif + + fill_with_object_impl(start, words); +} + oop CollectedHeap::new_store_barrier(oop new_obj) { // %%% This needs refactoring. (It was imported from the server compiler.) guarantee(can_elide_tlab_store_barriers(), "store barrier elision not supported"); diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index 69369e3f7d4..13d30c70b6d 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -47,6 +47,9 @@ class CollectedHeap : public CHeapObj { static int _fire_out_of_memory_count; #endif + // Used for filler objects (static, but initialized in ctor). + static size_t _filler_array_max_size; + protected: MemRegion _reserved; BarrierSet* _barrier_set; @@ -119,6 +122,21 @@ class CollectedHeap : public CHeapObj { // Clears an allocated object. inline static void init_obj(HeapWord* obj, size_t size); + // Filler object utilities. + static inline size_t filler_array_hdr_size(); + static inline size_t filler_array_min_size(); + static inline size_t filler_array_max_size(); + + DEBUG_ONLY(static void fill_args_check(HeapWord* start, size_t words);) + DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words);) + + // Fill with a single array; caller must ensure filler_array_min_size() <= + // words <= filler_array_max_size(). + static inline void fill_with_array(HeapWord* start, size_t words); + + // Fill with a single object (either an int array or a java.lang.Object). + static inline void fill_with_object_impl(HeapWord* start, size_t words); + // Verification functions virtual void check_for_bad_heap_word_value(HeapWord* addr, size_t size) PRODUCT_RETURN; @@ -294,6 +312,27 @@ class CollectedHeap : public CHeapObj { // The boundary between a "large" and "small" array of primitives, in words. virtual size_t large_typearray_limit() = 0; + // Utilities for turning raw memory into filler objects. + // + // min_fill_size() is the smallest region that can be filled. + // fill_with_objects() can fill arbitrary-sized regions of the heap using + // multiple objects. fill_with_object() is for regions known to be smaller + // than the largest array of integers; it uses a single object to fill the + // region and has slightly less overhead. + static size_t min_fill_size() { + return size_t(align_object_size(oopDesc::header_size())); + } + + static void fill_with_objects(HeapWord* start, size_t words); + + static void fill_with_object(HeapWord* start, size_t words); + static void fill_with_object(MemRegion region) { + fill_with_object(region.start(), region.word_size()); + } + static void fill_with_object(HeapWord* start, HeapWord* end) { + fill_with_object(start, pointer_delta(end, start)); + } + // Some heaps may offer a contiguous region for shared non-blocking // allocation, via inlined code (by exporting the address of the top and // end fields defining the extent of the contiguous allocation region.) diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp index efc3210bf0a..c8e59edac33 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp @@ -34,7 +34,6 @@ void CollectedHeap::post_allocation_setup_common(KlassHandle klass, void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass, HeapWord* objPtr, size_t size) { - oop obj = (oop)objPtr; assert(obj != NULL, "NULL object pointer"); @@ -44,9 +43,6 @@ void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass, // May be bootstrapping obj->set_mark(markOopDesc::prototype()); } - - // support low memory notifications (no-op if not enabled) - LowMemoryDetector::detect_low_memory_for_collected_pools(); } void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass, @@ -65,6 +61,9 @@ void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass, // Support for jvmti and dtrace inline void post_allocation_notify(KlassHandle klass, oop obj) { + // support low memory notifications (no-op if not enabled) + LowMemoryDetector::detect_low_memory_for_collected_pools(); + // support for JVMTI VMObjectAlloc event (no-op if not enabled) JvmtiExport::vm_object_alloc_event_collector(obj); diff --git a/hotspot/src/share/vm/includeDB_gc b/hotspot/src/share/vm/includeDB_gc index 662805cc0d4..336148bf8fa 100644 --- a/hotspot/src/share/vm/includeDB_gc +++ b/hotspot/src/share/vm/includeDB_gc @@ -28,21 +28,22 @@ collectedHeap.cpp collectedHeap.hpp collectedHeap.cpp collectedHeap.inline.hpp collectedHeap.cpp init.hpp collectedHeap.cpp oop.inline.hpp +collectedHeap.cpp systemDictionary.hpp collectedHeap.cpp thread_.inline.hpp collectedHeap.hpp allocation.hpp collectedHeap.hpp barrierSet.hpp collectedHeap.hpp gcCause.hpp collectedHeap.hpp handles.hpp -collectedHeap.hpp perfData.hpp +collectedHeap.hpp perfData.hpp collectedHeap.hpp safepoint.hpp collectedHeap.inline.hpp arrayOop.hpp collectedHeap.inline.hpp collectedHeap.hpp collectedHeap.inline.hpp copy.hpp collectedHeap.inline.hpp jvmtiExport.hpp -collectedHeap.inline.hpp lowMemoryDetector.hpp -collectedHeap.inline.hpp sharedRuntime.hpp +collectedHeap.inline.hpp lowMemoryDetector.hpp +collectedHeap.inline.hpp sharedRuntime.hpp collectedHeap.inline.hpp thread.hpp collectedHeap.inline.hpp threadLocalAllocBuffer.inline.hpp collectedHeap.inline.hpp universe.hpp diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp index 8a006a4042b..ee9ed1fc8be 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp @@ -283,7 +283,7 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { } else { entry = byte_after(old_region.last()); } - assert(index_for(new_region.last()) < (int) _guard_index, + assert(index_for(new_region.last()) < _guard_index, "The guard card will be overwritten"); // This line commented out cleans the newly expanded region and // not the aligned up expanded region. diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp index 440d42c6ac1..9a48ab5497d 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp @@ -428,7 +428,7 @@ public: } // Mapping from address to card marking array index. - int index_for(void* p) { + size_t index_for(void* p) { assert(_whole_heap.contains(p), "out of bounds access to card marking array"); return byte_for(p) - _byte_map; diff --git a/hotspot/src/share/vm/memory/permGen.cpp b/hotspot/src/share/vm/memory/permGen.cpp index e31c19c80ed..65635fe26cf 100644 --- a/hotspot/src/share/vm/memory/permGen.cpp +++ b/hotspot/src/share/vm/memory/permGen.cpp @@ -26,20 +26,24 @@ #include "incls/_permGen.cpp.incl" HeapWord* PermGen::mem_allocate_in_gen(size_t size, Generation* gen) { - MutexLocker ml(Heap_lock); GCCause::Cause next_cause = GCCause::_permanent_generation_full; GCCause::Cause prev_cause = GCCause::_no_gc; + unsigned int gc_count_before, full_gc_count_before; + HeapWord* obj; for (;;) { - HeapWord* obj = gen->allocate(size, false); - if (obj != NULL) { - return obj; - } - if (gen->capacity() < _capacity_expansion_limit || - prev_cause != GCCause::_no_gc) { - obj = gen->expand_and_allocate(size, false); - } - if (obj == NULL && prev_cause != GCCause::_last_ditch_collection) { + { + MutexLocker ml(Heap_lock); + if ((obj = gen->allocate(size, false)) != NULL) { + return obj; + } + if (gen->capacity() < _capacity_expansion_limit || + prev_cause != GCCause::_no_gc) { + obj = gen->expand_and_allocate(size, false); + } + if (obj != NULL || prev_cause == GCCause::_last_ditch_collection) { + return obj; + } if (GC_locker::is_active_and_needs_gc()) { // If this thread is not in a jni critical section, we stall // the requestor until the critical section has cleared and @@ -61,31 +65,27 @@ HeapWord* PermGen::mem_allocate_in_gen(size_t size, Generation* gen) { return NULL; } } - // Read the GC count while holding the Heap_lock - unsigned int gc_count_before = SharedHeap::heap()->total_collections(); - unsigned int full_gc_count_before = SharedHeap::heap()->total_full_collections(); - { - MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_GenCollectForPermanentAllocation op(size, gc_count_before, full_gc_count_before, - next_cause); - VMThread::execute(&op); - if (!op.prologue_succeeded() || op.gc_locked()) { - assert(op.result() == NULL, "must be NULL if gc_locked() is true"); - continue; // retry and/or stall as necessary - } - obj = op.result(); - assert(obj == NULL || SharedHeap::heap()->is_in_reserved(obj), - "result not in heap"); - if (obj != NULL) { - return obj; - } - } - prev_cause = next_cause; - next_cause = GCCause::_last_ditch_collection; - } else { + gc_count_before = SharedHeap::heap()->total_collections(); + full_gc_count_before = SharedHeap::heap()->total_full_collections(); + } + + // Give up heap lock above, VMThread::execute below gets it back + VM_GenCollectForPermanentAllocation op(size, gc_count_before, full_gc_count_before, + next_cause); + VMThread::execute(&op); + if (!op.prologue_succeeded() || op.gc_locked()) { + assert(op.result() == NULL, "must be NULL if gc_locked() is true"); + continue; // retry and/or stall as necessary + } + obj = op.result(); + assert(obj == NULL || SharedHeap::heap()->is_in_reserved(obj), + "result not in heap"); + if (obj != NULL) { return obj; } + prev_cause = next_cause; + next_cause = GCCause::_last_ditch_collection; } } diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index 853b0ebb310..392487a31ad 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -248,46 +248,6 @@ void SharedHeap::ref_processing_init() { perm_gen()->ref_processor_init(); } -void SharedHeap::fill_region_with_object(MemRegion mr) { - // Disable the posting of JVMTI VMObjectAlloc events as we - // don't want the filling of tlabs with filler arrays to be - // reported to the profiler. - NoJvmtiVMObjectAllocMark njm; - - // Disable low memory detector because there is no real allocation. - LowMemoryDetectorDisabler lmd_dis; - - // It turns out that post_allocation_setup_array takes a handle, so the - // call below contains an implicit conversion. Best to free that handle - // as soon as possible. - HandleMark hm; - - size_t word_size = mr.word_size(); - size_t aligned_array_header_size = - align_object_size(typeArrayOopDesc::header_size(T_INT)); - - if (word_size >= aligned_array_header_size) { - const size_t array_length = - pointer_delta(mr.end(), mr.start()) - - typeArrayOopDesc::header_size(T_INT); - const size_t array_length_words = - array_length * (HeapWordSize/sizeof(jint)); - post_allocation_setup_array(Universe::intArrayKlassObj(), - mr.start(), - mr.word_size(), - (int)array_length_words); -#ifdef ASSERT - HeapWord* elt_words = (mr.start() + typeArrayOopDesc::header_size(T_INT)); - Copy::fill_to_words(elt_words, array_length, 0xDEAFBABE); -#endif - } else { - assert(word_size == (size_t)oopDesc::header_size(), "Unaligned?"); - post_allocation_setup_obj(SystemDictionary::object_klass(), - mr.start(), - mr.word_size()); - } -} - // Some utilities. void SharedHeap::print_size_transition(outputStream* out, size_t bytes_before, diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index 662f011c7ab..c8c570e87db 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -108,14 +108,6 @@ public: void set_perm(PermGen* perm_gen) { _perm_gen = perm_gen; } - // A helper function that fills a region of the heap with - // with a single object. - static void fill_region_with_object(MemRegion mr); - - // Minimum garbage fill object size - static size_t min_fill_size() { return (size_t)align_object_size(oopDesc::header_size()); } - static size_t min_fill_size_in_bytes() { return min_fill_size() * HeapWordSize; } - // This function returns the "GenRemSet" object that allows us to scan // generations; at least the perm gen, possibly more in a fully // generational heap. diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 82529444c0a..652d585bb8f 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -409,19 +409,9 @@ bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q, size_t deadlength) { if (allowed_deadspace_words >= deadlength) { allowed_deadspace_words -= deadlength; - oop(q)->set_mark(markOopDesc::prototype()->set_marked()); - const size_t min_int_array_size = typeArrayOopDesc::header_size(T_INT); - if (deadlength >= min_int_array_size) { - oop(q)->set_klass(Universe::intArrayKlassObj()); - typeArrayOop(q)->set_length((int)((deadlength - min_int_array_size) - * (HeapWordSize/sizeof(jint)))); - } else { - assert((int) deadlength == instanceOopDesc::header_size(), - "size for smallest fake dead object doesn't match"); - oop(q)->set_klass(SystemDictionary::object_klass()); - } - assert((int) deadlength == oop(q)->size(), - "make sure size for fake dead object match"); + CollectedHeap::fill_with_object(q, deadlength); + oop(q)->set_mark(oop(q)->mark()->set_marked()); + assert((int) deadlength == oop(q)->size(), "bad filler object size"); // Recall that we required "q == compaction_top". return true; } else { diff --git a/hotspot/src/share/vm/memory/tenuredGeneration.cpp b/hotspot/src/share/vm/memory/tenuredGeneration.cpp index dcd6626e80d..56eed211d98 100644 --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp @@ -387,7 +387,7 @@ void TenuredGeneration::par_promote_alloc_undo(int thread_num, "should contain whole object"); buf->undo_allocation(obj, word_sz); } else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + CollectedHeap::fill_with_object(obj, word_sz); } } diff --git a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp index fdcfdd28e13..01d7d6e6a2f 100644 --- a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp @@ -100,8 +100,7 @@ void ThreadLocalAllocBuffer::accumulate_statistics() { void ThreadLocalAllocBuffer::make_parsable(bool retire) { if (end() != NULL) { invariants(); - MemRegion mr(top(), hard_end()); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(top(), hard_end()); if (retire || ZeroTLAB) { // "Reset" the TLAB set_start(NULL); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index ffe583ecc16..88243f2d56c 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -49,16 +49,16 @@ klassOop Universe::_constantPoolKlassObj = NULL; klassOop Universe::_constantPoolCacheKlassObj = NULL; klassOop Universe::_compiledICHolderKlassObj = NULL; klassOop Universe::_systemObjArrayKlassObj = NULL; -oop Universe::_int_mirror = NULL; -oop Universe::_float_mirror = NULL; -oop Universe::_double_mirror = NULL; -oop Universe::_byte_mirror = NULL; -oop Universe::_bool_mirror = NULL; -oop Universe::_char_mirror = NULL; -oop Universe::_long_mirror = NULL; -oop Universe::_short_mirror = NULL; -oop Universe::_void_mirror = NULL; -oop Universe::_mirrors[T_VOID+1] = { NULL /*, NULL...*/ }; +oop Universe::_int_mirror = NULL; +oop Universe::_float_mirror = NULL; +oop Universe::_double_mirror = NULL; +oop Universe::_byte_mirror = NULL; +oop Universe::_bool_mirror = NULL; +oop Universe::_char_mirror = NULL; +oop Universe::_long_mirror = NULL; +oop Universe::_short_mirror = NULL; +oop Universe::_void_mirror = NULL; +oop Universe::_mirrors[T_VOID+1] = { NULL /*, NULL...*/ }; oop Universe::_main_thread_group = NULL; oop Universe::_system_thread_group = NULL; typeArrayOop Universe::_the_empty_byte_array = NULL; @@ -257,16 +257,16 @@ void Universe::genesis(TRAPS) { _typeArrayKlassObjs[T_INT] = _intArrayKlassObj; _typeArrayKlassObjs[T_LONG] = _longArrayKlassObj; - _methodKlassObj = methodKlass::create_klass(CHECK); - _constMethodKlassObj = constMethodKlass::create_klass(CHECK); - _methodDataKlassObj = methodDataKlass::create_klass(CHECK); + _methodKlassObj = methodKlass::create_klass(CHECK); + _constMethodKlassObj = constMethodKlass::create_klass(CHECK); + _methodDataKlassObj = methodDataKlass::create_klass(CHECK); _constantPoolKlassObj = constantPoolKlass::create_klass(CHECK); _constantPoolCacheKlassObj = constantPoolCacheKlass::create_klass(CHECK); _compiledICHolderKlassObj = compiledICHolderKlass::create_klass(CHECK); _systemObjArrayKlassObj = objArrayKlassKlass::cast(objArrayKlassKlassObj())->allocate_system_objArray_klass(CHECK); - _the_empty_byte_array = oopFactory::new_permanent_byteArray(0, CHECK); + _the_empty_byte_array = oopFactory::new_permanent_byteArray(0, CHECK); _the_empty_short_array = oopFactory::new_permanent_shortArray(0, CHECK); _the_empty_int_array = oopFactory::new_permanent_intArray(0, CHECK); _the_empty_system_obj_array = oopFactory::new_system_objArray(0, CHECK); @@ -274,7 +274,6 @@ void Universe::genesis(TRAPS) { _the_array_interfaces_array = oopFactory::new_system_objArray(2, CHECK); _vm_exception = oopFactory::new_symbol("vm exception holder", CHECK); } else { - FileMapInfo *mapinfo = FileMapInfo::current_info(); char* buffer = mapinfo->region_base(CompactingPermGenGen::md); void** vtbl_list = (void**)buffer; diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 118800f780b..45c9f96d21f 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -92,6 +92,7 @@ class LatestMethodOopCache : public CommonMethodOopCache { class Universe: AllStatic { + // Ugh. Universe is much too friendly. friend class MarkSweep; friend class oopDesc; friend class ClassLoader; diff --git a/hotspot/src/share/vm/oops/arrayOop.hpp b/hotspot/src/share/vm/oops/arrayOop.hpp index 8ede056496a..364d1dbfe40 100644 --- a/hotspot/src/share/vm/oops/arrayOop.hpp +++ b/hotspot/src/share/vm/oops/arrayOop.hpp @@ -96,19 +96,20 @@ class arrayOopDesc : public oopDesc { : typesize_in_bytes/HeapWordSize); } - // This method returns the maximum length that can passed into - // typeArrayOop::object_size(scale, length, header_size) without causing an - // overflow. We substract an extra 2*wordSize to guard against double word - // alignments. It gets the scale from the type2aelembytes array. + // Return the maximum length of an array of BasicType. The length can passed + // to typeArrayOop::object_size(scale, length, header_size) without causing an + // overflow. static int32_t max_array_length(BasicType type) { assert(type >= 0 && type < T_CONFLICT, "wrong type"); assert(type2aelembytes(type) != 0, "wrong type"); - // We use max_jint, since object_size is internally represented by an 'int' - // This gives us an upper bound of max_jint words for the size of the oop. - int32_t max_words = (max_jint - header_size(type) - 2); - int elembytes = type2aelembytes(type); - jlong len = ((jlong)max_words * HeapWordSize) / elembytes; - return (len > max_jint) ? max_jint : (int32_t)len; - } + const int bytes_per_element = type2aelembytes(type); + if (bytes_per_element < HeapWordSize) { + return max_jint; + } + const int32_t max_words = align_size_down(max_jint, MinObjAlignment); + const int32_t max_element_words = max_words - header_size(type); + const int32_t words_per_element = bytes_per_element >> LogHeapWordSize; + return max_element_words / words_per_element; + } }; diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index d48f8b4f25b..2e0ffbcba26 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -36,13 +36,14 @@ bool typeArrayKlass::compute_is_subtype_of(klassOop k) { return element_type() == tak->element_type(); } -klassOop typeArrayKlass::create_klass(BasicType type, int scale, TRAPS) { +klassOop typeArrayKlass::create_klass(BasicType type, int scale, + const char* name_str, TRAPS) { typeArrayKlass o; symbolHandle sym(symbolOop(NULL)); // bootstrapping: don't create sym if symbolKlass not created yet - if (Universe::symbolKlassObj() != NULL) { - sym = oopFactory::new_symbol_handle(external_name(type), CHECK_NULL); + if (Universe::symbolKlassObj() != NULL && name_str != NULL) { + sym = oopFactory::new_symbol_handle(name_str, CHECK_NULL); } KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj()); diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.hpp b/hotspot/src/share/vm/oops/typeArrayKlass.hpp index 72336fb8db0..dac77f6b9bf 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp @@ -39,7 +39,11 @@ class typeArrayKlass : public arrayKlass { // klass allocation DEFINE_ALLOCATE_PERMANENT(typeArrayKlass); - static klassOop create_klass(BasicType type, int scale, TRAPS); + static klassOop create_klass(BasicType type, int scale, const char* name_str, + TRAPS); + static inline klassOop create_klass(BasicType type, int scale, TRAPS) { + return create_klass(type, scale, external_name(type), CHECK_NULL); + } int oop_size(oop obj) const; int klass_oop_size() const { return object_size(); } diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index f9b3392d0f2..de05e5fb84a 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -2192,6 +2192,9 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { case Op_DecodeN: assert(!n->in(1)->is_EncodeP(), "should be optimized out"); + // DecodeN could be pinned on Sparc where it can't be fold into + // an address expression, see the code for Op_CastPP above. + assert(n->in(0) == NULL || !Matcher::clone_shift_expressions, "no control except on sparc"); break; case Op_EncodeP: { diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 1152917d907..4d74a434fec 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -1724,6 +1724,13 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) { if (klass_node == NULL) { Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); +#ifdef _LP64 + if (UseCompressedOops && klass_node->is_DecodeN()) { + assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity"); + klass_node->in(1)->init_req(0, ctrl); + } else +#endif + klass_node->init_req(0, ctrl); } Node *proto_node = make_load(ctrl, mem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeX_X, TypeX_X->basic_type()); diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 49ace5c9823..b4a82b9e547 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -2173,7 +2173,8 @@ static char* get_bad_address() { size_t size = os::vm_allocation_granularity(); bad_address = os::reserve_memory(size); if (bad_address != NULL) { - os::protect_memory(bad_address, size, os::MEM_PROT_READ); + os::protect_memory(bad_address, size, os::MEM_PROT_READ, + /*is_committed*/false); } } return bad_address; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 831218796cf..b9c943d10b2 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -444,9 +444,9 @@ char* SysClassPath::add_jars_to_path(char* path, const char* directory) { } // Parses a memory size specification string. -static bool atomll(const char *s, jlong* result) { - jlong n = 0; - int args_read = sscanf(s, os::jlong_format_specifier(), &n); +static bool atomull(const char *s, julong* result) { + julong n = 0; + int args_read = sscanf(s, os::julong_format_specifier(), &n); if (args_read != 1) { return false; } @@ -460,15 +460,20 @@ static bool atomll(const char *s, jlong* result) { switch (*s) { case 'T': case 't': *result = n * G * K; + // Check for overflow. + if (*result/((julong)G * K) != n) return false; return true; case 'G': case 'g': *result = n * G; + if (*result/G != n) return false; return true; case 'M': case 'm': *result = n * M; + if (*result/M != n) return false; return true; case 'K': case 'k': *result = n * K; + if (*result/K != n) return false; return true; case '\0': *result = n; @@ -478,10 +483,10 @@ static bool atomll(const char *s, jlong* result) { } } -Arguments::ArgsRange Arguments::check_memory_size(jlong size, jlong min_size) { +Arguments::ArgsRange Arguments::check_memory_size(julong size, julong min_size) { if (size < min_size) return arg_too_small; // Check that size will fit in a size_t (only relevant on 32-bit) - if ((julong) size > max_uintx) return arg_too_big; + if (size > max_uintx) return arg_too_big; return arg_in_range; } @@ -522,10 +527,10 @@ static bool set_fp_numeric_flag(char* name, char* value, FlagValueOrigin origin) static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { - jlong v; + julong v; intx intx_v; bool is_neg = false; - // Check the sign first since atomll() parses only unsigned values. + // Check the sign first since atomull() parses only unsigned values. if (*value == '-') { if (!CommandLineFlags::intxAt(name, &intx_v)) { return false; @@ -533,7 +538,7 @@ static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { value++; is_neg = true; } - if (!atomll(value, &v)) { + if (!atomull(value, &v)) { return false; } intx_v = (intx) v; @@ -1517,6 +1522,16 @@ bool Arguments::check_vm_args_consistency() { MarkSweepAlwaysCompactCount = 1; // Move objects every gc. } + if (UseParallelOldGC && ParallelOldGCSplitALot) { + // Settings to encourage splitting. + if (!FLAG_IS_CMDLINE(NewRatio)) { + FLAG_SET_CMDLINE(intx, NewRatio, 2); + } + if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) { + FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); + } + } + status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); status = status && verify_percentage(GCTimeLimit, "GCTimeLimit"); if (GCTimeLimit == 100) { @@ -1667,9 +1682,9 @@ static bool match_option(const JavaVMOption* option, const char** names, const c } Arguments::ArgsRange Arguments::parse_memory_size(const char* s, - jlong* long_arg, - jlong min_size) { - if (!atomll(s, long_arg)) return arg_unreadable; + julong* long_arg, + julong min_size) { + if (!atomull(s, long_arg)) return arg_unreadable; return check_memory_size(*long_arg, min_size); } @@ -1847,7 +1862,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, FLAG_SET_CMDLINE(bool, BackgroundCompilation, false); // -Xmn for compatibility with other JVM vendors } else if (match_option(option, "-Xmn", &tail)) { - jlong long_initial_eden_size = 0; + julong long_initial_eden_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_initial_eden_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1859,7 +1874,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, FLAG_SET_CMDLINE(uintx, NewSize, (size_t) long_initial_eden_size); // -Xms } else if (match_option(option, "-Xms", &tail)) { - jlong long_initial_heap_size = 0; + julong long_initial_heap_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1872,7 +1887,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, set_min_heap_size(initial_heap_size()); // -Xmx } else if (match_option(option, "-Xmx", &tail)) { - jlong long_max_heap_size = 0; + julong long_max_heap_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1905,7 +1920,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } // -Xss } else if (match_option(option, "-Xss", &tail)) { - jlong long_ThreadStackSize = 0; + julong long_ThreadStackSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ThreadStackSize, 1000); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1921,9 +1936,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // HotSpot does not have separate native and Java stacks, ignore silently for compatibility // -Xmaxjitcodesize } else if (match_option(option, "-Xmaxjitcodesize", &tail)) { - jlong long_ReservedCodeCacheSize = 0; + julong long_ReservedCodeCacheSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, - InitialCodeCacheSize); + (size_t)InitialCodeCacheSize); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), "Invalid maximum code cache size: %s\n", @@ -2228,7 +2243,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-XX:TLEFragmentationRatio=", &tail)) { // No longer used. } else if (match_option(option, "-XX:TLESize=", &tail)) { - jlong long_tlab_size = 0; + julong long_tlab_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_tlab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2283,7 +2298,7 @@ SOLARIS_ONLY( "-XX:ParCMSPromoteBlocksToClaim in the future\n"); } else if (match_option(option, "-XX:ParallelGCOldGenAllocBufferSize=", &tail)) { - jlong old_plab_size = 0; + julong old_plab_size = 0; ArgsRange errcode = parse_memory_size(tail, &old_plab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2291,13 +2306,13 @@ SOLARIS_ONLY( describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, OldPLABSize, (julong)old_plab_size); + FLAG_SET_CMDLINE(uintx, OldPLABSize, old_plab_size); jio_fprintf(defaultStream::error_stream(), "Please use -XX:OldPLABSize in place of " "-XX:ParallelGCOldGenAllocBufferSize in the future\n"); } else if (match_option(option, "-XX:ParallelGCToSpaceAllocBufferSize=", &tail)) { - jlong young_plab_size = 0; + julong young_plab_size = 0; ArgsRange errcode = parse_memory_size(tail, &young_plab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2305,7 +2320,7 @@ SOLARIS_ONLY( describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, YoungPLABSize, (julong)young_plab_size); + FLAG_SET_CMDLINE(uintx, YoungPLABSize, young_plab_size); jio_fprintf(defaultStream::error_stream(), "Please use -XX:YoungPLABSize in place of " "-XX:ParallelGCToSpaceAllocBufferSize in the future\n"); diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 5dfd4aa78f9..b5dca5b90de 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -339,9 +339,9 @@ class Arguments : AllStatic { } static bool verify_percentage(uintx value, const char* name); static void describe_range_error(ArgsRange errcode); - static ArgsRange check_memory_size(jlong size, jlong min_size); - static ArgsRange parse_memory_size(const char* s, jlong* long_arg, - jlong min_size); + static ArgsRange check_memory_size(julong size, julong min_size); + static ArgsRange parse_memory_size(const char* s, julong* long_arg, + julong min_size); // methods to build strings from individual args static void build_jvm_args(const char* arg); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 5d08a653bd5..7d9e1a614ae 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -625,6 +625,9 @@ class CommandLineFlags { develop(bool, CheckZapUnusedHeapArea, false, \ "Check zapping of unused heap space") \ \ + develop(bool, ZapFillerObjects, trueInDebug, \ + "Zap filler objects with 0xDEAFBABE") \ + \ develop(bool, PrintVMMessages, true, \ "Print vm messages on console") \ \ @@ -818,7 +821,7 @@ class CommandLineFlags { product(bool, ClassUnloading, true, \ "Do unloading of classes") \ \ - diagnostic(bool, LinkWellKnownClasses, true, \ + diagnostic(bool, LinkWellKnownClasses, false, \ "Resolve a well known class as soon as its name is seen") \ \ develop(bool, DisableStartThread, false, \ @@ -1200,11 +1203,12 @@ class CommandLineFlags { product(uintx, ParallelCMSThreads, 0, \ "Max number of threads CMS will use for concurrent work") \ \ - develop(bool, ParallelOldMTUnsafeMarkBitMap, false, \ - "Use the Parallel Old MT unsafe in marking the bitmap") \ + develop(bool, ParallelOldGCSplitALot, false, \ + "Provoke splitting (copying data from a young gen space to" \ + "multiple destination spaces)") \ \ - develop(bool, ParallelOldMTUnsafeUpdateLiveData, false, \ - "Use the Parallel Old MT unsafe in update of live size") \ + develop(uintx, ParallelOldGCSplitInterval, 3, \ + "How often to provoke splitting a young gen space") \ \ develop(bool, TraceRegionTasksQueuing, false, \ "Trace the queuing of the region tasks") \ diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 02e9424c8f2..77950cf7679 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -504,7 +504,7 @@ class SignatureChekker : public SignatureIterator { intptr_t v = _value[p]; if (v != 0 ) { size_t t = (size_t)v; - bad = (t < (size_t)os::vm_page_size() ) || !(*(oop*)v)->is_oop_or_null(true); + bad = (t < (size_t)os::vm_page_size() ) || !Handle::raw_resolve((oop *)v)->is_oop_or_null(true); if (CheckJNICalls && bad) { ReportJNIFatalError((JavaThread*)_thread, "Bad JNI oop argument"); } diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 088a07ff45e..da6d719edc0 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -932,8 +932,9 @@ void os::serialize_thread_states() { // the mutator thread if such case is encountered. See bug 6546278 for details. Thread::muxAcquire(&SerializePageLock, "serialize_thread_states"); os::protect_memory((char *)os::get_memory_serialize_page(), - os::vm_page_size(), MEM_PROT_READ, /*is_committed*/true ); - os::unguard_memory((char *)os::get_memory_serialize_page(), os::vm_page_size()); + os::vm_page_size(), MEM_PROT_READ); + os::protect_memory((char *)os::get_memory_serialize_page(), + os::vm_page_size(), MEM_PROT_RW); Thread::muxRelease(&SerializePageLock); } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 423cc800529..0856d23a03b 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -208,7 +208,7 @@ class os: AllStatic { enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot, - bool is_committed = false); + bool is_committed = true); static bool guard_memory(char* addr, size_t bytes); static bool unguard_memory(char* addr, size_t bytes); diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index eb4e2cac0c4..aeb66980add 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -3363,13 +3363,13 @@ void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) { // If the wakee is cold then transiently setting it's affinity // to the current CPU is a good idea. // See http://j2se.east/~dice/PERSIST/050624-PullAffinity.txt + DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self); Trigger->unpark() ; // Maintain stats and report events to JVMTI if (ObjectSynchronizer::_sync_Parks != NULL) { ObjectSynchronizer::_sync_Parks->inc() ; } - DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self); } diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index 387deee7325..f58e546ea13 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -694,10 +694,10 @@ JVM_ENTRY(jlong, jmm_SetPoolThreshold(JNIEnv* env, jobject obj, jmmThresholdType -1); } - if (threshold > max_intx) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Invalid threshold value > max value of size_t", - -1); + if ((size_t)threshold > max_uintx) { + stringStream st; + st.print("Invalid valid threshold value. Threshold value (" UINT64_FORMAT ") > max value of size_t (" SIZE_FORMAT ")", (size_t)threshold, max_uintx); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), st.as_string(), -1); } MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_(0L)); diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index a9d7a72f1cd..d2a0161a7cc 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -332,6 +332,8 @@ void VMError::report(outputStream* st) { // VM version st->print_cr("#"); + JDK_Version::current().to_string(buf, sizeof(buf)); + st->print_cr("# JRE version: %s", buf); st->print_cr("# Java VM: %s (%s %s %s %s)", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release(), diff --git a/hotspot/test/compiler/6757316/Test6757316.java b/hotspot/test/compiler/6757316/Test6757316.java new file mode 100644 index 00000000000..2efc5acd84d --- /dev/null +++ b/hotspot/test/compiler/6757316/Test6757316.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008 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 6757316 + * @summary load_constant() produces a wrong long constant, with high a low words swapped + * @run main/othervm -Xcomp Test6757316 + */ + +public class Test6757316 { + public static void main(String[] args) { + long[] arr = { + 0x11111111aaaaaaaaL, + 0xaaaaaaaa11111111L, + 0x11111111aaaaaaaaL, + 0xaaaaaaaa11111111L + }; + if (arr[0] == arr[1]) { + throw new InternalError(); + } + } +} diff --git a/hotspot/test/compiler/6758234/Test6758234.java b/hotspot/test/compiler/6758234/Test6758234.java new file mode 100644 index 00000000000..be916a2a191 --- /dev/null +++ b/hotspot/test/compiler/6758234/Test6758234.java @@ -0,0 +1,40 @@ +/* + * Copyright 2008 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 6758234 + * @summary if (k cond (a ? : b: c)) returns reversed answer if k is constant and b and c are longs + * @run main/othervm -Xcomp -XX:CompileOnly=Test6758234.main Test6758234 + */ + +public class Test6758234 { + static int x = 0; + static int y = 1; + + public static void main(String[] args) { + if (1 != ((x < y) ? 1L : 0)) { + throw new InternalError(); + } + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 21d9f6758e4..7c3480f9563 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -16,3 +16,4 @@ e9f750f0a3a00413a7b77028b2ecdabb7129ae32 jdk7-b38 831b80be6cea8e7d7da197ccdac5fd4c701a5033 jdk7-b39 54946f466e2c047c44c903f1bec400b685c2508e jdk7-b40 0758bd3e2852e4f931ba211cc4d48f589450eeb4 jdk7-b41 +036e0dca841a5a17f784d15c86a9da88d2a6f1e6 jdk7-b42 diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 22c78532543..e8f9d708fec 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -16,3 +16,4 @@ a2a6f9edf761934faf59ea60d7fe7178371302cd jdk7-b37 077bc9b1b035a409a76bd5366f73ed9dd9846934 jdk7-b39 70a6ac6dd737fe45c2fadb57646195b2b4fe269d jdk7-b40 a8379d24aa03386610169cb0f4e4b8ed266a2e8d jdk7-b41 +621c02d83abc850c170fb6726d57b19f1eaf5033 jdk7-b42 diff --git a/jdk/make/sun/awt/mapfile-mawt-vers b/jdk/make/sun/awt/mapfile-mawt-vers index ca3b430c57b..7eeef21f278 100644 --- a/jdk/make/sun/awt/mapfile-mawt-vers +++ b/jdk/make/sun/awt/mapfile-mawt-vers @@ -407,6 +407,7 @@ SUNWprivate_1.1 { Java_sun_java2d_x11_X11SurfaceData_initSurface; Java_sun_java2d_x11_X11SurfaceData_isDrawableValid; Java_sun_java2d_x11_X11SurfaceData_isDgaAvailable; + Java_sun_java2d_x11_X11SurfaceData_isShmPMAvailable; Java_sun_java2d_x11_X11SurfaceData_setInvalid; Java_sun_java2d_x11_X11SurfaceData_flushNativeSurface; Java_sun_java2d_x11_X11SurfaceData_XCreateGC; diff --git a/jdk/make/sun/xawt/mapfile-vers b/jdk/make/sun/xawt/mapfile-vers index 9e0b434b557..d4b5b6e32ba 100644 --- a/jdk/make/sun/xawt/mapfile-vers +++ b/jdk/make/sun/xawt/mapfile-vers @@ -337,6 +337,7 @@ SUNWprivate_1.1 { Java_sun_java2d_x11_X11SurfaceData_initIDs; Java_sun_java2d_x11_X11SurfaceData_isDrawableValid; Java_sun_java2d_x11_X11SurfaceData_isDgaAvailable; + Java_sun_java2d_x11_X11SurfaceData_isShmPMAvailable; Java_sun_java2d_x11_X11SurfaceData_initOps; Java_sun_java2d_x11_X11SurfaceData_initSurface; Java_sun_java2d_x11_X11SurfaceData_flushNativeSurface; diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java index 0f5407075a7..84a593264be 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java @@ -44,7 +44,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.Iterator; -import java.util.List; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import javax.imageio.IIOException; @@ -57,6 +56,7 @@ import javax.imageio.stream.ImageInputStream; import com.sun.imageio.plugins.common.InputStreamAdapter; import com.sun.imageio.plugins.common.ReaderUtil; import com.sun.imageio.plugins.common.SubImageInputStream; +import java.io.ByteArrayOutputStream; import sun.awt.image.ByteInterleavedRaster; class PNGImageDataEnumeration implements Enumeration { @@ -207,6 +207,15 @@ public class PNGImageReader extends ImageReader { resetStreamSettings(); } + private String readNullTerminatedString(String charset) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int b; + while ((b = stream.read()) != 0) { + baos.write(b); + } + return new String(baos.toByteArray(), charset); + } + private String readNullTerminatedString() throws IOException { StringBuilder b = new StringBuilder(); int c; @@ -445,26 +454,27 @@ public class PNGImageReader extends ImageReader { metadata.iTXt_keyword.add(keyword); int compressionFlag = stream.readUnsignedByte(); - metadata.iTXt_compressionFlag.add(new Integer(compressionFlag)); + metadata.iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag == 1)); int compressionMethod = stream.readUnsignedByte(); - metadata.iTXt_compressionMethod.add(new Integer(compressionMethod)); + metadata.iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); - String languageTag = readNullTerminatedString(); + String languageTag = readNullTerminatedString("UTF8"); metadata.iTXt_languageTag.add(languageTag); - String translatedKeyword = stream.readUTF(); + String translatedKeyword = + readNullTerminatedString("UTF8"); metadata.iTXt_translatedKeyword.add(translatedKeyword); - stream.skipBytes(1); // Null separator String text; + long pos = stream.getStreamPosition(); + byte[] b = new byte[(int)(chunkStart + chunkLength - pos)]; + stream.readFully(b); + if (compressionFlag == 1) { // Decompress the text - long pos = stream.getStreamPosition(); - byte[] b = new byte[(int)(chunkStart + chunkLength - pos)]; - stream.readFully(b); - text = inflate(b); + text = new String(inflate(b), "UTF8"); } else { - text = stream.readUTF(); + text = new String(b, "UTF8"); } metadata.iTXt_text.add(text); } @@ -613,15 +623,20 @@ public class PNGImageReader extends ImageReader { metadata.tRNS_present = true; } - private static String inflate(byte[] b) throws IOException { + private static byte[] inflate(byte[] b) throws IOException { InputStream bais = new ByteArrayInputStream(b); InputStream iis = new InflaterInputStream(bais); - StringBuilder sb = new StringBuilder(80); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int c; - while ((c = iis.read()) != -1) { - sb.append((char)c); + try { + while ((c = iis.read()) != -1) { + baos.write(c); + } + } finally { + iis.close(); } - return sb.toString(); + return baos.toByteArray(); } private void parse_zTXt_chunk(int chunkLength) throws IOException { @@ -633,7 +648,7 @@ public class PNGImageReader extends ImageReader { byte[] b = new byte[chunkLength - keyword.length() - 2]; stream.readFully(b); - metadata.zTXt_text.add(inflate(b)); + metadata.zTXt_text.add(new String(inflate(b))); } private void readMetadata() throws IIOException { @@ -1244,13 +1259,26 @@ public class PNGImageReader extends ImageReader { destinationBands = param.getDestinationBands(); destinationOffset = param.getDestinationOffset(); } - + Inflater inf = null; try { stream.seek(imageStartPosition); Enumeration e = new PNGImageDataEnumeration(stream); InputStream is = new SequenceInputStream(e); - is = new InflaterInputStream(is, new Inflater()); + + /* InflaterInputStream uses an Inflater instance which consumes + * native (non-GC visible) resources. This is normally implicitly + * freed when the stream is closed. However since the + * InflaterInputStream wraps a client-supplied input stream, + * we cannot close it. + * But the app may depend on GC finalization to close the stream. + * Therefore to ensure timely freeing of native resources we + * explicitly create the Inflater instance and free its resources + * when we are done with the InflaterInputStream by calling + * inf.end(); + */ + inf = new Inflater(); + is = new InflaterInputStream(is, inf); is = new BufferedInputStream(is); this.pixelStream = new DataInputStream(is); @@ -1283,6 +1311,10 @@ public class PNGImageReader extends ImageReader { } } catch (IOException e) { throw new IIOException("Error reading PNG image data", e); + } finally { + if (inf != null) { + inf.end(); + } } } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 60db32fa10e..ea4233a68ea 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -244,13 +244,17 @@ final class IDATOutputStream extends ImageOutputStreamImpl { } public void finish() throws IOException { - if (!def.finished()) { - def.finish(); - while (!def.finished()) { - deflate(); + try { + if (!def.finished()) { + def.finish(); + while (!def.finished()) { + deflate(); + } } + finishChunk(); + } finally { + def.end(); } - finishChunk(); } protected void finalize() throws Throwable { @@ -667,13 +671,13 @@ public class PNGImageWriter extends ImageWriter { } } - private byte[] deflate(String s) throws IOException { + private byte[] deflate(byte[] b) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(baos); - int len = s.length(); + int len = b.length; for (int i = 0; i < len; i++) { - dos.write((int)s.charAt(i)); + dos.write((int)(0xff & b[i])); } dos.close(); @@ -681,38 +685,37 @@ public class PNGImageWriter extends ImageWriter { } private void write_iTXt() throws IOException { - Iterator keywordIter = metadata.iTXt_keyword.iterator(); - Iterator flagIter = metadata.iTXt_compressionFlag.iterator(); - Iterator methodIter = metadata.iTXt_compressionMethod.iterator(); - Iterator languageIter = metadata.iTXt_languageTag.iterator(); - Iterator translatedKeywordIter = + Iterator keywordIter = metadata.iTXt_keyword.iterator(); + Iterator flagIter = metadata.iTXt_compressionFlag.iterator(); + Iterator methodIter = metadata.iTXt_compressionMethod.iterator(); + Iterator languageIter = metadata.iTXt_languageTag.iterator(); + Iterator translatedKeywordIter = metadata.iTXt_translatedKeyword.iterator(); - Iterator textIter = metadata.iTXt_text.iterator(); + Iterator textIter = metadata.iTXt_text.iterator(); while (keywordIter.hasNext()) { ChunkStream cs = new ChunkStream(PNGImageReader.iTXt_TYPE, stream); - String keyword = (String)keywordIter.next(); - cs.writeBytes(keyword); + + cs.writeBytes(keywordIter.next()); cs.writeByte(0); - int flag = ((Integer)flagIter.next()).intValue(); - cs.writeByte(flag); - int method = ((Integer)methodIter.next()).intValue(); - cs.writeByte(method); + Boolean compressed = flagIter.next(); + cs.writeByte(compressed ? 1 : 0); - String languageTag = (String)languageIter.next(); - cs.writeBytes(languageTag); + cs.writeByte(methodIter.next().intValue()); + + cs.writeBytes(languageIter.next()); cs.writeByte(0); - String translatedKeyword = (String)translatedKeywordIter.next(); - cs.writeBytes(translatedKeyword); + + cs.write(translatedKeywordIter.next().getBytes("UTF8")); cs.writeByte(0); - String text = (String)textIter.next(); - if (flag == 1) { - cs.write(deflate(text)); + String text = textIter.next(); + if (compressed) { + cs.write(deflate(text.getBytes("UTF8"))); } else { - cs.writeUTF(text); + cs.write(text.getBytes("UTF8")); } cs.finish(); } @@ -733,7 +736,7 @@ public class PNGImageWriter extends ImageWriter { cs.writeByte(compressionMethod); String text = (String)textIter.next(); - cs.write(deflate(text)); + cs.write(deflate(text.getBytes())); cs.finish(); } } @@ -928,23 +931,24 @@ public class PNGImageWriter extends ImageWriter { // Use sourceXOffset, etc. private void write_IDAT(RenderedImage image) throws IOException { IDATOutputStream ios = new IDATOutputStream(stream, 32768); - - if (metadata.IHDR_interlaceMethod == 1) { - for (int i = 0; i < 7; i++) { - encodePass(ios, image, - PNGImageReader.adam7XOffset[i], - PNGImageReader.adam7YOffset[i], - PNGImageReader.adam7XSubsampling[i], - PNGImageReader.adam7YSubsampling[i]); - if (abortRequested()) { - break; + try { + if (metadata.IHDR_interlaceMethod == 1) { + for (int i = 0; i < 7; i++) { + encodePass(ios, image, + PNGImageReader.adam7XOffset[i], + PNGImageReader.adam7YOffset[i], + PNGImageReader.adam7XSubsampling[i], + PNGImageReader.adam7YSubsampling[i]); + if (abortRequested()) { + break; + } } + } else { + encodePass(ios, image, 0, 0, 1, 1); } - } else { - encodePass(ios, image, 0, 0, 1, 1); + } finally { + ios.finish(); } - - ios.finish(); } private void writeIEND() throws IOException { diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 19f4f67013e..5475fc79651 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -174,12 +174,12 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { public byte[] iCCP_compressedProfile; // iTXt chunk - public ArrayList iTXt_keyword = new ArrayList(); // Strings - public ArrayList iTXt_compressionFlag = new ArrayList(); // Integers - public ArrayList iTXt_compressionMethod = new ArrayList(); // Integers - public ArrayList iTXt_languageTag = new ArrayList(); // Strings - public ArrayList iTXt_translatedKeyword = new ArrayList(); // Strings - public ArrayList iTXt_text = new ArrayList(); // Strings + public ArrayList iTXt_keyword = new ArrayList(); + public ArrayList iTXt_compressionFlag = new ArrayList(); + public ArrayList iTXt_compressionMethod = new ArrayList(); + public ArrayList iTXt_languageTag = new ArrayList(); + public ArrayList iTXt_translatedKeyword = new ArrayList(); + public ArrayList iTXt_text = new ArrayList(); // pHYs chunk public boolean pHYs_present; @@ -597,19 +597,17 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { if (iTXt_keyword.size() > 0) { IIOMetadataNode iTXt_parent = new IIOMetadataNode("iTXt"); for (int i = 0; i < iTXt_keyword.size(); i++) { - Integer val; - IIOMetadataNode iTXt_node = new IIOMetadataNode("iTXtEntry"); - iTXt_node.setAttribute("keyword", (String)iTXt_keyword.get(i)); - val = (Integer)iTXt_compressionFlag.get(i); - iTXt_node.setAttribute("compressionFlag", val.toString()); - val = (Integer)iTXt_compressionMethod.get(i); - iTXt_node.setAttribute("compressionMethod", val.toString()); + iTXt_node.setAttribute("keyword", iTXt_keyword.get(i)); + iTXt_node.setAttribute("compressionFlag", + iTXt_compressionFlag.get(i) ? "1" : "0"); + iTXt_node.setAttribute("compressionMethod", + iTXt_compressionMethod.get(i).toString()); iTXt_node.setAttribute("languageTag", - (String)iTXt_languageTag.get(i)); + iTXt_languageTag.get(i)); iTXt_node.setAttribute("translatedKeyword", - (String)iTXt_translatedKeyword.get(i)); - iTXt_node.setAttribute("text", (String)iTXt_text.get(i)); + iTXt_translatedKeyword.get(i)); + iTXt_node.setAttribute("text", iTXt_text.get(i)); iTXt_parent.appendChild(iTXt_node); } @@ -1037,11 +1035,11 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { for (int i = 0; i < iTXt_keyword.size(); i++) { node = new IIOMetadataNode("TextEntry"); - node.setAttribute("keyword", (String)iTXt_keyword.get(i)); - node.setAttribute("value", (String)iTXt_text.get(i)); + node.setAttribute("keyword", iTXt_keyword.get(i)); + node.setAttribute("value", iTXt_text.get(i)); node.setAttribute("language", - (String)iTXt_languageTag.get(i)); - if (((Integer)iTXt_compressionFlag.get(i)).intValue() == 1) { + iTXt_languageTag.get(i)); + if (iTXt_compressionFlag.get(i)) { node.setAttribute("compression", "deflate"); } else { node.setAttribute("compression", "none"); @@ -1427,11 +1425,11 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { boolean compressionFlag = getBooleanAttribute(iTXt_node, "compressionFlag"); - iTXt_compressionFlag.add(new Boolean(compressionFlag)); + iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag)); String compressionMethod = getAttribute(iTXt_node, "compressionMethod"); - iTXt_compressionMethod.add(compressionMethod); + iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); String languageTag = getAttribute(iTXt_node, "languageTag"); @@ -1950,13 +1948,10 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { tEXt_text.add(value); } } else { - int flag = compression.equals("zip") ? - 1 : 0; - // Use an iTXt node iTXt_keyword.add(keyword); - iTXt_compressionFlag.add(new Integer(flag)); - iTXt_compressionMethod.add(new Integer(0)); + iTXt_compressionFlag.add(Boolean.valueOf(compression.equals("zip"))); + iTXt_compressionMethod.add(Integer.valueOf(0)); iTXt_languageTag.add(language); iTXt_translatedKeyword.add(keyword); // fake it iTXt_text.add(value); @@ -1993,12 +1988,12 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { gAMA_present = false; hIST_present = false; iCCP_present = false; - iTXt_keyword = new ArrayList(); - iTXt_compressionFlag = new ArrayList(); - iTXt_compressionMethod = new ArrayList(); - iTXt_languageTag = new ArrayList(); - iTXt_translatedKeyword = new ArrayList(); - iTXt_text = new ArrayList(); + iTXt_keyword = new ArrayList(); + iTXt_compressionFlag = new ArrayList(); + iTXt_compressionMethod = new ArrayList(); + iTXt_languageTag = new ArrayList(); + iTXt_translatedKeyword = new ArrayList(); + iTXt_text = new ArrayList(); pHYs_present = false; sBIT_present = false; sPLT_present = false; diff --git a/jdk/src/share/classes/java/awt/print/PrinterJob.java b/jdk/src/share/classes/java/awt/print/PrinterJob.java index 28e500db79d..f0ec3152bb3 100644 --- a/jdk/src/share/classes/java/awt/print/PrinterJob.java +++ b/jdk/src/share/classes/java/awt/print/PrinterJob.java @@ -117,15 +117,18 @@ public abstract class PrinterJob { * FileOutputStream outstream; * StreamPrintService psPrinter; * String psMimeType = "application/postscript"; + * PrinterJob pj = PrinterJob.getPrinterJob(); * * StreamPrintServiceFactory[] factories = * PrinterJob.lookupStreamPrintServices(psMimeType); * if (factories.length > 0) { * try { * outstream = new File("out.ps"); - * psPrinter = factories[0].getPrintService(fos); + * psPrinter = factories[0].getPrintService(outstream); * // psPrinter can now be set as the service on a PrinterJob - * } catch (FileNotFoundException e) { + * pj.setPrintService(psPrinter) + * } catch (Exception e) { + * e.printStackTrace(); * } * } * diff --git a/jdk/src/share/classes/javax/print/Doc.java b/jdk/src/share/classes/javax/print/Doc.java index ef1bdb5550e..01fe4a064a2 100644 --- a/jdk/src/share/classes/javax/print/Doc.java +++ b/jdk/src/share/classes/javax/print/Doc.java @@ -28,9 +28,7 @@ package javax.print; import java.io.InputStream; import java.io.IOException; import java.io.Reader; -import java.io.UnsupportedEncodingException; -import javax.print.attribute.AttributeSet; import javax.print.attribute.DocAttributeSet; diff --git a/jdk/src/share/classes/javax/print/DocFlavor.java b/jdk/src/share/classes/javax/print/DocFlavor.java index bda24a70d80..e72970c9f45 100644 --- a/jdk/src/share/classes/javax/print/DocFlavor.java +++ b/jdk/src/share/classes/javax/print/DocFlavor.java @@ -30,7 +30,6 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import java.util.Map; /** * Class DocFlavor encapsulates an object that specifies the diff --git a/jdk/src/share/classes/javax/print/DocPrintJob.java b/jdk/src/share/classes/javax/print/DocPrintJob.java index 57040658d61..671a51d6e19 100644 --- a/jdk/src/share/classes/javax/print/DocPrintJob.java +++ b/jdk/src/share/classes/javax/print/DocPrintJob.java @@ -25,7 +25,6 @@ package javax.print; -import javax.print.attribute.AttributeSet; import javax.print.attribute.PrintJobAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.event.PrintJobAttributeListener; diff --git a/jdk/src/share/classes/javax/print/MultiDocPrintService.java b/jdk/src/share/classes/javax/print/MultiDocPrintService.java index 4c6e31c0876..e8262086991 100644 --- a/jdk/src/share/classes/javax/print/MultiDocPrintService.java +++ b/jdk/src/share/classes/javax/print/MultiDocPrintService.java @@ -25,11 +25,6 @@ package javax.print; -import java.util.Map; - -import javax.print.attribute.Attribute; -import javax.print.event.PrintServiceAttributeListener; - /** Interface MultiPrintService is the factory for a MultiDocPrintJob. * A MultiPrintService diff --git a/jdk/src/share/classes/javax/print/PrintServiceLookup.java b/jdk/src/share/classes/javax/print/PrintServiceLookup.java index 1a78eded166..33bc357beef 100644 --- a/jdk/src/share/classes/javax/print/PrintServiceLookup.java +++ b/jdk/src/share/classes/javax/print/PrintServiceLookup.java @@ -28,7 +28,6 @@ package javax.print; import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import javax.print.attribute.AttributeSet; import sun.awt.AppContext; diff --git a/jdk/src/share/classes/javax/print/attribute/URISyntax.java b/jdk/src/share/classes/javax/print/attribute/URISyntax.java index e4bfa9de2f6..3ae7acc988e 100644 --- a/jdk/src/share/classes/javax/print/attribute/URISyntax.java +++ b/jdk/src/share/classes/javax/print/attribute/URISyntax.java @@ -28,7 +28,6 @@ package javax.print.attribute; import java.io.Serializable; import java.net.URI; -import java.net.URISyntaxException; /** * Class URISyntax is an abstract base class providing the common diff --git a/jdk/src/share/classes/javax/print/event/PrintServiceAttributeEvent.java b/jdk/src/share/classes/javax/print/event/PrintServiceAttributeEvent.java index 3ab488ffebd..d65d1376e83 100644 --- a/jdk/src/share/classes/javax/print/event/PrintServiceAttributeEvent.java +++ b/jdk/src/share/classes/javax/print/event/PrintServiceAttributeEvent.java @@ -25,7 +25,6 @@ package javax.print.event; -import java.util.List; import javax.print.PrintService; import javax.print.attribute.AttributeSetUtilities; import javax.print.attribute.PrintServiceAttributeSet; diff --git a/jdk/src/share/classes/sun/font/Decoration.java b/jdk/src/share/classes/sun/font/Decoration.java index ebdf7c49ac6..647baf45ea5 100644 --- a/jdk/src/share/classes/sun/font/Decoration.java +++ b/jdk/src/share/classes/sun/font/Decoration.java @@ -267,7 +267,9 @@ public class Decoration { CoreMetrics cm = label.getCoreMetrics(); if (strikethrough) { Stroke savedStroke = g2d.getStroke(); - g2d.setStroke(new BasicStroke(cm.strikethroughThickness)); + g2d.setStroke(new BasicStroke(cm.strikethroughThickness, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER)); float strikeY = y + cm.strikethroughOffset; g2d.draw(new Line2D.Float(x1, strikeY, x2, strikeY)); g2d.setStroke(savedStroke); @@ -341,7 +343,7 @@ public class Decoration { Rectangle2D visBounds = label.handleGetVisualBounds(); - if (swapColors || bgPaint != null + if (swapColors || bgPaint != null || strikethrough || stdUnderline != null || imUnderline != null) { float minX = 0; @@ -377,6 +379,7 @@ public class Decoration { // NOTE: The performace of the following code may // be very poor. float ulThickness = cm.underlineThickness; + float ulOffset = cm.underlineOffset; Rectangle2D lb = label.getLogicalBounds(); float x1 = x; @@ -385,12 +388,15 @@ public class Decoration { Area area = null; if (stdUnderline != null) { - Shape ul = stdUnderline.getUnderlineShape(ulThickness, x1, x2, y); + Shape ul = stdUnderline.getUnderlineShape(ulThickness, + x1, x2, y+ulOffset); area = new Area(ul); } if (strikethrough) { - Stroke stStroke = new BasicStroke(cm.strikethroughThickness); + Stroke stStroke = new BasicStroke(cm.strikethroughThickness, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER); float shiftY = y + cm.strikethroughOffset; Line2D line = new Line2D.Float(x1, shiftY, x2, shiftY); Area slArea = new Area(stStroke.createStrokedShape(line)); @@ -402,7 +408,8 @@ public class Decoration { } if (imUnderline != null) { - Shape ul = imUnderline.getUnderlineShape(ulThickness, x1, x2, y); + Shape ul = imUnderline.getUnderlineShape(ulThickness, + x1, x2, y+ulOffset); Area ulArea = new Area(ul); if (area == null) { area = ulArea; diff --git a/jdk/src/share/classes/sun/font/FontManager.java b/jdk/src/share/classes/sun/font/FontManager.java index d217be16d98..f709f381ada 100644 --- a/jdk/src/share/classes/sun/font/FontManager.java +++ b/jdk/src/share/classes/sun/font/FontManager.java @@ -3344,7 +3344,7 @@ public final class FontManager { int fontFormat = FONTFORMAT_NONE; int fontRank = Font2D.UNKNOWN_RANK; - if (ext.equals(".ttf") || isTTC) { + if (ext.equals(".ttf") || ext.equals(".otf") || isTTC) { fontFormat = FONTFORMAT_TRUETYPE; fontRank = Font2D.TTF_RANK; } else if (ext.equals(".pfa") || ext.equals(".pfb")) { diff --git a/jdk/src/share/classes/sun/font/TrueTypeFont.java b/jdk/src/share/classes/sun/font/TrueTypeFont.java index f77003dd624..5d9477b6e92 100644 --- a/jdk/src/share/classes/sun/font/TrueTypeFont.java +++ b/jdk/src/share/classes/sun/font/TrueTypeFont.java @@ -90,6 +90,7 @@ public class TrueTypeFont extends FileFont { public static final int ttcfTag = 0x74746366; // 'ttcf' - TTC file public static final int v1ttTag = 0x00010000; // 'v1tt' - Version 1 TT font public static final int trueTag = 0x74727565; // 'true' - Version 2 TT font + public static final int ottoTag = 0x4f54544f; // 'otto' - OpenType font /* -- ID's used in the 'name' table */ public static final int MS_PLATFORM_ID = 3; @@ -490,6 +491,7 @@ public class TrueTypeFont extends FileFont { case v1ttTag: case trueTag: + case ottoTag: break; default: diff --git a/jdk/src/share/classes/sun/font/Underline.java b/jdk/src/share/classes/sun/font/Underline.java index efe78985da8..ad1910b8412 100644 --- a/jdk/src/share/classes/sun/font/Underline.java +++ b/jdk/src/share/classes/sun/font/Underline.java @@ -126,7 +126,9 @@ abstract class Underline { private BasicStroke createStroke(float lineThickness) { if (dashPattern == null) { - return new BasicStroke(lineThickness); + return new BasicStroke(lineThickness, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER); } else { return new BasicStroke(lineThickness, diff --git a/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java b/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java index e0e03d36a2a..14029a0f8bb 100644 --- a/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -812,7 +812,9 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment return(name.startsWith(".ttf", offset) || name.startsWith(".TTF", offset) || name.startsWith(".ttc", offset) || - name.startsWith(".TTC", offset)); + name.startsWith(".TTC", offset) || + name.startsWith(".otf", offset) || + name.startsWith(".OTF", offset)); } } } @@ -835,31 +837,11 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment } } - public static class TTorT1Filter implements FilenameFilter { - public boolean accept(File dir, String name) { - - /* all conveniently have the same suffix length */ - int offset = name.length()-4; - if (offset <= 0) { /* must be at least A.ttf or A.pfa */ - return false; - } else { - boolean isTT = - name.startsWith(".ttf", offset) || - name.startsWith(".TTF", offset) || - name.startsWith(".ttc", offset) || - name.startsWith(".TTC", offset); - if (isTT) { - return true; - } else if (noType1Font) { - return false; - } else { - return(name.startsWith(".pfa", offset) || - name.startsWith(".pfb", offset) || - name.startsWith(".PFA", offset) || - name.startsWith(".PFB", offset)); - } - } - } + public static class TTorT1Filter implements FilenameFilter { + public boolean accept(File dir, String name) { + return SunGraphicsEnvironment.ttFilter.accept(dir, name) || + SunGraphicsEnvironment.t1Filter.accept(dir, name); + } } /* No need to keep consing up new instances - reuse a singleton. @@ -1290,6 +1272,13 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment displayChanger.notifyPaletteChanged(); } + /** + * Returns true when the display is local, false for remote displays. + * + * @return true when the display is local, false for remote displays + */ + public abstract boolean isDisplayLocal(); + /* * ----DISPLAY CHANGE SUPPORT---- */ diff --git a/jdk/src/share/classes/sun/java2d/SurfaceData.java b/jdk/src/share/classes/sun/java2d/SurfaceData.java index 84acfbd8f0f..65a04c23220 100644 --- a/jdk/src/share/classes/sun/java2d/SurfaceData.java +++ b/jdk/src/share/classes/sun/java2d/SurfaceData.java @@ -449,7 +449,8 @@ public abstract class SurfaceData // For now the answer can only be true in the following cases: if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && - sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR) + sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE) { if (haveLCDLoop == LCDLOOP_UNKNOWN) { DrawGlyphListLCD loop = diff --git a/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java b/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java index 5be4fec72dd..37dce4264b2 100644 --- a/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java +++ b/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java @@ -25,17 +25,13 @@ package sun.java2d.opengl; -import java.awt.AlphaComposite; -import java.awt.Color; import java.awt.Composite; import java.awt.Transparency; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; -import java.awt.image.ColorModel; import java.lang.ref.WeakReference; -import sun.awt.image.BufImgSurfaceData; import sun.java2d.SurfaceData; import sun.java2d.loops.Blit; import sun.java2d.loops.CompositeType; @@ -84,6 +80,8 @@ class OGLBlitLoops { OGLSurfaceData.PF_INT_BGR), new OGLSwToSurfaceBlit(SurfaceType.IntBgrx, OGLSurfaceData.PF_INT_BGRX), + new OGLSwToSurfaceBlit(SurfaceType.ThreeByteBgr, + OGLSurfaceData.PF_3BYTE_BGR), new OGLSwToSurfaceBlit(SurfaceType.Ushort565Rgb, OGLSurfaceData.PF_USHORT_565_RGB), new OGLSwToSurfaceBlit(SurfaceType.Ushort555Rgb, @@ -106,6 +104,8 @@ class OGLBlitLoops { OGLSurfaceData.PF_INT_BGR), new OGLSwToSurfaceScale(SurfaceType.IntBgrx, OGLSurfaceData.PF_INT_BGRX), + new OGLSwToSurfaceScale(SurfaceType.ThreeByteBgr, + OGLSurfaceData.PF_3BYTE_BGR), new OGLSwToSurfaceScale(SurfaceType.Ushort565Rgb, OGLSurfaceData.PF_USHORT_565_RGB), new OGLSwToSurfaceScale(SurfaceType.Ushort555Rgb, @@ -127,6 +127,8 @@ class OGLBlitLoops { OGLSurfaceData.PF_INT_BGR), new OGLSwToSurfaceTransform(SurfaceType.IntBgrx, OGLSurfaceData.PF_INT_BGRX), + new OGLSwToSurfaceTransform(SurfaceType.ThreeByteBgr, + OGLSurfaceData.PF_3BYTE_BGR), new OGLSwToSurfaceTransform(SurfaceType.Ushort565Rgb, OGLSurfaceData.PF_USHORT_565_RGB), new OGLSwToSurfaceTransform(SurfaceType.Ushort555Rgb, @@ -155,6 +157,8 @@ class OGLBlitLoops { OGLSurfaceData.PF_INT_BGR), new OGLSwToTextureBlit(SurfaceType.IntBgrx, OGLSurfaceData.PF_INT_BGRX), + new OGLSwToTextureBlit(SurfaceType.ThreeByteBgr, + OGLSurfaceData.PF_3BYTE_BGR), new OGLSwToTextureBlit(SurfaceType.Ushort565Rgb, OGLSurfaceData.PF_USHORT_565_RGB), new OGLSwToTextureBlit(SurfaceType.Ushort555Rgb, diff --git a/jdk/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/jdk/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 78f16f7dcca..dc509a71af4 100644 --- a/jdk/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/jdk/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -120,6 +120,7 @@ public abstract class OGLSurfaceData extends SurfaceData public static final int PF_USHORT_555_RGBX = 8; public static final int PF_BYTE_GRAY = 9; public static final int PF_USHORT_GRAY = 10; + public static final int PF_3BYTE_BGR = 11; /** * SurfaceTypes @@ -401,6 +402,7 @@ public abstract class OGLSurfaceData extends SurfaceData * - the fragment shader extension is available, and * - blending is disabled, and * - the source color is opaque + * - and the destination is opaque * * Eventually, we could enhance the native OGL text rendering code * and remove the above restrictions, but that would require significantly @@ -410,7 +412,8 @@ public abstract class OGLSurfaceData extends SurfaceData return graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) && sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && - sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR; + sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; } public void validatePipe(SunGraphics2D sg2d) { diff --git a/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java b/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java index 05989523083..886ba1e11d4 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java +++ b/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java @@ -90,7 +90,8 @@ public abstract class BufferedContext { private Region validatedClip; private Composite validatedComp; private Paint validatedPaint; - private boolean isValidatedPaintAColor; + // renamed from isValidatedPaintAColor as part of a work around for 6764257 + private boolean isValidatedPaintJustAColor; private int validatedRGB; private int validatedFlags; private boolean xformInUse; @@ -182,7 +183,7 @@ public abstract class BufferedContext { if (paint instanceof Color) { // REMIND: not 30-bit friendly int newRGB = ((Color)paint).getRGB(); - if (isValidatedPaintAColor) { + if (isValidatedPaintJustAColor) { if (newRGB != validatedRGB) { validatedRGB = newRGB; updatePaint = true; @@ -190,13 +191,13 @@ public abstract class BufferedContext { } else { validatedRGB = newRGB; updatePaint = true; - isValidatedPaintAColor = true; + isValidatedPaintJustAColor = true; } } else if (validatedPaint != paint) { updatePaint = true; // this should be set when we are switching from paint to color // in which case this condition will be true - isValidatedPaintAColor = false; + isValidatedPaintJustAColor = false; } if ((currentContext != this) || @@ -281,7 +282,7 @@ public abstract class BufferedContext { txChanged = true; } // non-Color paints may require paint revalidation - if (!isValidatedPaintAColor && txChanged) { + if (!isValidatedPaintJustAColor && txChanged) { updatePaint = true; } @@ -427,10 +428,12 @@ public abstract class BufferedContext { resetTransform(); resetComposite(); resetClip(); + BufferedPaints.resetPaint(rq); invalidateSurfaces(); validatedComp = null; validatedClip = null; validatedPaint = null; + isValidatedPaintJustAColor = false; xformInUse = false; } diff --git a/jdk/src/share/classes/sun/print/PSPathGraphics.java b/jdk/src/share/classes/sun/print/PSPathGraphics.java index 15bea939df4..3e7b057b83e 100644 --- a/jdk/src/share/classes/sun/print/PSPathGraphics.java +++ b/jdk/src/share/classes/sun/print/PSPathGraphics.java @@ -30,7 +30,6 @@ import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; -import java.awt.Paint; import java.awt.Shape; import java.awt.Transparency; diff --git a/jdk/src/share/classes/sun/print/PrintJobAttributeException.java b/jdk/src/share/classes/sun/print/PrintJobAttributeException.java index 7a29690c4e3..52a939f86b9 100644 --- a/jdk/src/share/classes/sun/print/PrintJobAttributeException.java +++ b/jdk/src/share/classes/sun/print/PrintJobAttributeException.java @@ -25,7 +25,6 @@ package sun.print; -import javax.print.DocFlavor; import javax.print.AttributeException; import javax.print.PrintException; import javax.print.attribute.Attribute; diff --git a/jdk/src/share/classes/sun/print/SunMinMaxPage.java b/jdk/src/share/classes/sun/print/SunMinMaxPage.java index 19962c56eeb..0bd9acb2a73 100644 --- a/jdk/src/share/classes/sun/print/SunMinMaxPage.java +++ b/jdk/src/share/classes/sun/print/SunMinMaxPage.java @@ -25,7 +25,6 @@ package sun.print; -import javax.print.attribute.EnumSyntax; import javax.print.attribute.PrintRequestAttribute; /* diff --git a/jdk/src/share/classes/sun/print/SunPageSelection.java b/jdk/src/share/classes/sun/print/SunPageSelection.java index 2c2d82b8da9..f51f26e9233 100644 --- a/jdk/src/share/classes/sun/print/SunPageSelection.java +++ b/jdk/src/share/classes/sun/print/SunPageSelection.java @@ -26,7 +26,6 @@ package sun.print; import javax.print.attribute.PrintRequestAttribute; -import javax.print.attribute.standard.Media; /* * A class used to determine the range of pages to be printed. diff --git a/jdk/src/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/share/classes/sun/swing/SwingUtilities2.java index 3a12a497106..3a4bc2141c3 100644 --- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java +++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java @@ -55,6 +55,7 @@ import java.io.*; import java.util.*; import sun.font.FontDesignMetrics; import sun.font.FontManager; +import sun.java2d.SunGraphicsEnvironment; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -1478,22 +1479,14 @@ public class SwingUtilities2 { * appear capable of performing gamma correction needed for LCD text. */ public static boolean isLocalDisplay() { - try { - // On Windows just return true. Permission to read os.name - // is granted to all code but wrapped in try to be safe. - if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { - return true; - } - // Else probably Solaris or Linux in which case may be remote X11 - Class x11Class = Class.forName("sun.awt.X11GraphicsEnvironment"); - Method isDisplayLocalMethod = x11Class.getMethod( - "isDisplayLocal", new Class[0]); - return (Boolean)isDisplayLocalMethod.invoke(null, (Object[])null); - } catch (Throwable t) { + boolean isLocal; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + if (ge instanceof SunGraphicsEnvironment) { + isLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal(); + } else { + isLocal = true; } - // If we get here we're most likely being run on some other O/S - // or we didn't properly detect Windows. - return true; + return isLocal; } /** diff --git a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/ImageTests.java b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/ImageTests.java index 51c4828e83c..ab06b9f4924 100644 --- a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/ImageTests.java +++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/ImageTests.java @@ -60,6 +60,9 @@ import java.awt.image.VolatileImage; import java.awt.image.WritableRaster; import java.awt.Transparency; import java.awt.geom.AffineTransform; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; import java.util.ArrayList; import javax.swing.JComponent; @@ -84,6 +87,7 @@ public abstract class ImageTests extends GraphicsTests { static Group.EnableSet bufimgsrcroot; static Group imgtestroot; + static Group imgoptionsroot; static Group imageOpRoot; static Group imageOpOptRoot; @@ -92,6 +96,7 @@ public abstract class ImageTests extends GraphicsTests { static Group bufImgOpTestRoot; static Group rasterOpTestRoot; static Option opList; + static Option doTouchSrc; static String transNodeNames[] = { null, "opaque", "bitmask", "translucent", @@ -105,9 +110,19 @@ public abstract class ImageTests extends GraphicsTests { imageroot = new Group(graphicsroot, "imaging", "Imaging Benchmarks"); imageroot.setTabbed(); + imgsrcroot = new Group.EnableSet(imageroot, "src", "Image Rendering Sources"); imgsrcroot.setBordered(true); + + imgoptionsroot = new Group(imgsrcroot, "options", + "Image Source Options"); + imgoptionsroot.setBordered(true); + doTouchSrc = + new Option.Toggle(imgoptionsroot, "touchsrc", + "Touch src image before every operation", + Option.Toggle.Off); + imgtestroot = new Group(imageroot, "tests", "Image Rendering Tests"); imgtestroot.setBordered(true); @@ -131,7 +146,11 @@ public abstract class ImageTests extends GraphicsTests { new BufImg(BufferedImage.TYPE_INT_RGB); new BufImg(BufferedImage.TYPE_INT_ARGB); new BufImg(BufferedImage.TYPE_BYTE_GRAY); + new BufImg(BufferedImage.TYPE_3BYTE_BGR); new BmByteIndexBufImg(); + new BufImg(BufferedImage.TYPE_INT_RGB, true); + new BufImg(BufferedImage.TYPE_INT_ARGB, true); + new BufImg(BufferedImage.TYPE_3BYTE_BGR, true); imageOpRoot = new Group(imageroot, "imageops", "Image Op Benchmarks"); @@ -193,6 +212,7 @@ public abstract class ImageTests extends GraphicsTests { } public static class Context extends GraphicsTests.Context { + boolean touchSrc; Image src; AffineTransform tx; } @@ -206,6 +226,7 @@ public abstract class ImageTests extends GraphicsTests { { super(parent, nodeName, description); addDependency(imgsrcroot, srcFilter); + addDependency(doTouchSrc); } public GraphicsTests.Context createContext() { @@ -217,6 +238,7 @@ public abstract class ImageTests extends GraphicsTests { ImageTests.Context ictx = (ImageTests.Context) ctx; ictx.src = env.getSrcImage(); + ictx.touchSrc = env.isEnabled(doTouchSrc); } public abstract static class TriStateImageType extends Group { @@ -272,13 +294,6 @@ public abstract class ImageTests extends GraphicsTests { public static class CompatImg extends TriStateImageType { int transparency; - public static String Descriptions[] = { - "Default Compatible Image", - "Opaque Compatible Image", - "Bitmask Compatible Image", - "Translucent Compatible Image", - }; - public CompatImg(int transparency) { super(imgsrcroot, Destinations.CompatImg.ShortNames[transparency], @@ -296,6 +311,7 @@ public abstract class ImageTests extends GraphicsTests { public static class BufImg extends TriStateImageType { int type; + boolean unmanaged; static int Transparencies[] = { Transparency.TRANSLUCENT, // "custom", @@ -315,15 +331,37 @@ public abstract class ImageTests extends GraphicsTests { }; public BufImg(int type) { + this(type, false); + } + + public BufImg(int type, boolean unmanaged) { super(bufimgsrcroot, + (unmanaged ? "unmanaged" : "") + Destinations.BufImg.ShortNames[type], + (unmanaged ? "Unmanaged " : "") + Destinations.BufImg.Descriptions[type], Transparencies[type]); this.type = type; + this.unmanaged = unmanaged; } public Image makeImage(TestEnvironment env, int w, int h) { - return new BufferedImage(w, h, type); + BufferedImage img = new BufferedImage(w, h, type); + if (unmanaged) { + DataBuffer db = img.getRaster().getDataBuffer(); + if (db instanceof DataBufferInt) { + ((DataBufferInt)db).getData(); + } else if (db instanceof DataBufferShort) { + ((DataBufferShort)db).getData(); + } else if (db instanceof DataBufferByte) { + ((DataBufferByte)db).getData(); + } else { + try { + img.setAccelerationPriority(0.0f); + } catch (Throwable e) {} + } + } + return img; } } @@ -471,15 +509,33 @@ public abstract class ImageTests extends GraphicsTests { g.translate(ictx.orgX, ictx.orgY); Image src = ictx.src; if (ictx.animate) { - do { - g.drawImage(src, x, y, null); - if ((x -= 3) < 0) x += ictx.maxX; - if ((y -= 1) < 0) y += ictx.maxY; - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } } else { - do { - g.drawImage(src, x, y, null); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, null); + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, null); + } while (--numReps > 0); + } } g.translate(-ictx.orgX, -ictx.orgY); } @@ -505,15 +561,33 @@ public abstract class ImageTests extends GraphicsTests { Image src = ictx.src; Color bg = Color.orange; if (ictx.animate) { - do { - g.drawImage(src, x, y, bg, null); - if ((x -= 3) < 0) x += ictx.maxX; - if ((y -= 1) < 0) y += ictx.maxY; - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, bg, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, bg, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } } else { - do { - g.drawImage(src, x, y, bg, null); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, bg, null); + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, bg, null); + } while (--numReps > 0); + } } g.translate(-ictx.orgX, -ictx.orgY); } @@ -524,7 +598,7 @@ public abstract class ImageTests extends GraphicsTests { public DrawImageScale(String dir, float scale) { super(imgtestroot, "drawimagescale"+dir, - "drawImage(img, x, y, w*"+scale+", h*"+scale+", obs);"); + "drawImage(img, x, y, w*"+scale+", h*"+scale+", obs);"); this.scale = scale; } @@ -546,15 +620,33 @@ public abstract class ImageTests extends GraphicsTests { g.translate(ictx.orgX, ictx.orgY); Image src = ictx.src; if (ictx.animate) { - do { - g.drawImage(src, x, y, w, h, null); - if ((x -= 3) < 0) x += ictx.maxX; - if ((y -= 1) < 0) y += ictx.maxY; - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, w, h, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, w, h, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } } else { - do { - g.drawImage(src, x, y, w, h, null); - } while (--numReps > 0); + Graphics srcG = src.getGraphics(); + if (ictx.touchSrc) { + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, x, y, w, h, null); + } while (--numReps > 0); + } else { + do { + g.drawImage(src, x, y, w, h, null); + } while (--numReps > 0); + } } g.translate(-ictx.orgX, -ictx.orgY); } @@ -588,17 +680,36 @@ public abstract class ImageTests extends GraphicsTests { Image src = ictx.src; AffineTransform tx = ictx.tx; if (ictx.animate) { - do { - tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y); - g.drawImage(src, tx, null); - if ((x -= 3) < 0) x += ictx.maxX; - if ((y -= 1) < 0) y += ictx.maxY; - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y); + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, tx, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } else { + do { + tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y); + g.drawImage(src, tx, null); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } } else { tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y); - do { - g.drawImage(src, tx, null); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics srcG = src.getGraphics(); + do { + srcG.fillRect(0, 0, 1, 1); + g.drawImage(src, tx, null); + } while (--numReps > 0); + } else { + do { + g.drawImage(src, tx, null); + } while (--numReps > 0); + } } g.translate(-ictx.orgX, -ictx.orgY); } @@ -736,15 +847,33 @@ public abstract class ImageTests extends GraphicsTests { Graphics2D g2 = (Graphics2D)ictx.graphics; g2.translate(ictx.orgX, ictx.orgY); if (ictx.animate) { - do { - g2.drawImage(src, op, x, y); - if ((x -= 3) < 0) x += ictx.maxX; - if ((y -= 1) < 0) y += ictx.maxY; - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics gSrc = src.getGraphics(); + do { + gSrc.fillRect(0, 0, 1, 1); + g2.drawImage(src, op, x, y); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } else { + do { + g2.drawImage(src, op, x, y); + if ((x -= 3) < 0) x += ictx.maxX; + if ((y -= 1) < 0) y += ictx.maxY; + } while (--numReps > 0); + } } else { - do { - g2.drawImage(src, op, x, y); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics gSrc = src.getGraphics(); + do { + gSrc.fillRect(0, 0, 1, 1); + g2.drawImage(src, op, x, y); + } while (--numReps > 0); + } else { + do { + g2.drawImage(src, op, x, y); + } while (--numReps > 0); + } } g2.translate(-ictx.orgX, -ictx.orgY); } @@ -778,9 +907,17 @@ public abstract class ImageTests extends GraphicsTests { BufferedImageOp op = ictx.bufImgOp; BufferedImage src = ictx.bufSrc; BufferedImage dst = ictx.bufDst; - do { - op.filter(src, dst); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics gSrc = src.getGraphics(); + do { + gSrc.fillRect(0, 0, 1, 1); + op.filter(src, dst); + } while (--numReps > 0); + } else { + do { + op.filter(src, dst); + } while (--numReps > 0); + } } } @@ -814,9 +951,17 @@ public abstract class ImageTests extends GraphicsTests { RasterOp op = ictx.rasterOp; Raster src = ictx.rasSrc; WritableRaster dst = ictx.rasDst; - do { - op.filter(src, dst); - } while (--numReps > 0); + if (ictx.touchSrc) { + Graphics gSrc = ictx.bufSrc.getGraphics(); + do { + gSrc.fillRect(0, 0, 1, 1); + op.filter(src, dst); + } while (--numReps > 0); + } else { + do { + op.filter(src, dst); + } while (--numReps > 0); + } } } } diff --git a/jdk/src/share/native/sun/font/freetypeScaler.c b/jdk/src/share/native/sun/font/freetypeScaler.c index 5f6385b2868..59c1a180c29 100644 --- a/jdk/src/share/native/sun/font/freetypeScaler.c +++ b/jdk/src/share/native/sun/font/freetypeScaler.c @@ -1281,7 +1281,7 @@ Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative( sunFontIDs.rect2DFloatClass, sunFontIDs.rect2DFloatCtr4, F26Dot6ToFloat(bbox.xMin), - F26Dot6ToFloat(bbox.yMax), + F26Dot6ToFloat(-bbox.yMax), F26Dot6ToFloat(bbox.xMax-bbox.xMin), F26Dot6ToFloat(bbox.yMax-bbox.yMin)); } diff --git a/jdk/src/share/native/sun/java2d/opengl/OGLBlitLoops.c b/jdk/src/share/native/sun/java2d/opengl/OGLBlitLoops.c index 0a16a2b737c..a9f98c80c5a 100644 --- a/jdk/src/share/native/sun/java2d/opengl/OGLBlitLoops.c +++ b/jdk/src/share/native/sun/java2d/opengl/OGLBlitLoops.c @@ -203,7 +203,24 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL); j2d_glPixelZoom(scalex, -scaley); - j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase); + + // in case pixel stride is not a multiple of scanline stride the copy + // has to be done line by line (see 6207877) + if (srcInfo->scanStride % srcInfo->pixelStride != 0) { + jint width = sx2-sx1; + jint height = sy2-sy1; + GLvoid *pSrc = srcInfo->rasBase; + + while (height > 0) { + j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc); + j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-1, NULL); + pSrc = PtrAddBytes(pSrc, srcInfo->scanStride); + height--; + } + } else { + j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase); + } + j2d_glPixelZoom(1.0, 1.0); if (oglc->extraAlpha != 1.0f) { @@ -250,6 +267,7 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, jint sx, sy, sw, sh; GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR : GL_NEAREST; jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha); + jboolean slowPath; if (oglc->blitTextureID == 0) { if (!OGLContext_InitBlitTileTexture(oglc)) { @@ -279,6 +297,10 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f); } + // in case pixel stride is not a multiple of scanline stride the copy + // has to be done line by line (see 6207877) + slowPath = srcInfo->scanStride % srcInfo->pixelStride != 0; + for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) { sh = ((sy + th) > sy2) ? (sy2 - sy) : th; dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh; @@ -291,13 +313,29 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, ty2 = ((GLdouble)sh) / th; if (swsurface) { - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy); + if (slowPath) { + jint tmph = sh; + GLvoid *pSrc = PtrCoord(srcInfo->rasBase, + sx, srcInfo->pixelStride, + sy, srcInfo->scanStride); - j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, 0, sw, sh, - pf->format, pf->type, - srcInfo->rasBase); + while (tmph > 0) { + j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, sh - tmph, sw, 1, + pf->format, pf->type, + pSrc); + pSrc = PtrAddBytes(pSrc, srcInfo->scanStride); + tmph--; + } + } else { + j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx); + j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy); + + j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, sw, sh, + pf->format, pf->type, + srcInfo->rasBase); + } // the texture image is "right side up", so we align the // upper-left texture corner with the upper-left quad corner @@ -356,9 +394,25 @@ OGLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, OGLPixelFormat *pf, jint dx1, jint dy1, jint dx2, jint dy2) { j2d_glBindTexture(dstOps->textureTarget, dstOps->textureID); - j2d_glTexSubImage2D(dstOps->textureTarget, 0, - dx1, dy1, dx2-dx1, dy2-dy1, - pf->format, pf->type, srcInfo->rasBase); + // in case pixel stride is not a multiple of scanline stride the copy + // has to be done line by line (see 6207877) + if (srcInfo->scanStride % srcInfo->pixelStride != 0) { + jint width = dx2 - dx1; + jint height = dy2 - dy1; + GLvoid *pSrc = srcInfo->rasBase; + + while (height > 0) { + j2d_glTexSubImage2D(dstOps->textureTarget, 0, + dx1, dy2 - height, width, 1, + pf->format, pf->type, pSrc); + pSrc = PtrAddBytes(pSrc, srcInfo->scanStride); + height--; + } + } else { + j2d_glTexSubImage2D(dstOps->textureTarget, 0, + dx1, dy1, dx2-dx1, dy2-dy1, + pf->format, pf->type, srcInfo->rasBase); + } } /** diff --git a/jdk/src/share/native/sun/java2d/opengl/OGLSurfaceData.c b/jdk/src/share/native/sun/java2d/opengl/OGLSurfaceData.c index 2b45a610be3..0cb11d105af 100644 --- a/jdk/src/share/native/sun/java2d/opengl/OGLSurfaceData.c +++ b/jdk/src/share/native/sun/java2d/opengl/OGLSurfaceData.c @@ -73,7 +73,8 @@ OGLPixelFormat PixelFormats[] = { 1, 0, 1, }, /* 9 - ByteGray */ { GL_LUMINANCE, GL_UNSIGNED_SHORT, 2, 0, 1, }, /*10 - UshortGray */ -}; + { GL_BGR, GL_UNSIGNED_BYTE, + 1, 0, 1, }, /*11 - ThreeByteBgr */}; /** * Given a starting value and a maximum limit, returns the first power-of-two diff --git a/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java b/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java index dadfe84d71f..47ca64f1daa 100644 --- a/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java +++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java @@ -209,7 +209,7 @@ public class X11GraphicsEnvironment private static native int checkShmExt(); private static native String getDisplayString(); - private static Boolean isDisplayLocal; + private Boolean isDisplayLocal; /** * This should only be called from the static initializer, so no need for @@ -234,7 +234,8 @@ public class X11GraphicsEnvironment return getScreenDevices()[getDefaultScreenNum()]; } - public static boolean isDisplayLocal() { + @Override + public boolean isDisplayLocal() { if (isDisplayLocal == null) { SunToolkit.awtLock(); try { diff --git a/jdk/src/solaris/classes/sun/java2d/opengl/GLXGraphicsConfig.java b/jdk/src/solaris/classes/sun/java2d/opengl/GLXGraphicsConfig.java index 8e8e18448b6..d21e177542d 100644 --- a/jdk/src/solaris/classes/sun/java2d/opengl/GLXGraphicsConfig.java +++ b/jdk/src/solaris/classes/sun/java2d/opengl/GLXGraphicsConfig.java @@ -120,12 +120,14 @@ public class GLXGraphicsConfig new GLXGetConfigInfo(device.getScreen(), visualnum); rq.flushAndInvokeNow(action); cfginfo = action.getConfigInfo(); - OGLContext.setScratchSurface(cfginfo); - rq.flushAndInvokeNow(new Runnable() { - public void run() { - ids[0] = OGLContext.getOGLIdString(); - } - }); + if (cfginfo != 0L) { + OGLContext.setScratchSurface(cfginfo); + rq.flushAndInvokeNow(new Runnable() { + public void run() { + ids[0] = OGLContext.getOGLIdString(); + } + }); + } } finally { rq.unlock(); } diff --git a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java index 986f1b51e20..54f79769343 100644 --- a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java +++ b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java @@ -50,6 +50,7 @@ import sun.awt.image.PixelConverter; import sun.font.X11TextRenderer; import sun.java2d.InvalidPipeException; import sun.java2d.SunGraphics2D; +import sun.java2d.SunGraphicsEnvironment; import sun.java2d.SurfaceData; import sun.java2d.SurfaceDataProxy; import sun.java2d.loops.SurfaceType; @@ -240,6 +241,11 @@ public abstract class X11SurfaceData extends SurfaceData { */ public static native boolean isDgaAvailable(); + /** + * Returns true if shared memory pixmaps are available + */ + private static native boolean isShmPMAvailable(); + public static boolean isAccelerationEnabled() { if (accelerationEnabled == null) { @@ -253,8 +259,17 @@ public abstract class X11SurfaceData extends SurfaceData { // true iff prop==true, false otherwise accelerationEnabled = Boolean.valueOf(prop); } else { - // use pixmaps if there is no dga, no matter local or remote - accelerationEnabled = Boolean.valueOf(!isDgaAvailable()); + boolean isDisplayLocal = false; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + if (ge instanceof SunGraphicsEnvironment) { + isDisplayLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal(); + } + + // EXA based drivers tend to place pixmaps in VRAM, slowing down readbacks. + // Don't use pixmaps if dga is available, + // or we are local and shared memory Pixmaps are not available. + accelerationEnabled = + !(isDgaAvailable() || (isDisplayLocal && !isShmPMAvailable())); } } } diff --git a/jdk/src/solaris/classes/sun/print/CUPSPrinter.java b/jdk/src/solaris/classes/sun/print/CUPSPrinter.java index cd7de38b260..a8c0dd0d3ea 100644 --- a/jdk/src/solaris/classes/sun/print/CUPSPrinter.java +++ b/jdk/src/solaris/classes/sun/print/CUPSPrinter.java @@ -46,9 +46,9 @@ import javax.print.attribute.standard.PrinterName; public class CUPSPrinter { - + private static final String debugPrefix = "CUPSPrinter>> "; private static final double PRINTER_DPI = 72.0; - private static boolean initialized; + private boolean initialized; private static native String getCupsServer(); private static native int getCupsPort(); private static native boolean canConnect(String server, int port); @@ -156,7 +156,7 @@ public class CUPSPrinter { /** * Initialize media by translating PPD info to PrintService attributes. */ - private void initMedia() { + private synchronized void initMedia() { if (initialized) { return; } else { @@ -392,9 +392,9 @@ public class CUPSPrinter { * Detects if CUPS is running. */ public static boolean isCupsRunning() { - IPPPrintService.debug_println("libFound "+libFound); + IPPPrintService.debug_println(debugPrefix+"libFound "+libFound); if (libFound) { - IPPPrintService.debug_println("CUPS server "+getServer()+ + IPPPrintService.debug_println(debugPrefix+"CUPS server "+getServer()+ " port "+getPort()); return canConnect(getServer(), getPort()); } else { diff --git a/jdk/src/solaris/classes/sun/print/IPPPrintService.java b/jdk/src/solaris/classes/sun/print/IPPPrintService.java index ba438a93031..07b68b18fa8 100644 --- a/jdk/src/solaris/classes/sun/print/IPPPrintService.java +++ b/jdk/src/solaris/classes/sun/print/IPPPrintService.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,18 +57,28 @@ import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Iterator; +import java.util.HashSet; public class IPPPrintService implements PrintService, SunPrinterJobService { - public static boolean debugPrint = false; - private static String debugPrefix = "IPPPrintService>> "; + public static final boolean debugPrint; + private static final String debugPrefix = "IPPPrintService>> "; protected static void debug_println(String str) { if (debugPrint) { System.out.println(str); } } + private static final String FORCE_PIPE_PROP = "sun.print.ippdebug"; + + static { + String debugStr = + (String)java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction(FORCE_PIPE_PROP)); + + debugPrint = "true".equalsIgnoreCase(debugStr); + } private String printer; private URI myURI; @@ -382,7 +392,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { if ((urlConnection = getIPPConnection(myURL)) == null) { mediaSizeNames = new MediaSizeName[0]; mediaTrays = new MediaTray[0]; - debug_println("NULL urlConnection "); + debug_println(debugPrefix+"initAttributes, NULL urlConnection "); init = true; return; } @@ -407,7 +417,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { return; } catch (Exception e) { IPPPrintService.debug_println(debugPrefix+ - " error creating CUPSPrinter e="+e); + "initAttributes, error creating CUPSPrinter e="+e); } } @@ -486,28 +496,26 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { /* Test if the flavor is compatible with the category */ if ((category == Copies.class) || (category == CopiesSupported.class)) { - CopiesSupported cs = new CopiesSupported(1, MAXCOPIES); - AttributeClass attribClass = (getAttMap != null) ? - (AttributeClass)getAttMap.get(cs.getName()) : null; - if (attribClass != null) { - int[] range = attribClass.getIntRangeValue(); - cs = new CopiesSupported(range[0], range[1]); + if (flavor == null || + !(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) || + flavor.equals(DocFlavor.URL.POSTSCRIPT) || + flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) { + CopiesSupported cs = new CopiesSupported(1, MAXCOPIES); + AttributeClass attribClass = (getAttMap != null) ? + (AttributeClass)getAttMap.get(cs.getName()) : null; + if (attribClass != null) { + int[] range = attribClass.getIntRangeValue(); + cs = new CopiesSupported(range[0], range[1]); + } + return cs; + } else { + return null; } - return cs; } else if (category == Chromaticity.class) { if (flavor == null || flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || - flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || - flavor.equals(DocFlavor.INPUT_STREAM.GIF) || - flavor.equals(DocFlavor.URL.GIF) || - flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || - flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || - flavor.equals(DocFlavor.URL.JPEG) || - flavor.equals(DocFlavor.BYTE_ARRAY.PNG) || - flavor.equals(DocFlavor.INPUT_STREAM.PNG) || - flavor.equals(DocFlavor.URL.PNG)) { - + !isIPPSupportedImages(flavor.getMimeType())) { Chromaticity[]arr = new Chromaticity[1]; arr[0] = Chromaticity.COLOR; return (arr); @@ -822,7 +830,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { boolean psSupported = false; String[] docFlavors = attribClass.getArrayOfStringValues(); DocFlavor[] flavors; - ArrayList docList = new ArrayList(); + HashSet docList = new HashSet(); int j; String hostEnc = DocFlavor.hostEncoding. toLowerCase(Locale.ENGLISH); @@ -839,18 +847,6 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { docList.addAll(Arrays.asList(flavors)); - if (isCupsPrinter) { - /* - Always add Pageable and Printable for CUPS - since it uses Filters to convert from Postscript - to device printer language. - */ - docList.add( - DocFlavor.SERVICE_FORMATTED.PAGEABLE); - docList.add( - DocFlavor.SERVICE_FORMATTED.PRINTABLE); - } - if (mimeType.equals("text/plain") && addHostEncoding) { docList.add(Arrays.asList(textPlainHost)); @@ -880,16 +876,19 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { } // check if we need to add image DocFlavors + // and Pageable/Printable flavors if (psSupported || isCupsPrinter) { - if (!jpgImagesAdded) { - docList.addAll(Arrays.asList(imageJPG)); - } - if (!pngImagesAdded) { - docList.addAll(Arrays.asList(imagePNG)); - } - if (!gifImagesAdded) { - docList.addAll(Arrays.asList(imageGIF)); - } + /* + Always add Pageable and Printable for CUPS + since it uses Filters to convert from Postscript + to device printer language. + */ + docList.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE); + docList.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE); + + docList.addAll(Arrays.asList(imageJPG)); + docList.addAll(Arrays.asList(imagePNG)); + docList.addAll(Arrays.asList(imageGIF)); } supportedDocFlavors = new DocFlavor[docList.size()]; docList.toArray(supportedDocFlavors); @@ -922,6 +921,9 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { * Finds matching CustomMediaSizeName of given media. */ public CustomMediaSizeName findCustomMedia(MediaSizeName media) { + if (customMediaSizeNames == null) { + return null; + } for (int i=0; i< customMediaSizeNames.length; i++) { CustomMediaSizeName custom = (CustomMediaSizeName)customMediaSizeNames[i]; @@ -1203,7 +1205,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { return true; } for (int i=0; i= GRPTAG_OP_ATTRIBUTES) && (response[0] <= GRPTAG_PRINTER_ATTRIBUTES) && (response[0] != GRPTAG_END_ATTRIBUTES)) { - debug_println(debugPrefix+"checking group tag, response[0]= "+ + debug_println(debugPrefix+"readIPPResponse, checking group tag, response[0]= "+ response[0]); outObj = new ByteArrayOutputStream(); @@ -1786,6 +1786,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { outArray); responseMap.put(ac.getName(), ac); + debug_println(debugPrefix+ "readIPPResponse "+ac); } outObj = new ByteArrayOutputStream(); @@ -1858,6 +1859,9 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { } catch (java.io.IOException e) { debug_println(debugPrefix+"readIPPResponse: "+e); + if (debugPrint) { + e.printStackTrace(); + } return null; } } @@ -1872,4 +1876,8 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { (obj instanceof IPPPrintService && ((IPPPrintService)obj).getName().equals(getName()))); } + + public int hashCode() { + return this.getClass().hashCode()+getName().hashCode(); + } } diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintService.java b/jdk/src/solaris/classes/sun/print/UnixPrintService.java index f451f804c7a..30d2dc82ca8 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintService.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintService.java @@ -686,19 +686,7 @@ public class UnixPrintService implements PrintService, AttributeUpdater, } if (category == Chromaticity.class) { - if (flavor == null || - flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || - flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || - flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || - flavor.equals(DocFlavor.INPUT_STREAM.GIF) || - flavor.equals(DocFlavor.URL.GIF) || - flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || - flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || - flavor.equals(DocFlavor.URL.JPEG) || - flavor.equals(DocFlavor.BYTE_ARRAY.PNG) || - flavor.equals(DocFlavor.INPUT_STREAM.PNG) || - flavor.equals(DocFlavor.URL.PNG)) { - + if (flavor == null || isServiceFormattedFlavor(flavor)) { Chromaticity[]arr = new Chromaticity[1]; arr[0] = Chromaticity.COLOR; return (arr); @@ -730,18 +718,7 @@ public class UnixPrintService implements PrintService, AttributeUpdater, } return new RequestingUserName(userName, null); } else if (category == OrientationRequested.class) { - if (flavor == null || - flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || - flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || - flavor.equals(DocFlavor.INPUT_STREAM.GIF) || - flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || - flavor.equals(DocFlavor.INPUT_STREAM.PNG) || - flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || - flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || - flavor.equals(DocFlavor.BYTE_ARRAY.PNG) || - flavor.equals(DocFlavor.URL.GIF) || - flavor.equals(DocFlavor.URL.JPEG) || - flavor.equals(DocFlavor.URL.PNG)) { + if (flavor == null || isServiceFormattedFlavor(flavor)) { OrientationRequested []arr = new OrientationRequested[3]; arr[0] = OrientationRequested.PORTRAIT; arr[1] = OrientationRequested.LANDSCAPE; @@ -752,7 +729,14 @@ public class UnixPrintService implements PrintService, AttributeUpdater, } } else if ((category == Copies.class) || (category == CopiesSupported.class)) { - return new CopiesSupported(1, MAXCOPIES); + if (flavor == null || + !(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) || + flavor.equals(DocFlavor.URL.POSTSCRIPT) || + flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) { + return new CopiesSupported(1, MAXCOPIES); + } else { + return null; + } } else if (category == Media.class) { Media []arr = new Media[mediaSizes.length]; System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length); @@ -917,8 +901,10 @@ public class UnixPrintService implements PrintService, AttributeUpdater, } } else if (attr.getCategory() == Copies.class) { - return - (flavor == null || isServiceFormattedFlavor(flavor)) && + return (flavor == null || + !(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) || + flavor.equals(DocFlavor.URL.POSTSCRIPT) || + flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) && isSupportedCopies((Copies)attr); } else if (attr.getCategory() == Destination.class) { URI uri = ((Destination)attr).getURI(); diff --git a/jdk/src/solaris/native/sun/awt/fontpath.c b/jdk/src/solaris/native/sun/awt/fontpath.c index 8f9f3d9a894..b944ff93360 100644 --- a/jdk/src/solaris/native/sun/awt/fontpath.c +++ b/jdk/src/solaris/native/sun/awt/fontpath.c @@ -156,7 +156,7 @@ jboolean isDisplayLocal(JNIEnv *env) { isLocal = JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11GraphicsEnvironment", - "isDisplayLocal", + "_isDisplayLocal", "()Z").z; isLocalSet = True; return isLocal; @@ -1233,7 +1233,7 @@ Java_sun_font_FontManager_getFontConfig for (j=0; jfonts[j]; FcChar8 *fontformat; - FcCharSet *unionCharset, *charset; + FcCharSet *unionCharset = NULL, *charset; fontformat = NULL; (*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat); @@ -1256,7 +1256,7 @@ Java_sun_font_FontManager_getFontConfig if (nfonts==10) { minGlyphs = 50; } - if (j == 0) { + if (unionCharset == NULL) { unionCharset = charset; } else { if ((*FcCharSetSubtractCount)(charset, unionCharset) diff --git a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c index 8b275bc91a8..8423f1eee04 100644 --- a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c +++ b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c @@ -208,6 +208,23 @@ Java_sun_java2d_x11_X11SurfaceData_isDgaAvailable(JNIEnv *env, jobject this) #endif /* HEADLESS */ } + +/* + * Class: sun_java2d_x11_X11SurfaceData + * Method: isShmPMAvailable + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_sun_java2d_x11_X11SurfaceData_isShmPMAvailable(JNIEnv *env, jobject this) +{ +#if defined(HEADLESS) || !defined(MITSHM) + return JNI_FALSE; +#else + return useMitShmPixmaps; +#endif /* HEADLESS, MITSHM */ +} + + /* * Class: sun_java2d_x11_X11SurfaceData * Method: initOps diff --git a/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java index 80ee7747004..73b73dbb033 100644 --- a/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java +++ b/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java @@ -393,4 +393,9 @@ public class Win32GraphicsEnvironment private static void dwmCompositionChanged(boolean enabled) { isDWMCompositionEnabled = enabled; } + + @Override + public boolean isDisplayLocal() { + return true; + } } diff --git a/jdk/src/windows/classes/sun/java2d/d3d/D3DBlitLoops.java b/jdk/src/windows/classes/sun/java2d/d3d/D3DBlitLoops.java index 459a197fab6..45d6cd8fdd0 100644 --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DBlitLoops.java +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DBlitLoops.java @@ -85,6 +85,8 @@ class D3DBlitLoops { D3DSurfaceData.ST_INT_RGB), new D3DSwToSurfaceBlit(SurfaceType.IntBgr, D3DSurfaceData.ST_INT_BGR), + new D3DSwToSurfaceBlit(SurfaceType.ThreeByteBgr, + D3DSurfaceData.ST_3BYTE_BGR), new D3DSwToSurfaceBlit(SurfaceType.Ushort565Rgb, D3DSurfaceData.ST_USHORT_565_RGB), new D3DSwToSurfaceBlit(SurfaceType.Ushort555Rgb, @@ -106,6 +108,8 @@ class D3DBlitLoops { D3DSurfaceData.ST_INT_RGB), new D3DSwToSurfaceScale(SurfaceType.IntBgr, D3DSurfaceData.ST_INT_BGR), + new D3DSwToSurfaceScale(SurfaceType.ThreeByteBgr, + D3DSurfaceData.ST_3BYTE_BGR), new D3DSwToSurfaceScale(SurfaceType.Ushort565Rgb, D3DSurfaceData.ST_USHORT_565_RGB), new D3DSwToSurfaceScale(SurfaceType.Ushort555Rgb, @@ -124,6 +128,8 @@ class D3DBlitLoops { D3DSurfaceData.ST_INT_RGB), new D3DSwToSurfaceTransform(SurfaceType.IntBgr, D3DSurfaceData.ST_INT_BGR), + new D3DSwToSurfaceTransform(SurfaceType.ThreeByteBgr, + D3DSurfaceData.ST_3BYTE_BGR), new D3DSwToSurfaceTransform(SurfaceType.Ushort565Rgb, D3DSurfaceData.ST_USHORT_565_RGB), new D3DSwToSurfaceTransform(SurfaceType.Ushort555Rgb, @@ -147,6 +153,8 @@ class D3DBlitLoops { D3DSurfaceData.ST_INT_ARGB), new D3DSwToTextureBlit(SurfaceType.IntBgr, D3DSurfaceData.ST_INT_BGR), + new D3DSwToTextureBlit(SurfaceType.ThreeByteBgr, + D3DSurfaceData.ST_3BYTE_BGR), new D3DSwToTextureBlit(SurfaceType.Ushort565Rgb, D3DSurfaceData.ST_USHORT_565_RGB), new D3DSwToTextureBlit(SurfaceType.Ushort555Rgb, diff --git a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index 3d1457c721f..722440a77bd 100644 --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -135,6 +135,7 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { public static final int ST_USHORT_555_RGB = 6; public static final int ST_BYTE_INDEXED = 7; public static final int ST_BYTE_INDEXED_BM = 8; + public static final int ST_3BYTE_BGR = 9; /** Equals to D3DSWAPEFFECT_DISCARD */ public static final int SWAP_DISCARD = 1; @@ -501,12 +502,14 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { * - the pixel shaders are available, and * - blending is disabled, and * - the source color is opaque + * - and the destination is opaque */ public boolean canRenderLCDText(SunGraphics2D sg2d) { return graphicsDevice.isCapPresent(CAPS_LCD_SHADER) && sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && - sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR; + sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; } public void validatePipe(SunGraphics2D sg2d) { diff --git a/jdk/src/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java b/jdk/src/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java index 7ff7e1e8d09..bdd0ade4638 100644 --- a/jdk/src/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java +++ b/jdk/src/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java @@ -127,12 +127,14 @@ public class WGLGraphicsConfig new WGLGetConfigInfo(device.getScreen(), pixfmt); rq.flushAndInvokeNow(action); cfginfo = action.getConfigInfo(); - OGLContext.setScratchSurface(cfginfo); - rq.flushAndInvokeNow(new Runnable() { - public void run() { - ids[0] = OGLContext.getOGLIdString(); - } - }); + if (cfginfo != 0L) { + OGLContext.setScratchSurface(cfginfo); + rq.flushAndInvokeNow(new Runnable() { + public void run() { + ids[0] = OGLContext.getOGLIdString(); + } + }); + } } finally { rq.unlock(); } diff --git a/jdk/src/windows/native/sun/font/fontpath.c b/jdk/src/windows/native/sun/font/fontpath.c index 71b1da85f17..2fd3c3af9be 100644 --- a/jdk/src/windows/native/sun/font/fontpath.c +++ b/jdk/src/windows/native/sun/font/fontpath.c @@ -153,7 +153,8 @@ static int CALLBACK EnumFontFacesInFamilyProcA( JNIEnv *env = fmi->env; jstring fullname, fullnameLC; - if (FontType != TRUETYPE_FONTTYPE) { + /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ + if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { return 1; } @@ -227,7 +228,8 @@ static int CALLBACK EnumFontFacesInFamilyProcW( JNIEnv *env = fmi->env; jstring fullname, fullnameLC; - if (FontType != TRUETYPE_FONTTYPE) { + /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ + if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { return 1; } @@ -274,7 +276,8 @@ static int CALLBACK EnumFamilyNamesA( jstring familyLC; LOGFONTA lfa; - if (FontType != TRUETYPE_FONTTYPE) { + /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ + if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { return 1; } @@ -323,7 +326,8 @@ static int CALLBACK EnumFamilyNamesW( int slen; LOGFONTW lfw; - if (FontType != TRUETYPE_FONTTYPE) { + /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ + if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { return 1; } /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ @@ -383,15 +387,16 @@ static int CALLBACK EnumFamilyNamesW( * Also if a Font has a name for this locale that name also * exists in the registry using the appropriate platform encoding. * What do we do then? + * + * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista + * but " (OpenType)" on XP. */ -/* static const wchar_t W_TTSUFFIX[] = L" (TrueType)"; */ -/* static const char C_TTSUFFIX[] = " (TrueType)"; */ -/* static int TTSLEN = 11; hard-coded - be careful */ -static BOOL RegistryToBaseTTNameA(LPCSTR name) { +static BOOL RegistryToBaseTTNameA(LPSTR name) { static const char TTSUFFIX[] = " (TrueType)"; + static const char OTSUFFIX[] = " (OpenType)"; int TTSLEN = strlen(TTSUFFIX); - char *match; + char *suffix; int len = strlen(name); if (len == 0) { @@ -403,19 +408,21 @@ static BOOL RegistryToBaseTTNameA(LPCSTR name) { if (len <= TTSLEN) { return FALSE; } - match = strstr(name, TTSUFFIX); - if ((match != NULL) && (match == name+(len-TTSLEN))) { - match[0] = '\0'; /* truncate name */ + + /* suffix length is the same for truetype and opentype fonts */ + suffix = name + len - TTSLEN; + if (strcmp(suffix, TTSUFFIX) == 0 || strcmp(suffix, OTSUFFIX) == 0) { + suffix[0] = '\0'; /* truncate name */ return TRUE; - } else { - return FALSE; } + return FALSE; } static BOOL RegistryToBaseTTNameW(LPWSTR name) { static const wchar_t TTSUFFIX[] = L" (TrueType)"; + static const wchar_t OTSUFFIX[] = L" (OpenType)"; int TTSLEN = wcslen(TTSUFFIX); - wchar_t *match; + wchar_t *suffix; int len = wcslen(name); if (len == 0) { @@ -427,13 +434,13 @@ static BOOL RegistryToBaseTTNameW(LPWSTR name) { if (len <= TTSLEN) { return FALSE; } - match = wcsstr(name, TTSUFFIX); - if ((match != NULL) && (match == name+(len-TTSLEN))) { - match[0] = L'\0'; /* truncate name */ + /* suffix length is the same for truetype and opentype fonts */ + suffix = name + (len - TTSLEN); + if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { + suffix[0] = L'\0'; /* truncate name */ return TRUE; - } else { - return FALSE; } + return FALSE; } static void registerFontA(GdiFontMapInfo *fmi, jobject fontToFileMap, @@ -675,18 +682,19 @@ Java_sun_font_FontManager_populateFontFileNameMap } if (IS_NT) { if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { - /* If the filename ends with ".ttf" also accept it. + /* If the filename ends with ".ttf" or ".otf" also accept it. * Not expecting to need to do this for .ttc files. * Also note this code is not mirrored in the "A" (win9x) path. */ LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); - if (dot == NULL || (wcsicmp(dot, L".ttf") != 0)) { + if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) + && (wcsicmp(dot, L".otf") != 0))) { continue; /* not a TT font... */ } } registerFontW(&fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); } else { - if (!RegistryToBaseTTNameA(cname) ) { + if (!RegistryToBaseTTNameA((LPSTR)cname)) { continue; /* not a TT font... */ } registerFontA(&fmi, fontToFileMap, cname, (LPCSTR)data); diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DBadHardware.h b/jdk/src/windows/native/sun/java2d/d3d/D3DBadHardware.h index 52629d1a5d0..20c9ad1e378 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DBadHardware.h +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DBadHardware.h @@ -85,6 +85,19 @@ static const ADAPTER_INFO badHardware[] = { { 0x1002, 0x71C5, D_VERSION(6,14,10,6706), OS_WINXP }, { 0x1002, 0x71C5, D_VERSION(7,14,10,0567), OS_VISTA }, + // ATI Mobility Radeon 9700 + // Reason: workaround for 6773336 + { 0x1002, 0x4E50, D_VERSION(6,14,10,6561), OS_WINXP }, + + // Nvidia FX 5200 + // Reason: workaround for 6717988 + { 0x10DE, 0x0322, D_VERSION(6,14,11,6921), OS_WINXP }, + + // Nvidia FX Go5600, Go5700 + // Reason: workaround for 6714579 + { 0x10DE, 0x031A, D_VERSION(6,14,11,6921), OS_WINXP }, + { 0x10DE, 0x0347, D_VERSION(6,14,11,6921), OS_WINXP }, + // Nvidia Quadro NVS 110M // Reason: workaround for 6629891 { 0x10DE, 0x01D7, D_VERSION(6,14,11,5665), OS_WINXP }, @@ -93,6 +106,32 @@ static const ADAPTER_INFO badHardware[] = { // Reason: workaround for 6653860 { 0x10DE, 0x00FD, D_VERSION(6,14,10,6573), OS_WINXP }, + // Nvidia Quadro FX family + // Reason: workaround for 6772137 + { 0x10DE, 0x00F8, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x009D, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x029C, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x029D, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x029E, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x029F, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x01DE, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x039E, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x019D, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x019E, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x040A, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x040E, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x040F, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x061A, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x06F9, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x05FD, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x05FE, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x004E, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x00CD, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x00CE, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x014C, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x014D, D_VERSION(6,14,10,9381), OS_WINXP }, + { 0x10DE, 0x014E, D_VERSION(6,14,10,9381), OS_WINXP }, + // Nvidia GeForce 6200 TurboCache(TM) // Reason: workaround for 6588384 { 0x10DE, 0x0161, NO_VERSION, OS_VISTA }, diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp b/jdk/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp index 6792a444a7d..c8a5d786144 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp @@ -47,6 +47,7 @@ extern "C" BlitFunc IntArgbToIntArgbPreConvert; extern "C" BlitFunc IntArgbPreToIntArgbConvert; extern "C" BlitFunc IntArgbBmToIntArgbConvert; extern "C" BlitFunc IntRgbToIntArgbConvert; +extern "C" BlitFunc ThreeByteBgrToIntArgbConvert; extern "C" BlitFunc Ushort565RgbToIntArgbConvert; extern "C" BlitFunc Ushort555RgbToIntArgbConvert; extern "C" BlitFunc IntBgrToIntArgbConvert; @@ -220,12 +221,17 @@ D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo, " srctype=%d rect={%-4d, %-4d, %-4d, %-4d}", srctype, r.left, r.top, r.right, r.bottom); - if (pDesc->Usage == D3DUSAGE_DYNAMIC && - dstx == 0 && dstx == 0 && - srcWidth == pDesc->Width && srcHeight == pDesc->Height) - { + if (pDesc->Usage == D3DUSAGE_DYNAMIC) { + // it is safe to lock with discard because we don't care about the + // contents of dynamic textures, and some drivers are happier if + // dynamic textures are always locked with DISCARD dwLockFlags |= D3DLOCK_DISCARD; pR = NULL; + } else { + // in non-DYNAMIC case we lock the exact rect so there's no need to + // offset the destination pointer + dstx = 0; + dsty = 0; } res = pDstSurface->LockRect(&lockedRect, pR, dwLockFlags); @@ -242,7 +248,9 @@ D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo, void *pSrcBase = PtrCoord(pSrcInfo->rasBase, srcx, pSrcInfo->pixelStride, srcy, pSrcInfo->scanStride); - void *pDstBase = lockedRect.pBits; + void *pDstBase = PtrCoord(lockedRect.pBits, + dstx, dstInfo.pixelStride, + dsty, dstInfo.scanStride); switch (srctype) { case ST_INT_ARGB: @@ -251,11 +259,15 @@ D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo, pSrcInfo, &dstInfo, NULL, NULL); break; case ST_INT_ARGB_PRE: - case ST_INT_RGB: AnyIntIsomorphicCopy(pSrcBase, pDstBase, srcWidth, srcHeight, pSrcInfo, &dstInfo, NULL, NULL); break; + case ST_INT_RGB: + IntRgbToIntArgbConvert(pSrcBase, pDstBase, + srcWidth, srcHeight, + pSrcInfo, &dstInfo, NULL, NULL); + break; case ST_INT_ARGB_BM: // REMIND: we don't have such sw loop // so this path is disabled for now on java level @@ -268,6 +280,11 @@ D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo, srcWidth, srcHeight, pSrcInfo, &dstInfo, NULL, NULL); break; + case ST_3BYTE_BGR: + ThreeByteBgrToIntArgbConvert(pSrcBase, pDstBase, + srcWidth, srcHeight, + pSrcInfo, &dstInfo, NULL, NULL); + break; case ST_USHORT_555_RGB: Ushort555RgbToIntArgbConvert(pSrcBase, pDstBase, srcWidth, srcHeight, diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DContext.cpp b/jdk/src/windows/native/sun/java2d/d3d/D3DContext.cpp index e3937b8d3e9..186f4d7557c 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DContext.cpp +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DContext.cpp @@ -1174,11 +1174,10 @@ D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels, " rect={%-4d, %-4d, %-4d, %-4d}", r.left, r.top, r.right, r.bottom); - // REMIND: we should also check for dstx, dsty being 0 here, - // but they're always 0 in dynamic texture case - if (pDesc->Usage == D3DUSAGE_DYNAMIC && - srcWidth == pDesc->Width && srcHeight == pDesc->Height) - { + if (pDesc->Usage == D3DUSAGE_DYNAMIC) { + // it is safe to lock with discard because we don't care about the + // contents of dynamic textures and dstx,dsty for this case is + // always 0,0 because we are uploading into a tile texture dwLockFlags |= D3DLOCK_DISCARD; pR = NULL; } diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DSurfaceData.h b/jdk/src/windows/native/sun/java2d/d3d/D3DSurfaceData.h index 22a89bc156d..b115ed837e9 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DSurfaceData.h +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DSurfaceData.h @@ -68,6 +68,7 @@ struct _D3DSDOps { #define ST_USHORT_555_RGB sun_java2d_d3d_D3DSurfaceData_ST_USHORT_555_RGB #define ST_BYTE_INDEXED sun_java2d_d3d_D3DSurfaceData_ST_BYTE_INDEXED #define ST_BYTE_INDEXED_BM sun_java2d_d3d_D3DSurfaceData_ST_BYTE_INDEXED_BM +#define ST_3BYTE_BGR sun_java2d_d3d_D3DSurfaceData_ST_3BYTE_BGR /** * These are defined to be the same as ExtendedBufferCapabilities.VSyncType diff --git a/jdk/test/java/awt/FullScreen/UninitializedDisplayModeChangeTest/DisplayModeChanger.java b/jdk/test/java/awt/FullScreen/UninitializedDisplayModeChangeTest/DisplayModeChanger.java new file mode 100644 index 00000000000..e73457f128d --- /dev/null +++ b/jdk/test/java/awt/FullScreen/UninitializedDisplayModeChangeTest/DisplayModeChanger.java @@ -0,0 +1,93 @@ +/* + * Copyright 2006-2008 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. + */ + +import java.awt.DisplayMode; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.lang.reflect.InvocationTargetException; + +/** + * Used by the UninitializedDisplayModeChangeTest to change the + * display mode. + */ +public class DisplayModeChanger { + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException + { + final GraphicsDevice gd = + GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice(); + + EventQueue.invokeAndWait(new Runnable() { + public void run() { + Frame f = null; + if (gd.isFullScreenSupported()) { + try { + f = new Frame("DisplayChanger Frame"); + gd.setFullScreenWindow(f); + if (gd.isDisplayChangeSupported()) { + DisplayMode dm = findDisplayMode(gd); + if (gd != null) { + gd.setDisplayMode(dm); + } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + gd.setFullScreenWindow(null); + } finally { + if (f != null) { + f.dispose(); + } + } + } + } + }); + } + + /** + * Finds a display mode that is different from the current display + * mode and is likely to cause a display change event. + */ + private static DisplayMode findDisplayMode(GraphicsDevice gd) { + DisplayMode dms[] = gd.getDisplayModes(); + DisplayMode currentDM = gd.getDisplayMode(); + for (DisplayMode dm : dms) { + if (!dm.equals(currentDM) && + dm.getRefreshRate() == currentDM.getRefreshRate()) + { + // different from the current dm and refresh rate is the same + // means that something else is different => more likely to + // cause a DM change event + return dm; + } + } + return null; + } + +} diff --git a/jdk/test/java/awt/font/TextLayout/DecorationBoundsTest.java b/jdk/test/java/awt/font/TextLayout/DecorationBoundsTest.java new file mode 100644 index 00000000000..286b75d8bfb --- /dev/null +++ b/jdk/test/java/awt/font/TextLayout/DecorationBoundsTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2008 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 + * @summary verify bounds enclose rendering of decorations. + * @bug 6751621 + */ + +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.awt.image.*; +import java.util.*; + +public class DecorationBoundsTest { + + public static void main(String[] args) { + BufferedImage bi = + new BufferedImage(600, 300, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, 600, 300); + + float x = 10; + float y = 90; + Map map = new HashMap(); + map.put(TextAttribute.STRIKETHROUGH, + TextAttribute.STRIKETHROUGH_ON); + map.put(TextAttribute.SIZE, new Float(80)); + + FontRenderContext frc = g2d.getFontRenderContext(); + + String text = "Welcome to "; + TextLayout tl = new TextLayout(text, map, frc); + g2d.translate(x, y); + g2d.setColor(Color.RED); + tl.draw(g2d, 0, 0); + g2d.setColor(Color.GREEN); + Rectangle2D bds = tl.getBounds(); + /* Since due to pixelisation the glyphs may touch above + * or below the theoretical outline bounds, pad in the + * y direction to avoid spurious failures. + */ + bds.setRect(bds.getX(), bds.getY()-1, + bds.getWidth(), bds.getHeight()+2); + g2d.fill(bds); + + map = new HashMap(); + map.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + map.put(TextAttribute.SIZE, new Float(80)); + tl = new TextLayout(text, map, frc); + g2d.translate(0, 100); + g2d.setColor(Color.RED); + tl.draw(g2d, 0, 0); + + g2d.setColor(Color.GREEN); + bds = tl.getBounds(); + bds.setRect(bds.getX(), bds.getY()-1, + bds.getWidth(), bds.getHeight()+2); + g2d.fill(bds); + + checkBI(bi, Color.RED); + } + + static void checkBI(BufferedImage bi, Color badColor) { + int badrgb = badColor.getRGB(); + int w = bi.getWidth(null); + int h = bi.getHeight(null); + for (int x=0; x OPAQUE) { + gg.setColor(new Color(0, 0, 0, 0)); + gg.setComposite(AlphaComposite.Src); + } else { + gg.setColor(new Color(0xAD, 0xD8, 0xE6)); + } + gg.fillRect(0, 0, w, h); + } + + private void render(Image im, int type, String s) { + Graphics2D g2d = (Graphics2D) im.getGraphics(); + clear(g2d, type, im.getWidth(null), im.getHeight(null)); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + Font f = new Font("Dialog", Font.BOLD, 40);// g2d.getFont().deriveFont(32.0f); + g2d.setColor(Color.white); + g2d.setFont(g2d.getFont().deriveFont(36.0f)); + g2d.drawString(s, 10, im.getHeight(null) / 2); + } + + Image images[]; + private void initImages(int w, int h) { + if (images == null) { + images = new Image[6]; + GraphicsConfiguration gc = getGraphicsConfiguration(); + for (int i = OPAQUE; i <= TRANSLUCENT; i++) { + VolatileImage vi = + gc.createCompatibleVolatileImage(w,h/images.length,i); + images[i-1] = vi; + vi.validate(gc); + String s = "LCD AA Text rendered to " + tr[i - 1] + " HW destination"; + render(vi, i, s); + + s = "LCD AA Text rendered to " + tr[i - 1] + " SW destination"; + images[i-1+3] = gc.createCompatibleImage(w, h/images.length, i); + render(images[i-1+3], i, s); + } + } + } + + public static void main(String[] args) throws InterruptedException { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + NonOpaqueDestLCDAATest t = new NonOpaqueDestLCDAATest(); + t.pack(); + t.setVisible(true); + } + }); + + complete.await(); + if (!passed) { + throw new RuntimeException("Test Failed!"); + } + } +} diff --git a/jdk/test/sun/java2d/DirectX/OpaqueImageToSurfaceBlitTest/OpaqueImageToSurfaceBlitTest.java b/jdk/test/sun/java2d/DirectX/OpaqueImageToSurfaceBlitTest/OpaqueImageToSurfaceBlitTest.java new file mode 100644 index 00000000000..2135fa75ec1 --- /dev/null +++ b/jdk/test/sun/java2d/DirectX/OpaqueImageToSurfaceBlitTest/OpaqueImageToSurfaceBlitTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2007-2008 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 6764257 + * @summary Tests that the alpha in opaque images doesn't affect result of alpha + * compositing + * @author Dmitri.Trembovetski@sun.com: area=Graphics + * @run main/othervm OpaqueImageToSurfaceBlitTest + * @run main/othervm -Dsun.java2d.noddraw=true OpaqueImageToSurfaceBlitTest + * @run main/othervm -Dsun.java2d.opengl=True OpaqueImageToSurfaceBlitTest + */ + +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.VolatileImage; + +public class OpaqueImageToSurfaceBlitTest { + + public static void main(String[] args) { + + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(16, 16); + vi.validate(gc); + + BufferedImage bi = + new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB); + int data[] = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + data[0] = 0x0000007f; + data[1] = 0x0000007f; + data[2] = 0xff00007f; + data[3] = 0xff00007f; + Graphics2D g = vi.createGraphics(); + g.setComposite(AlphaComposite.SrcOver.derive(0.999f)); + g.drawImage(bi, 0, 0, null); + + bi = vi.getSnapshot(); + if (bi.getRGB(0, 0) != bi.getRGB(1, 1)) { + throw new RuntimeException("Test FAILED: color at 0x0 ="+ + Integer.toHexString(bi.getRGB(0, 0))+" differs from 1x1 ="+ + Integer.toHexString(bi.getRGB(1,1))); + } + + System.out.println("Test PASSED."); + } +} diff --git a/jdk/test/sun/java2d/pipe/hw/RSLContextInvalidationTest/RSLContextInvalidationTest.java b/jdk/test/sun/java2d/pipe/hw/RSLContextInvalidationTest/RSLContextInvalidationTest.java new file mode 100644 index 00000000000..1a895c3c550 --- /dev/null +++ b/jdk/test/sun/java2d/pipe/hw/RSLContextInvalidationTest/RSLContextInvalidationTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 2007-2008 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 6764257 + * @summary Tests that the color is reset properly after save/restore context + * @author Dmitri.Trembovetski@sun.com: area=Graphics + * @compile -XDignore.symbol.file=true RSLContextInvalidationTest.java + * @run main/othervm RSLContextInvalidationTest + * @run main/othervm -Dsun.java2d.noddraw=true RSLContextInvalidationTest + * @run main/othervm -Dsun.java2d.opengl=True RSLContextInvalidationTest + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import sun.java2d.DestSurfaceProvider; +import sun.java2d.Surface; +import sun.java2d.pipe.RenderQueue; +import sun.java2d.pipe.hw.*; + +public class RSLContextInvalidationTest { + + public static void main(String[] args) { + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(100, 100); + vi.validate(gc); + VolatileImage vi1 = gc.createCompatibleVolatileImage(100, 100); + vi1.validate(gc); + + if (!(vi instanceof DestSurfaceProvider)) { + System.out.println("Test considered PASSED: no HW acceleration"); + return; + } + + DestSurfaceProvider p = (DestSurfaceProvider)vi; + Surface s = p.getDestSurface(); + if (!(s instanceof AccelSurface)) { + System.out.println("Test considered PASSED: no HW acceleration"); + return; + } + AccelSurface dst = (AccelSurface)s; + + Graphics g = vi.createGraphics(); + g.drawImage(vi1, 95, 95, null); + g.setColor(Color.red); + g.fillRect(0, 0, 100, 100); + g.setColor(Color.black); + g.fillRect(0, 0, 100, 100); + // after this the validated context color is black + + RenderQueue rq = dst.getContext().getRenderQueue(); + rq.lock(); + try { + dst.getContext().saveState(); + dst.getContext().restoreState(); + } finally { + rq.unlock(); + } + + // this will cause ResetPaint (it will set color to extended EA=ff, + // which is ffffffff==Color.white) + g.drawImage(vi1, 95, 95, null); + + // now try filling with black again, but it will come up as white + // because this fill rect won't validate the color properly + g.setColor(Color.black); + g.fillRect(0, 0, 100, 100); + + BufferedImage bi = vi.getSnapshot(); + if (bi.getRGB(50, 50) != Color.black.getRGB()) { + throw new RuntimeException("Test FAILED: found color="+ + Integer.toHexString(bi.getRGB(50, 50))+" instead of "+ + Integer.toHexString(Color.black.getRGB())); + } + + System.out.println("Test PASSED."); + } +} diff --git a/langtools/.hgtags b/langtools/.hgtags index 8e794f05e1b..51e7a2f4bf8 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -16,3 +16,4 @@ eaf608c64fecf70f955dc9f29f94c055b183aeec jdk7-b30 3fb51e47622bb771571680bc6a7b64c6172b482d jdk7-b39 32e30988324601d08b87989f0821d99aa8534511 jdk7-b40 ded6b40f558e8d19b3c17715b3d67ee001606645 jdk7-b41 +5e5567c2db56a931cf07768218c20903d9828b5f jdk7-b42 diff --git a/langtools/test/com/sun/javadoc/testSourceTab/DoubleTab/C.java b/langtools/test/com/sun/javadoc/testSourceTab/DoubleTab/C.java index eb0f2fa312c..ea9d15f132e 100644 --- a/langtools/test/com/sun/javadoc/testSourceTab/DoubleTab/C.java +++ b/langtools/test/com/sun/javadoc/testSourceTab/DoubleTab/C.java @@ -1,4 +1,4 @@ -/* +/* * Copyright 2002-2004 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -23,15 +23,15 @@ /** *
- * 		This source
- * 		is indented
- * 		with tabs.
+ * \t\tThis source
+ * \t\tis indented
+ * \t\twith tabs.
  * 
*/ public class C { - - //This source - //is indented - //with tabs. - + +\t\t//This source +\t\t//is indented +\t\t//with tabs. + } diff --git a/langtools/test/com/sun/javadoc/testSourceTab/SingleTab/C.java b/langtools/test/com/sun/javadoc/testSourceTab/SingleTab/C.java index 3acafe93fee..990d927185a 100644 --- a/langtools/test/com/sun/javadoc/testSourceTab/SingleTab/C.java +++ b/langtools/test/com/sun/javadoc/testSourceTab/SingleTab/C.java @@ -1,4 +1,4 @@ -/* +/* * Copyright 2002-2004 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -23,15 +23,15 @@ /** *
- *	This source
- * 	is indented
- * 	with tabs.
+ *\tThis source
+ * \tis indented
+ * \twith tabs.
  * 
*/ public class C { - - //This source - //is indented - //with tabs. - + +\t//This source +\t//is indented +\t//with tabs. + } diff --git a/langtools/test/com/sun/javadoc/testSourceTab/TestSourceTab.java b/langtools/test/com/sun/javadoc/testSourceTab/TestSourceTab.java index d94d8f16f24..31ec810e2fe 100644 --- a/langtools/test/com/sun/javadoc/testSourceTab/TestSourceTab.java +++ b/langtools/test/com/sun/javadoc/testSourceTab/TestSourceTab.java @@ -1,5 +1,5 @@ -/* - * Copyright 2002-2004 Sun Microsystems, Inc. All Rights Reserved. +/* + * Copyright 2002-2008 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 @@ -33,59 +33,102 @@ * @run main TestSourceTab */ +import java.io.*; + public class TestSourceTab extends JavadocTester { - + private static final String BUG_ID = "4510979"; + private static final String TMP_SRC_DIR = "tmpSrc"; private static final String OUTPUT_DIR1 = BUG_ID + "-tabLengthEight"; private static final String OUTPUT_DIR2 = BUG_ID + "-tabLengthFour"; private static final String[][] TEST = NO_TEST; private static final String[][] NEGATED_TEST = NO_TEST; - + //Run Javadoc on a source file with that is indented with a single tab per line private static final String[] ARGS1 = new String[] { - "-d", OUTPUT_DIR1, "-sourcepath", SRC_DIR, - "-notimestamp", "-linksource", SRC_DIR + FS + "SingleTab" + FS + "C.java" + "-d", OUTPUT_DIR1, "-sourcepath", TMP_SRC_DIR, + "-notimestamp", "-linksource", TMP_SRC_DIR + FS + "SingleTab" + FS + "C.java" }; - + //Run Javadoc on a source file with that is indented with a two tab per line //If we double the tabs and decrease the tab length by a half, the output should //be the same as the one generated above. private static final String[] ARGS2 = new String[] { - "-d", OUTPUT_DIR2, "-sourcepath", SRC_DIR, - "-notimestamp", "-sourcetab", "4", SRC_DIR + FS + "DoubleTab" + FS + "C.java" + "-d", OUTPUT_DIR2, "-sourcepath", TMP_SRC_DIR, + "-notimestamp", "-sourcetab", "4", TMP_SRC_DIR + FS + "DoubleTab" + FS + "C.java" }; - + //Files to diff private static final String[][] FILES_TO_DIFF = { {OUTPUT_DIR1 + FS + "src-html" + FS + "C.html", OUTPUT_DIR2 + FS + "src-html" + FS + "C.html" - }, + }, {OUTPUT_DIR1 + FS + "C.html", OUTPUT_DIR2 + FS + "C.html" } - + }; - + /** * The entry point of the test. * @param args the array of command line arguments. */ - public static void main(String[] args) { + public static void main(String[] args) throws IOException { TestSourceTab tester = new TestSourceTab(); run(tester, ARGS1, TEST, NEGATED_TEST); run(tester, ARGS2, TEST, NEGATED_TEST); tester.runDiffs(FILES_TO_DIFF); } - + + TestSourceTab() throws IOException { + initTabs(new File(SRC_DIR), new File(TMP_SRC_DIR)); + } + + void initTabs(File from, File to) throws IOException { + for (File f: from.listFiles()) { + File t = new File(to, f.getName()); + if (f.isDirectory()) { + initTabs(f, t); + } else if (f.getName().endsWith(".java")) { + write(t, read(f).replace("\\t", "\t")); + } + } + } + + String read(File f) throws IOException { + StringBuilder sb = new StringBuilder(); + BufferedReader in = new BufferedReader(new FileReader(f)); + try { + String line; + while ((line = in.readLine()) != null) { + sb.append(line); + sb.append("\n"); + } + } finally { + in.close(); + } + return sb.toString(); + } + + void write(File f, String s) throws IOException { + f.getParentFile().mkdirs(); + Writer out = new FileWriter(f); + try { + out.write(s); + } finally { + out.close(); + } + } + /** * {@inheritDoc} */ public String getBugId() { return BUG_ID; } - + /** * {@inheritDoc} */