diff --git a/.hgtags b/.hgtags index 966c17a5710..cbaa3d31764 100644 --- a/.hgtags +++ b/.hgtags @@ -100,3 +100,5 @@ a4e6aa1f45ad23a6f083ed98d970b5006ea4d292 jdk7-b116 142129d8599d1f56b29387e7f9a5fad53b6d61df jdk7-b123 aa894c225b1a517b665ac2a58295217ea2245134 jdk7-b124 f658ec2730fa29323c36d23c27e54c7219ef5e16 jdk7-b125 +f1df068076986679ea1105532a65529d63a89060 jdk7-b126 +f83cd8bd35c678f94e526990e03dc838d0ec2717 jdk7-b127 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 5bdac4ada74..3e2de35b9c2 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -100,3 +100,5 @@ f1591eed71f64f6eba79fb7426f5616cc4dfea73 jdk7-b122 ed6950da30cf1e8904b4bdb034d471647942271f jdk7-b123 024a6755895bf91b5a3c98984c89ee018efbf538 jdk7-b124 5c4df7e992775c102f08e9f1c0a124b324641b70 jdk7-b125 +b566d490905691787f8931f69947a92c67c6d5e4 jdk7-b126 +bd70f76b0309068f157ae759c36eac8f2c6d098e jdk7-b127 diff --git a/Makefile b/Makefile index 7c5b2db01c0..2aec754e6f8 100644 --- a/Makefile +++ b/Makefile @@ -29,15 +29,6 @@ ifndef TOPDIR TOPDIR:=. endif -# Openjdk sources (only used if SKIP_OPENJDK_BUILD!=true) -OPENJDK_SOURCETREE=$(TOPDIR)/openjdk -OPENJDK_BUILDDIR:=$(shell \ - if [ -r $(OPENJDK_SOURCETREE)/Makefile ]; then \ - echo "$(OPENJDK_SOURCETREE)"; \ - else \ - echo "."; \ - fi) - ifndef JDK_TOPDIR JDK_TOPDIR=$(TOPDIR)/jdk endif @@ -70,7 +61,7 @@ include ./make/deploy-rules.gmk all:: @$(START_ECHO) -all:: openjdk_check sanity +all:: sanity ifeq ($(SKIP_FASTDEBUG_BUILD), false) all:: fastdebug_build @@ -80,10 +71,6 @@ ifeq ($(SKIP_DEBUG_BUILD), false) all:: debug_build endif -ifneq ($(SKIP_OPENJDK_BUILD), true) - all:: openjdk_build -endif - all:: all_product_build all:: @@ -267,81 +254,6 @@ product_build:: build_product_image debug_build:: build_debug_image fastdebug_build:: build_fastdebug_image -# Check on whether we really can build the openjdk, need source etc. -openjdk_check: FRC -ifneq ($(SKIP_OPENJDK_BUILD), true) - @$(ECHO) " " - @$(ECHO) "=================================================" - @if [ ! -r $(OPENJDK_BUILDDIR)/Makefile ] ; then \ - $(ECHO) "ERROR: No openjdk source tree available at: $(OPENJDK_BUILDDIR)"; \ - exit 1; \ - else \ - $(ECHO) "OpenJDK will be built after JDK is built"; \ - $(ECHO) " OPENJDK_BUILDDIR=$(OPENJDK_BUILDDIR)"; \ - fi - @$(ECHO) "=================================================" - @$(ECHO) " " -endif - -# If we have bundle rules, we have a chance here to do a complete cycle -# build, of production and open build. -# FIXUP: We should create the openjdk source bundle and build that? -# But how do we reliable create or get at a formal openjdk source tree? -# The one we have needs to be trimmed of built bits and closed dirs. -# The repositories might not be available. -# The openjdk source bundle is probably not available. - -ifneq ($(SKIP_OPENJDK_BUILD), true) - ifeq ($(BUILD_JDK), true) - ifeq ($(BUNDLE_RULES_AVAILABLE), true) - -OPENJDK_OUTPUTDIR=$(ABS_OUTPUTDIR)/open-output -OPENJDK_BUILD_NAME \ - = openjdk-$(JDK_MINOR_VERSION)-$(BUILD_NUMBER)-$(PLATFORM)-$(ARCH)-$(BUNDLE_DATE) -OPENJDK_BUILD_BINARY_ZIP=$(ABS_BIN_BUNDLEDIR)/$(OPENJDK_BUILD_NAME).zip -BUILT_IMAGE=$(ABS_OUTPUTDIR)/j2sdk-image -ifeq ($(PLATFORM)$(ARCH_DATA_MODEL),solaris64) - OPENJDK_BOOTDIR=$(BOOTDIR) - OPENJDK_IMPORTJDK=$(JDK_IMPORT_PATH) -else - OPENJDK_BOOTDIR=$(BUILT_IMAGE) - OPENJDK_IMPORTJDK=$(BUILT_IMAGE) -endif - -openjdk_build: - @$(START_ECHO) - @$(ECHO) " " - @$(ECHO) "=================================================" - @$(ECHO) "Starting openjdk build" - @$(ECHO) " Using: ALT_JDK_DEVTOOLS_DIR=$(JDK_DEVTOOLS_DIR)" - @$(ECHO) "=================================================" - @$(ECHO) " " - $(RM) -r $(OPENJDK_OUTPUTDIR) - $(MKDIR) -p $(OPENJDK_OUTPUTDIR) - ($(CD) $(OPENJDK_BUILDDIR) && $(MAKE) \ - OPENJDK=true \ - GENERATE_DOCS=false \ - ALT_JDK_DEVTOOLS_DIR=$(JDK_DEVTOOLS_DIR) \ - ALT_OUTPUTDIR=$(OPENJDK_OUTPUTDIR) \ - ALT_BOOTDIR=$(OPENJDK_BOOTDIR) \ - ALT_JDK_IMPORT_PATH=$(OPENJDK_IMPORTJDK) \ - product_build ) - $(RM) $(OPENJDK_BUILD_BINARY_ZIP) - ( $(CD) $(OPENJDK_OUTPUTDIR)/j2sdk-image && \ - $(ZIPEXE) -q -r $(OPENJDK_BUILD_BINARY_ZIP) .) - $(RM) -r $(OPENJDK_OUTPUTDIR) - @$(ECHO) " " - @$(ECHO) "=================================================" - @$(ECHO) "Finished openjdk build" - @$(ECHO) " Binary Bundle: $(OPENJDK_BUILD_BINARY_ZIP)" - @$(ECHO) "=================================================" - @$(ECHO) " " - @$(FINISH_ECHO) - - endif - endif -endif - clobber:: $(RM) -r $(OUTPUTDIR)/* $(RM) -r $(OUTPUTDIR)/../$(PLATFORM)-$(ARCH)-debug/* @@ -448,7 +360,6 @@ CACERTS_FILE.desc = Location of certificates file DEVTOOLS_PATH.desc = Directory containing zip and gnumake CUPS_HEADERS_PATH.desc = Include directory location for CUPS header files DXSDK_PATH.desc = Root directory of DirectX SDK -MSVCRT_DLL_PATH.desc = Directory containing mscvrt.dll # Make variables to print out (description and value) VARIABLE_PRINTVAL_LIST += \ @@ -477,12 +388,10 @@ VARIABLE_CHECKFIL_LIST += \ ifeq ($(PLATFORM), windows) VARIABLE_PRINTVAL_LIST += \ - DXSDK_PATH \ - MSVCRT_DLL_PATH + DXSDK_PATH VARIABLE_CHECKDIR_LIST += \ - DXSDK_PATH \ - MSVCRT_DLL_PATH + DXSDK_PATH endif diff --git a/README-builds.html b/README-builds.html index e48aaff3612..f98260ceca4 100644 --- a/README-builds.html +++ b/README-builds.html @@ -1414,14 +1414,14 @@ but it's normally found via the DirectX environment variable DXSDK_DIR. - MSVCR100.DLL + MSVCR100.DLL
The OpenJDK build requires access to a redistributable MSVCR100.DLL. This is usually picked up automatically from the redist directories of Visual Studio 2010. If this cannot be found set the - ALT_MSVCRT_DLL_PATH + ALT_MSVCRNN_DLL_PATH variable to the location of this file.

@@ -1671,15 +1671,10 @@ variable DXSDK_DIR, failing that, look in C:/DXSDK. -
ALT_MSVCRT_DLL_PATH
-
- The location of the - MSVCRT.DLL. -
ALT_MSVCRNN_DLL_PATH
The location of the - MSVCR100.DLL. + MSVCR100.DLL.
diff --git a/corba/.hgtags b/corba/.hgtags index 88d03298a46..3af1bd0f35e 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -100,3 +100,5 @@ cff5a173ec1e89013359e804a3e31736ef6fb462 jdk7-b120 a230c142628cea22475ab9dc5cd544266ddf2466 jdk7-b123 f90b3e014e831eb4f32ef035a1dad2b8ba87949f jdk7-b124 1ce58c72b7892cb813eb920276c7e7f17a1b79fe jdk7-b125 +d7532bcd3742f1576dd07ff9fbb535c9c9a276e9 jdk7-b126 +64775e83f4df894355f45555f50c410de6727b4e jdk7-b127 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 6b879a83409..2f8ef840141 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -141,3 +141,6 @@ f5603a6e50422046ebc0d2f1671d55cb8f1bf1e9 jdk7-b120 0a8e0d4345b37b71ec49dda08ee03b68c4f1b592 jdk7-b124 0a8e0d4345b37b71ec49dda08ee03b68c4f1b592 hs20-b05 e24ab3fa6aafad3efabbe7dba9918c5f461a20b1 jdk7-b125 +4c851c931d001a882cab809aaf3a55371b919244 jdk7-b126 +e24ab3fa6aafad3efabbe7dba9918c5f461a20b1 hs20-b06 +102466e70debc4b907afbd7624e34ddb1aafee9f jdk7-b127 diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 8fe599f75e4..0442c544cb6 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011 HS_MAJOR_VER=20 HS_MINOR_VER=0 -HS_BUILD_NUMBER=06 +HS_BUILD_NUMBER=07 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index f1c39036251..0d81e2d1254 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -4104,7 +4104,7 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t1); sub(top, t1, t1); // size of tlab's allocated portion - incr_allocated_bytes(t1, 0, t2); + incr_allocated_bytes(t1, t2, t3); // refill the tlab with an eden allocation bind(do_refill); @@ -4138,19 +4138,14 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case delayed()->nop(); } -void MacroAssembler::incr_allocated_bytes(Register var_size_in_bytes, - int con_size_in_bytes, - Register t1) { +void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, + Register t1, Register t2) { // Bump total bytes allocated by this thread assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch - assert_different_registers(var_size_in_bytes, t1); + assert_different_registers(size_in_bytes.register_or_noreg(), t1, t2); // v8 support has gone the way of the dodo ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1); - if (var_size_in_bytes->is_valid()) { - add(t1, var_size_in_bytes, t1); - } else { - add(t1, con_size_in_bytes, t1); - } + add(t1, ensure_simm13_or_reg(size_in_bytes, t2), t1); stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset())); } diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 296305664cc..b6d7d9ab14a 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -823,15 +823,23 @@ class Assembler : public AbstractAssembler { }; // test if x is within signed immediate range for nbits - static bool is_simm(int x, int nbits) { return -( 1 << nbits-1 ) <= x && x < ( 1 << nbits-1 ); } + static bool is_simm(intptr_t x, int nbits) { return -( intptr_t(1) << nbits-1 ) <= x && x < ( intptr_t(1) << nbits-1 ); } // test if -4096 <= x <= 4095 - static bool is_simm13(int x) { return is_simm(x, 13); } + static bool is_simm13(intptr_t x) { return is_simm(x, 13); } + + static bool is_in_wdisp_range(address a, address b, int nbits) { + intptr_t d = intptr_t(b) - intptr_t(a); + return is_simm(d, nbits + 2); + } // test if label is in simm16 range in words (wdisp16). bool is_in_wdisp16_range(Label& L) { - intptr_t d = intptr_t(pc()) - intptr_t(target(L)); - return is_simm(d, 18); + return is_in_wdisp_range(target(L), pc(), 16); + } + // test if the distance between two addresses fits in simm30 range in words + static bool is_in_wdisp30_range(address a, address b) { + return is_in_wdisp_range(a, b, 30); } enum ASIs { // page 72, v9 @@ -1843,6 +1851,8 @@ class MacroAssembler: public Assembler { inline void jmp( Register s1, Register s2 ); inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); + // Check if the call target is out of wdisp30 range (relative to the code cache) + static inline bool is_far_target(address d); inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); inline void callr( Register s1, Register s2 ); @@ -2389,7 +2399,8 @@ public: Label& slow_case // continuation point if fast allocation fails ); void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); - void incr_allocated_bytes(Register var_size_in_bytes, int con_size_in_bytes, Register t1); + void incr_allocated_bytes(RegisterOrConstant size_in_bytes, + Register t1, Register t2); // interface method calling void lookup_interface_method(Register recv_klass, diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 106aa14e5b0..9b292b0ad81 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -588,10 +588,13 @@ inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, Label& L inline void MacroAssembler::jmp( Register s1, Register s2 ) { jmpl( s1, s2, G0 ); } inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); } +inline bool MacroAssembler::is_far_target(address d) { + return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound()); +} + // Call with a check to see if we need to deal with the added // expense of relocation and if we overflow the displacement -// of the quick call instruction./ -// Check to see if we have to deal with relocations +// of the quick call instruction. inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { #ifdef _LP64 intptr_t disp; @@ -603,14 +606,12 @@ inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { // Is this address within range of the call instruction? // If not, use the expensive instruction sequence - disp = (intptr_t)d - (intptr_t)pc(); - if ( disp != (intptr_t)(int32_t)disp ) { + if (is_far_target(d)) { relocate(rt); AddressLiteral dest(d); jumpl_to(dest, O7, O7); - } - else { - Assembler::call( d, rt ); + } else { + Assembler::call(d, rt); } #else Assembler::call( d, rt ); diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 15ca82f28fe..109f7869220 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2358,6 +2358,8 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { op->tmp3()->as_register() == G4 && op->tmp4()->as_register() == O1 && op->klass()->as_register() == G5, "must be"); + + LP64_ONLY( __ signx(op->len()->as_register()); ) if (UseSlowPath || (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { diff --git a/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp index 85eb668337c..c3556e2147e 100644 --- a/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp @@ -170,11 +170,13 @@ void C1_MacroAssembler::try_allocate( Register t2, // temp register Label& slow_case // continuation point if fast allocation fails ) { + RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid() + ? RegisterOrConstant(var_size_in_bytes) : RegisterOrConstant(con_size_in_bytes); if (UseTLAB) { tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); } else { eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); - incr_allocated_bytes(var_size_in_bytes, con_size_in_bytes, t1); + incr_allocated_bytes(size_in_bytes, t1, t2); } } diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 7ce9a73b610..3a10d5ad8a9 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -343,9 +343,10 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { // returned. restore_live_registers(sasm); - __ restore(); - __ br(Assembler::always, false, Assembler::pt, deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type); - __ delayed()->nop(); + + AddressLiteral dest(deopt_blob->unpack_with_reexecution()); + __ jump_to(dest, O0); + __ delayed()->restore(); __ bind(no_deopt); restore_live_registers(sasm); @@ -461,7 +462,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // get the instance size __ ld(G5_klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), G1_obj_size); __ eden_allocate(O0_obj, G1_obj_size, 0, G3_t1, G4_t2, slow_path); - __ incr_allocated_bytes(G1_obj_size, 0, G3_t1); + __ incr_allocated_bytes(G1_obj_size, G3_t1, G4_t2); __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2); __ verify_oop(O0_obj); @@ -577,7 +578,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ and3(G1_arr_size, ~MinObjAlignmentInBytesMask, G1_arr_size); __ eden_allocate(O0_obj, G1_arr_size, 0, G3_t1, O1_t2, slow_path); // preserves G1_arr_size - __ incr_allocated_bytes(G1_arr_size, 0, G3_t1); + __ incr_allocated_bytes(G1_arr_size, G3_t1, O1_t2); __ initialize_header(O0_obj, G5_klass, G4_length, G3_t1, O1_t2); __ ldub(klass_lh, G3_t1, klass_lh_header_size_offset); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index ea17d6f574e..c6b33222a6c 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1295,16 +1295,13 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { // Get the method data pointer from the methodOop and set the // specified register to its value. -void InterpreterMacroAssembler::set_method_data_pointer_offset(Register Roff) { +void InterpreterMacroAssembler::set_method_data_pointer() { assert(ProfileInterpreter, "must be profiling interpreter"); Label get_continue; ld_ptr(Lmethod, in_bytes(methodOopDesc::method_data_offset()), ImethodDataPtr); test_method_data_pointer(get_continue); add(ImethodDataPtr, in_bytes(methodDataOopDesc::data_offset()), ImethodDataPtr); - if (Roff != noreg) - // Roff contains a method data index ("mdi"). It defaults to zero. - add(ImethodDataPtr, Roff, ImethodDataPtr); bind(get_continue); } @@ -1315,10 +1312,11 @@ void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { Label zero_continue; // Test MDO to avoid the call if it is NULL. - ld_ptr(Lmethod, methodOopDesc::method_data_offset(), ImethodDataPtr); + ld_ptr(Lmethod, in_bytes(methodOopDesc::method_data_offset()), ImethodDataPtr); test_method_data_pointer(zero_continue); call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), Lmethod, Lbcp); - set_method_data_pointer_offset(O0); + add(ImethodDataPtr, in_bytes(methodDataOopDesc::data_offset()), ImethodDataPtr); + add(ImethodDataPtr, O0, ImethodDataPtr); bind(zero_continue); } @@ -1369,7 +1367,6 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, - Register cur_bcp, Register Rtmp, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1400,8 +1397,8 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat delayed()->nop(); // Build it now. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), cur_bcp); - set_method_data_pointer_offset(O0); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + set_method_data_pointer_for_bcp(); ba(false, profile_continue); delayed()->nop(); bind(done); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index 835dcac6836..be3840c67bf 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -269,12 +269,11 @@ class InterpreterMacroAssembler: public MacroAssembler { #ifndef CC_INTERP // Interpreter profiling operations - void set_method_data_pointer() { set_method_data_pointer_offset(noreg); } + void set_method_data_pointer(); void set_method_data_pointer_for_bcp(); - void set_method_data_pointer_offset(Register mdi_reg); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register cur_bcp, Register Rtmp, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register Rtmp, Label &profile_continue); void set_mdp_data_at(int constant, Register value); void increment_mdp_data_at(Address counter, Register bumped_count, diff --git a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp index 2fb2e56d8b3..4fc102fa480 100644 --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -395,7 +395,7 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { // // Generate an "entry" field for a method handle. // This determines how the method handle will respond to calls. -void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) { +void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { // Here is the register state during an interpreted call, // as set up by generate_method_handle_interpreter_entry(): // - G5: garbage temp (was MethodHandle.invoke methodOop, unused) @@ -447,8 +447,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // exception. Since we use a C2I adapter to set up the // interpreter state, arguments are expected in compiler // argument registers. - methodHandle mh(raise_exception_method()); - address c2i_entry = methodOopDesc::make_adapters(mh, CATCH); + assert(raise_exception_method(), "must be set"); + address c2i_entry = raise_exception_method()->get_c2i_entry(); + assert(c2i_entry, "method must be linked"); __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started. diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 25117f205b2..422b83f1476 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -575,7 +575,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() { int MachCallRuntimeNode::ret_addr_offset() { #ifdef _LP64 - return NativeFarCall::instruction_size; // farcall; delay slot + if (MacroAssembler::is_far_target(entry_point())) { + return NativeFarCall::instruction_size; + } else { + return NativeCall::instruction_size; + } #else return NativeCall::instruction_size; // call; delay slot #endif @@ -941,7 +945,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te #endif } -void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocType rtype, bool preserve_g2 = false, bool force_far_call = false) { +void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocType rtype, bool preserve_g2 = false) { // The method which records debug information at every safepoint // expects the call to be the first instruction in the snippet as // it creates a PcDesc structure which tracks the offset of a call @@ -963,20 +967,7 @@ void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocTyp int startpos = __ offset(); #endif /* ASSERT */ -#ifdef _LP64 - // Calls to the runtime or native may not be reachable from compiled code, - // so we generate the far call sequence on 64 bit sparc. - // This code sequence is relocatable to any address, even on LP64. - if ( force_far_call ) { - __ relocate(rtype); - AddressLiteral dest(entry_point); - __ jumpl_to(dest, O7, O7); - } - else -#endif - { - __ call((address)entry_point, rtype); - } + __ call((address)entry_point, rtype); if (preserve_g2) __ delayed()->mov(G2, L7); else __ delayed()->nop(); @@ -2507,7 +2498,7 @@ encode %{ // CALL directly to the runtime // The user of this is responsible for ensuring that R_L7 is empty (killed). emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type, - /*preserve_g2=*/true, /*force far call*/true); + /*preserve_g2=*/true); %} enc_class preserve_SP %{ diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 80e3a759d1d..8984a1df357 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1364,15 +1364,8 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { // We have decided to profile this method in the interpreter __ bind(profile_method); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), Lbcp, true); - -#ifdef ASSERT - __ tst(O0); - __ breakpoint_trap(Assembler::notEqual); -#endif - - __ set_method_data_pointer(); - + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + __ set_method_data_pointer_for_bcp(); __ ba(false, profile_method_continue); __ delayed()->nop(); } diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 6bfaccd64e3..0706eb140df 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1689,7 +1689,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const Register G4_invoke_ctr = G4; __ increment_backedge_counter(G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, Lbcp, G3_scratch, Lforward); + __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); if (UseOnStackReplacement) { __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch); } @@ -3447,7 +3447,8 @@ void TemplateTable::_new() { __ delayed()->nop(); // bump total bytes allocated by this thread - __ incr_allocated_bytes(Roffset, 0, G1_scratch); + // RoldTopValue and RtopAddr are dead, so can use G1 and G3 + __ incr_allocated_bytes(Roffset, G1_scratch, G3_scratch); } if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index f3ba0a2ce02..2a65de51e5b 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1641,12 +1641,14 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { } void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { + Register len = op->len()->as_register(); + LP64_ONLY( __ movslq(len, len); ) + if (UseSlowPath || (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { __ jmp(*op->stub()->entry()); } else { - Register len = op->len()->as_register(); Register tmp1 = op->tmp1()->as_register(); Register tmp2 = op->tmp2()->as_register(); Register tmp3 = op->tmp3()->as_register(); diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 41917378b56..bdd705484a0 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -62,7 +62,7 @@ define_pd_global(intx, StackRedPages, 1); // due to lack of optimization caused by C++ compiler bugs define_pd_global(intx, StackShadowPages, SOLARIS_ONLY(20) NOT_SOLARIS(6) DEBUG_ONLY(+2)); #else -define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); +define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+5)); #endif // AMD64 define_pd_global(intx, PreInflateSpin, 10); diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index 6cc321b5576..33daeac2441 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -819,7 +819,7 @@ void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, Label& ze // Set the method data pointer for the current bcp. void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { assert(ProfileInterpreter, "must be profiling interpreter"); - Label zero_continue; + Label set_mdp; push(rax); push(rbx); @@ -827,21 +827,17 @@ void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { // Test MDO to avoid the call if it is NULL. movptr(rax, Address(rbx, in_bytes(methodOopDesc::method_data_offset()))); testptr(rax, rax); - jcc(Assembler::zero, zero_continue); - + jcc(Assembler::zero, set_mdp); // rbx,: method // rsi: bcp call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, rsi); // rax,: mdi - + // mdo is guaranteed to be non-zero here, we checked for it before the call. movptr(rbx, Address(rbx, in_bytes(methodOopDesc::method_data_offset()))); - testptr(rbx, rbx); - jcc(Assembler::zero, zero_continue); addptr(rbx, in_bytes(methodDataOopDesc::data_offset())); - addptr(rbx, rax); - movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rbx); - - bind(zero_continue); + addptr(rax, rbx); + bind(set_mdp); + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rax); pop(rbx); pop(rax); } diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index a156d24d66a..3c235ce2190 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -855,7 +855,7 @@ void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, // Set the method data pointer for the current bcp. void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { assert(ProfileInterpreter, "must be profiling interpreter"); - Label zero_continue; + Label set_mdp; push(rax); push(rbx); @@ -863,21 +863,17 @@ void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { // Test MDO to avoid the call if it is NULL. movptr(rax, Address(rbx, in_bytes(methodOopDesc::method_data_offset()))); testptr(rax, rax); - jcc(Assembler::zero, zero_continue); - + jcc(Assembler::zero, set_mdp); // rbx: method // r13: bcp call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, r13); // rax: mdi - + // mdo is guaranteed to be non-zero here, we checked for it before the call. movptr(rbx, Address(rbx, in_bytes(methodOopDesc::method_data_offset()))); - testptr(rbx, rbx); - jcc(Assembler::zero, zero_continue); addptr(rbx, in_bytes(methodDataOopDesc::data_offset())); - addptr(rbx, rax); - movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rbx); - - bind(zero_continue); + addptr(rax, rbx); + bind(set_mdp); + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rax); pop(rbx); pop(rax); } diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index f92beb4839f..bbbc29d6408 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -390,7 +390,7 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { // // Generate an "entry" field for a method handle. // This determines how the method handle will respond to calls. -void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) { +void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { // Here is the register state during an interpreted call, // as set up by generate_method_handle_interpreter_entry(): // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused) @@ -451,8 +451,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // exception. Since we use a C2I adapter to set up the // interpreter state, arguments are expected in compiler // argument registers. - methodHandle mh(raise_exception_method()); - address c2i_entry = methodOopDesc::make_adapters(mh, CHECK); + assert(raise_exception_method(), "must be set"); + address c2i_entry = raise_exception_method()->get_c2i_entry(); + assert(c2i_entry, "method must be linked"); const Register rdi_pc = rax; __ pop(rdi_pc); // caller PC diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index ee518b31405..74c4b6e3fb9 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1367,15 +1367,9 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { if (ProfileInterpreter) { // We have decided to profile this method in the interpreter __ bind(profile_method); - - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), rsi, true); - - __ movptr(rbx, Address(rbp, method_offset)); // restore methodOop - __ movptr(rax, Address(rbx, in_bytes(methodOopDesc::method_data_offset()))); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rax); - __ test_method_data_pointer(rax, profile_method_continue); - __ addptr(rax, in_bytes(methodDataOopDesc::data_offset())); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rax); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + __ set_method_data_pointer_for_bcp(); + __ get_method(rbx); __ jmp(profile_method_continue); } // Handle overflow of counter and compile method diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 2d7aa60cfca..8191a23878b 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1383,20 +1383,9 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { if (ProfileInterpreter) { // We have decided to profile this method in the interpreter __ bind(profile_method); - - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), - r13, true); - - __ movptr(rbx, Address(rbp, method_offset)); // restore methodOop - __ movptr(rax, Address(rbx, - in_bytes(methodOopDesc::method_data_offset()))); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), - rax); - __ test_method_data_pointer(rax, profile_method_continue); - __ addptr(rax, in_bytes(methodDataOopDesc::data_offset())); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), - rax); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + __ set_method_data_pointer_for_bcp(); + __ get_method(rbx); __ jmp(profile_method_continue); } // Handle overflow of counter and compile method diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index 345b5f62c5e..844a32d7ab3 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1665,16 +1665,9 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Out-of-line code to allocate method data oop. __ bind(profile_method); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), rsi); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); __ load_unsigned_byte(rbx, Address(rsi, 0)); // restore target bytecode - __ movptr(rcx, Address(rbp, method_offset)); - __ movptr(rcx, Address(rcx, in_bytes(methodOopDesc::method_data_offset()))); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rcx); - __ test_method_data_pointer(rcx, dispatch); - // offset non-null mdp by MDO::data_offset() + IR::profile_method() - __ addptr(rcx, in_bytes(methodDataOopDesc::data_offset())); - __ addptr(rcx, rax); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rcx); + __ set_method_data_pointer_for_bcp(); __ jmp(dispatch); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index cd45253d592..458d1fedc16 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1695,21 +1695,9 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Out-of-line code to allocate method data oop. __ bind(profile_method); - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::profile_method), r13); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); __ load_unsigned_byte(rbx, Address(r13, 0)); // restore target bytecode - __ movptr(rcx, Address(rbp, method_offset)); - __ movptr(rcx, Address(rcx, - in_bytes(methodOopDesc::method_data_offset()))); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), - rcx); - __ test_method_data_pointer(rcx, dispatch); - // offset non-null mdp by MDO::data_offset() + IR::profile_method() - __ addptr(rcx, in_bytes(methodDataOopDesc::data_offset())); - __ addptr(rcx, rax); - __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), - rcx); + __ set_method_data_pointer_for_bcp(); __ jmp(dispatch); } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 330e347a7e5..5d34fc50c7d 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1610,10 +1610,9 @@ int os::current_process_id() { const char* os::dll_file_extension() { return ".so"; } -const char* os::get_temp_directory() { - const char *prop = Arguments::get_property("java.io.tmpdir"); - return prop == NULL ? "/tmp" : prop; -} +// This must be hard coded because it's the system's temporary +// directory not the java application's temp directory, ala java.io.tmpdir. +const char* os::get_temp_directory() { return "/tmp"; } static bool file_exists(const char* filename) { struct stat statbuf; diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index f6f816cf3ad..80c7c4d5058 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1884,10 +1884,9 @@ void os::set_error_file(const char *logfile) {} const char* os::dll_file_extension() { return ".so"; } -const char* os::get_temp_directory() { - const char *prop = Arguments::get_property("java.io.tmpdir"); - return prop == NULL ? "/tmp" : prop; -} +// This must be hard coded because it's the system's temporary +// directory not the java application's temp directory, ala java.io.tmpdir. +const char* os::get_temp_directory() { return "/tmp"; } static bool file_exists(const char* filename) { struct stat statbuf; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0422063c50e..2eeb3d33392 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1044,9 +1044,9 @@ os::closedir(DIR *dirp) return 0; } +// This must be hard coded because it's the system's temporary +// directory not the java application's temp directory, ala java.io.tmpdir. const char* os::get_temp_directory() { - const char *prop = Arguments::get_property("java.io.tmpdir"); - if (prop != 0) return prop; static char path_buf[MAX_PATH]; if (GetTempPath(MAX_PATH, path_buf)>0) return path_buf; diff --git a/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp b/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp index 648543eadb8..a409f27b422 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ inline void Atomic::dec (volatile jint* dest) { (void)add (-1, dest); inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } +inline jlong Atomic::load(volatile jlong* src) { return *src; } + inline jint Atomic::add (jint add_value, volatile jint* dest) { intptr_t rv; __asm__ volatile( diff --git a/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp b/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp index 7a89e56e107..7ec3dace4b1 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,11 +100,6 @@ inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* return exchange_value; } -extern "C" { - // defined in linux_x86.s - jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong, bool); -} - #ifdef AMD64 inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } @@ -164,9 +159,9 @@ inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); } -#else -//inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -//inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } +inline jlong Atomic::load(volatile jlong* src) { return *src; } + +#else // !AMD64 inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { return (intptr_t)Atomic::add((jint)add_value, (volatile jint*)dest); @@ -189,6 +184,12 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); } +extern "C" { + // defined in linux_x86.s + jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong, bool); + void _Atomic_move_long(volatile jlong* src, volatile jlong* dst); +} + inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) { return _Atomic_cmpxchg_long(exchange_value, dest, compare_value, os::is_MP()); } @@ -200,6 +201,21 @@ inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value) { return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); } + +inline jlong Atomic::load(volatile jlong* src) { + volatile jlong dest; + _Atomic_move_long(src, &dest); + return dest; +} + +inline void Atomic::store(jlong store_value, jlong* dest) { + _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); +} + +inline void Atomic::store(jlong store_value, volatile jlong* dest) { + _Atomic_move_long((volatile jlong*)&store_value, dest); +} + #endif // AMD64 #endif // OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_INLINE_HPP diff --git a/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s b/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s index 819293c8faa..08c6391c4cb 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s +++ b/hotspot/src/os_cpu/linux_x86/vm/linux_x86_32.s @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ .globl _mmx_Copy_arrayof_conjoint_jshorts .globl _Atomic_cmpxchg_long + .globl _Atomic_move_long .text @@ -653,3 +654,15 @@ _Atomic_cmpxchg_long: popl %ebx ret + + # Support for jlong Atomic::load and Atomic::store. + # void _Atomic_move_long(volatile jlong* src, volatile jlong* dst) + .p2align 4,,15 + .type _Atomic_move_long,@function +_Atomic_move_long: + movl 4(%esp), %eax # src + fildll (%eax) + movl 8(%esp), %eax # dest + fistpll (%eax) + ret + diff --git a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp index 9adf947ad37..8c6e566e270 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef OS_CPU_LINUX_X86_VM_ORDERACCESS_LINUX_X86_INLINE_HPP #define OS_CPU_LINUX_X86_VM_ORDERACCESS_LINUX_X86_INLINE_HPP +#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "vm_version_x86.hpp" @@ -64,11 +65,11 @@ inline void OrderAccess::fence() { inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } inline jshort OrderAccess::load_acquire(volatile jshort* p) { return *p; } inline jint OrderAccess::load_acquire(volatile jint* p) { return *p; } -inline jlong OrderAccess::load_acquire(volatile jlong* p) { return *p; } +inline jlong OrderAccess::load_acquire(volatile jlong* p) { return Atomic::load(p); } inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { return *p; } inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; } inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; } -inline julong OrderAccess::load_acquire(volatile julong* p) { return *p; } +inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); } inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; } inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; } @@ -79,11 +80,11 @@ inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return * inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { *p = v; } inline void OrderAccess::release_store(volatile jshort* p, jshort v) { *p = v; } inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { *p = v; } +inline void OrderAccess::release_store(volatile jlong* p, jlong v) { Atomic::store(v, p); } inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { *p = v; } inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p = v; } inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; } -inline void OrderAccess::release_store(volatile julong* p, julong v) { *p = v; } +inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); } inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; } inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; } @@ -178,7 +179,7 @@ inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) : "0" (v), "r" (p) : "memory"); #else - *p = v; fence(); + release_store(p, v); fence(); #endif // AMD64 } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp index 006962519ac..4830bfbb799 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,14 +35,12 @@ inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } @@ -54,8 +52,49 @@ inline void Atomic::dec (volatile jint* dest) { (void)add (-1, dest); inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } + +#ifdef _LP64 + +inline void Atomic::store(jlong store_value, jlong* dest) { *dest = store_value; } +inline void Atomic::store(jlong store_value, volatile jlong* dest) { *dest = store_value; } inline jlong Atomic::load(volatile jlong* src) { return *src; } +#else + +extern "C" void _Atomic_move_long_v8(volatile jlong* src, volatile jlong* dst); +extern "C" void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst); + +inline void Atomic_move_long(volatile jlong* src, volatile jlong* dst) { +#ifdef COMPILER2 + // Compiler2 does not support v8, it is used only for v9. + assert (VM_Version::v9_instructions_work(), "only supported on v9"); + _Atomic_move_long_v9(src, dst); +#else + // The branch is cheaper then emulated LDD. + if (VM_Version::v9_instructions_work()) { + _Atomic_move_long_v9(src, dst); + } else { + _Atomic_move_long_v8(src, dst); + } +#endif +} + +inline jlong Atomic::load(volatile jlong* src) { + volatile jlong dest; + Atomic_move_long(src, &dest); + return dest; +} + +inline void Atomic::store(jlong store_value, jlong* dest) { + Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); +} + +inline void Atomic::store(jlong store_value, volatile jlong* dest) { + Atomic_move_long((volatile jlong*)&store_value, dest); +} + +#endif + #ifdef _GNU_SOURCE inline jint Atomic::add (jint add_value, volatile jint* dest) { diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp index bb732bd6b16..8f3e781e674 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,11 +77,11 @@ inline void OrderAccess::fence() { inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } inline jshort OrderAccess::load_acquire(volatile jshort* p) { return *p; } inline jint OrderAccess::load_acquire(volatile jint* p) { return *p; } -inline jlong OrderAccess::load_acquire(volatile jlong* p) { return *p; } +inline jlong OrderAccess::load_acquire(volatile jlong* p) { return Atomic::load(p); } inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { return *p; } inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; } inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; } -inline julong OrderAccess::load_acquire(volatile julong* p) { return *p; } +inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); } inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; } inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; } @@ -92,11 +92,11 @@ inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return * inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { *p = v; } inline void OrderAccess::release_store(volatile jshort* p, jshort v) { *p = v; } inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { *p = v; } +inline void OrderAccess::release_store(volatile jlong* p, jlong v) { Atomic::store(v, p); } inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { *p = v; } inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p = v; } inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; } -inline void OrderAccess::release_store(volatile julong* p, julong v) { *p = v; } +inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); } inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; } inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; } @@ -120,11 +120,11 @@ inline void OrderAccess::store_ptr_fence(void** p, void* v) { *p = v; inline void OrderAccess::release_store_fence(volatile jbyte* p, jbyte v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jshort* p, jshort v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jint* p, jint v) { *p = v; fence(); } -inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { *p = v; fence(); } +inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { release_store(p, v); fence(); } inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { *p = v; fence(); } -inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { *p = v; fence(); } +inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store(p, v); fence(); } inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il b/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il index 071ab1bb6ad..2821c7077f0 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il +++ b/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il @@ -1,5 +1,5 @@ // -// Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -152,6 +152,39 @@ .nonvolatile .end + // Support for jlong Atomic::load and Atomic::store on v8. + // + // void _Atomic_move_long_v8(volatile jlong* src, volatile jlong* dst) + // + // Arguments: + // src: O0 + // dest: O1 + // + // Overwrites O2 and O3 + + .inline _Atomic_move_long_v8,2 + .volatile + ldd [%o0], %o2 + std %o2, [%o1] + .nonvolatile + .end + + // Support for jlong Atomic::load and Atomic::store on v9. + // + // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst) + // + // Arguments: + // src: O0 + // dest: O1 + // + // Overwrites O2 + + .inline _Atomic_move_long_v9,2 + .volatile + ldx [%o0], %o2 + stx %o2, [%o1] + .nonvolatile + .end // Support for jint Atomic::add(jint add_value, volatile jint* dest). // diff --git a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp index a4b04606b9a..d91812db9c6 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,14 +151,22 @@ inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); } -extern "C" void _Atomic_load_long(volatile jlong* src, volatile jlong* dst); +extern "C" void _Atomic_move_long(volatile jlong* src, volatile jlong* dst); inline jlong Atomic::load(volatile jlong* src) { volatile jlong dest; - _Atomic_load_long(src, &dest); + _Atomic_move_long(src, &dest); return dest; } +inline void Atomic::store(jlong store_value, jlong* dest) { + _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); +} + +inline void Atomic::store(jlong store_value, volatile jlong* dest) { + _Atomic_move_long((volatile jlong*)&store_value, dest); +} + #endif // AMD64 #ifdef _GNU_SOURCE diff --git a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp index a4894c8f89a..223e69e5cde 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_INLINE_HPP #define OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_INLINE_HPP +#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "vm_version_x86.hpp" @@ -80,11 +81,11 @@ extern "C" { inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } inline jshort OrderAccess::load_acquire(volatile jshort* p) { return *p; } inline jint OrderAccess::load_acquire(volatile jint* p) { return *p; } -inline jlong OrderAccess::load_acquire(volatile jlong* p) { return *p; } +inline jlong OrderAccess::load_acquire(volatile jlong* p) { return Atomic::load(p); } inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { return *p; } inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; } inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; } -inline julong OrderAccess::load_acquire(volatile julong* p) { return *p; } +inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); } inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; } inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; } @@ -95,11 +96,11 @@ inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return * inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { *p = v; } inline void OrderAccess::release_store(volatile jshort* p, jshort v) { *p = v; } inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { *p = v; } +inline void OrderAccess::release_store(volatile jlong* p, jlong v) { Atomic::store(v, p); } inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { *p = v; } inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p = v; } inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; } -inline void OrderAccess::release_store(volatile julong* p, julong v) { *p = v; } +inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); } inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; } inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; } @@ -123,11 +124,11 @@ inline void OrderAccess::store_ptr_fence(void** p, void* v) { *p = v; inline void OrderAccess::release_store_fence(volatile jbyte* p, jbyte v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jshort* p, jshort v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jint* p, jint v) { *p = v; fence(); } -inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { *p = v; fence(); } +inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { release_store(p, v); fence(); } inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { *p = v; fence(); } -inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { *p = v; fence(); } +inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store(p, v); fence(); } inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); } inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); } 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 be111f4322e..056cb140293 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 @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -104,8 +104,9 @@ popl %ebx .end - // Support for void Atomic::load(volatile jlong* src, volatile jlong* dest). - .inline _Atomic_load_long,2 + // Support for jlong Atomic::load and Atomic::store. + // void _Atomic_move_long(volatile jlong* src, volatile jlong* dst) + .inline _Atomic_move_long,2 movl 0(%esp), %eax // src fildll (%eax) movl 4(%esp), %eax // dest diff --git a/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp b/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp index 7c26cb61051..37d2879662e 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,10 +137,10 @@ inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); } +inline jlong Atomic::load(volatile jlong* src) { return *src; } + #else // !AMD64 -//inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -//inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } inline jint Atomic::add (jint add_value, volatile jint* dest) { int mp = os::is_MP(); __asm { @@ -254,6 +254,33 @@ inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value) { return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); } + +inline jlong Atomic::load(volatile jlong* src) { + volatile jlong dest; + volatile jlong* pdest = &dest; + __asm { + mov eax, src + fild qword ptr [eax] + mov eax, pdest + fistp qword ptr [eax] + } + return dest; +} + +inline void Atomic::store(jlong store_value, volatile jlong* dest) { + volatile jlong* src = &store_value; + __asm { + mov eax, src + fild qword ptr [eax] + mov eax, dest + fistp qword ptr [eax] + } +} + +inline void Atomic::store(jlong store_value, jlong* dest) { + Atomic::store(store_value, (volatile jlong*)dest); +} + #endif // AMD64 #pragma warning(default: 4035) // Enables warnings reporting missing return statement diff --git a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp index b47753bf656..682990dc6b7 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP #define OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP +#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "vm_version_x86.hpp" @@ -65,11 +66,11 @@ inline void OrderAccess::fence() { inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } inline jshort OrderAccess::load_acquire(volatile jshort* p) { return *p; } inline jint OrderAccess::load_acquire(volatile jint* p) { return *p; } -inline jlong OrderAccess::load_acquire(volatile jlong* p) { return *p; } +inline jlong OrderAccess::load_acquire(volatile jlong* p) { return Atomic::load(p); } inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { return *p; } inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; } inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; } -inline julong OrderAccess::load_acquire(volatile julong* p) { return *p; } +inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); } inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; } inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; } @@ -80,11 +81,11 @@ inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return * inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { *p = v; } inline void OrderAccess::release_store(volatile jshort* p, jshort v) { *p = v; } inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { *p = v; } +inline void OrderAccess::release_store(volatile jlong* p, jlong v) { Atomic::store(v, p); } inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { *p = v; } inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p = v; } inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; } -inline void OrderAccess::release_store(volatile julong* p, julong v) { *p = v; } +inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); } inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; } inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; } @@ -188,7 +189,7 @@ inline void OrderAccess::release_store_fence(volatile jint* p, jint v) { #endif // AMD64 } -inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { *p = v; fence(); } +inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { release_store(p, v); fence(); } inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { release_store_fence((volatile jbyte*)p, (jbyte)v); } inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { release_store_fence((volatile jshort*)p, (jshort)v); } diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 1aa2cc00a54..c1f1e1744b5 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -319,24 +319,24 @@ void BlockListBuilder::set_leaders() { case Bytecodes::_tableswitch: { // set block for each case - Bytecode_tableswitch *switch_ = Bytecode_tableswitch_at(s.cur_bcp()); - int l = switch_->length(); + Bytecode_tableswitch sw(&s); + int l = sw.length(); for (int i = 0; i < l; i++) { - make_block_at(cur_bci + switch_->dest_offset_at(i), current); + make_block_at(cur_bci + sw.dest_offset_at(i), current); } - make_block_at(cur_bci + switch_->default_offset(), current); + make_block_at(cur_bci + sw.default_offset(), current); current = NULL; break; } case Bytecodes::_lookupswitch: { // set block for each case - Bytecode_lookupswitch *switch_ = Bytecode_lookupswitch_at(s.cur_bcp()); - int l = switch_->number_of_pairs(); + Bytecode_lookupswitch sw(&s); + int l = sw.number_of_pairs(); for (int i = 0; i < l; i++) { - make_block_at(cur_bci + switch_->pair_at(i)->offset(), current); + make_block_at(cur_bci + sw.pair_at(i).offset(), current); } - make_block_at(cur_bci + switch_->default_offset(), current); + make_block_at(cur_bci + sw.default_offset(), current); current = NULL; break; } @@ -1275,15 +1275,15 @@ void GraphBuilder::ret(int local_index) { void GraphBuilder::table_switch() { - Bytecode_tableswitch* switch_ = Bytecode_tableswitch_at(method()->code() + bci()); - const int l = switch_->length(); + Bytecode_tableswitch sw(stream()); + const int l = sw.length(); if (CanonicalizeNodes && l == 1) { // total of 2 successors => use If instead of switch // Note: This code should go into the canonicalizer as soon as it can // can handle canonicalized forms that contain more than one node. - Value key = append(new Constant(new IntConstant(switch_->low_key()))); - BlockBegin* tsux = block_at(bci() + switch_->dest_offset_at(0)); - BlockBegin* fsux = block_at(bci() + switch_->default_offset()); + Value key = append(new Constant(new IntConstant(sw.low_key()))); + BlockBegin* tsux = block_at(bci() + sw.dest_offset_at(0)); + BlockBegin* fsux = block_at(bci() + sw.default_offset()); bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); ValueStack* state_before = is_bb ? copy_state_before() : NULL; append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); @@ -1293,29 +1293,29 @@ void GraphBuilder::table_switch() { int i; bool has_bb = false; for (i = 0; i < l; i++) { - sux->at_put(i, block_at(bci() + switch_->dest_offset_at(i))); - if (switch_->dest_offset_at(i) < 0) has_bb = true; + sux->at_put(i, block_at(bci() + sw.dest_offset_at(i))); + if (sw.dest_offset_at(i) < 0) has_bb = true; } // add default successor - sux->at_put(i, block_at(bci() + switch_->default_offset())); + sux->at_put(i, block_at(bci() + sw.default_offset())); ValueStack* state_before = has_bb ? copy_state_before() : NULL; - append(new TableSwitch(ipop(), sux, switch_->low_key(), state_before, has_bb)); + append(new TableSwitch(ipop(), sux, sw.low_key(), state_before, has_bb)); } } void GraphBuilder::lookup_switch() { - Bytecode_lookupswitch* switch_ = Bytecode_lookupswitch_at(method()->code() + bci()); - const int l = switch_->number_of_pairs(); + Bytecode_lookupswitch sw(stream()); + const int l = sw.number_of_pairs(); if (CanonicalizeNodes && l == 1) { // total of 2 successors => use If instead of switch // Note: This code should go into the canonicalizer as soon as it can // can handle canonicalized forms that contain more than one node. // simplify to If - LookupswitchPair* pair = switch_->pair_at(0); - Value key = append(new Constant(new IntConstant(pair->match()))); - BlockBegin* tsux = block_at(bci() + pair->offset()); - BlockBegin* fsux = block_at(bci() + switch_->default_offset()); + LookupswitchPair pair = sw.pair_at(0); + Value key = append(new Constant(new IntConstant(pair.match()))); + BlockBegin* tsux = block_at(bci() + pair.offset()); + BlockBegin* fsux = block_at(bci() + sw.default_offset()); bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); ValueStack* state_before = is_bb ? copy_state_before() : NULL; append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); @@ -1326,13 +1326,13 @@ void GraphBuilder::lookup_switch() { int i; bool has_bb = false; for (i = 0; i < l; i++) { - LookupswitchPair* pair = switch_->pair_at(i); - if (pair->offset() < 0) has_bb = true; - sux->at_put(i, block_at(bci() + pair->offset())); - keys->at_put(i, pair->match()); + LookupswitchPair pair = sw.pair_at(i); + if (pair.offset() < 0) has_bb = true; + sux->at_put(i, block_at(bci() + pair.offset())); + keys->at_put(i, pair.match()); } // add default successor - sux->at_put(i, block_at(bci() + switch_->default_offset())); + sux->at_put(i, block_at(bci() + sw.default_offset())); ValueStack* state_before = has_bb ? copy_state_before() : NULL; append(new LookupSwitch(ipop(), sux, keys, state_before, has_bb)); } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 8dc579d0dcc..78e81e26f54 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1990,9 +1990,8 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { LIR_Opr reg = reg = rlock_result(x, x->basic_type()); - if (x->is_volatile() && os::is_MP()) __ membar_acquire(); get_Object_unsafe(reg, src.result(), off.result(), type, x->is_volatile()); - if (x->is_volatile() && os::is_MP()) __ membar(); + if (x->is_volatile() && os::is_MP()) __ membar_acquire(); } @@ -2014,6 +2013,7 @@ void LIRGenerator::do_UnsafePutObject(UnsafePutObject* x) { if (x->is_volatile() && os::is_MP()) __ membar_release(); put_Object_unsafe(src.result(), off.result(), data.result(), type, x->is_volatile()); + if (x->is_volatile() && os::is_MP()) __ membar(); } diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 89cb28c38af..205d49b5298 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,7 +369,7 @@ static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, meth if (branch_bci != InvocationEntryBci) { // Compute desination bci address pc = method()->code_base() + branch_bci; - Bytecodes::Code branch = Bytecodes::code_at(pc, method()); + Bytecodes::Code branch = Bytecodes::code_at(method(), pc); int offset = 0; switch (branch) { case Bytecodes::_if_icmplt: case Bytecodes::_iflt: @@ -659,14 +659,14 @@ JRT_END static klassOop resolve_field_return_klass(methodHandle caller, int bci, TRAPS) { - Bytecode_field* field_access = Bytecode_field_at(caller, bci); + Bytecode_field field_access(caller, bci); // This can be static or non-static field access - Bytecodes::Code code = field_access->code(); + Bytecodes::Code code = field_access.code(); // We must load class, initialize class and resolvethe field FieldAccessInfo result; // initialize class if needed constantPoolHandle constants(THREAD, caller->constants()); - LinkResolver::resolve_field(result, constants, field_access->index(), Bytecodes::java_code(code), false, CHECK_NULL); + LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK_NULL); return result.klass()(); } @@ -767,7 +767,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i Events::log("patch_code @ " INTPTR_FORMAT , caller_frame.pc()); - Bytecodes::Code code = Bytecode_at(caller_method->bcp_from(bci))->java_code(); + Bytecodes::Code code = caller_method()->java_code_at(bci); #ifndef PRODUCT // this is used by assertions in the access_field_patching_id @@ -779,11 +779,11 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i Handle load_klass(THREAD, NULL); // oop needed by load_klass_patching code if (stub_id == Runtime1::access_field_patching_id) { - Bytecode_field* field_access = Bytecode_field_at(caller_method, bci); + Bytecode_field field_access(caller_method, bci); FieldAccessInfo result; // initialize class if needed - Bytecodes::Code code = field_access->code(); + Bytecodes::Code code = field_access.code(); constantPoolHandle constants(THREAD, caller_method->constants()); - LinkResolver::resolve_field(result, constants, field_access->index(), Bytecodes::java_code(code), false, CHECK); + LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK); patch_field_offset = result.field_offset(); // If we're patching a field which is volatile then at compile it @@ -811,36 +811,36 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i } break; case Bytecodes::_new: - { Bytecode_new* bnew = Bytecode_new_at(caller_method->bcp_from(bci)); - k = caller_method->constants()->klass_at(bnew->index(), CHECK); + { Bytecode_new bnew(caller_method(), caller_method->bcp_from(bci)); + k = caller_method->constants()->klass_at(bnew.index(), CHECK); } break; case Bytecodes::_multianewarray: - { Bytecode_multianewarray* mna = Bytecode_multianewarray_at(caller_method->bcp_from(bci)); - k = caller_method->constants()->klass_at(mna->index(), CHECK); + { Bytecode_multianewarray mna(caller_method(), caller_method->bcp_from(bci)); + k = caller_method->constants()->klass_at(mna.index(), CHECK); } break; case Bytecodes::_instanceof: - { Bytecode_instanceof* io = Bytecode_instanceof_at(caller_method->bcp_from(bci)); - k = caller_method->constants()->klass_at(io->index(), CHECK); + { Bytecode_instanceof io(caller_method(), caller_method->bcp_from(bci)); + k = caller_method->constants()->klass_at(io.index(), CHECK); } break; case Bytecodes::_checkcast: - { Bytecode_checkcast* cc = Bytecode_checkcast_at(caller_method->bcp_from(bci)); - k = caller_method->constants()->klass_at(cc->index(), CHECK); + { Bytecode_checkcast cc(caller_method(), caller_method->bcp_from(bci)); + k = caller_method->constants()->klass_at(cc.index(), CHECK); } break; case Bytecodes::_anewarray: - { Bytecode_anewarray* anew = Bytecode_anewarray_at(caller_method->bcp_from(bci)); - klassOop ek = caller_method->constants()->klass_at(anew->index(), CHECK); + { Bytecode_anewarray anew(caller_method(), caller_method->bcp_from(bci)); + klassOop ek = caller_method->constants()->klass_at(anew.index(), CHECK); k = Klass::cast(ek)->array_klass(CHECK); } break; case Bytecodes::_ldc: case Bytecodes::_ldc_w: { - Bytecode_loadconstant* cc = Bytecode_loadconstant_at(caller_method, bci); - k = cc->resolve_constant(CHECK); + Bytecode_loadconstant cc(caller_method, bci); + k = cc.resolve_constant(CHECK); assert(k != NULL && !k->is_klass(), "must be class mirror or other Java constant"); } break; diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index acf3bfaad4c..9017232a237 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -761,15 +761,15 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl case Bytecodes::_tableswitch: { state.spop(); - Bytecode_tableswitch* switch_ = Bytecode_tableswitch_at(s.cur_bcp()); - int len = switch_->length(); + Bytecode_tableswitch sw(&s); + int len = sw.length(); int dest_bci; for (int i = 0; i < len; i++) { - dest_bci = s.cur_bci() + switch_->dest_offset_at(i); + dest_bci = s.cur_bci() + sw.dest_offset_at(i); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); } - dest_bci = s.cur_bci() + switch_->default_offset(); + dest_bci = s.cur_bci() + sw.default_offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); assert(s.next_bci() == limit_bci, "branch must end block"); @@ -779,15 +779,15 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl case Bytecodes::_lookupswitch: { state.spop(); - Bytecode_lookupswitch* switch_ = Bytecode_lookupswitch_at(s.cur_bcp()); - int len = switch_->number_of_pairs(); + Bytecode_lookupswitch sw(&s); + int len = sw.number_of_pairs(); int dest_bci; for (int i = 0; i < len; i++) { - dest_bci = s.cur_bci() + switch_->pair_at(i)->offset(); + dest_bci = s.cur_bci() + sw.pair_at(i).offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); } - dest_bci = s.cur_bci() + switch_->default_offset(); + dest_bci = s.cur_bci() + sw.default_offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index eab8de7670d..2f20fcc9861 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -409,15 +409,15 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, } else { fail_type = _unloaded_ciinstance_klass; } - klassOop found_klass; + KlassHandle found_klass; if (!require_local) { - found_klass = - SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, - KILL_COMPILE_ON_FATAL_(fail_type)); + klassOop kls = SystemDictionary::find_constrained_instance_or_array_klass( + sym, loader, KILL_COMPILE_ON_FATAL_(fail_type)); + found_klass = KlassHandle(THREAD, kls); } else { - found_klass = - SystemDictionary::find_instance_or_array_klass(sym, loader, domain, - KILL_COMPILE_ON_FATAL_(fail_type)); + klassOop kls = SystemDictionary::find_instance_or_array_klass( + sym, loader, domain, KILL_COMPILE_ON_FATAL_(fail_type)); + found_klass = KlassHandle(THREAD, kls); } // If we fail to find an array klass, look again for its element type. @@ -444,9 +444,9 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, } } - if (found_klass != NULL) { + if (found_klass() != NULL) { // Found it. Build a CI handle. - return get_object(found_klass)->as_klass(); + return get_object(found_klass())->as_klass(); } if (require_local) return NULL; diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 63d4bdc7c37..745806c0c06 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,7 +144,7 @@ class ciMethod : public ciObject { Bytecodes::Code java_code_at_bci(int bci) { address bcp = code() + bci; - return Bytecodes::java_code_at(bcp); + return Bytecodes::java_code_at(NULL, bcp); } BCEscapeAnalyzer *get_bcea(); ciMethodBlocks *get_method_blocks(); diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp index e54f94c72b4..614e75dc3bf 100644 --- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,15 +175,15 @@ void ciMethodBlocks::do_analysis() { case Bytecodes::_tableswitch : { cur_block->set_control_bci(bci); - Bytecode_tableswitch* switch_ = Bytecode_tableswitch_at(s.cur_bcp()); - int len = switch_->length(); + Bytecode_tableswitch sw(&s); + int len = sw.length(); ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) { - dest_bci = s.cur_bci() + switch_->dest_offset_at(i); + dest_bci = s.cur_bci() + sw.dest_offset_at(i); dest = make_block_at(dest_bci); } - dest_bci = s.cur_bci() + switch_->default_offset(); + dest_bci = s.cur_bci() + sw.default_offset(); make_block_at(dest_bci); if (s.next_bci() < limit_bci) { dest = make_block_at(s.next_bci()); @@ -194,15 +194,15 @@ void ciMethodBlocks::do_analysis() { case Bytecodes::_lookupswitch: { cur_block->set_control_bci(bci); - Bytecode_lookupswitch* switch_ = Bytecode_lookupswitch_at(s.cur_bcp()); - int len = switch_->number_of_pairs(); + Bytecode_lookupswitch sw(&s); + int len = sw.number_of_pairs(); ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) { - dest_bci = s.cur_bci() + switch_->pair_at(i)->offset(); + dest_bci = s.cur_bci() + sw.pair_at(i).offset(); dest = make_block_at(dest_bci); } - dest_bci = s.cur_bci() + switch_->default_offset(); + dest_bci = s.cur_bci() + sw.default_offset(); dest = make_block_at(dest_bci); if (s.next_bci() < limit_bci) { dest = make_block_at(s.next_bci()); diff --git a/hotspot/src/share/vm/ci/ciMethodHandle.cpp b/hotspot/src/share/vm/ci/ciMethodHandle.cpp index c8e7cf18142..1355b504c4c 100644 --- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp +++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,11 +38,12 @@ // Return an adapter for this MethodHandle. ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const { VM_ENTRY_MARK; - Handle h(get_oop()); methodHandle callee(_callee->get_methodOop()); - MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD); - methodHandle m = mhc.compile(CHECK_NULL); + // We catch all exceptions here that could happen in the method + // handle compiler and stop the VM. + MethodHandleCompiler mhc(h, callee, is_invokedynamic, CATCH); + methodHandle m = mhc.compile(CATCH); return CURRENT_ENV->get_object(m())->as_method(); } diff --git a/hotspot/src/share/vm/ci/ciStreams.hpp b/hotspot/src/share/vm/ci/ciStreams.hpp index 78ff279811e..7ad6ef082e9 100644 --- a/hotspot/src/share/vm/ci/ciStreams.hpp +++ b/hotspot/src/share/vm/ci/ciStreams.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,8 +78,8 @@ private: else { assert(!is_wide(), "must not be a wide instruction"); } } - Bytecode* bytecode() const { return Bytecode_at(_bc_start); } - Bytecode* next_bytecode() const { return Bytecode_at(_pc); } + Bytecode bytecode() const { return Bytecode(this, _bc_start); } + Bytecode next_bytecode() const { return Bytecode(this, _pc); } public: // End-Of-Bytecodes @@ -151,11 +151,11 @@ public: bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } int get_index_u1() const { - return bytecode()->get_index_u1(cur_bc_raw()); + return bytecode().get_index_u1(cur_bc_raw()); } int get_index_u1_cpcache() const { - return bytecode()->get_index_u1_cpcache(cur_bc_raw()); + return bytecode().get_index_u1_cpcache(cur_bc_raw()); } // Get a byte index following this bytecode. @@ -169,29 +169,29 @@ public: // Get 2-byte index (byte swapping depending on which bytecode) int get_index_u2(bool is_wide = false) const { - return bytecode()->get_index_u2(cur_bc_raw(), is_wide); + return bytecode().get_index_u2(cur_bc_raw(), is_wide); } // Get 2-byte index in native byte order. (Rewriter::rewrite makes these.) int get_index_u2_cpcache() const { - return bytecode()->get_index_u2_cpcache(cur_bc_raw()); + return bytecode().get_index_u2_cpcache(cur_bc_raw()); } // Get 4-byte index, for invokedynamic. int get_index_u4() const { - return bytecode()->get_index_u4(cur_bc_raw()); + return bytecode().get_index_u4(cur_bc_raw()); } bool has_index_u4() const { - return bytecode()->has_index_u4(cur_bc_raw()); + return bytecode().has_index_u4(cur_bc_raw()); } // Get dimensions byte (multinewarray) int get_dimensions() const { return *(unsigned char*)(_pc-1); } // Sign-extended index byte/short, no widening - int get_constant_u1() const { return bytecode()->get_constant_u1(instruction_size()-1, cur_bc_raw()); } - int get_constant_u2(bool is_wide = false) const { return bytecode()->get_constant_u2(instruction_size()-2, cur_bc_raw(), is_wide); } + int get_constant_u1() const { return bytecode().get_constant_u1(instruction_size()-1, cur_bc_raw()); } + int get_constant_u2(bool is_wide = false) const { return bytecode().get_constant_u2(instruction_size()-2, cur_bc_raw(), is_wide); } // Get a byte signed constant for "iinc". Invalid for other bytecodes. // If prefixed with a wide bytecode, get a wide constant @@ -199,18 +199,18 @@ public: // 2-byte branch offset from current pc int get_dest() const { - return cur_bci() + bytecode()->get_offset_s2(cur_bc_raw()); + return cur_bci() + bytecode().get_offset_s2(cur_bc_raw()); } // 2-byte branch offset from next pc int next_get_dest() const { assert(_pc < _end, ""); - return next_bci() + next_bytecode()->get_offset_s2(Bytecodes::_ifeq); + return next_bci() + next_bytecode().get_offset_s2(Bytecodes::_ifeq); } // 4-byte branch offset from current pc int get_far_dest() const { - return cur_bci() + bytecode()->get_offset_s4(cur_bc_raw()); + return cur_bci() + bytecode().get_offset_s4(cur_bc_raw()); } // For a lookup or switch table, return target destination @@ -407,4 +407,11 @@ public: } }; + + +// Implementation for declarations in bytecode.hpp +Bytecode::Bytecode(const ciBytecodeStream* stream, address bcp): _bcp(bcp != NULL ? bcp : stream->cur_bcp()), _code(Bytecodes::code_at(NULL, addr_at(0))) {} +Bytecode_lookupswitch::Bytecode_lookupswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); } +Bytecode_tableswitch::Bytecode_tableswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); } + #endif // SHARE_VM_CI_CISTREAMS_HPP diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index d8af850f185..5986df0abaf 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1698,18 +1698,17 @@ ciTypeFlow::Block::successors(ciBytecodeStream* str, break; case Bytecodes::_tableswitch: { - Bytecode_tableswitch *tableswitch = - Bytecode_tableswitch_at(str->cur_bcp()); + Bytecode_tableswitch tableswitch(str); - int len = tableswitch->length(); + int len = tableswitch.length(); _successors = new (arena) GrowableArray(arena, len+1, 0, NULL); - int bci = current_bci + tableswitch->default_offset(); + int bci = current_bci + tableswitch.default_offset(); Block* block = analyzer->block_at(bci, jsrs); assert(_successors->length() == SWITCH_DEFAULT, ""); _successors->append(block); while (--len >= 0) { - int bci = current_bci + tableswitch->dest_offset_at(len); + int bci = current_bci + tableswitch.dest_offset_at(len); block = analyzer->block_at(bci, jsrs); assert(_successors->length() >= SWITCH_CASES, ""); _successors->append_if_missing(block); @@ -1718,19 +1717,18 @@ ciTypeFlow::Block::successors(ciBytecodeStream* str, } case Bytecodes::_lookupswitch: { - Bytecode_lookupswitch *lookupswitch = - Bytecode_lookupswitch_at(str->cur_bcp()); + Bytecode_lookupswitch lookupswitch(str); - int npairs = lookupswitch->number_of_pairs(); + int npairs = lookupswitch.number_of_pairs(); _successors = new (arena) GrowableArray(arena, npairs+1, 0, NULL); - int bci = current_bci + lookupswitch->default_offset(); + int bci = current_bci + lookupswitch.default_offset(); Block* block = analyzer->block_at(bci, jsrs); assert(_successors->length() == SWITCH_DEFAULT, ""); _successors->append(block); while(--npairs >= 0) { - LookupswitchPair *pair = lookupswitch->pair_at(npairs); - int bci = current_bci + pair->offset(); + LookupswitchPair pair = lookupswitch.pair_at(npairs); + int bci = current_bci + pair.offset(); Block* block = analyzer->block_at(bci, jsrs); assert(_successors->length() >= SWITCH_CASES, ""); _successors->append_if_missing(block); diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 00231243233..593bc9177a9 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1382,3 +1382,61 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { } #endif //PRODUCT + +// Please keep following two functions at end of this file. With them placed at top or in middle of the file, +// they could get inlined by agressive compiler, an unknown trick, see bug 6966589. +void PerfClassTraceTime::initialize() { + if (!UsePerfData) return; + + if (_eventp != NULL) { + // increment the event counter + _eventp->inc(); + } + + // stop the current active thread-local timer to measure inclusive time + _prev_active_event = -1; + for (int i=0; i < EVENT_TYPE_COUNT; i++) { + if (_timers[i].is_active()) { + assert(_prev_active_event == -1, "should have only one active timer"); + _prev_active_event = i; + _timers[i].stop(); + } + } + + if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) { + // start the inclusive timer if not recursively called + _t.start(); + } + + // start thread-local timer of the given event type + if (!_timers[_event_type].is_active()) { + _timers[_event_type].start(); + } +} + +PerfClassTraceTime::~PerfClassTraceTime() { + if (!UsePerfData) return; + + // stop the thread-local timer as the event completes + // and resume the thread-local timer of the event next on the stack + _timers[_event_type].stop(); + jlong selftime = _timers[_event_type].ticks(); + + if (_prev_active_event >= 0) { + _timers[_prev_active_event].start(); + } + + if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return; + + // increment the counters only on the leaf call + _t.stop(); + _timep->inc(_t.ticks()); + if (_selftimep != NULL) { + _selftimep->inc(selftime); + } + // add all class loading related event selftime to the accumulated time counter + ClassLoader::perf_accumulated_time()->inc(selftime); + + // reset the timer + _timers[_event_type].reset(); +} diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 3c6b215f994..5073f882653 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -356,111 +356,57 @@ class ClassLoader: AllStatic { // (i.e. only one event type) are active at a time even multiple PerfClassTraceTime // instances have been created as multiple events are happening. class PerfClassTraceTime { - public: - enum { - CLASS_LOAD = 0, - PARSE_CLASS = 1, - CLASS_LINK = 2, - CLASS_VERIFY = 3, - CLASS_CLINIT = 4, - DEFINE_CLASS = 5, - EVENT_TYPE_COUNT = 6 - }; - protected: - // _t tracks time from initialization to destruction of this timer instance - // including time for all other event types, and recursive calls of this type. - // When a timer is called recursively, the elapsedTimer _t would not be used. - elapsedTimer _t; - PerfLongCounter* _timep; - PerfLongCounter* _selftimep; - PerfLongCounter* _eventp; - // pointer to thread-local recursion counter and timer array - // The thread_local timers track cumulative time for specific event types - // exclusive of time for other event types, but including recursive calls - // of the same type. - int* _recursion_counters; - elapsedTimer* _timers; - int _event_type; - int _prev_active_event; + public: + enum { + CLASS_LOAD = 0, + PARSE_CLASS = 1, + CLASS_LINK = 2, + CLASS_VERIFY = 3, + CLASS_CLINIT = 4, + DEFINE_CLASS = 5, + EVENT_TYPE_COUNT = 6 + }; + protected: + // _t tracks time from initialization to destruction of this timer instance + // including time for all other event types, and recursive calls of this type. + // When a timer is called recursively, the elapsedTimer _t would not be used. + elapsedTimer _t; + PerfLongCounter* _timep; + PerfLongCounter* _selftimep; + PerfLongCounter* _eventp; + // pointer to thread-local recursion counter and timer array + // The thread_local timers track cumulative time for specific event types + // exclusive of time for other event types, but including recursive calls + // of the same type. + int* _recursion_counters; + elapsedTimer* _timers; + int _event_type; + int _prev_active_event; - public: + public: - inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ - PerfLongCounter* selftimep, /* counter incremented with exclusive time */ - PerfLongCounter* eventp, /* event counter */ - int* recursion_counters, /* thread-local recursion counter array */ - elapsedTimer* timers, /* thread-local timer array */ - int type /* event type */ ) : - _timep(timep), _selftimep(selftimep), _eventp(eventp), _recursion_counters(recursion_counters), _timers(timers), _event_type(type) { - initialize(); - } + inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ + PerfLongCounter* selftimep, /* counter incremented with exclusive time */ + PerfLongCounter* eventp, /* event counter */ + int* recursion_counters, /* thread-local recursion counter array */ + elapsedTimer* timers, /* thread-local timer array */ + int type /* event type */ ) : + _timep(timep), _selftimep(selftimep), _eventp(eventp), _recursion_counters(recursion_counters), _timers(timers), _event_type(type) { + initialize(); + } - inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ - elapsedTimer* timers, /* thread-local timer array */ - int type /* event type */ ) : - _timep(timep), _selftimep(NULL), _eventp(NULL), _recursion_counters(NULL), _timers(timers), _event_type(type) { - initialize(); - } + inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ + elapsedTimer* timers, /* thread-local timer array */ + int type /* event type */ ) : + _timep(timep), _selftimep(NULL), _eventp(NULL), _recursion_counters(NULL), _timers(timers), _event_type(type) { + initialize(); + } - void initialize() { - if (!UsePerfData) return; + inline void suspend() { _t.stop(); _timers[_event_type].stop(); } + inline void resume() { _t.start(); _timers[_event_type].start(); } - if (_eventp != NULL) { - // increment the event counter - _eventp->inc(); - } - - // stop the current active thread-local timer to measure inclusive time - _prev_active_event = -1; - for (int i=0; i < EVENT_TYPE_COUNT; i++) { - if (_timers[i].is_active()) { - assert(_prev_active_event == -1, "should have only one active timer"); - _prev_active_event = i; - _timers[i].stop(); - } - } - - if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) { - // start the inclusive timer if not recursively called - _t.start(); - } - - // start thread-local timer of the given event type - if (!_timers[_event_type].is_active()) { - _timers[_event_type].start(); - } - } - - inline void suspend() { _t.stop(); _timers[_event_type].stop(); } - inline void resume() { _t.start(); _timers[_event_type].start(); } - - ~PerfClassTraceTime() { - if (!UsePerfData) return; - - // stop the thread-local timer as the event completes - // and resume the thread-local timer of the event next on the stack - _timers[_event_type].stop(); - jlong selftime = _timers[_event_type].ticks(); - - if (_prev_active_event >= 0) { - _timers[_prev_active_event].start(); - } - - if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return; - - // increment the counters only on the leaf call - _t.stop(); - _timep->inc(_t.ticks()); - if (_selftimep != NULL) { - _selftimep->inc(selftime); - } - // add all class loading related event selftime to the accumulated time counter - ClassLoader::perf_accumulated_time()->inc(selftime); - - // reset the timer - _timers[_event_type].reset(); - } + ~PerfClassTraceTime(); + void initialize(); }; - #endif // SHARE_VM_CLASSFILE_CLASSLOADER_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index a83c8d55120..9dc5b933f80 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,6 +172,8 @@ class SymbolPropertyTable; \ template(sun_jkernel_DownloadManager_klass, sun_jkernel_DownloadManager, Opt_Kernel) \ \ + template(sun_misc_PostVMInitHook_klass, sun_misc_PostVMInitHook, Opt) \ + \ /* Preload boxing klasses */ \ template(Boolean_klass, java_lang_Boolean, Pre) \ template(Character_klass, java_lang_Character, Pre) \ diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 59168b8c544..6a9ef12a525 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,6 +111,7 @@ template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(setBootClassLoaderHook_name, "setBootClassLoaderHook") \ + template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ \ /* class file format tags */ \ template(tag_source_file, "SourceFile") \ diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 98bad3ca098..5f7d994cbd0 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1863,9 +1863,9 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map #ifndef SHARK if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); - Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci()); - bool has_receiver = call->has_receiver(); - symbolOop signature = call->signature(); + Bytecode_invoke call(ssd.method(), ssd.bci()); + bool has_receiver = call.has_receiver(); + symbolOop signature = call.signature(); fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); } #endif // !SHARK @@ -2698,8 +2698,7 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, } else if (sd->method()->is_native()) { st->print("method is native"); } else { - address bcp = sd->method()->bcp_from(sd->bci()); - Bytecodes::Code bc = Bytecodes::java_code_at(bcp); + Bytecodes::Code bc = sd->method()->java_code_at(sd->bci()); st->print(";*%s", Bytecodes::name(bc)); switch (bc) { case Bytecodes::_invokevirtual: @@ -2707,10 +2706,10 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: { - Bytecode_invoke* invoke = Bytecode_invoke_at(sd->method(), sd->bci()); + Bytecode_invoke invoke(sd->method(), sd->bci()); st->print(" "); - if (invoke->name() != NULL) - invoke->name()->print_symbol_on(st); + if (invoke.name() != NULL) + invoke.name()->print_symbol_on(st); else st->print(""); break; @@ -2720,10 +2719,10 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, case Bytecodes::_getstatic: case Bytecodes::_putstatic: { - Bytecode_field* field = Bytecode_field_at(sd->method(), sd->bci()); + Bytecode_field field(sd->method(), sd->bci()); st->print(" "); - if (field->name() != NULL) - field->name()->print_symbol_on(st); + if (field.name() != NULL) + field.name()->print_symbol_on(st); else st->print(""); } diff --git a/hotspot/src/share/vm/compiler/methodLiveness.cpp b/hotspot/src/share/vm/compiler/methodLiveness.cpp index 42450ec10ea..4fcc5613336 100644 --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -286,16 +286,15 @@ void MethodLiveness::init_basic_blocks() { break; case Bytecodes::_tableswitch: { - Bytecode_tableswitch *tableswitch = - Bytecode_tableswitch_at(bytes.cur_bcp()); + Bytecode_tableswitch tableswitch(&bytes); - int len = tableswitch->length(); + int len = tableswitch.length(); - dest = _block_map->at(bci + tableswitch->default_offset()); + dest = _block_map->at(bci + tableswitch.default_offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); while (--len >= 0) { - dest = _block_map->at(bci + tableswitch->dest_offset_at(len)); + dest = _block_map->at(bci + tableswitch.dest_offset_at(len)); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); } @@ -304,17 +303,16 @@ void MethodLiveness::init_basic_blocks() { case Bytecodes::_lookupswitch: { - Bytecode_lookupswitch *lookupswitch = - Bytecode_lookupswitch_at(bytes.cur_bcp()); + Bytecode_lookupswitch lookupswitch(&bytes); - int npairs = lookupswitch->number_of_pairs(); + int npairs = lookupswitch.number_of_pairs(); - dest = _block_map->at(bci + lookupswitch->default_offset()); + dest = _block_map->at(bci + lookupswitch.default_offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); while(--npairs >= 0) { - LookupswitchPair *pair = lookupswitch->pair_at(npairs); - dest = _block_map->at( bci + pair->offset()); + LookupswitchPair pair = lookupswitch.pair_at(npairs); + dest = _block_map->at( bci + pair.offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); } diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 36a070a1826..2bbe0aa1f9f 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -3478,6 +3478,7 @@ void CMSCollector::checkpointRootsInitial(bool asynch) { assert(_collectorState == InitialMarking, "Wrong collector state"); check_correct_thread_executing(); TraceCMSMemoryManagerStats tms(_collectorState); + ReferenceProcessor* rp = ref_processor(); SpecializationStats::clear(); assert(_restart_addr == NULL, "Control point invariant"); @@ -4978,6 +4979,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch, if (should_unload_classes()) { CodeCache::gc_epilogue(); } + JvmtiExport::gc_epilogue(); // If we encountered any (marking stack / work queue) overflow // events during the current CMS cycle, take appropriate @@ -5940,11 +5942,6 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) { } rp->verify_no_references_recorded(); assert(!rp->discovery_enabled(), "should have been disabled"); - - // JVMTI object tagging is based on JNI weak refs. If any of these - // refs were cleared then JVMTI needs to update its maps and - // maybe post ObjectFrees to agents. - JvmtiExport::cms_ref_processing_epilogue(); } #ifndef PRODUCT @@ -6305,6 +6302,7 @@ void CMSCollector::do_CMS_operation(CMS_op_type op) { switch (op) { case CMS_op_checkpointRootsInitial: { + SvcGCMarker sgcm(SvcGCMarker::OTHER); checkpointRootsInitial(true); // asynch if (PrintGC) { _cmsGen->printOccupancy("initial-mark"); @@ -6312,6 +6310,7 @@ void CMSCollector::do_CMS_operation(CMS_op_type op) { break; } case CMS_op_checkpointRootsFinal: { + SvcGCMarker sgcm(SvcGCMarker::OTHER); checkpointRootsFinal(true, // asynch false, // !clear_all_soft_refs false); // !init_mark_was_synchronous @@ -7881,25 +7880,23 @@ SweepClosure::SweepClosure(CMSCollector* collector, } // We need this destructor to reclaim any space at the end -// of the space, which do_blk below may not have added back to -// the free lists. [basically dealing with the "fringe effect"] +// of the space, which do_blk below may not yet have added back to +// the free lists. SweepClosure::~SweepClosure() { assert_lock_strong(_freelistLock); - // this should be treated as the end of a free run if any - // The current free range should be returned to the free lists - // as one coalesced chunk. + assert(_limit >= _sp->bottom() && _limit <= _sp->end(), + "sweep _limit out of bounds"); + // Flush any remaining coterminal free run as a single + // coalesced chunk to the appropriate free list. if (inFreeRange()) { - flushCurFreeChunk(freeFinger(), - pointer_delta(_limit, freeFinger())); - assert(freeFinger() < _limit, "the finger pointeth off base"); + assert(freeFinger() < _limit, "freeFinger points too high"); + flush_cur_free_chunk(freeFinger(), pointer_delta(_limit, freeFinger())); if (CMSTraceSweeper) { - gclog_or_tty->print("destructor:"); - gclog_or_tty->print("Sweep:put_free_blk 0x%x ("SIZE_FORMAT") " - "[coalesced:"SIZE_FORMAT"]\n", - freeFinger(), pointer_delta(_limit, freeFinger()), - lastFreeRangeCoalesced()); + gclog_or_tty->print("Sweep: last chunk: "); + gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") [coalesced:"SIZE_FORMAT"]\n", + freeFinger(), pointer_delta(_limit, freeFinger()), lastFreeRangeCoalesced()); } - } + } // else nothing to flush NOT_PRODUCT( if (Verbose && PrintGC) { gclog_or_tty->print("Collected "SIZE_FORMAT" objects, " @@ -7936,9 +7933,8 @@ SweepClosure::~SweepClosure() { void SweepClosure::initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists) { if (CMSTraceSweeper) { - gclog_or_tty->print("---- Start free range 0x%x with free block [%d] (%d)\n", - freeFinger, _sp->block_size(freeFinger), - freeRangeInFreeLists); + gclog_or_tty->print("---- Start free range at 0x%x with free block (%d)\n", + freeFinger, freeRangeInFreeLists); } assert(!inFreeRange(), "Trampling existing free range"); set_inFreeRange(true); @@ -7993,21 +7989,36 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { // may have caused us to coalesce the block ending at the address _limit // with a newly expanded chunk (this happens when _limit was set to the // previous _end of the space), so we may have stepped past _limit; see CR 6977970. - if (addr >= _limit) { // we have swept up to or past the limit, do nothing more + if (addr >= _limit) { // we have swept up to or past the limit: finish up assert(_limit >= _sp->bottom() && _limit <= _sp->end(), "sweep _limit out of bounds"); assert(addr < _sp->end(), "addr out of bounds"); - // help the closure application finish + // Flush any remaining coterminal free run as a single + // coalesced chunk to the appropriate free list. + if (inFreeRange()) { + assert(freeFinger() < _limit, "finger points too high"); + flush_cur_free_chunk(freeFinger(), + pointer_delta(addr, freeFinger())); + if (CMSTraceSweeper) { + gclog_or_tty->print("Sweep: last chunk: "); + gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") " + "[coalesced:"SIZE_FORMAT"]\n", + freeFinger(), pointer_delta(addr, freeFinger()), + lastFreeRangeCoalesced()); + } + } + + // help the iterator loop finish return pointer_delta(_sp->end(), addr); } - assert(addr < _limit, "sweep invariant"); + assert(addr < _limit, "sweep invariant"); // check if we should yield do_yield_check(addr); if (fc->isFree()) { // Chunk that is already free res = fc->size(); - doAlreadyFreeChunk(fc); + do_already_free_chunk(fc); debug_only(_sp->verifyFreeLists()); assert(res == fc->size(), "Don't expect the size to change"); NOT_PRODUCT( @@ -8017,7 +8028,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { NOT_PRODUCT(_last_fc = fc;) } else if (!_bitMap->isMarked(addr)) { // Chunk is fresh garbage - res = doGarbageChunk(fc); + res = do_garbage_chunk(fc); debug_only(_sp->verifyFreeLists()); NOT_PRODUCT( _numObjectsFreed++; @@ -8025,7 +8036,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { ) } else { // Chunk that is alive. - res = doLiveChunk(fc); + res = do_live_chunk(fc); debug_only(_sp->verifyFreeLists()); NOT_PRODUCT( _numObjectsLive++; @@ -8078,7 +8089,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { // to a free list which may be overpopulated. // -void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { +void SweepClosure::do_already_free_chunk(FreeChunk* fc) { size_t size = fc->size(); // Chunks that cannot be coalesced are not in the // free lists. @@ -8094,23 +8105,23 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { // addr and purported end of this block. _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); - // Some chunks cannot be coalesced in under any circumstances. + // Some chunks cannot be coalesced under any circumstances. // See the definition of cantCoalesce(). if (!fc->cantCoalesce()) { // This chunk can potentially be coalesced. if (_sp->adaptive_freelists()) { // All the work is done in - doPostIsFreeOrGarbageChunk(fc, size); + do_post_free_or_garbage_chunk(fc, size); } else { // Not adaptive free lists // this is a free chunk that can potentially be coalesced by the sweeper; if (!inFreeRange()) { // if the next chunk is a free block that can't be coalesced // it doesn't make sense to remove this chunk from the free lists FreeChunk* nextChunk = (FreeChunk*)(addr + size); - assert((HeapWord*)nextChunk <= _limit, "sweep invariant"); - if ((HeapWord*)nextChunk < _limit && // there's a next chunk... - nextChunk->isFree() && // which is free... - nextChunk->cantCoalesce()) { // ... but cant be coalesced + assert((HeapWord*)nextChunk <= _sp->end(), "Chunk size out of bounds?"); + if ((HeapWord*)nextChunk < _sp->end() && // There is another free chunk to the right ... + nextChunk->isFree() && // ... which is free... + nextChunk->cantCoalesce()) { // ... but can't be coalesced // nothing to do } else { // Potentially the start of a new free range: @@ -8156,14 +8167,14 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { // as the end of a free run if any if (inFreeRange()) { // we kicked some butt; time to pick up the garbage - assert(freeFinger() < addr, "the finger pointeth off base"); - flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); + assert(freeFinger() < addr, "freeFinger points too high"); + flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); } // else, nothing to do, just continue } } -size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { +size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) { // This is a chunk of garbage. It is not in any free list. // Add it to a free list or let it possibly be coalesced into // a larger chunk. @@ -8175,7 +8186,7 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { // addr and purported end of just dead object. _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); - doPostIsFreeOrGarbageChunk(fc, size); + do_post_free_or_garbage_chunk(fc, size); } else { if (!inFreeRange()) { // start of a new free range @@ -8214,35 +8225,16 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { return size; } -size_t SweepClosure::doLiveChunk(FreeChunk* fc) { +size_t SweepClosure::do_live_chunk(FreeChunk* fc) { HeapWord* addr = (HeapWord*) fc; // The sweeper has just found a live object. Return any accumulated // left hand chunk to the free lists. if (inFreeRange()) { - if (_sp->adaptive_freelists()) { - flushCurFreeChunk(freeFinger(), - pointer_delta(addr, freeFinger())); - } else { // not adaptive freelists - set_inFreeRange(false); - // Add the free range back to the free list if it is not already - // there. - if (!freeRangeInFreeLists()) { - assert(freeFinger() < addr, "the finger pointeth off base"); - if (CMSTraceSweeper) { - gclog_or_tty->print("Sweep:put_free_blk 0x%x (%d) " - "[coalesced:%d]\n", - freeFinger(), pointer_delta(addr, freeFinger()), - lastFreeRangeCoalesced()); - } - _sp->addChunkAndRepairOffsetTable(freeFinger(), - pointer_delta(addr, freeFinger()), lastFreeRangeCoalesced()); - } - } + assert(freeFinger() < addr, "freeFinger points too high"); + flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); } - // Common code path for original and adaptive free lists. - - // this object is live: we'd normally expect this to be + // This object is live: we'd normally expect this to be // an oop, and like to assert the following: // assert(oop(addr)->is_oop(), "live block should be an oop"); // However, as we commented above, this may be an object whose @@ -8257,7 +8249,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { assert(size == CompactibleFreeListSpace::adjustObjectSize(size), "alignment problem"); - #ifdef DEBUG +#ifdef DEBUG if (oop(addr)->klass_or_null() != NULL && ( !_collector->should_unload_classes() || (oop(addr)->is_parsable()) && @@ -8271,7 +8263,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()), "P-mark and computed size do not agree"); } - #endif +#endif } else { // This should be an initialized object that's alive. @@ -8298,19 +8290,17 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { return size; } -void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc, - size_t chunkSize) { - // doPostIsFreeOrGarbageChunk() should only be called in the smart allocation - // scheme. +void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc, + size_t chunkSize) { + // do_post_free_or_garbage_chunk() should only be called in the case + // of the adaptive free list allocator. bool fcInFreeLists = fc->isFree(); assert(_sp->adaptive_freelists(), "Should only be used in this case."); assert((HeapWord*)fc <= _limit, "sweep invariant"); if (CMSTestInFreeList && fcInFreeLists) { - assert(_sp->verifyChunkInFreeLists(fc), - "free chunk is not in free lists"); + assert(_sp->verifyChunkInFreeLists(fc), "free chunk is not in free lists"); } - if (CMSTraceSweeper) { gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize); } @@ -8382,20 +8372,21 @@ void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc, if (inFreeRange()) { // In a free range but cannot coalesce with the right hand chunk. // Put the current free range into the free lists. - flushCurFreeChunk(freeFinger(), - pointer_delta(addr, freeFinger())); + flush_cur_free_chunk(freeFinger(), + pointer_delta(addr, freeFinger())); } // Set up for new free range. Pass along whether the right hand // chunk is in the free lists. initialize_free_range((HeapWord*)fc, fcInFreeLists); } } -void SweepClosure::flushCurFreeChunk(HeapWord* chunk, size_t size) { + +void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) { assert(inFreeRange(), "Should only be called if currently in a free range."); assert(size > 0, "A zero sized chunk cannot be added to the free lists."); if (!freeRangeInFreeLists()) { - if(CMSTestInFreeList) { + if (CMSTestInFreeList) { FreeChunk* fc = (FreeChunk*) chunk; fc->setSize(size); assert(!_sp->verifyChunkInFreeLists(fc), @@ -8430,7 +8421,7 @@ void SweepClosure::do_yield_work(HeapWord* addr) { // chunk just flushed, they will need to wait for the next // sweep to be coalesced. if (inFreeRange()) { - flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); + flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); } // First give up the locks, then yield, then re-lock. diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index 118380ddd5d..a54f5eff702 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -1701,7 +1701,9 @@ class SweepClosure: public BlkClosureCareful { CMSCollector* _collector; // collector doing the work ConcurrentMarkSweepGeneration* _g; // Generation being swept CompactibleFreeListSpace* _sp; // Space being swept - HeapWord* _limit; + HeapWord* _limit;// the address at which the sweep should stop because + // we do not expect blocks eligible for sweeping past + // that address. Mutex* _freelistLock; // Free list lock (in space) CMSBitMap* _bitMap; // Marking bit map (in // generation) @@ -1745,14 +1747,13 @@ class SweepClosure: public BlkClosureCareful { private: // Code that is common to a free chunk or garbage when // encountered during sweeping. - void doPostIsFreeOrGarbageChunk(FreeChunk *fc, - size_t chunkSize); + void do_post_free_or_garbage_chunk(FreeChunk *fc, size_t chunkSize); // Process a free chunk during sweeping. - void doAlreadyFreeChunk(FreeChunk *fc); + void do_already_free_chunk(FreeChunk *fc); // Process a garbage chunk during sweeping. - size_t doGarbageChunk(FreeChunk *fc); + size_t do_garbage_chunk(FreeChunk *fc); // Process a live chunk during sweeping. - size_t doLiveChunk(FreeChunk* fc); + size_t do_live_chunk(FreeChunk* fc); // Accessors. HeapWord* freeFinger() const { return _freeFinger; } @@ -1769,7 +1770,7 @@ class SweepClosure: public BlkClosureCareful { // Initialize a free range. void initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists); // Return this chunk to the free lists. - void flushCurFreeChunk(HeapWord* chunk, size_t size); + void flush_cur_free_chunk(HeapWord* chunk, size_t size); // Check if we should yield and do so when necessary. inline void do_yield_check(HeapWord* addr); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index d1989d4a24e..e082c1b21d9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "gc_implementation/g1/g1RemSet.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" +#include "gc_implementation/shared/vmGCOperations.hpp" #include "memory/genOopClosures.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" @@ -457,6 +458,7 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, _marking_task_overhead(1.0), _cleanup_sleep_factor(0.0), _cleanup_task_overhead(1.0), + _cleanup_list("Cleanup List"), _region_bm(max_regions, false /* in_resource_area*/), _card_bm((rs.size() + CardTableModRefBS::card_size - 1) >> CardTableModRefBS::card_shift, @@ -520,12 +522,6 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); satb_qs.set_buffer_size(G1SATBBufferSize); - int size = (int) MAX2(ParallelGCThreads, (size_t)1); - _par_cleanup_thread_state = NEW_C_HEAP_ARRAY(ParCleanupThreadState*, size); - for (int i = 0 ; i < size; i++) { - _par_cleanup_thread_state[i] = new ParCleanupThreadState; - } - _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_task_num); _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_task_num); @@ -710,11 +706,6 @@ void ConcurrentMark::set_non_marking_state() { } ConcurrentMark::~ConcurrentMark() { - int size = (int) MAX2(ParallelGCThreads, (size_t)1); - for (int i = 0; i < size; i++) delete _par_cleanup_thread_state[i]; - FREE_C_HEAP_ARRAY(ParCleanupThreadState*, - _par_cleanup_thread_state); - for (int i = 0; i < (int) _max_task_num; ++i) { delete _task_queues->queue(i); delete _tasks[i]; @@ -1142,6 +1133,8 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { return; } + SvcGCMarker sgcm(SvcGCMarker::OTHER); + if (VerifyDuringGC) { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(before)"); @@ -1168,12 +1161,12 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (G1TraceMarkStackOverflow) gclog_or_tty->print_cr("\nRemark led to restart for overflow."); } else { + SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); // We're done with marking. // This is the end of the marking cycle, we're expected all // threads to have SATB queues with active set to true. - JavaThread::satb_mark_queue_set().set_active_all_threads( - false, /* new active value */ - true /* expected_active */); + satb_mq_set.set_active_all_threads(false, /* new active value */ + true /* expected_active */); if (VerifyDuringGC) { HandleMark hm; // handle scope @@ -1507,21 +1500,20 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { size_t _max_live_bytes; size_t _regions_claimed; size_t _freed_bytes; - size_t _cleared_h_regions; - size_t _freed_regions; - UncleanRegionList* _unclean_region_list; + FreeRegionList _local_cleanup_list; + HumongousRegionSet _humongous_proxy_set; double _claimed_region_time; double _max_region_time; public: G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1, - UncleanRegionList* list, int worker_num); size_t freed_bytes() { return _freed_bytes; } - size_t cleared_h_regions() { return _cleared_h_regions; } - size_t freed_regions() { return _freed_regions; } - UncleanRegionList* unclean_region_list() { - return _unclean_region_list; + FreeRegionList* local_cleanup_list() { + return &_local_cleanup_list; + } + HumongousRegionSet* humongous_proxy_set() { + return &_humongous_proxy_set; } bool doHeapRegion(HeapRegion *r); @@ -1534,25 +1526,22 @@ public: class G1ParNoteEndTask: public AbstractGangTask { friend class G1NoteEndOfConcMarkClosure; + protected: G1CollectedHeap* _g1h; size_t _max_live_bytes; size_t _freed_bytes; - ConcurrentMark::ParCleanupThreadState** _par_cleanup_thread_state; + FreeRegionList* _cleanup_list; + public: G1ParNoteEndTask(G1CollectedHeap* g1h, - ConcurrentMark::ParCleanupThreadState** - par_cleanup_thread_state) : + FreeRegionList* cleanup_list) : AbstractGangTask("G1 note end"), _g1h(g1h), - _max_live_bytes(0), _freed_bytes(0), - _par_cleanup_thread_state(par_cleanup_thread_state) - {} + _max_live_bytes(0), _freed_bytes(0), _cleanup_list(cleanup_list) { } void work(int i) { double start = os::elapsedTime(); - G1NoteEndOfConcMarkClosure g1_note_end(_g1h, - &_par_cleanup_thread_state[i]->list, - i); + G1NoteEndOfConcMarkClosure g1_note_end(_g1h, i); if (G1CollectedHeap::use_parallel_gc_threads()) { _g1h->heap_region_par_iterate_chunked(&g1_note_end, i, HeapRegion::NoteEndClaimValue); @@ -1561,14 +1550,18 @@ public: } assert(g1_note_end.complete(), "Shouldn't have yielded!"); - // Now finish up freeing the current thread's regions. - _g1h->finish_free_region_work(g1_note_end.freed_bytes(), - g1_note_end.cleared_h_regions(), - 0, NULL); + // Now update the lists + _g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(), + NULL /* free_list */, + g1_note_end.humongous_proxy_set(), + true /* par */); { MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); _max_live_bytes += g1_note_end.max_live_bytes(); _freed_bytes += g1_note_end.freed_bytes(); + + _cleanup_list->add_as_tail(g1_note_end.local_cleanup_list()); + assert(g1_note_end.local_cleanup_list()->is_empty(), "post-condition"); } double end = os::elapsedTime(); if (G1PrintParCleanupStats) { @@ -1609,30 +1602,28 @@ public: G1NoteEndOfConcMarkClosure:: G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1, - UncleanRegionList* list, int worker_num) : _g1(g1), _worker_num(worker_num), _max_live_bytes(0), _regions_claimed(0), - _freed_bytes(0), _cleared_h_regions(0), _freed_regions(0), + _freed_bytes(0), _claimed_region_time(0.0), _max_region_time(0.0), - _unclean_region_list(list) -{} + _local_cleanup_list("Local Cleanup List"), + _humongous_proxy_set("Local Cleanup Humongous Proxy Set") { } -bool G1NoteEndOfConcMarkClosure::doHeapRegion(HeapRegion *r) { +bool G1NoteEndOfConcMarkClosure::doHeapRegion(HeapRegion *hr) { // We use a claim value of zero here because all regions // were claimed with value 1 in the FinalCount task. - r->reset_gc_time_stamp(); - if (!r->continuesHumongous()) { + hr->reset_gc_time_stamp(); + if (!hr->continuesHumongous()) { double start = os::elapsedTime(); _regions_claimed++; - r->note_end_of_marking(); - _max_live_bytes += r->max_live_bytes(); - _g1->free_region_if_totally_empty_work(r, - _freed_bytes, - _cleared_h_regions, - _freed_regions, - _unclean_region_list, - true /*par*/); + hr->note_end_of_marking(); + _max_live_bytes += hr->max_live_bytes(); + _g1->free_region_if_totally_empty(hr, + &_freed_bytes, + &_local_cleanup_list, + &_humongous_proxy_set, + true /* par */); double region_time = (os::elapsedTime() - start); _claimed_region_time += region_time; if (region_time > _max_region_time) _max_region_time = region_time; @@ -1652,6 +1643,8 @@ void ConcurrentMark::cleanup() { return; } + g1h->verify_region_sets_optional(); + if (VerifyDuringGC) { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(before)"); @@ -1716,7 +1709,7 @@ void ConcurrentMark::cleanup() { // Note end of marking in all heap regions. double note_end_start = os::elapsedTime(); - G1ParNoteEndTask g1_par_note_end_task(g1h, _par_cleanup_thread_state); + G1ParNoteEndTask g1_par_note_end_task(g1h, &_cleanup_list); if (G1CollectedHeap::use_parallel_gc_threads()) { int n_workers = g1h->workers()->total_workers(); g1h->set_par_threads(n_workers); @@ -1728,9 +1721,14 @@ void ConcurrentMark::cleanup() { } else { g1_par_note_end_task.work(0); } - g1h->set_unclean_regions_coming(true); + + if (!cleanup_list_is_empty()) { + // The cleanup list is not empty, so we'll have to process it + // concurrently. Notify anyone else that might be wanting free + // regions that there will be more free regions coming soon. + g1h->set_free_regions_coming(); + } double note_end_end = os::elapsedTime(); - // Tell the mutators that there might be unclean regions coming... if (G1PrintParCleanupStats) { gclog_or_tty->print_cr(" note end of marking: %8.3f ms.", (note_end_end - note_end_start)*1000.0); @@ -1796,33 +1794,63 @@ void ConcurrentMark::cleanup() { /* silent */ false, /* prev marking */ true); } + + g1h->verify_region_sets_optional(); } void ConcurrentMark::completeCleanup() { - // A full collection intervened. if (has_aborted()) return; - int first = 0; - int last = (int)MAX2(ParallelGCThreads, (size_t)1); - for (int t = 0; t < last; t++) { - UncleanRegionList* list = &_par_cleanup_thread_state[t]->list; - assert(list->well_formed(), "Inv"); - HeapRegion* hd = list->hd(); - while (hd != NULL) { - // Now finish up the other stuff. - hd->rem_set()->clear(); - HeapRegion* next_hd = hd->next_from_unclean_list(); - (void)list->pop(); - assert(list->hd() == next_hd, "how not?"); - _g1h->put_region_on_unclean_list(hd); - if (!hd->isHumongous()) { - // Add this to the _free_regions count by 1. - _g1h->finish_free_region_work(0, 0, 1, NULL); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + _cleanup_list.verify_optional(); + FreeRegionList local_free_list("Local Cleanup List"); + + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " + "cleanup list has "SIZE_FORMAT" entries", + _cleanup_list.length()); + } + + // Noone else should be accessing the _cleanup_list at this point, + // so it's not necessary to take any locks + while (!_cleanup_list.is_empty()) { + HeapRegion* hr = _cleanup_list.remove_head(); + assert(hr != NULL, "the list was not empty"); + hr->rem_set()->clear(); + local_free_list.add_as_tail(hr); + + // Instead of adding one region at a time to the secondary_free_list, + // we accumulate them in the local list and move them a few at a + // time. This also cuts down on the number of notify_all() calls + // we do during this process. We'll also append the local list when + // _cleanup_list is empty (which means we just removed the last + // region from the _cleanup_list). + if ((local_free_list.length() % G1SecondaryFreeListAppendLength == 0) || + _cleanup_list.is_empty()) { + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " + "appending "SIZE_FORMAT" entries to the " + "secondary_free_list, clean list still has " + SIZE_FORMAT" entries", + local_free_list.length(), + _cleanup_list.length()); + } + + { + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + g1h->secondary_free_list_add_as_tail(&local_free_list); + SecondaryFreeList_lock->notify_all(); + } + + if (G1StressConcRegionFreeing) { + for (uintx i = 0; i < G1StressConcRegionFreeingDelayMillis; ++i) { + os::sleep(Thread::current(), (jlong) 1, false); + } } - hd = list->hd(); - assert(hd == next_hd, "how not?"); } } + assert(local_free_list.is_empty(), "post-condition"); } bool G1CMIsAliveClosure::do_object_b(oop obj) { @@ -2894,9 +2922,9 @@ public: virtual void do_oop( oop* p) { do_oop_work(p); } template void do_oop_work(T* p) { - assert(_g1h->is_in_g1_reserved((HeapWord*) p), "invariant"); - assert(!_g1h->heap_region_containing((HeapWord*) p)->is_on_free_list(), - "invariant"); + assert( _g1h->is_in_g1_reserved((HeapWord*) p), "invariant"); + assert(!_g1h->is_on_free_list( + _g1h->heap_region_containing((HeapWord*) p)), "invariant"); oop obj = oopDesc::load_decode_heap_oop(p); if (_cm->verbose_high()) @@ -3116,8 +3144,8 @@ void CMTask::deal_with_reference(oop obj) { void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); - assert(!_g1h->heap_region_containing(objAddr)->is_on_free_list(), - "invariant"); + assert(!_g1h->is_on_free_list( + _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant"); assert(!_g1h->is_obj_ill(obj), "invariant"); assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); @@ -3362,8 +3390,8 @@ void CMTask::drain_local_queue(bool partially) { (void*) obj); assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" ); - assert(!_g1h->heap_region_containing(obj)->is_on_free_list(), - "invariant"); + assert(!_g1h->is_on_free_list( + _g1h->heap_region_containing((HeapWord*) obj)), "invariant"); scan_object(obj); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index f02d6f049fa..9aa961bae4e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP -#include "gc_implementation/g1/heapRegion.hpp" +#include "gc_implementation/g1/heapRegionSets.hpp" #include "utilities/taskqueue.hpp" class G1CollectedHeap; @@ -369,13 +369,7 @@ protected: double _cleanup_sleep_factor; double _cleanup_task_overhead; - // Stuff related to age cohort processing. - struct ParCleanupThreadState { - char _pre[64]; - UncleanRegionList list; - char _post[64]; - }; - ParCleanupThreadState** _par_cleanup_thread_state; + FreeRegionList _cleanup_list; // CMS marking support structures CMBitMap _markBitMap1; @@ -484,6 +478,10 @@ protected: // prints all gathered CM-related statistics void print_stats(); + bool cleanup_list_is_empty() { + return _cleanup_list.is_empty(); + } + // accessor methods size_t parallel_marking_threads() { return _parallel_marking_threads; } double sleep_factor() { return _sleep_factor; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index 6eedf71a267..8186e61ce04 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,8 +95,8 @@ void ConcurrentMarkThread::run() { _vtime_start = os::elapsedVTime(); wait_for_universe_init(); - G1CollectedHeap* g1 = G1CollectedHeap::heap(); - G1CollectorPolicy* g1_policy = g1->g1_policy(); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1CollectorPolicy* g1_policy = g1h->g1_policy(); G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker(); Thread *current_thread = Thread::current(); @@ -119,7 +119,7 @@ void ConcurrentMarkThread::run() { if (!g1_policy->in_young_gc_mode()) { // this ensures the flag is not set if we bail out of the marking // cycle; normally the flag is cleared immediately after cleanup - g1->set_marking_complete(); + g1h->set_marking_complete(); if (g1_policy->adaptive_young_list_length()) { double now = os::elapsedTime(); @@ -228,10 +228,20 @@ void ConcurrentMarkThread::run() { VM_CGC_Operation op(&cl_cl, verbose_str); VMThread::execute(&op); } else { - G1CollectedHeap::heap()->set_marking_complete(); + g1h->set_marking_complete(); } - if (!cm()->has_aborted()) { + // Check if cleanup set the free_regions_coming flag. If it + // hasn't, we can just skip the next step. + if (g1h->free_regions_coming()) { + // The following will finish freeing up any regions that we + // found to be empty during cleanup. We'll do this part + // without joining the suspendible set. If an evacuation pause + // takes places, then we would carry on freeing regions in + // case they are needed by the pause. If a Full GC takes + // places, it would wait for us to process the regions + // reclaimed by cleanup. + double cleanup_start_sec = os::elapsedTime(); if (PrintGC) { gclog_or_tty->date_stamp(PrintGCDateStamps); @@ -240,23 +250,22 @@ void ConcurrentMarkThread::run() { } // Now do the remainder of the cleanup operation. - _sts.join(); _cm->completeCleanup(); - if (!cm()->has_aborted()) { - g1_policy->record_concurrent_mark_cleanup_completed(); + g1_policy->record_concurrent_mark_cleanup_completed(); - double cleanup_end_sec = os::elapsedTime(); - if (PrintGC) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]", - cleanup_end_sec - cleanup_start_sec); - } + double cleanup_end_sec = os::elapsedTime(); + if (PrintGC) { + gclog_or_tty->date_stamp(PrintGCDateStamps); + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]", + cleanup_end_sec - cleanup_start_sec); } - _sts.leave(); + + // We're done: no more free regions coming. + g1h->reset_free_regions_coming(); } - // We're done: no more unclean regions coming. - G1CollectedHeap::heap()->set_unclean_regions_coming(false); + guarantee(cm()->cleanup_list_is_empty(), + "at this point there should be no regions on the cleanup list"); if (cm()->has_aborted()) { if (PrintGC) { @@ -278,7 +287,7 @@ void ConcurrentMarkThread::run() { // Java thread is waiting for a full GC to happen (e.g., it // called System.gc() with +ExplicitGCInvokesConcurrent). _sts.join(); - g1->increment_full_collections_completed(true /* concurrent */); + g1h->increment_full_collections_completed(true /* concurrent */); _sts.leave(); } assert(_should_terminate, "just checking"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.cpp deleted file mode 100644 index 425d67fcd56..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc_implementation/g1/concurrentZFThread.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/heapRegion.hpp" -#include "memory/space.inline.hpp" -#include "runtime/mutexLocker.hpp" -#include "utilities/copy.hpp" - -// ======= Concurrent Zero-Fill Thread ======== - -// The CM thread is created when the G1 garbage collector is used - -int ConcurrentZFThread::_region_allocs = 0; -int ConcurrentZFThread::_sync_zfs = 0; -int ConcurrentZFThread::_zf_waits = 0; -int ConcurrentZFThread::_regions_filled = 0; - -ConcurrentZFThread::ConcurrentZFThread() : - ConcurrentGCThread() -{ - create_and_start(); -} - -void ConcurrentZFThread::wait_for_ZF_completed(HeapRegion* hr) { - assert(ZF_mon->owned_by_self(), "Precondition."); - note_zf_wait(); - while (hr->zero_fill_state() == HeapRegion::ZeroFilling) { - ZF_mon->wait(Mutex::_no_safepoint_check_flag); - } -} - -void ConcurrentZFThread::processHeapRegion(HeapRegion* hr) { - assert(!Universe::heap()->is_gc_active(), - "This should not happen during GC."); - assert(hr != NULL, "Precondition"); - // These are unlocked reads, but if this test is successful, then no - // other thread will attempt this zero filling. Only a GC thread can - // modify the ZF state of a region whose state is zero-filling, and this - // should only happen while the ZF thread is locking out GC. - if (hr->zero_fill_state() == HeapRegion::ZeroFilling - && hr->zero_filler() == Thread::current()) { - assert(hr->top() == hr->bottom(), "better be empty!"); - assert(!hr->isHumongous(), "Only free regions on unclean list."); - Copy::fill_to_words(hr->bottom(), hr->capacity()/HeapWordSize); - note_region_filled(); - } -} - -void ConcurrentZFThread::run() { - initialize_in_thread(); - Thread* thr_self = Thread::current(); - _vtime_start = os::elapsedVTime(); - wait_for_universe_init(); - - G1CollectedHeap* g1 = G1CollectedHeap::heap(); - _sts.join(); - while (!_should_terminate) { - _sts.leave(); - - { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - - // This local variable will hold a region being zero-filled. This - // region will neither be on the unclean or zero-filled lists, and - // will not be available for allocation; thus, we might have an - // allocation fail, causing a full GC, because of this, but this is a - // price we will pay. (In future, we might want to make the fact - // that there's a region being zero-filled apparent to the G1 heap, - // which could then wait for it in this extreme case...) - HeapRegion* to_fill; - - while (!g1->should_zf() - || (to_fill = g1->pop_unclean_region_list_locked()) == NULL) - ZF_mon->wait(Mutex::_no_safepoint_check_flag); - while (to_fill->zero_fill_state() == HeapRegion::ZeroFilling) - ZF_mon->wait(Mutex::_no_safepoint_check_flag); - - // So now to_fill is non-NULL and is not ZeroFilling. It might be - // Allocated or ZeroFilled. (The latter could happen if this thread - // starts the zero-filling of a region, but a GC intervenes and - // pushes new regions needing on the front of the filling on the - // front of the list.) - - switch (to_fill->zero_fill_state()) { - case HeapRegion::Allocated: - to_fill = NULL; - break; - - case HeapRegion::NotZeroFilled: - to_fill->set_zero_fill_in_progress(thr_self); - - ZF_mon->unlock(); - _sts.join(); - processHeapRegion(to_fill); - _sts.leave(); - ZF_mon->lock_without_safepoint_check(); - - if (to_fill->zero_fill_state() == HeapRegion::ZeroFilling - && to_fill->zero_filler() == thr_self) { - to_fill->set_zero_fill_complete(); - (void)g1->put_free_region_on_list_locked(to_fill); - } - break; - - case HeapRegion::ZeroFilled: - (void)g1->put_free_region_on_list_locked(to_fill); - break; - - case HeapRegion::ZeroFilling: - ShouldNotReachHere(); - break; - } - } - _vtime_accum = (os::elapsedVTime() - _vtime_start); - _sts.join(); - } - _sts.leave(); - - assert(_should_terminate, "just checking"); - terminate(); -} - -bool ConcurrentZFThread::offer_yield() { - if (_sts.should_yield()) { - _sts.yield("Concurrent ZF"); - return true; - } else { - return false; - } -} - -void ConcurrentZFThread::stop() { - // it is ok to take late safepoints here, if needed - MutexLockerEx mu(Terminator_lock); - _should_terminate = true; - while (!_has_terminated) { - Terminator_lock->wait(); - } -} - -void ConcurrentZFThread::print() const { - print_on(tty); -} - -void ConcurrentZFThread::print_on(outputStream* st) const { - st->print("\"G1 Concurrent Zero-Fill Thread\" "); - Thread::print_on(st); - st->cr(); -} - - -double ConcurrentZFThread::_vtime_accum; - -void ConcurrentZFThread::print_summary_info() { - gclog_or_tty->print("\nConcurrent Zero-Filling:\n"); - gclog_or_tty->print(" Filled %d regions, used %5.2fs.\n", - _regions_filled, - vtime_accum()); - gclog_or_tty->print(" Of %d region allocs, %d (%5.2f%%) required sync ZF,\n", - _region_allocs, _sync_zfs, - (_region_allocs > 0 ? - (float)_sync_zfs/(float)_region_allocs*100.0 : - 0.0)); - gclog_or_tty->print(" and %d (%5.2f%%) required a ZF wait.\n", - _zf_waits, - (_region_allocs > 0 ? - (float)_zf_waits/(float)_region_allocs*100.0 : - 0.0)); - -} diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.hpp deleted file mode 100644 index 34731c96242..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentZFThread.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTZFTHREAD_HPP -#define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTZFTHREAD_HPP - -#include "gc_implementation/shared/concurrentGCThread.hpp" - -// The Concurrent ZF Thread. Performs concurrent zero-filling. - -class ConcurrentZFThread: public ConcurrentGCThread { - friend class VMStructs; - friend class ZeroFillRegionClosure; - - private: - - // Zero fill the heap region. - void processHeapRegion(HeapRegion* r); - - // Stats - // Allocation (protected by heap lock). - static int _region_allocs; // Number of regions allocated - static int _sync_zfs; // Synchronous zero-fills + - static int _zf_waits; // Wait for conc zero-fill completion. - - // Number of regions CFZ thread fills. - static int _regions_filled; - - double _vtime_start; // Initial virtual time. - - // These are static because the "print_summary_info" method is, and - // it currently assumes there is only one ZF thread. We'll change when - // we need to. - static double _vtime_accum; // Initial virtual time. - static double vtime_accum() { return _vtime_accum; } - - // Offer yield for GC. Returns true if yield occurred. - bool offer_yield(); - - public: - // Constructor - ConcurrentZFThread(); - - // Main loop. - virtual void run(); - - // Printing - void print_on(outputStream* st) const; - void print() const; - - // Waits until "r" has been zero-filled. Requires caller to hold the - // ZF_mon. - static void wait_for_ZF_completed(HeapRegion* r); - - // Get or clear the current unclean region. Should be done - // while holding the ZF_needed_mon lock. - - // shutdown - void stop(); - - // Stats - static void note_region_alloc() {_region_allocs++; } - static void note_sync_zfs() { _sync_zfs++; } - static void note_zf_wait() { _zf_waits++; } - static void note_region_filled() { _regions_filled++; } - - static void print_summary_info(); -}; - -#endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTZFTHREAD_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp index 270e1fa3d62..d16685a7ebc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,7 +222,7 @@ void G1BlockOffsetArray::split_block(HeapWord* blk, size_t blk_size, // Action_mark - update the BOT for the block [blk_start, blk_end). // Current typical use is for splitting a block. -// Action_single - udpate the BOT for an allocation. +// Action_single - update the BOT for an allocation. // Action_verify - BOT verification. void G1BlockOffsetArray::do_block_internal(HeapWord* blk_start, HeapWord* blk_end, @@ -331,47 +331,6 @@ G1BlockOffsetArray::mark_block(HeapWord* blk_start, HeapWord* blk_end) { do_block_internal(blk_start, blk_end, Action_mark); } -void G1BlockOffsetArray::join_blocks(HeapWord* blk1, HeapWord* blk2) { - HeapWord* blk1_start = Universe::heap()->block_start(blk1); - HeapWord* blk2_start = Universe::heap()->block_start(blk2); - assert(blk1 == blk1_start && blk2 == blk2_start, - "Must be block starts."); - assert(blk1 + _sp->block_size(blk1) == blk2, "Must be contiguous."); - size_t blk1_start_index = _array->index_for(blk1); - size_t blk2_start_index = _array->index_for(blk2); - assert(blk1_start_index <= blk2_start_index, "sanity"); - HeapWord* blk2_card_start = _array->address_for_index(blk2_start_index); - if (blk2 == blk2_card_start) { - // blk2 starts a card. Does blk1 start on the prevous card, or futher - // back? - assert(blk1_start_index < blk2_start_index, "must be lower card."); - if (blk1_start_index + 1 == blk2_start_index) { - // previous card; new value for blk2 card is size of blk1. - _array->set_offset_array(blk2_start_index, (u_char) _sp->block_size(blk1)); - } else { - // Earlier card; go back a card. - _array->set_offset_array(blk2_start_index, N_words); - } - } else { - // blk2 does not start a card. Does it cross a card? If not, nothing - // to do. - size_t blk2_end_index = - _array->index_for(blk2 + _sp->block_size(blk2) - 1); - assert(blk2_end_index >= blk2_start_index, "sanity"); - if (blk2_end_index > blk2_start_index) { - // Yes, it crosses a card. The value for the next card must change. - if (blk1_start_index + 1 == blk2_start_index) { - // previous card; new value for second blk2 card is size of blk1. - _array->set_offset_array(blk2_start_index + 1, - (u_char) _sp->block_size(blk1)); - } else { - // Earlier card; go back a card. - _array->set_offset_array(blk2_start_index + 1, N_words); - } - } - } -} - HeapWord* G1BlockOffsetArray::block_start_unsafe(const void* addr) { assert(_bottom <= addr && addr < _end, "addr must be covered by this Array"); @@ -580,16 +539,51 @@ void G1BlockOffsetArray::alloc_block_work2(HeapWord** threshold_, size_t* index_ #endif } -void -G1BlockOffsetArray::set_for_starts_humongous(HeapWord* new_end) { - assert(_end == new_end, "_end should have already been updated"); - - // The first BOT entry should have offset 0. - _array->set_offset_array(_array->index_for(_bottom), 0); - // The rest should point to the first one. - set_remainder_to_point_to_start(_bottom + N_words, new_end); +bool +G1BlockOffsetArray::verify_for_object(HeapWord* obj_start, + size_t word_size) const { + size_t first_card = _array->index_for(obj_start); + size_t last_card = _array->index_for(obj_start + word_size - 1); + if (!_array->is_card_boundary(obj_start)) { + // If the object is not on a card boundary the BOT entry of the + // first card should point to another object so we should not + // check that one. + first_card += 1; + } + for (size_t card = first_card; card <= last_card; card += 1) { + HeapWord* card_addr = _array->address_for_index(card); + HeapWord* block_start = block_start_const(card_addr); + if (block_start != obj_start) { + gclog_or_tty->print_cr("block start: "PTR_FORMAT" is incorrect - " + "card index: "SIZE_FORMAT" " + "card addr: "PTR_FORMAT" BOT entry: %u " + "obj: "PTR_FORMAT" word size: "SIZE_FORMAT" " + "cards: ["SIZE_FORMAT","SIZE_FORMAT"]", + block_start, card, card_addr, + _array->offset_array(card), + obj_start, word_size, first_card, last_card); + return false; + } + } + return true; } +#ifndef PRODUCT +void +G1BlockOffsetArray::print_on(outputStream* out) { + size_t from_index = _array->index_for(_bottom); + size_t to_index = _array->index_for(_end); + out->print_cr(">> BOT for area ["PTR_FORMAT","PTR_FORMAT") " + "cards ["SIZE_FORMAT","SIZE_FORMAT")", + _bottom, _end, from_index, to_index); + for (size_t i = from_index; i < to_index; ++i) { + out->print_cr(" entry "SIZE_FORMAT_W(8)" | "PTR_FORMAT" : %3u", + i, _array->address_for_index(i), + (uint) _array->offset_array(i)); + } +} +#endif // !PRODUCT + ////////////////////////////////////////////////////////////////////// // G1BlockOffsetArrayContigSpace ////////////////////////////////////////////////////////////////////// @@ -641,10 +635,20 @@ void G1BlockOffsetArrayContigSpace::zero_bottom_entry() { } void -G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_end) { - G1BlockOffsetArray::set_for_starts_humongous(new_end); +G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) { + assert(new_top <= _end, "_end should have already been updated"); - // Make sure _next_offset_threshold and _next_offset_index point to new_end. - _next_offset_threshold = new_end; - _next_offset_index = _array->index_for(new_end); + // The first BOT entry should have offset 0. + zero_bottom_entry(); + initialize_threshold(); + alloc_block(_bottom, new_top); + } + +#ifndef PRODUCT +void +G1BlockOffsetArrayContigSpace::print_on(outputStream* out) { + G1BlockOffsetArray::print_on(out); + out->print_cr(" next offset threshold: "PTR_FORMAT, _next_offset_threshold); + out->print_cr(" next offset index: "SIZE_FORMAT, _next_offset_index); } +#endif // !PRODUCT diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp index 82568dddd8c..b6a42c73eba 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -352,11 +352,6 @@ public: // The following methods are useful and optimized for a // general, non-contiguous space. - // The given arguments are required to be the starts of adjacent ("blk1" - // before "blk2") well-formed blocks covered by "this". After this call, - // they should be considered to form one block. - virtual void join_blocks(HeapWord* blk1, HeapWord* blk2); - // Given a block [blk_start, blk_start + full_blk_size), and // a left_blk_size < full_blk_size, adjust the BOT to show two // blocks [blk_start, blk_start + left_blk_size) and @@ -429,6 +424,12 @@ public: verify_single_block(blk, blk + size); } + // Used by region verification. Checks that the contents of the + // BOT reflect that there's a single object that spans the address + // range [obj_start, obj_start + word_size); returns true if this is + // the case, returns false if it's not. + bool verify_for_object(HeapWord* obj_start, size_t word_size) const; + // Verify that the given block is before _unallocated_block inline void verify_not_unallocated(HeapWord* blk_start, HeapWord* blk_end) const { @@ -444,7 +445,7 @@ public: void check_all_cards(size_t left_card, size_t right_card) const; - virtual void set_for_starts_humongous(HeapWord* new_end); + virtual void print_on(outputStream* out) PRODUCT_RETURN; }; // A subtype of BlockOffsetArray that takes advantage of the fact @@ -494,7 +495,9 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray { HeapWord* block_start_unsafe(const void* addr); HeapWord* block_start_unsafe_const(const void* addr) const; - virtual void set_for_starts_humongous(HeapWord* new_end); + void set_for_starts_humongous(HeapWord* new_top); + + virtual void print_on(outputStream* out) PRODUCT_RETURN; }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 030aecade77..db86135530b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "gc_implementation/g1/concurrentG1Refine.hpp" #include "gc_implementation/g1/concurrentG1RefineThread.hpp" #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" -#include "gc_implementation/g1/concurrentZFThread.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" @@ -425,11 +424,9 @@ HeapRegion* G1CollectedHeap::pop_dirty_cards_region() void G1CollectedHeap::stop_conc_gc_threads() { _cg1r->stop(); - _czft->stop(); _cmThread->stop(); } - void G1CollectedHeap::check_ct_logs_at_safepoint() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); @@ -481,49 +478,92 @@ G1CollectedHeap* G1CollectedHeap::_g1h; // Private methods. -// Finds a HeapRegion that can be used to allocate a given size of block. +HeapRegion* +G1CollectedHeap::new_region_try_secondary_free_list(size_t word_size) { + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + while (!_secondary_free_list.is_empty() || free_regions_coming()) { + if (!_secondary_free_list.is_empty()) { + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " + "secondary_free_list has "SIZE_FORMAT" entries", + _secondary_free_list.length()); + } + // It looks as if there are free regions available on the + // secondary_free_list. Let's move them to the free_list and try + // again to allocate from it. + append_secondary_free_list(); + assert(!_free_list.is_empty(), "if the secondary_free_list was not " + "empty we should have moved at least one entry to the free_list"); + HeapRegion* res = _free_list.remove_head(); + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " + "allocated "HR_FORMAT" from secondary_free_list", + HR_FORMAT_PARAMS(res)); + } + return res; + } -HeapRegion* G1CollectedHeap::newAllocRegion_work(size_t word_size, - bool do_expand, - bool zero_filled) { - ConcurrentZFThread::note_region_alloc(); - HeapRegion* res = alloc_free_region_from_lists(zero_filled); + // Wait here until we get notifed either when (a) there are no + // more free regions coming or (b) some regions have been moved on + // the secondary_free_list. + SecondaryFreeList_lock->wait(Mutex::_no_safepoint_check_flag); + } + + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " + "could not allocate from secondary_free_list"); + } + return NULL; +} + +HeapRegion* G1CollectedHeap::new_region_work(size_t word_size, + bool do_expand) { + assert(!isHumongous(word_size) || + word_size <= (size_t) HeapRegion::GrainWords, + "the only time we use this to allocate a humongous region is " + "when we are allocating a single humongous region"); + + HeapRegion* res; + if (G1StressConcRegionFreeing) { + if (!_secondary_free_list.is_empty()) { + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " + "forced to look at the secondary_free_list"); + } + res = new_region_try_secondary_free_list(word_size); + if (res != NULL) { + return res; + } + } + } + res = _free_list.remove_head_or_null(); + if (res == NULL) { + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " + "res == NULL, trying the secondary_free_list"); + } + res = new_region_try_secondary_free_list(word_size); + } if (res == NULL && do_expand) { expand(word_size * HeapWordSize); - res = alloc_free_region_from_lists(zero_filled); - assert(res == NULL || - (!res->isHumongous() && - (!zero_filled || - res->zero_fill_state() == HeapRegion::Allocated)), - "Alloc Regions must be zero filled (and non-H)"); + res = _free_list.remove_head_or_null(); } if (res != NULL) { - if (res->is_empty()) { - _free_regions--; - } - assert(!res->isHumongous() && - (!zero_filled || res->zero_fill_state() == HeapRegion::Allocated), - err_msg("Non-young alloc Regions must be zero filled (and non-H):" - " res->isHumongous()=%d, zero_filled=%d, res->zero_fill_state()=%d", - res->isHumongous(), zero_filled, res->zero_fill_state())); - assert(!res->is_on_unclean_list(), - "Alloc Regions must not be on the unclean list"); if (G1PrintHeapRegions) { - gclog_or_tty->print_cr("new alloc region %d:["PTR_FORMAT", "PTR_FORMAT"], " - "top "PTR_FORMAT, - res->hrs_index(), res->bottom(), res->end(), res->top()); + gclog_or_tty->print_cr("new alloc region %d:["PTR_FORMAT","PTR_FORMAT"], " + "top "PTR_FORMAT, res->hrs_index(), + res->bottom(), res->end(), res->top()); } } return res; } -HeapRegion* G1CollectedHeap::newAllocRegionWithExpansion(int purpose, - size_t word_size, - bool zero_filled) { +HeapRegion* G1CollectedHeap::new_gc_alloc_region(int purpose, + size_t word_size) { HeapRegion* alloc_region = NULL; if (_gc_alloc_region_counts[purpose] < g1_policy()->max_regions(purpose)) { - alloc_region = newAllocRegion_work(word_size, true, zero_filled); + alloc_region = new_region_work(word_size, true /* do_expand */); if (purpose == GCAllocForSurvived && alloc_region != NULL) { alloc_region->set_survivor(); } @@ -534,81 +574,220 @@ HeapRegion* G1CollectedHeap::newAllocRegionWithExpansion(int purpose, return alloc_region; } +int G1CollectedHeap::humongous_obj_allocate_find_first(size_t num_regions, + size_t word_size) { + int first = -1; + if (num_regions == 1) { + // Only one region to allocate, no need to go through the slower + // path. The caller will attempt the expasion if this fails, so + // let's not try to expand here too. + HeapRegion* hr = new_region_work(word_size, false /* do_expand */); + if (hr != NULL) { + first = hr->hrs_index(); + } else { + first = -1; + } + } else { + // We can't allocate humongous regions while cleanupComplete() is + // running, since some of the regions we find to be empty might not + // yet be added to the free list and it is not straightforward to + // know which list they are on so that we can remove them. Note + // that we only need to do this if we need to allocate more than + // one region to satisfy the current humongous allocation + // request. If we are only allocating one region we use the common + // region allocation code (see above). + wait_while_free_regions_coming(); + append_secondary_free_list_if_not_empty(); + + if (free_regions() >= num_regions) { + first = _hrs->find_contiguous(num_regions); + if (first != -1) { + for (int i = first; i < first + (int) num_regions; ++i) { + HeapRegion* hr = _hrs->at(i); + assert(hr->is_empty(), "sanity"); + assert(is_on_free_list(hr), "sanity"); + hr->set_pending_removal(true); + } + _free_list.remove_all_pending(num_regions); + } + } + } + return first; +} + // If could fit into free regions w/o expansion, try. // Otherwise, if can expand, do so. // Otherwise, if using ex regions might help, try with ex given back. HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { - assert_heap_locked_or_at_safepoint(); - assert(regions_accounted_for(), "Region leakage!"); + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); - // We can't allocate humongous regions while cleanupComplete is - // running, since some of the regions we find to be empty might not - // yet be added to the unclean list. If we're already at a - // safepoint, this call is unnecessary, not to mention wrong. - if (!SafepointSynchronize::is_at_safepoint()) { - wait_for_cleanup_complete(); - } + verify_region_sets_optional(); size_t num_regions = round_to(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords; - - // Special case if < one region??? - - // Remember the ft size. size_t x_size = expansion_regions(); - - HeapWord* res = NULL; - bool eliminated_allocated_from_lists = false; - - // Can the allocation potentially fit in the free regions? - if (free_regions() >= num_regions) { - res = _hrs->obj_allocate(word_size); - } - if (res == NULL) { - // Try expansion. - size_t fs = _hrs->free_suffix(); + size_t fs = _hrs->free_suffix(); + int first = humongous_obj_allocate_find_first(num_regions, word_size); + if (first == -1) { + // The only thing we can do now is attempt expansion. if (fs + x_size >= num_regions) { expand((num_regions - fs) * HeapRegion::GrainBytes); - res = _hrs->obj_allocate(word_size); - assert(res != NULL, "This should have worked."); - } else { - // Expansion won't help. Are there enough free regions if we get rid - // of reservations? - size_t avail = free_regions(); - if (avail >= num_regions) { - res = _hrs->obj_allocate(word_size); - if (res != NULL) { - remove_allocated_regions_from_lists(); - eliminated_allocated_from_lists = true; - } - } + first = humongous_obj_allocate_find_first(num_regions, word_size); + assert(first != -1, "this should have worked"); } } - if (res != NULL) { - // Increment by the number of regions allocated. - // FIXME: Assumes regions all of size GrainBytes. -#ifndef PRODUCT - mr_bs()->verify_clean_region(MemRegion(res, res + num_regions * - HeapRegion::GrainWords)); -#endif - if (!eliminated_allocated_from_lists) - remove_allocated_regions_from_lists(); - _summary_bytes_used += word_size * HeapWordSize; - _free_regions -= num_regions; - _num_humongous_regions += (int) num_regions; + + if (first != -1) { + // Index of last region in the series + 1. + int last = first + (int) num_regions; + + // We need to initialize the region(s) we just discovered. This is + // a bit tricky given that it can happen concurrently with + // refinement threads refining cards on these regions and + // potentially wanting to refine the BOT as they are scanning + // those cards (this can happen shortly after a cleanup; see CR + // 6991377). So we have to set up the region(s) carefully and in + // a specific order. + + // The word size sum of all the regions we will allocate. + size_t word_size_sum = num_regions * HeapRegion::GrainWords; + assert(word_size <= word_size_sum, "sanity"); + + // This will be the "starts humongous" region. + HeapRegion* first_hr = _hrs->at(first); + // The header of the new object will be placed at the bottom of + // the first region. + HeapWord* new_obj = first_hr->bottom(); + // This will be the new end of the first region in the series that + // should also match the end of the last region in the seriers. + HeapWord* new_end = new_obj + word_size_sum; + // This will be the new top of the first region that will reflect + // this allocation. + HeapWord* new_top = new_obj + word_size; + + // First, we need to zero the header of the space that we will be + // allocating. When we update top further down, some refinement + // threads might try to scan the region. By zeroing the header we + // ensure that any thread that will try to scan the region will + // come across the zero klass word and bail out. + // + // NOTE: It would not have been correct to have used + // CollectedHeap::fill_with_object() and make the space look like + // an int array. The thread that is doing the allocation will + // later update the object header to a potentially different array + // type and, for a very short period of time, the klass and length + // fields will be inconsistent. This could cause a refinement + // thread to calculate the object size incorrectly. + Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); + + // We will set up the first region as "starts humongous". This + // will also update the BOT covering all the regions to reflect + // that there is a single object that starts at the bottom of the + // first region. + first_hr->set_startsHumongous(new_top, new_end); + + // Then, if there are any, we will set up the "continues + // humongous" regions. + HeapRegion* hr = NULL; + for (int i = first + 1; i < last; ++i) { + hr = _hrs->at(i); + hr->set_continuesHumongous(first_hr); + } + // If we have "continues humongous" regions (hr != NULL), then the + // end of the last one should match new_end. + assert(hr == NULL || hr->end() == new_end, "sanity"); + + // Up to this point no concurrent thread would have been able to + // do any scanning on any region in this series. All the top + // fields still point to bottom, so the intersection between + // [bottom,top] and [card_start,card_end] will be empty. Before we + // update the top fields, we'll do a storestore to make sure that + // no thread sees the update to top before the zeroing of the + // object header and the BOT initialization. + OrderAccess::storestore(); + + // Now that the BOT and the object header have been initialized, + // we can update top of the "starts humongous" region. + assert(first_hr->bottom() < new_top && new_top <= first_hr->end(), + "new_top should be in this region"); + first_hr->set_top(new_top); + + // Now, we will update the top fields of the "continues humongous" + // regions. The reason we need to do this is that, otherwise, + // these regions would look empty and this will confuse parts of + // G1. For example, the code that looks for a consecutive number + // of empty regions will consider them empty and try to + // re-allocate them. We can extend is_empty() to also include + // !continuesHumongous(), but it is easier to just update the top + // fields here. The way we set top for all regions (i.e., top == + // end for all regions but the last one, top == new_top for the + // last one) is actually used when we will free up the humongous + // region in free_humongous_region(). + hr = NULL; + for (int i = first + 1; i < last; ++i) { + hr = _hrs->at(i); + if ((i + 1) == last) { + // last continues humongous region + assert(hr->bottom() < new_top && new_top <= hr->end(), + "new_top should fall on this region"); + hr->set_top(new_top); + } else { + // not last one + assert(new_top > hr->end(), "new_top should be above this region"); + hr->set_top(hr->end()); + } + } + // If we have continues humongous regions (hr != NULL), then the + // end of the last one should match new_end and its top should + // match new_top. + assert(hr == NULL || + (hr->end() == new_end && hr->top() == new_top), "sanity"); + + assert(first_hr->used() == word_size * HeapWordSize, "invariant"); + _summary_bytes_used += first_hr->used(); + _humongous_set.add(first_hr); + + return new_obj; } - assert(regions_accounted_for(), "Region Leakage"); - return res; + + verify_region_sets_optional(); + return NULL; } void G1CollectedHeap::retire_cur_alloc_region(HeapRegion* cur_alloc_region) { - // The cleanup operation might update _summary_bytes_used - // concurrently with this method. So, right now, if we don't wait - // for it to complete, updates to _summary_bytes_used might get - // lost. This will be resolved in the near future when the operation - // of the free region list is revamped as part of CR 6977804. - wait_for_cleanup_complete(); + // Other threads might still be trying to allocate using CASes out + // of the region we are retiring, as they can do so without holding + // the Heap_lock. So we first have to make sure that noone else can + // allocate in it by doing a maximal allocation. Even if our CAS + // attempt fails a few times, we'll succeed sooner or later given + // that a failed CAS attempt mean that the region is getting closed + // to being full (someone else succeeded in allocating into it). + size_t free_word_size = cur_alloc_region->free() / HeapWordSize; + + // This is the minimum free chunk we can turn into a dummy + // object. If the free space falls below this, then noone can + // allocate in this region anyway (all allocation requests will be + // of a size larger than this) so we won't have to perform the dummy + // allocation. + size_t min_word_size_to_fill = CollectedHeap::min_fill_size(); + + while (free_word_size >= min_word_size_to_fill) { + HeapWord* dummy = + cur_alloc_region->par_allocate_no_bot_updates(free_word_size); + if (dummy != NULL) { + // If the allocation was successful we should fill in the space. + CollectedHeap::fill_with_object(dummy, free_word_size); + break; + } + + free_word_size = cur_alloc_region->free() / HeapWordSize; + // It's also possible that someone else beats us to the + // allocation and they fill up the region. In that case, we can + // just get out of the loop + } + assert(cur_alloc_region->free() / HeapWordSize < min_word_size_to_fill, + "sanity"); retire_cur_alloc_region_common(cur_alloc_region); assert(_cur_alloc_region == NULL, "post-condition"); @@ -621,7 +800,7 @@ G1CollectedHeap::replace_cur_alloc_region_and_allocate(size_t word_size, bool at_safepoint, bool do_dirtying, bool can_expand) { - assert_heap_locked_or_at_safepoint(); + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); assert(_cur_alloc_region == NULL, "replace_cur_alloc_region_and_allocate() should only be called " "after retiring the previous current alloc region"); @@ -632,25 +811,12 @@ G1CollectedHeap::replace_cur_alloc_region_and_allocate(size_t word_size, "we are not allowed to expand the young gen"); if (can_expand || !g1_policy()->is_young_list_full()) { - if (!at_safepoint) { - // The cleanup operation might update _summary_bytes_used - // concurrently with this method. So, right now, if we don't - // wait for it to complete, updates to _summary_bytes_used might - // get lost. This will be resolved in the near future when the - // operation of the free region list is revamped as part of - // CR 6977804. If we're already at a safepoint, this call is - // unnecessary, not to mention wrong. - wait_for_cleanup_complete(); - } - - HeapRegion* new_cur_alloc_region = newAllocRegion(word_size, - false /* zero_filled */); + HeapRegion* new_cur_alloc_region = new_alloc_region(word_size); if (new_cur_alloc_region != NULL) { assert(new_cur_alloc_region->is_empty(), "the newly-allocated region should be empty, " "as right now we only allocate new regions out of the free list"); g1_policy()->update_region_num(true /* next_is_young */); - _summary_bytes_used -= new_cur_alloc_region->used(); set_region_short_lived_locked(new_cur_alloc_region); assert(!new_cur_alloc_region->isHumongous(), @@ -661,27 +827,29 @@ G1CollectedHeap::replace_cur_alloc_region_and_allocate(size_t word_size, // young type. OrderAccess::storestore(); - // Now allocate out of the new current alloc region. We could - // have re-used allocate_from_cur_alloc_region() but its - // operation is slightly different to what we need here. First, - // allocate_from_cur_alloc_region() is only called outside a - // safepoint and will always unlock the Heap_lock if it returns - // a non-NULL result. Second, it assumes that the current alloc - // region is what's already assigned in _cur_alloc_region. What - // we want here is to actually do the allocation first before we - // assign the new region to _cur_alloc_region. This ordering is - // not currently important, but it will be essential when we - // change the code to support CAS allocation in the future (see - // CR 6994297). - // - // This allocate method does BOT updates and we don't need them in - // the young generation. This will be fixed in the near future by - // CR 6994297. - HeapWord* result = new_cur_alloc_region->allocate(word_size); + // Now, perform the allocation out of the region we just + // allocated. Note that noone else can access that region at + // this point (as _cur_alloc_region has not been updated yet), + // so we can just go ahead and do the allocation without any + // atomics (and we expect this allocation attempt to + // suceeded). Given that other threads can attempt an allocation + // with a CAS and without needing the Heap_lock, if we assigned + // the new region to _cur_alloc_region before first allocating + // into it other threads might have filled up the new region + // before we got a chance to do the allocation ourselves. In + // that case, we would have needed to retire the region, grab a + // new one, and go through all this again. Allocating out of the + // new region before assigning it to _cur_alloc_region avoids + // all this. + HeapWord* result = + new_cur_alloc_region->allocate_no_bot_updates(word_size); assert(result != NULL, "we just allocate out of an empty region " "so allocation should have been successful"); assert(is_in(result), "result should be in the heap"); + // Now make sure that the store to _cur_alloc_region does not + // float above the store to top. + OrderAccess::storestore(); _cur_alloc_region = new_cur_alloc_region; if (!at_safepoint) { @@ -698,7 +866,7 @@ G1CollectedHeap::replace_cur_alloc_region_and_allocate(size_t word_size, assert(_cur_alloc_region == NULL, "we failed to allocate a new current " "alloc region, it should still be NULL"); - assert_heap_locked_or_at_safepoint(); + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); return NULL; } @@ -710,6 +878,10 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size) { assert(!isHumongous(word_size), "attempt_allocation_slow() should not be " "used for humongous allocations"); + // We should only reach here when we were unable to allocate + // otherwise. So, we should have not active current alloc region. + assert(_cur_alloc_region == NULL, "current alloc region should be NULL"); + // We will loop while succeeded is false, which means that we tried // to do a collection, but the VM op did not succeed. So, when we // exit the loop, either one of the allocation attempts was @@ -718,28 +890,8 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size) { for (int try_count = 1; /* we'll return or break */; try_count += 1) { bool succeeded = true; - { - // We may have concurrent cleanup working at the time. Wait for - // it to complete. In the future we would probably want to make - // the concurrent cleanup truly concurrent by decoupling it from - // the allocation. This will happen in the near future as part - // of CR 6977804 which will revamp the operation of the free - // region list. The fact that wait_for_cleanup_complete() will - // do a wait() means that we'll give up the Heap_lock. So, it's - // possible that when we exit wait_for_cleanup_complete() we - // might be able to allocate successfully (since somebody else - // might have done a collection meanwhile). So, we'll attempt to - // allocate again, just in case. When we make cleanup truly - // concurrent with allocation, we should remove this allocation - // attempt as it's redundant (we only reach here after an - // allocation attempt has been unsuccessful). - wait_for_cleanup_complete(); - HeapWord* result = attempt_allocation(word_size); - if (result != NULL) { - assert_heap_not_locked(); - return result; - } - } + // Every time we go round the loop we should be holding the Heap_lock. + assert_heap_locked(); if (GC_locker::is_active_and_needs_gc()) { // We are locked out of GC because of the GC locker. We can @@ -748,7 +900,6 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size) { if (g1_policy()->can_expand_young_list()) { // Yes, we are allowed to expand the young gen. Let's try to // allocate a new current alloc region. - HeapWord* result = replace_cur_alloc_region_and_allocate(word_size, false, /* at_safepoint */ @@ -771,20 +922,23 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size) { // rather than causing more, now probably unnecessary, GC attempts. JavaThread* jthr = JavaThread::current(); assert(jthr != NULL, "sanity"); - if (!jthr->in_critical()) { - MutexUnlocker mul(Heap_lock); - GC_locker::stall_until_clear(); - - // We'll then fall off the end of the ("if GC locker active") - // if-statement and retry the allocation further down in the - // loop. - } else { + if (jthr->in_critical()) { if (CheckJNICalls) { fatal("Possible deadlock due to allocating while" " in jni critical section"); } + // We are returning NULL so the protocol is that we're still + // holding the Heap_lock. + assert_heap_locked(); return NULL; } + + Heap_lock->unlock(); + GC_locker::stall_until_clear(); + + // No need to relock the Heap_lock. We'll fall off to the code + // below the else-statement which assumes that we are not + // holding the Heap_lock. } else { // We are not locked out. So, let's try to do a GC. The VM op // will retry the allocation before it completes. @@ -805,11 +959,10 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size) { dirty_young_block(result, word_size); return result; } - - Heap_lock->lock(); } - assert_heap_locked(); + // Both paths that get us here from above unlock the Heap_lock. + assert_heap_not_locked(); // We can reach here when we were unsuccessful in doing a GC, // because another thread beat us to it, or because we were locked @@ -854,7 +1007,7 @@ G1CollectedHeap::attempt_allocation_humongous(size_t word_size, // allocation paths that attempt to allocate a humongous object // should eventually reach here. Currently, the only paths are from // mem_allocate() and attempt_allocation_at_safepoint(). - assert_heap_locked_or_at_safepoint(); + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); assert(isHumongous(word_size), "attempt_allocation_humongous() " "should only be used for humongous allocations"); assert(SafepointSynchronize::is_at_safepoint() == at_safepoint, @@ -931,13 +1084,13 @@ G1CollectedHeap::attempt_allocation_humongous(size_t word_size, } } - assert_heap_locked_or_at_safepoint(); + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); return NULL; } HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, bool expect_null_cur_alloc_region) { - assert_at_safepoint(); + assert_at_safepoint(true /* should_be_vm_thread */); assert(_cur_alloc_region == NULL || !expect_null_cur_alloc_region, err_msg("the current alloc region was unexpectedly found " "to be non-NULL, cur alloc region: "PTR_FORMAT" " @@ -948,10 +1101,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, if (!expect_null_cur_alloc_region) { HeapRegion* cur_alloc_region = _cur_alloc_region; if (cur_alloc_region != NULL) { - // This allocate method does BOT updates and we don't need them in - // the young generation. This will be fixed in the near future by - // CR 6994297. - HeapWord* result = cur_alloc_region->allocate(word_size); + // We are at a safepoint so no reason to use the MT-safe version. + HeapWord* result = cur_alloc_region->allocate_no_bot_updates(word_size); if (result != NULL) { assert(is_in(result), "result should be in the heap"); @@ -983,20 +1134,17 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) { assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "we do not allow TLABs of humongous size"); - Heap_lock->lock(); - - // First attempt: try allocating out of the current alloc region or - // after replacing the current alloc region. + // First attempt: Try allocating out of the current alloc region + // using a CAS. If that fails, take the Heap_lock and retry the + // allocation, potentially replacing the current alloc region. HeapWord* result = attempt_allocation(word_size); if (result != NULL) { assert_heap_not_locked(); return result; } - assert_heap_locked(); - - // Second attempt: go into the even slower path where we might - // try to schedule a collection. + // Second attempt: Go to the slower path where we might try to + // schedule a collection. result = attempt_allocation_slow(word_size); if (result != NULL) { assert_heap_not_locked(); @@ -1004,6 +1152,7 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) { } assert_heap_locked(); + // Need to unlock the Heap_lock before returning. Heap_lock->unlock(); return NULL; } @@ -1022,11 +1171,10 @@ G1CollectedHeap::mem_allocate(size_t word_size, for (int try_count = 1; /* we'll return */; try_count += 1) { unsigned int gc_count_before; { - Heap_lock->lock(); - if (!isHumongous(word_size)) { - // First attempt: try allocating out of the current alloc - // region or after replacing the current alloc region. + // First attempt: Try allocating out of the current alloc region + // using a CAS. If that fails, take the Heap_lock and retry the + // allocation, potentially replacing the current alloc region. HeapWord* result = attempt_allocation(word_size); if (result != NULL) { assert_heap_not_locked(); @@ -1035,14 +1183,17 @@ G1CollectedHeap::mem_allocate(size_t word_size, assert_heap_locked(); - // Second attempt: go into the even slower path where we might - // try to schedule a collection. + // Second attempt: Go to the slower path where we might try to + // schedule a collection. result = attempt_allocation_slow(word_size); if (result != NULL) { assert_heap_not_locked(); return result; } } else { + // attempt_allocation_humongous() requires the Heap_lock to be held. + Heap_lock->lock(); + HeapWord* result = attempt_allocation_humongous(word_size, false /* at_safepoint */); if (result != NULL) { @@ -1054,7 +1205,8 @@ G1CollectedHeap::mem_allocate(size_t word_size, assert_heap_locked(); // Read the gc count while the heap lock is held. gc_count_before = SharedHeap::heap()->total_collections(); - // We cannot be at a safepoint, so it is safe to unlock the Heap_lock + + // Release the Heap_lock before attempting the collection. Heap_lock->unlock(); } @@ -1092,22 +1244,18 @@ G1CollectedHeap::mem_allocate(size_t word_size, } void G1CollectedHeap::abandon_cur_alloc_region() { - if (_cur_alloc_region != NULL) { - // We're finished with the _cur_alloc_region. - if (_cur_alloc_region->is_empty()) { - _free_regions++; - free_region(_cur_alloc_region); - } else { - // As we're builing (at least the young portion) of the collection - // set incrementally we'll add the current allocation region to - // the collection set here. - if (_cur_alloc_region->is_young()) { - g1_policy()->add_region_to_incremental_cset_lhs(_cur_alloc_region); - } - _summary_bytes_used += _cur_alloc_region->used(); - } - _cur_alloc_region = NULL; + assert_at_safepoint(true /* should_be_vm_thread */); + + HeapRegion* cur_alloc_region = _cur_alloc_region; + if (cur_alloc_region != NULL) { + assert(!cur_alloc_region->is_empty(), + "the current alloc region can never be empty"); + assert(cur_alloc_region->is_young(), + "the current alloc region should be young"); + + retire_cur_alloc_region_common(cur_alloc_region); } + assert(_cur_alloc_region == NULL, "post-condition"); } void G1CollectedHeap::abandon_gc_alloc_regions() { @@ -1188,19 +1336,20 @@ public: bool G1CollectedHeap::do_collection(bool explicit_gc, bool clear_all_soft_refs, size_t word_size) { + assert_at_safepoint(true /* should_be_vm_thread */); + if (GC_locker::check_active_before_gc()) { return false; } - DTraceGCProbeMarker gc_probe_marker(true /* full */); + SvcGCMarker sgcm(SvcGCMarker::FULL); ResourceMark rm; if (PrintHeapAtGC) { Universe::print_heap_before_gc(); } - assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); - assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread"); + verify_region_sets_optional(); const bool do_clear_all_soft_refs = clear_all_soft_refs || collector_policy()->should_clear_all_soft_refs(); @@ -1223,6 +1372,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, double start = os::elapsedTime(); g1_policy()->record_full_collection_start(); + wait_while_free_regions_coming(); + append_secondary_free_list_if_not_empty(); + gc_prologue(true); increment_total_collections(true /* full gc */); @@ -1235,7 +1387,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, gclog_or_tty->print(" VerifyBeforeGC:"); Universe::verify(true); } - assert(regions_accounted_for(), "Region leakage!"); COMPILER2_PRESENT(DerivedPointerTable::clear()); @@ -1259,7 +1410,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, assert(_cur_alloc_region == NULL, "Invariant."); g1_rem_set()->cleanupHRRS(); tear_down_region_lists(); - set_used_regions_to_need_zero_fill(); // We may have added regions to the current incremental collection // set between the last GC or pause and now. We need to clear the @@ -1294,9 +1444,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, HandleMark hm; // Discard invalid handles created during gc G1MarkSweep::invoke_at_safepoint(ref_processor(), do_clear_all_soft_refs); } - // Because freeing humongous regions may have added some unclean - // regions, it is necessary to tear down again before rebuilding. - tear_down_region_lists(); + assert(free_regions() == 0, "we should not have added any free regions"); rebuild_region_lists(); _summary_bytes_used = recalculate_used(); @@ -1378,7 +1526,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, JavaThread::dirty_card_queue_set().abandon_logs(); assert(!G1DeferredRSUpdate || (G1DeferredRSUpdate && (dirty_card_queue_set().completed_buffers_num() == 0)), "Should not be any"); - assert(regions_accounted_for(), "Region leakage!"); } if (g1_policy()->in_young_gc_mode()) { @@ -1392,6 +1539,8 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, // Update the number of full collections that have been completed. increment_full_collections_completed(false /* concurrent */); + verify_region_sets_optional(); + if (PrintHeapAtGC) { Universe::print_heap_after_gc(); } @@ -1532,10 +1681,7 @@ resize_if_necessary_after_full_collection(size_t word_size) { HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size, bool* succeeded) { - assert(SafepointSynchronize::is_at_safepoint(), - "satisfy_failed_allocation() should only be called at a safepoint"); - assert(Thread::current()->is_VM_thread(), - "satisfy_failed_allocation() should only be called by the VM thread"); + assert_at_safepoint(true /* should_be_vm_thread */); *succeeded = true; // Let's attempt the allocation first. @@ -1607,53 +1753,22 @@ G1CollectedHeap::satisfy_failed_allocation(size_t word_size, // allocated block, or else "NULL". HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { - assert(SafepointSynchronize::is_at_safepoint(), - "expand_and_allocate() should only be called at a safepoint"); - assert(Thread::current()->is_VM_thread(), - "expand_and_allocate() should only be called by the VM thread"); + assert_at_safepoint(true /* should_be_vm_thread */); + + verify_region_sets_optional(); size_t expand_bytes = word_size * HeapWordSize; if (expand_bytes < MinHeapDeltaBytes) { expand_bytes = MinHeapDeltaBytes; } expand(expand_bytes); - assert(regions_accounted_for(), "Region leakage!"); + + verify_region_sets_optional(); return attempt_allocation_at_safepoint(word_size, false /* expect_null_cur_alloc_region */); } -size_t G1CollectedHeap::free_region_if_totally_empty(HeapRegion* hr) { - size_t pre_used = 0; - size_t cleared_h_regions = 0; - size_t freed_regions = 0; - UncleanRegionList local_list; - free_region_if_totally_empty_work(hr, pre_used, cleared_h_regions, - freed_regions, &local_list); - - finish_free_region_work(pre_used, cleared_h_regions, freed_regions, - &local_list); - return pre_used; -} - -void -G1CollectedHeap::free_region_if_totally_empty_work(HeapRegion* hr, - size_t& pre_used, - size_t& cleared_h, - size_t& freed_regions, - UncleanRegionList* list, - bool par) { - assert(!hr->continuesHumongous(), "should have filtered these out"); - size_t res = 0; - if (hr->used() > 0 && hr->garbage_bytes() == hr->used() && - !hr->is_young()) { - if (G1PolicyVerbose > 0) - gclog_or_tty->print_cr("Freeing empty region "PTR_FORMAT "(" SIZE_FORMAT " bytes)" - " during cleanup", hr, hr->used()); - free_region_work(hr, pre_used, cleared_h, freed_regions, list, par); - } -} - // FIXME: both this and shrink could probably be more efficient by // doing one "VirtualSpace::expand_by" call rather than several. void G1CollectedHeap::expand(size_t expand_bytes) { @@ -1686,19 +1801,7 @@ void G1CollectedHeap::expand(size_t expand_bytes) { // Add it to the HeapRegionSeq. _hrs->insert(hr); - // Set the zero-fill state, according to whether it's already - // zeroed. - { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - if (is_zeroed) { - hr->set_zero_fill_complete(); - put_free_region_on_list_locked(hr); - } else { - hr->set_zero_fill_needed(); - put_region_on_unclean_list_locked(hr); - } - } - _free_regions++; + _free_list.add_as_tail(hr); // And we used up an expansion region to create it. _expansion_regions--; // Tell the cardtable about it. @@ -1707,6 +1810,7 @@ void G1CollectedHeap::expand(size_t expand_bytes) { _bot_shared->resize(_g1_committed.word_size()); } } + if (Verbose && PrintGC) { size_t new_mem_size = _g1_storage.committed_size(); gclog_or_tty->print_cr("Expanding garbage-first heap from %ldK by %ldK to %ldK", @@ -1731,7 +1835,6 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) assert(mr.start() == (HeapWord*)_g1_storage.high(), "Bad shrink!"); _g1_committed.set_end(mr.start()); - _free_regions -= num_regions_deleted; _expansion_regions += num_regions_deleted; // Tell the cardtable about it. @@ -1751,10 +1854,17 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) } void G1CollectedHeap::shrink(size_t shrink_bytes) { + verify_region_sets_optional(); + release_gc_alloc_regions(true /* totally */); + // Instead of tearing down / rebuilding the free lists here, we + // could instead use the remove_all_pending() method on free_list to + // remove only the ones that we need to remove. tear_down_region_lists(); // We will rebuild them in a moment. shrink_helper(shrink_bytes); rebuild_region_lists(); + + verify_region_sets_optional(); } // Public methods. @@ -1773,18 +1883,17 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _ref_processor(NULL), _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), - _par_alloc_during_gc_lock(Mutex::leaf, "par alloc during GC lock"), _objs_with_preserved_marks(NULL), _preserved_marks_of_objs(NULL), _evac_failure_scan_stack(NULL) , _mark_in_progress(false), - _cg1r(NULL), _czft(NULL), _summary_bytes_used(0), + _cg1r(NULL), _summary_bytes_used(0), _cur_alloc_region(NULL), _refine_cte_cl(NULL), - _free_region_list(NULL), _free_region_list_size(0), - _free_regions(0), _full_collection(false), - _unclean_region_list(), - _unclean_regions_coming(false), + _free_list("Master Free List"), + _secondary_free_list("Secondary Free List"), + _humongous_set("Master Humongous Set"), + _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), _surviving_young_words(NULL), @@ -1868,7 +1977,7 @@ jint G1CollectedHeap::initialize() { ReservedSpace heap_rs(max_byte_size + pgs->max_size(), HeapRegion::GrainBytes, - false /*ism*/, addr); + UseLargePages, addr); if (UseCompressedOops) { if (addr != NULL && !heap_rs.is_reserved()) { @@ -1877,13 +1986,13 @@ jint G1CollectedHeap::initialize() { // Try again to reserver heap higher. addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); ReservedSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, - false /*ism*/, addr); + UseLargePages, addr); if (addr != NULL && !heap_rs0.is_reserved()) { // Failed to reserve at specified address again - give up. addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); assert(addr == NULL, ""); ReservedSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, - false /*ism*/, addr); + UseLargePages, addr); heap_rs = heap_rs1; } else { heap_rs = heap_rs0; @@ -1905,8 +2014,6 @@ jint G1CollectedHeap::initialize() { _expansion_regions = max_byte_size/HeapRegion::GrainBytes; - _num_humongous_regions = 0; - // Create the gen rem set (and barrier set) for the entire reserved region. _rem_set = collector_policy()->create_rem_set(_reserved, 2); set_barrier_set(rem_set()->bs()); @@ -1951,6 +2058,8 @@ jint G1CollectedHeap::initialize() { guarantee((size_t) HeapRegion::CardsPerRegion < max_cards_per_region, "too many cards per region"); + HeapRegionSet::set_unrealistically_long_length(max_regions() + 1); + _bot_shared = new G1BlockOffsetSharedArray(_reserved, heap_word_size(init_byte_size)); @@ -1975,11 +2084,6 @@ jint G1CollectedHeap::initialize() { _cm = new ConcurrentMark(heap_rs, (int) max_regions()); _cmThread = _cm->cmThread(); - // ...and the concurrent zero-fill thread, if necessary. - if (G1ConcZeroFill) { - _czft = new ConcurrentZFThread(); - } - // Initialize the from_card cache structure of HeapRegionRemSet. HeapRegionRemSet::init_heap(max_regions()); @@ -2153,7 +2257,7 @@ size_t G1CollectedHeap::recalculate_used_regions() const { #endif // PRODUCT size_t G1CollectedHeap::unsafe_max_alloc() { - if (_free_regions > 0) return HeapRegion::GrainBytes; + if (free_regions() > 0) return HeapRegion::GrainBytes; // otherwise, is there space in the current allocation region? // We need to store the current allocation region in a local variable @@ -2233,8 +2337,7 @@ void G1CollectedHeap::increment_full_collections_completed(bool concurrent) { } void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { - assert(Thread::current()->is_VM_thread(), "Precondition#1"); - assert(Heap_lock->is_locked(), "Precondition#2"); + assert_at_safepoint(true /* should_be_vm_thread */); GCCauseSetter gcs(this, cause); switch (cause) { case GCCause::_heap_inspection: @@ -2257,12 +2360,6 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { { MutexLocker ml(Heap_lock); - // Don't want to do a GC until cleanup is completed. This - // limitation will be removed in the near future when the - // operation of the free region list is revamped as part of - // CR 6977804. - wait_for_cleanup_complete(); - // Read the GC count while holding the Heap_lock gc_count_before = SharedHeap::heap()->total_collections(); full_gc_count_before = SharedHeap::heap()->total_full_collections(); @@ -2641,10 +2738,6 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { } } -bool G1CollectedHeap::allocs_are_zero_filled() { - return false; -} - size_t G1CollectedHeap::large_typearray_limit() { // FIXME return HeapRegion::GrainBytes/HeapWordSize; @@ -2659,7 +2752,6 @@ jlong G1CollectedHeap::millis_since_last_gc() { return 0; } - void G1CollectedHeap::prepare_for_verify() { if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) { ensure_parsability(false); @@ -2870,7 +2962,9 @@ void G1CollectedHeap::verify(bool allow_dirty, &rootsCl); bool failures = rootsCl.failures(); rem_set()->invalidate(perm_gen()->used_region(), false); - if (!silent) { gclog_or_tty->print("heapRegions "); } + if (!silent) { gclog_or_tty->print("HeapRegionSets "); } + verify_region_sets(); + if (!silent) { gclog_or_tty->print("HeapRegions "); } if (GCParallelVerificationEnabled && ParallelGCThreads > 1) { assert(check_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity check"); @@ -2898,7 +2992,7 @@ void G1CollectedHeap::verify(bool allow_dirty, failures = true; } } - if (!silent) gclog_or_tty->print("remset "); + if (!silent) gclog_or_tty->print("RemSet "); rem_set()->verify(); if (failures) { @@ -2969,15 +3063,10 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const { if (G1CollectedHeap::use_parallel_gc_threads()) { workers()->print_worker_threads_on(st); } - _cmThread->print_on(st); st->cr(); - _cm->print_worker_threads_on(st); - _cg1r->print_worker_threads_on(st); - - _czft->print_on(st); st->cr(); } @@ -2987,7 +3076,6 @@ void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { } tc->do_thread(_cmThread); _cg1r->threads_do(tc); - tc->do_thread(_czft); } void G1CollectedHeap::print_tracing_info() const { @@ -3003,15 +3091,10 @@ void G1CollectedHeap::print_tracing_info() const { if (G1SummarizeConcMark) { concurrent_mark()->print_summary_info(); } - if (G1SummarizeZFStats) { - ConcurrentZFThread::print_summary_info(); - } g1_policy()->print_yg_surv_rate_info(); - SpecializationStats::print(); } - int G1CollectedHeap::addr_to_arena_id(void* addr) const { HeapRegion* hr = heap_region_containing(addr); if (hr == NULL) { @@ -3210,17 +3293,22 @@ void G1CollectedHeap::reset_taskqueue_stats() { bool G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { + assert_at_safepoint(true /* should_be_vm_thread */); + guarantee(!is_gc_active(), "collection is not reentrant"); + if (GC_locker::check_active_before_gc()) { return false; } - DTraceGCProbeMarker gc_probe_marker(false /* full */); + SvcGCMarker sgcm(SvcGCMarker::MINOR); ResourceMark rm; if (PrintHeapAtGC) { Universe::print_heap_before_gc(); } + verify_region_sets_optional(); + { // This call will decide whether this pause is an initial-mark // pause. If it is, during_initial_mark_pause() will return true @@ -3251,10 +3339,16 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { TraceMemoryManagerStats tms(false /* fullGC */); - assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); - assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread"); - guarantee(!is_gc_active(), "collection is not reentrant"); - assert(regions_accounted_for(), "Region leakage!"); + // If there are any free regions available on the secondary_free_list + // make sure we append them to the free_list. However, we don't + // have to wait for the rest of the cleanup operation to + // finish. If it's still going on that's OK. If we run out of + // regions, the region allocation code will check the + // secondary_free_list and potentially wait if more free regions + // are coming (see new_region_try_secondary_free_list()). + if (!G1StressConcRegionFreeing) { + append_secondary_free_list_if_not_empty(); + } increment_gc_time_stamp(); @@ -3334,8 +3428,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // progress, this will be zero. _cm->set_oops_do_bound(); - assert(regions_accounted_for(), "Region leakage."); - if (mark_in_progress()) concurrent_mark()->newCSet(); @@ -3431,8 +3523,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->record_pause_time_ms(pause_time_ms); g1_policy()->record_collection_pause_end(); - assert(regions_accounted_for(), "Region leakage."); - MemoryService::track_memory_usage(); if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { @@ -3463,8 +3553,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { gc_epilogue(false); } - assert(verify_region_lists(), "Bad region lists."); - if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) { gclog_or_tty->print_cr("Stopping after GC #%d", ExitAfterGCNum); print_tracing_info(); @@ -3472,6 +3560,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { } } + verify_region_sets_optional(); + TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); @@ -3578,7 +3668,7 @@ void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) { void G1CollectedHeap::push_gc_alloc_region(HeapRegion* hr) { assert(Thread::current()->is_VM_thread() || - par_alloc_during_gc_lock()->owned_by_self(), "Precondition"); + FreeList_lock->owned_by_self(), "Precondition"); assert(!hr->is_gc_alloc_region() && !hr->in_collection_set(), "Precondition."); hr->set_is_gc_alloc_region(true); @@ -3600,7 +3690,7 @@ public: #endif // G1_DEBUG void G1CollectedHeap::forget_alloc_region_list() { - assert(Thread::current()->is_VM_thread(), "Precondition"); + assert_at_safepoint(true /* should_be_vm_thread */); while (_gc_alloc_region_list != NULL) { HeapRegion* r = _gc_alloc_region_list; assert(r->is_gc_alloc_region(), "Invariant."); @@ -3620,9 +3710,6 @@ void G1CollectedHeap::forget_alloc_region_list() { _young_list->add_survivor_region(r); } } - if (r->is_empty()) { - ++_free_regions; - } } #ifdef G1_DEBUG FindGCAllocRegion fa; @@ -3675,7 +3762,7 @@ void G1CollectedHeap::get_gc_alloc_regions() { if (alloc_region == NULL) { // we will get a new GC alloc region - alloc_region = newAllocRegionWithExpansion(ap, 0); + alloc_region = new_gc_alloc_region(ap, 0); } else { // the region was retained from the last collection ++_gc_alloc_region_counts[ap]; @@ -3730,11 +3817,9 @@ void G1CollectedHeap::release_gc_alloc_regions(bool totally) { set_gc_alloc_region(ap, NULL); if (r->is_empty()) { - // we didn't actually allocate anything in it; let's just put - // it on the free list - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - r->set_zero_fill_complete(); - put_free_region_on_list_locked(r); + // We didn't actually allocate anything in it; let's just put + // it back on the free list. + _free_list.add_as_tail(r); } else if (_retain_gc_alloc_region[ap] && !totally) { // retain it so that we can use it at the beginning of the next GC _retained_gc_alloc_regions[ap] = r; @@ -3856,13 +3941,15 @@ private: size_t _next_marked_bytes; OopsInHeapRegionClosure *_cl; public: - RemoveSelfPointerClosure(G1CollectedHeap* g1, OopsInHeapRegionClosure* cl) : - _g1(g1), _cm(_g1->concurrent_mark()), _prev_marked_bytes(0), + RemoveSelfPointerClosure(G1CollectedHeap* g1, HeapRegion* hr, + OopsInHeapRegionClosure* cl) : + _g1(g1), _hr(hr), _cm(_g1->concurrent_mark()), _prev_marked_bytes(0), _next_marked_bytes(0), _cl(cl) {} size_t prev_marked_bytes() { return _prev_marked_bytes; } size_t next_marked_bytes() { return _next_marked_bytes; } + // // The original idea here was to coalesce evacuated and dead objects. // However that caused complications with the block offset table (BOT). // In particular if there were two TLABs, one of them partially refined. @@ -3871,15 +3958,24 @@ public: // of TLAB_2. If the last object of the TLAB_1 and the first object // of TLAB_2 are coalesced, then the cards of the unrefined part // would point into middle of the filler object. - // // The current approach is to not coalesce and leave the BOT contents intact. + // + // + // We now reset the BOT when we start the object iteration over the + // region and refine its entries for every object we come across. So + // the above comment is not really relevant and we should be able + // to coalesce dead objects if we want to. void do_object(oop obj) { + HeapWord* obj_addr = (HeapWord*) obj; + assert(_hr->is_in(obj_addr), "sanity"); + size_t obj_size = obj->size(); + _hr->update_bot_for_object(obj_addr, obj_size); if (obj->is_forwarded() && obj->forwardee() == obj) { // The object failed to move. assert(!_g1->is_obj_dead(obj), "We should not be preserving dead objs."); _cm->markPrev(obj); assert(_cm->isPrevMarked(obj), "Should be marked!"); - _prev_marked_bytes += (obj->size() * HeapWordSize); + _prev_marked_bytes += (obj_size * HeapWordSize); if (_g1->mark_in_progress() && !_g1->is_obj_ill(obj)) { _cm->markAndGrayObjectIfNecessary(obj); } @@ -3901,7 +3997,7 @@ public: } else { // The object has been either evacuated or is dead. Fill it with a // dummy object. - MemRegion mr((HeapWord*)obj, obj->size()); + MemRegion mr((HeapWord*)obj, obj_size); CollectedHeap::fill_with_object(mr); _cm->clearRangeBothMaps(mr); } @@ -3921,10 +4017,13 @@ void G1CollectedHeap::remove_self_forwarding_pointers() { HeapRegion* cur = g1_policy()->collection_set(); while (cur != NULL) { assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!"); + assert(!cur->isHumongous(), "sanity"); - RemoveSelfPointerClosure rspc(_g1h, cl); if (cur->evacuation_failed()) { assert(cur->in_collection_set(), "bad CS"); + RemoveSelfPointerClosure rspc(_g1h, cur, cl); + + cur->reset_bot(); cl->set_region(cur); cur->object_iterate(&rspc); @@ -3989,15 +4088,6 @@ void G1CollectedHeap::drain_evac_failure_scan_stack() { } } -void G1CollectedHeap::handle_evacuation_failure(oop old) { - markOop m = old->mark(); - // forward to self - assert(!old->is_forwarded(), "precondition"); - - old->forward_to(old); - handle_evacuation_failure_common(old, m); -} - oop G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop old) { @@ -4084,8 +4174,6 @@ HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose, HeapWord* block = alloc_region->par_allocate(word_size); if (block == NULL) { - MutexLockerEx x(par_alloc_during_gc_lock(), - Mutex::_no_safepoint_check_flag); block = allocate_during_gc_slow(purpose, alloc_region, true, word_size); } return block; @@ -4114,6 +4202,12 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose, err_msg("we should not be seeing humongous allocation requests " "during GC, word_size = "SIZE_FORMAT, word_size)); + // We need to make sure we serialize calls to this method. Given + // that the FreeList_lock guards accesses to the free_list anyway, + // and we need to potentially remove a region from it, we'll use it + // to protect the whole call. + MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); + HeapWord* block = NULL; // In the parallel case, a previous thread to obtain the lock may have // already assigned a new gc_alloc_region. @@ -4159,7 +4253,7 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose, } // Now allocate a new region for allocation. - alloc_region = newAllocRegionWithExpansion(purpose, word_size, false /*zero_filled*/); + alloc_region = new_gc_alloc_region(purpose, word_size); // let the caller handle alloc failure if (alloc_region != NULL) { @@ -4167,9 +4261,6 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose, assert(check_gc_alloc_regions(), "alloc regions messed up"); assert(alloc_region->saved_mark_at_top(), "Mark should have been saved already."); - // We used to assert that the region was zero-filled here, but no - // longer. - // This must be done last: once it's installed, other regions may // allocate in it (without holding the lock.) set_gc_alloc_region(purpose, alloc_region); @@ -4834,91 +4925,91 @@ void G1CollectedHeap::evacuate_collection_set() { COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } -void G1CollectedHeap::free_region(HeapRegion* hr) { - size_t pre_used = 0; - size_t cleared_h_regions = 0; - size_t freed_regions = 0; - UncleanRegionList local_list; - - HeapWord* start = hr->bottom(); - HeapWord* end = hr->prev_top_at_mark_start(); - size_t used_bytes = hr->used(); - size_t live_bytes = hr->max_live_bytes(); - if (used_bytes > 0) { - guarantee( live_bytes <= used_bytes, "invariant" ); - } else { - guarantee( live_bytes == 0, "invariant" ); - } - - size_t garbage_bytes = used_bytes - live_bytes; - if (garbage_bytes > 0) - g1_policy()->decrease_known_garbage_bytes(garbage_bytes); - - free_region_work(hr, pre_used, cleared_h_regions, freed_regions, - &local_list); - finish_free_region_work(pre_used, cleared_h_regions, freed_regions, - &local_list); -} - -void -G1CollectedHeap::free_region_work(HeapRegion* hr, - size_t& pre_used, - size_t& cleared_h_regions, - size_t& freed_regions, - UncleanRegionList* list, - bool par) { - pre_used += hr->used(); - if (hr->isHumongous()) { - assert(hr->startsHumongous(), - "Only the start of a humongous region should be freed."); - int ind = _hrs->find(hr); - assert(ind != -1, "Should have an index."); - // Clear the start region. - hr->hr_clear(par, true /*clear_space*/); - list->insert_before_head(hr); - cleared_h_regions++; - freed_regions++; - // Clear any continued regions. - ind++; - while ((size_t)ind < n_regions()) { - HeapRegion* hrc = _hrs->at(ind); - if (!hrc->continuesHumongous()) break; - // Otherwise, does continue the H region. - assert(hrc->humongous_start_region() == hr, "Huh?"); - hrc->hr_clear(par, true /*clear_space*/); - cleared_h_regions++; - freed_regions++; - list->insert_before_head(hrc); - ind++; +void G1CollectedHeap::free_region_if_totally_empty(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par) { + if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) { + if (hr->isHumongous()) { + assert(hr->startsHumongous(), "we should only see starts humongous"); + free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par); + } else { + free_region(hr, pre_used, free_list, par); } - } else { - hr->hr_clear(par, true /*clear_space*/); - list->insert_before_head(hr); - freed_regions++; - // If we're using clear2, this should not be enabled. - // assert(!hr->in_cohort(), "Can't be both free and in a cohort."); } } -void G1CollectedHeap::finish_free_region_work(size_t pre_used, - size_t cleared_h_regions, - size_t freed_regions, - UncleanRegionList* list) { - if (list != NULL && list->sz() > 0) { - prepend_region_list_on_unclean_list(list); +void G1CollectedHeap::free_region(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + bool par) { + assert(!hr->isHumongous(), "this is only for non-humongous regions"); + assert(!hr->is_empty(), "the region should not be empty"); + assert(free_list != NULL, "pre-condition"); + + *pre_used += hr->used(); + hr->hr_clear(par, true /* clear_space */); + free_list->add_as_tail(hr); +} + +void G1CollectedHeap::free_humongous_region(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par) { + assert(hr->startsHumongous(), "this is only for starts humongous regions"); + assert(free_list != NULL, "pre-condition"); + assert(humongous_proxy_set != NULL, "pre-condition"); + + size_t hr_used = hr->used(); + size_t hr_capacity = hr->capacity(); + size_t hr_pre_used = 0; + _humongous_set.remove_with_proxy(hr, humongous_proxy_set); + hr->set_notHumongous(); + free_region(hr, &hr_pre_used, free_list, par); + + int i = hr->hrs_index() + 1; + size_t num = 1; + while ((size_t) i < n_regions()) { + HeapRegion* curr_hr = _hrs->at(i); + if (!curr_hr->continuesHumongous()) { + break; + } + curr_hr->set_notHumongous(); + free_region(curr_hr, &hr_pre_used, free_list, par); + num += 1; + i += 1; } - // Acquire a lock, if we're parallel, to update possibly-shared - // variables. - Mutex* lock = (n_par_threads() > 0) ? ParGCRareEvent_lock : NULL; - { + assert(hr_pre_used == hr_used, + err_msg("hr_pre_used: "SIZE_FORMAT" and hr_used: "SIZE_FORMAT" " + "should be the same", hr_pre_used, hr_used)); + *pre_used += hr_pre_used; +} + +void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par) { + if (pre_used > 0) { + Mutex* lock = (par) ? ParGCRareEvent_lock : NULL; MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag); + assert(_summary_bytes_used >= pre_used, + err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" " + "should be >= pre_used: "SIZE_FORMAT, + _summary_bytes_used, pre_used)); _summary_bytes_used -= pre_used; - _num_humongous_regions -= (int) cleared_h_regions; - _free_regions += freed_regions; + } + if (free_list != NULL && !free_list->is_empty()) { + MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); + _free_list.add_as_tail(free_list); + } + if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) { + MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); + _humongous_set.update_from_proxy(humongous_proxy_set); } } - void G1CollectedHeap::dirtyCardsForYoungRegions(CardTableModRefBS* ct_bs, HeapRegion* list) { while (list != NULL) { guarantee( list->is_young(), "invariant" ); @@ -5041,6 +5132,9 @@ void G1CollectedHeap::cleanUpCardTable() { } void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { + size_t pre_used = 0; + FreeRegionList local_free_list("Local List for CSet Freeing"); + double young_time_ms = 0.0; double non_young_time_ms = 0.0; @@ -5059,6 +5153,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { size_t rs_lengths = 0; while (cur != NULL) { + assert(!is_on_free_list(cur), "sanity"); + if (non_young) { if (cur->is_young()) { double end_sec = os::elapsedTime(); @@ -5069,14 +5165,12 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { non_young = false; } } else { - if (!cur->is_on_free_list()) { - double end_sec = os::elapsedTime(); - double elapsed_ms = (end_sec - start_sec) * 1000.0; - young_time_ms += elapsed_ms; + double end_sec = os::elapsedTime(); + double elapsed_ms = (end_sec - start_sec) * 1000.0; + young_time_ms += elapsed_ms; - start_sec = os::elapsedTime(); - non_young = true; - } + start_sec = os::elapsedTime(); + non_young = true; } rs_lengths += cur->rem_set()->occupied(); @@ -5109,9 +5203,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { if (!cur->evacuation_failed()) { // And the region is empty. - assert(!cur->is_empty(), - "Should not have empty regions in a CS."); - free_region(cur); + assert(!cur->is_empty(), "Should not have empty regions in a CS."); + free_region(cur, &pre_used, &local_free_list, false /* par */); } else { cur->uninstall_surv_rate_group(); if (cur->is_young()) @@ -5132,6 +5225,9 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { else young_time_ms += elapsed_ms; + update_sets_after_freeing_regions(pre_used, &local_free_list, + NULL /* humongous_proxy_set */, + false /* par */); policy->record_young_free_cset_time_ms(young_time_ms); policy->record_non_young_free_cset_time_ms(non_young_time_ms); } @@ -5157,291 +5253,53 @@ void G1CollectedHeap::abandon_collection_set(HeapRegion* cs_head) { } } -HeapRegion* -G1CollectedHeap::alloc_region_from_unclean_list_locked(bool zero_filled) { - assert(ZF_mon->owned_by_self(), "Precondition"); - HeapRegion* res = pop_unclean_region_list_locked(); - if (res != NULL) { - assert(!res->continuesHumongous() && - res->zero_fill_state() != HeapRegion::Allocated, - "Only free regions on unclean list."); - if (zero_filled) { - res->ensure_zero_filled_locked(); - res->set_zero_fill_allocated(); - } +void G1CollectedHeap::set_free_regions_coming() { + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [cm thread] : " + "setting free regions coming"); } - return res; + + assert(!free_regions_coming(), "pre-condition"); + _free_regions_coming = true; } -HeapRegion* G1CollectedHeap::alloc_region_from_unclean_list(bool zero_filled) { - MutexLockerEx zx(ZF_mon, Mutex::_no_safepoint_check_flag); - return alloc_region_from_unclean_list_locked(zero_filled); -} - -void G1CollectedHeap::put_region_on_unclean_list(HeapRegion* r) { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - put_region_on_unclean_list_locked(r); - if (should_zf()) ZF_mon->notify_all(); // Wake up ZF thread. -} - -void G1CollectedHeap::set_unclean_regions_coming(bool b) { - MutexLockerEx x(Cleanup_mon); - set_unclean_regions_coming_locked(b); -} - -void G1CollectedHeap::set_unclean_regions_coming_locked(bool b) { - assert(Cleanup_mon->owned_by_self(), "Precondition"); - _unclean_regions_coming = b; - // Wake up mutator threads that might be waiting for completeCleanup to - // finish. - if (!b) Cleanup_mon->notify_all(); -} - -void G1CollectedHeap::wait_for_cleanup_complete() { - assert_not_at_safepoint(); - MutexLockerEx x(Cleanup_mon); - wait_for_cleanup_complete_locked(); -} - -void G1CollectedHeap::wait_for_cleanup_complete_locked() { - assert(Cleanup_mon->owned_by_self(), "precondition"); - while (_unclean_regions_coming) { - Cleanup_mon->wait(); - } -} - -void -G1CollectedHeap::put_region_on_unclean_list_locked(HeapRegion* r) { - assert(ZF_mon->owned_by_self(), "precondition."); -#ifdef ASSERT - if (r->is_gc_alloc_region()) { - ResourceMark rm; - stringStream region_str; - print_on(®ion_str); - assert(!r->is_gc_alloc_region(), err_msg("Unexpected GC allocation region: %s", - region_str.as_string())); - } -#endif - _unclean_region_list.insert_before_head(r); -} - -void -G1CollectedHeap::prepend_region_list_on_unclean_list(UncleanRegionList* list) { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - prepend_region_list_on_unclean_list_locked(list); - if (should_zf()) ZF_mon->notify_all(); // Wake up ZF thread. -} - -void -G1CollectedHeap:: -prepend_region_list_on_unclean_list_locked(UncleanRegionList* list) { - assert(ZF_mon->owned_by_self(), "precondition."); - _unclean_region_list.prepend_list(list); -} - -HeapRegion* G1CollectedHeap::pop_unclean_region_list_locked() { - assert(ZF_mon->owned_by_self(), "precondition."); - HeapRegion* res = _unclean_region_list.pop(); - if (res != NULL) { - // Inform ZF thread that there's a new unclean head. - if (_unclean_region_list.hd() != NULL && should_zf()) - ZF_mon->notify_all(); - } - return res; -} - -HeapRegion* G1CollectedHeap::peek_unclean_region_list_locked() { - assert(ZF_mon->owned_by_self(), "precondition."); - return _unclean_region_list.hd(); -} - - -bool G1CollectedHeap::move_cleaned_region_to_free_list_locked() { - assert(ZF_mon->owned_by_self(), "Precondition"); - HeapRegion* r = peek_unclean_region_list_locked(); - if (r != NULL && r->zero_fill_state() == HeapRegion::ZeroFilled) { - // Result of below must be equal to "r", since we hold the lock. - (void)pop_unclean_region_list_locked(); - put_free_region_on_list_locked(r); - return true; - } else { - return false; - } -} - -bool G1CollectedHeap::move_cleaned_region_to_free_list() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - return move_cleaned_region_to_free_list_locked(); -} - - -void G1CollectedHeap::put_free_region_on_list_locked(HeapRegion* r) { - assert(ZF_mon->owned_by_self(), "precondition."); - assert(_free_region_list_size == free_region_list_length(), "Inv"); - assert(r->zero_fill_state() == HeapRegion::ZeroFilled, - "Regions on free list must be zero filled"); - assert(!r->isHumongous(), "Must not be humongous."); - assert(r->is_empty(), "Better be empty"); - assert(!r->is_on_free_list(), - "Better not already be on free list"); - assert(!r->is_on_unclean_list(), - "Better not already be on unclean list"); - r->set_on_free_list(true); - r->set_next_on_free_list(_free_region_list); - _free_region_list = r; - _free_region_list_size++; - assert(_free_region_list_size == free_region_list_length(), "Inv"); -} - -void G1CollectedHeap::put_free_region_on_list(HeapRegion* r) { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - put_free_region_on_list_locked(r); -} - -HeapRegion* G1CollectedHeap::pop_free_region_list_locked() { - assert(ZF_mon->owned_by_self(), "precondition."); - assert(_free_region_list_size == free_region_list_length(), "Inv"); - HeapRegion* res = _free_region_list; - if (res != NULL) { - _free_region_list = res->next_from_free_list(); - _free_region_list_size--; - res->set_on_free_list(false); - res->set_next_on_free_list(NULL); - assert(_free_region_list_size == free_region_list_length(), "Inv"); - } - return res; -} - - -HeapRegion* G1CollectedHeap::alloc_free_region_from_lists(bool zero_filled) { - // By self, or on behalf of self. - assert(Heap_lock->is_locked(), "Precondition"); - HeapRegion* res = NULL; - bool first = true; - while (res == NULL) { - if (zero_filled || !first) { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - res = pop_free_region_list_locked(); - if (res != NULL) { - assert(!res->zero_fill_is_allocated(), - "No allocated regions on free list."); - res->set_zero_fill_allocated(); - } else if (!first) { - break; // We tried both, time to return NULL. - } - } - - if (res == NULL) { - res = alloc_region_from_unclean_list(zero_filled); - } - assert(res == NULL || - !zero_filled || - res->zero_fill_is_allocated(), - "We must have allocated the region we're returning"); - first = false; - } - return res; -} - -void G1CollectedHeap::remove_allocated_regions_from_lists() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); +void G1CollectedHeap::reset_free_regions_coming() { { - HeapRegion* prev = NULL; - HeapRegion* cur = _unclean_region_list.hd(); - while (cur != NULL) { - HeapRegion* next = cur->next_from_unclean_list(); - if (cur->zero_fill_is_allocated()) { - // Remove from the list. - if (prev == NULL) { - (void)_unclean_region_list.pop(); - } else { - _unclean_region_list.delete_after(prev); - } - cur->set_on_unclean_list(false); - cur->set_next_on_unclean_list(NULL); - } else { - prev = cur; - } - cur = next; - } - assert(_unclean_region_list.sz() == unclean_region_list_length(), - "Inv"); + assert(free_regions_coming(), "pre-condition"); + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + _free_regions_coming = false; + SecondaryFreeList_lock->notify_all(); + } + + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [cm thread] : " + "reset free regions coming"); + } +} + +void G1CollectedHeap::wait_while_free_regions_coming() { + // Most of the time we won't have to wait, so let's do a quick test + // first before we take the lock. + if (!free_regions_coming()) { + return; + } + + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [other] : " + "waiting for free regions"); } { - HeapRegion* prev = NULL; - HeapRegion* cur = _free_region_list; - while (cur != NULL) { - HeapRegion* next = cur->next_from_free_list(); - if (cur->zero_fill_is_allocated()) { - // Remove from the list. - if (prev == NULL) { - _free_region_list = cur->next_from_free_list(); - } else { - prev->set_next_on_free_list(cur->next_from_free_list()); - } - cur->set_on_free_list(false); - cur->set_next_on_free_list(NULL); - _free_region_list_size--; - } else { - prev = cur; - } - cur = next; + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + while (free_regions_coming()) { + SecondaryFreeList_lock->wait(Mutex::_no_safepoint_check_flag); } - assert(_free_region_list_size == free_region_list_length(), "Inv"); } -} -bool G1CollectedHeap::verify_region_lists() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - return verify_region_lists_locked(); -} - -bool G1CollectedHeap::verify_region_lists_locked() { - HeapRegion* unclean = _unclean_region_list.hd(); - while (unclean != NULL) { - guarantee(unclean->is_on_unclean_list(), "Well, it is!"); - guarantee(!unclean->is_on_free_list(), "Well, it shouldn't be!"); - guarantee(unclean->zero_fill_state() != HeapRegion::Allocated, - "Everything else is possible."); - unclean = unclean->next_from_unclean_list(); + if (G1ConcRegionFreeingVerbose) { + gclog_or_tty->print_cr("G1ConcRegionFreeing [other] : " + "done waiting for free regions"); } - guarantee(_unclean_region_list.sz() == unclean_region_list_length(), "Inv"); - - HeapRegion* free_r = _free_region_list; - while (free_r != NULL) { - assert(free_r->is_on_free_list(), "Well, it is!"); - assert(!free_r->is_on_unclean_list(), "Well, it shouldn't be!"); - switch (free_r->zero_fill_state()) { - case HeapRegion::NotZeroFilled: - case HeapRegion::ZeroFilling: - guarantee(false, "Should not be on free list."); - break; - default: - // Everything else is possible. - break; - } - free_r = free_r->next_from_free_list(); - } - guarantee(_free_region_list_size == free_region_list_length(), "Inv"); - // If we didn't do an assertion... - return true; -} - -size_t G1CollectedHeap::free_region_list_length() { - assert(ZF_mon->owned_by_self(), "precondition."); - size_t len = 0; - HeapRegion* cur = _free_region_list; - while (cur != NULL) { - len++; - cur = cur->next_from_free_list(); - } - return len; -} - -size_t G1CollectedHeap::unclean_region_list_length() { - assert(ZF_mon->owned_by_self(), "precondition."); - return _unclean_region_list.length(); } size_t G1CollectedHeap::n_regions() { @@ -5454,55 +5312,6 @@ size_t G1CollectedHeap::max_regions() { HeapRegion::GrainBytes; } -size_t G1CollectedHeap::free_regions() { - /* Possibly-expensive assert. - assert(_free_regions == count_free_regions(), - "_free_regions is off."); - */ - return _free_regions; -} - -bool G1CollectedHeap::should_zf() { - return _free_region_list_size < (size_t) G1ConcZFMaxRegions; -} - -class RegionCounter: public HeapRegionClosure { - size_t _n; -public: - RegionCounter() : _n(0) {} - bool doHeapRegion(HeapRegion* r) { - if (r->is_empty()) { - assert(!r->isHumongous(), "H regions should not be empty."); - _n++; - } - return false; - } - int res() { return (int) _n; } -}; - -size_t G1CollectedHeap::count_free_regions() { - RegionCounter rc; - heap_region_iterate(&rc); - size_t n = rc.res(); - if (_cur_alloc_region != NULL && _cur_alloc_region->is_empty()) - n--; - return n; -} - -size_t G1CollectedHeap::count_free_regions_list() { - size_t n = 0; - size_t o = 0; - ZF_mon->lock_without_safepoint_check(); - HeapRegion* cur = _free_region_list; - while (cur != NULL) { - cur = cur->next_from_free_list(); - n++; - } - size_t m = unclean_region_list_length(); - ZF_mon->unlock(); - return n + m; -} - void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) { assert(heap_lock_held_for_gc(), "the heap lock should already be held by or for this thread"); @@ -5574,28 +5383,19 @@ void G1CollectedHeap::retire_all_alloc_regions() { } } - // Done at the start of full GC. void G1CollectedHeap::tear_down_region_lists() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - while (pop_unclean_region_list_locked() != NULL) ; - assert(_unclean_region_list.hd() == NULL && _unclean_region_list.sz() == 0, - "Postconditions of loop."); - while (pop_free_region_list_locked() != NULL) ; - assert(_free_region_list == NULL, "Postcondition of loop."); - if (_free_region_list_size != 0) { - gclog_or_tty->print_cr("Size is %d.", _free_region_list_size); - print_on(gclog_or_tty, true /* extended */); - } - assert(_free_region_list_size == 0, "Postconditions of loop."); + _free_list.remove_all(); } - class RegionResetter: public HeapRegionClosure { - G1CollectedHeap* _g1; - int _n; + G1CollectedHeap* _g1h; + FreeRegionList _local_free_list; + public: - RegionResetter() : _g1(G1CollectedHeap::heap()), _n(0) {} + RegionResetter() : _g1h(G1CollectedHeap::heap()), + _local_free_list("Local Free List for RegionResetter") { } + bool doHeapRegion(HeapRegion* r) { if (r->continuesHumongous()) return false; if (r->top() > r->bottom()) { @@ -5603,152 +5403,32 @@ public: Copy::fill_to_words(r->top(), pointer_delta(r->end(), r->top())); } - r->set_zero_fill_allocated(); } else { assert(r->is_empty(), "tautology"); - _n++; - switch (r->zero_fill_state()) { - case HeapRegion::NotZeroFilled: - case HeapRegion::ZeroFilling: - _g1->put_region_on_unclean_list_locked(r); - break; - case HeapRegion::Allocated: - r->set_zero_fill_complete(); - // no break; go on to put on free list. - case HeapRegion::ZeroFilled: - _g1->put_free_region_on_list_locked(r); - break; - } + _local_free_list.add_as_tail(r); } return false; } - int getFreeRegionCount() {return _n;} + void update_free_lists() { + _g1h->update_sets_after_freeing_regions(0, &_local_free_list, NULL, + false /* par */); + } }; // Done at the end of full GC. void G1CollectedHeap::rebuild_region_lists() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); // This needs to go at the end of the full GC. RegionResetter rs; heap_region_iterate(&rs); - _free_regions = rs.getFreeRegionCount(); - // Tell the ZF thread it may have work to do. - if (should_zf()) ZF_mon->notify_all(); -} - -class UsedRegionsNeedZeroFillSetter: public HeapRegionClosure { - G1CollectedHeap* _g1; - int _n; -public: - UsedRegionsNeedZeroFillSetter() : _g1(G1CollectedHeap::heap()), _n(0) {} - bool doHeapRegion(HeapRegion* r) { - if (r->continuesHumongous()) return false; - if (r->top() > r->bottom()) { - // There are assertions in "set_zero_fill_needed()" below that - // require top() == bottom(), so this is technically illegal. - // We'll skirt the law here, by making that true temporarily. - DEBUG_ONLY(HeapWord* save_top = r->top(); - r->set_top(r->bottom())); - r->set_zero_fill_needed(); - DEBUG_ONLY(r->set_top(save_top)); - } - return false; - } -}; - -// Done at the start of full GC. -void G1CollectedHeap::set_used_regions_to_need_zero_fill() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - // This needs to go at the end of the full GC. - UsedRegionsNeedZeroFillSetter rs; - heap_region_iterate(&rs); + rs.update_free_lists(); } void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) { _refine_cte_cl->set_concurrent(concurrent); } -#ifndef PRODUCT - -class PrintHeapRegionClosure: public HeapRegionClosure { -public: - bool doHeapRegion(HeapRegion *r) { - gclog_or_tty->print("Region: "PTR_FORMAT":", r); - if (r != NULL) { - if (r->is_on_free_list()) - gclog_or_tty->print("Free "); - if (r->is_young()) - gclog_or_tty->print("Young "); - if (r->isHumongous()) - gclog_or_tty->print("Is Humongous "); - r->print(); - } - return false; - } -}; - -class SortHeapRegionClosure : public HeapRegionClosure { - size_t young_regions,free_regions, unclean_regions; - size_t hum_regions, count; - size_t unaccounted, cur_unclean, cur_alloc; - size_t total_free; - HeapRegion* cur; -public: - SortHeapRegionClosure(HeapRegion *_cur) : cur(_cur), young_regions(0), - free_regions(0), unclean_regions(0), - hum_regions(0), - count(0), unaccounted(0), - cur_alloc(0), total_free(0) - {} - bool doHeapRegion(HeapRegion *r) { - count++; - if (r->is_on_free_list()) free_regions++; - else if (r->is_on_unclean_list()) unclean_regions++; - else if (r->isHumongous()) hum_regions++; - else if (r->is_young()) young_regions++; - else if (r == cur) cur_alloc++; - else unaccounted++; - return false; - } - void print() { - total_free = free_regions + unclean_regions; - gclog_or_tty->print("%d regions\n", count); - gclog_or_tty->print("%d free: free_list = %d unclean = %d\n", - total_free, free_regions, unclean_regions); - gclog_or_tty->print("%d humongous %d young\n", - hum_regions, young_regions); - gclog_or_tty->print("%d cur_alloc\n", cur_alloc); - gclog_or_tty->print("UHOH unaccounted = %d\n", unaccounted); - } -}; - -void G1CollectedHeap::print_region_counts() { - SortHeapRegionClosure sc(_cur_alloc_region); - PrintHeapRegionClosure cl; - heap_region_iterate(&cl); - heap_region_iterate(&sc); - sc.print(); - print_region_accounting_info(); -}; - -bool G1CollectedHeap::regions_accounted_for() { - // TODO: regions accounting for young/survivor/tenured - return true; -} - -bool G1CollectedHeap::print_region_accounting_info() { - gclog_or_tty->print_cr("Free regions: %d (count: %d count list %d) (clean: %d unclean: %d).", - free_regions(), - count_free_regions(), count_free_regions_list(), - _free_region_list_size, _unclean_region_list.sz()); - gclog_or_tty->print_cr("cur_alloc: %d.", - (_cur_alloc_region == NULL ? 0 : 1)); - gclog_or_tty->print_cr("H regions: %d.", _num_humongous_regions); - - // TODO: check regions accounting for young/survivor/tenured - return true; -} +#ifdef ASSERT bool G1CollectedHeap::is_in_closed_subset(const void* p) const { HeapRegion* hr = heap_region_containing(p); @@ -5758,8 +5438,84 @@ bool G1CollectedHeap::is_in_closed_subset(const void* p) const { return hr->is_in(p); } } -#endif // !PRODUCT +#endif // ASSERT -void G1CollectedHeap::g1_unimplemented() { - // Unimplemented(); +class VerifyRegionListsClosure : public HeapRegionClosure { +private: + HumongousRegionSet* _humongous_set; + FreeRegionList* _free_list; + size_t _region_count; + +public: + VerifyRegionListsClosure(HumongousRegionSet* humongous_set, + FreeRegionList* free_list) : + _humongous_set(humongous_set), _free_list(free_list), + _region_count(0) { } + + size_t region_count() { return _region_count; } + + bool doHeapRegion(HeapRegion* hr) { + _region_count += 1; + + if (hr->continuesHumongous()) { + return false; + } + + if (hr->is_young()) { + // TODO + } else if (hr->startsHumongous()) { + _humongous_set->verify_next_region(hr); + } else if (hr->is_empty()) { + _free_list->verify_next_region(hr); + } + return false; + } +}; + +void G1CollectedHeap::verify_region_sets() { + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); + + // First, check the explicit lists. + _free_list.verify(); + { + // Given that a concurrent operation might be adding regions to + // the secondary free list we have to take the lock before + // verifying it. + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + _secondary_free_list.verify(); + } + _humongous_set.verify(); + + // If a concurrent region freeing operation is in progress it will + // be difficult to correctly attributed any free regions we come + // across to the correct free list given that they might belong to + // one of several (free_list, secondary_free_list, any local lists, + // etc.). So, if that's the case we will skip the rest of the + // verification operation. Alternatively, waiting for the concurrent + // operation to complete will have a non-trivial effect on the GC's + // operation (no concurrent operation will last longer than the + // interval between two calls to verification) and it might hide + // any issues that we would like to catch during testing. + if (free_regions_coming()) { + return; + } + + { + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + // Make sure we append the secondary_free_list on the free_list so + // that all free regions we will come across can be safely + // attributed to the free_list. + append_secondary_free_list(); + } + + // Finally, make sure that the region accounting in the lists is + // consistent with what we see in the heap. + _humongous_set.verify_start(); + _free_list.verify_start(); + + VerifyRegionListsClosure cl(&_humongous_set, &_free_list); + heap_region_iterate(&cl); + + _humongous_set.verify_end(); + _free_list.verify_end(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 0cec92564fe..709dbd62843 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1RemSet.hpp" -#include "gc_implementation/g1/heapRegion.hpp" +#include "gc_implementation/g1/heapRegionSets.hpp" #include "gc_implementation/parNew/parGCAllocBuffer.hpp" #include "memory/barrierSet.hpp" #include "memory/memRegion.hpp" @@ -66,8 +66,7 @@ typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion ) enum G1GCThreadGroups { G1CRGroup = 0, G1ZFGroup = 1, - G1CMGroup = 2, - G1CLGroup = 3 + G1CMGroup = 2 }; enum GCAllocPurpose { @@ -155,6 +154,7 @@ class G1CollectedHeap : public SharedHeap { friend class RefineCardTableEntryClosure; friend class G1PrepareCompactClosure; friend class RegionSorter; + friend class RegionResetter; friend class CountRCClosure; friend class EvacPopObjClosure; friend class G1ParCleanupCTTask; @@ -178,17 +178,20 @@ private: // The maximum part of _g1_storage that has ever been committed. MemRegion _g1_max_committed; - // The number of regions that are completely free. - size_t _free_regions; + // The master free list. It will satisfy all new region allocations. + MasterFreeRegionList _free_list; + + // The secondary free list which contains regions that have been + // freed up during the cleanup process. This will be appended to the + // master free list when appropriate. + SecondaryFreeRegionList _secondary_free_list; + + // It keeps track of the humongous regions. + MasterHumongousRegionSet _humongous_set; // The number of regions we could create by expansion. size_t _expansion_regions; - // Return the number of free regions in the heap (by direct counting.) - size_t count_free_regions(); - // Return the number of free regions on the free and unclean lists. - size_t count_free_regions_list(); - // The block offset table for the G1 heap. G1BlockOffsetSharedArray* _bot_shared; @@ -196,9 +199,6 @@ private: // lists, before and after full GC. void tear_down_region_lists(); void rebuild_region_lists(); - // This sets all non-empty regions to need zero-fill (which they will if - // they are empty after full collection.) - void set_used_regions_to_need_zero_fill(); // The sequence of all heap regions in the heap. HeapRegionSeq* _hrs; @@ -231,7 +231,7 @@ private: // Determines PLAB size for a particular allocation purpose. static size_t desired_plab_sz(GCAllocPurpose purpose); - // When called by par thread, require par_alloc_during_gc_lock() to be held. + // When called by par thread, requires the FreeList_lock to be held. void push_gc_alloc_region(HeapRegion* hr); // This should only be called single-threaded. Undeclares all GC alloc @@ -294,10 +294,11 @@ private: // line number, file, etc. #define heap_locking_asserts_err_msg(__extra_message) \ - err_msg("%s : Heap_lock %slocked, %sat a safepoint", \ + err_msg("%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ (__extra_message), \ - (!Heap_lock->owned_by_self()) ? "NOT " : "", \ - (!SafepointSynchronize::is_at_safepoint()) ? "NOT " : "") + BOOL_TO_STR(Heap_lock->owned_by_self()), \ + BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ + BOOL_TO_STR(Thread::current()->is_VM_thread())) #define assert_heap_locked() \ do { \ @@ -305,10 +306,11 @@ private: heap_locking_asserts_err_msg("should be holding the Heap_lock")); \ } while (0) -#define assert_heap_locked_or_at_safepoint() \ +#define assert_heap_locked_or_at_safepoint(__should_be_vm_thread) \ do { \ assert(Heap_lock->owned_by_self() || \ - SafepointSynchronize::is_at_safepoint(), \ + (SafepointSynchronize::is_at_safepoint() && \ + ((__should_be_vm_thread) == Thread::current()->is_VM_thread())), \ heap_locking_asserts_err_msg("should be holding the Heap_lock or " \ "should be at a safepoint")); \ } while (0) @@ -335,9 +337,10 @@ private: "should not be at a safepoint")); \ } while (0) -#define assert_at_safepoint() \ +#define assert_at_safepoint(__should_be_vm_thread) \ do { \ - assert(SafepointSynchronize::is_at_safepoint(), \ + assert(SafepointSynchronize::is_at_safepoint() && \ + ((__should_be_vm_thread) == Thread::current()->is_VM_thread()), \ heap_locking_asserts_err_msg("should be at a safepoint")); \ } while (0) @@ -362,31 +365,41 @@ protected: // The current policy object for the collector. G1CollectorPolicy* _g1_policy; - // Parallel allocation lock to protect the current allocation region. - Mutex _par_alloc_during_gc_lock; - Mutex* par_alloc_during_gc_lock() { return &_par_alloc_during_gc_lock; } + // This is the second level of trying to allocate a new region. If + // new_region_work didn't find a region in the free_list, this call + // will check whether there's anything available in the + // secondary_free_list and/or wait for more regions to appear in that + // list, if _free_regions_coming is set. + HeapRegion* new_region_try_secondary_free_list(size_t word_size); - // If possible/desirable, allocate a new HeapRegion for normal object - // allocation sufficient for an allocation of the given "word_size". - // If "do_expand" is true, will attempt to expand the heap if necessary - // to to satisfy the request. If "zero_filled" is true, requires a - // zero-filled region. - // (Returning NULL will trigger a GC.) - virtual HeapRegion* newAllocRegion_work(size_t word_size, - bool do_expand, - bool zero_filled); + // It will try to allocate a single non-humongous HeapRegion + // sufficient for an allocation of the given word_size. If + // do_expand is true, it will attempt to expand the heap if + // necessary to satisfy the allocation request. Note that word_size + // is only used to make sure that we expand sufficiently but, given + // that the allocation request is assumed not to be humongous, + // having word_size is not strictly necessary (expanding by a single + // region will always be sufficient). But let's keep that parameter + // in case we need it in the future. + HeapRegion* new_region_work(size_t word_size, bool do_expand); - virtual HeapRegion* newAllocRegion(size_t word_size, - bool zero_filled = true) { - return newAllocRegion_work(word_size, false, zero_filled); + // It will try to allocate a new region to be used for allocation by + // mutator threads. It will not try to expand the heap if not region + // is available. + HeapRegion* new_alloc_region(size_t word_size) { + return new_region_work(word_size, false /* do_expand */); } - virtual HeapRegion* newAllocRegionWithExpansion(int purpose, - size_t word_size, - bool zero_filled = true); + + // It will try to allocate a new region to be used for allocation by + // a GC thread. It will try to expand the heap if no region is + // available. + HeapRegion* new_gc_alloc_region(int purpose, size_t word_size); + + int humongous_obj_allocate_find_first(size_t num_regions, size_t word_size); // Attempt to allocate an object of the given (very large) "word_size". // Returns "NULL" on failure. - virtual HeapWord* humongous_obj_allocate(size_t word_size); + HeapWord* humongous_obj_allocate(size_t word_size); // The following two methods, allocate_new_tlab() and // mem_allocate(), are the two main entry points from the runtime @@ -430,7 +443,8 @@ protected: bool* gc_overhead_limit_was_exceeded); // The following methods, allocate_from_cur_allocation_region(), - // attempt_allocation(), replace_cur_alloc_region_and_allocate(), + // attempt_allocation(), attempt_allocation_locked(), + // replace_cur_alloc_region_and_allocate(), // attempt_allocation_slow(), and attempt_allocation_humongous() // have very awkward pre- and post-conditions with respect to // locking: @@ -481,20 +495,30 @@ protected: // successfully manage to allocate it, or NULL. // It tries to satisfy an allocation request out of the current - // allocating region, which is passed as a parameter. It assumes - // that the caller has checked that the current allocating region is - // not NULL. Given that the caller has to check the current - // allocating region for at least NULL, it might as well pass it as - // the first parameter so that the method doesn't have to read it - // from the _cur_alloc_region field again. + // alloc region, which is passed as a parameter. It assumes that the + // caller has checked that the current alloc region is not NULL. + // Given that the caller has to check the current alloc region for + // at least NULL, it might as well pass it as the first parameter so + // that the method doesn't have to read it from the + // _cur_alloc_region field again. It is called from both + // attempt_allocation() and attempt_allocation_locked() and the + // with_heap_lock parameter indicates whether the caller was holding + // the heap lock when it called it or not. inline HeapWord* allocate_from_cur_alloc_region(HeapRegion* cur_alloc_region, - size_t word_size); + size_t word_size, + bool with_heap_lock); - // It attempts to allocate out of the current alloc region. If that - // fails, it retires the current alloc region (if there is one), - // tries to get a new one and retries the allocation. + // First-level of allocation slow path: it attempts to allocate out + // of the current alloc region in a lock-free manner using a CAS. If + // that fails it takes the Heap_lock and calls + // attempt_allocation_locked() for the second-level slow path. inline HeapWord* attempt_allocation(size_t word_size); + // Second-level of allocation slow path: while holding the Heap_lock + // it tries to allocate out of the current alloc region and, if that + // fails, tries to allocate out of a new current alloc region. + inline HeapWord* attempt_allocation_locked(size_t word_size); + // It assumes that the current alloc region has been retired and // tries to allocate a new one. If it's successful, it performs the // allocation out of the new current alloc region and updates @@ -506,11 +530,11 @@ protected: bool do_dirtying, bool can_expand); - // The slow path when we are unable to allocate a new current alloc - // region to satisfy an allocation request (i.e., when - // attempt_allocation() fails). It will try to do an evacuation - // pause, which might stall due to the GC locker, and retry the - // allocation attempt when appropriate. + // Third-level of allocation slow path: when we are unable to + // allocate a new current alloc region to satisfy an allocation + // request (i.e., when attempt_allocation_locked() fails). It will + // try to do an evacuation pause, which might stall due to the GC + // locker, and retry the allocation attempt when appropriate. HeapWord* attempt_allocation_slow(size_t word_size); // The method that tries to satisfy a humongous allocation @@ -749,20 +773,29 @@ protected: // Invoke "save_marks" on all heap regions. void save_marks(); - // Free a heap region. - void free_region(HeapRegion* hr); - // A component of "free_region", exposed for 'batching'. - // All the params after "hr" are out params: the used bytes of the freed - // region(s), the number of H regions cleared, the number of regions - // freed, and pointers to the head and tail of a list of freed contig - // regions, linked throught the "next_on_unclean_list" field. - void free_region_work(HeapRegion* hr, - size_t& pre_used, - size_t& cleared_h, - size_t& freed_regions, - UncleanRegionList* list, - bool par = false); + // It frees a non-humongous region by initializing its contents and + // adding it to the free list that's passed as a parameter (this is + // usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. + void free_region(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + bool par); + // It frees a humongous region by collapsing it into individual + // regions and calling free_region() for each of them. The freed + // regions will be added to the free list that's passed as a parameter + // (this is usually a local list which will be appended to the + // master free list later). The used bytes of freed regions are + // accumulated in pre_used. If par is true, the region's RSet will + // not be freed up. The assumption is that this will be done later. + void free_humongous_region(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par); // The concurrent marker (and the thread it runs in.) ConcurrentMark* _cm; @@ -772,9 +805,6 @@ protected: // The concurrent refiner. ConcurrentG1Refine* _cg1r; - // The concurrent zero-fill thread. - ConcurrentZFThread* _czft; - // The parallel task queues RefToScanQueueSet *_task_queues; @@ -826,7 +856,6 @@ protected: void finalize_for_evac_failure(); // An attempt to evacuate "obj" has failed; take necessary steps. - void handle_evacuation_failure(oop obj); oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj); void handle_evacuation_failure_common(oop obj, markOop m); @@ -867,9 +896,7 @@ protected: SubTasksDone* _process_strong_tasks; - // List of regions which require zero filling. - UncleanRegionList _unclean_region_list; - bool _unclean_regions_coming; + volatile bool _free_regions_coming; public: @@ -992,71 +1019,64 @@ public: size_t max_regions(); // The number of regions that are completely free. - size_t free_regions(); + size_t free_regions() { + return _free_list.length(); + } // The number of regions that are not completely free. size_t used_regions() { return n_regions() - free_regions(); } - // True iff the ZF thread should run. - bool should_zf(); - // The number of regions available for "regular" expansion. size_t expansion_regions() { return _expansion_regions; } -#ifndef PRODUCT - bool regions_accounted_for(); - bool print_region_accounting_info(); - void print_region_counts(); -#endif + // verify_region_sets() performs verification over the region + // lists. It will be compiled in the product code to be used when + // necessary (i.e., during heap verification). + void verify_region_sets(); - HeapRegion* alloc_region_from_unclean_list(bool zero_filled); - HeapRegion* alloc_region_from_unclean_list_locked(bool zero_filled); + // verify_region_sets_optional() is planted in the code for + // list verification in non-product builds (and it can be enabled in + // product builds by definning HEAP_REGION_SET_FORCE_VERIFY to be 1). +#if HEAP_REGION_SET_FORCE_VERIFY + void verify_region_sets_optional() { + verify_region_sets(); + } +#else // HEAP_REGION_SET_FORCE_VERIFY + void verify_region_sets_optional() { } +#endif // HEAP_REGION_SET_FORCE_VERIFY - void put_region_on_unclean_list(HeapRegion* r); - void put_region_on_unclean_list_locked(HeapRegion* r); +#ifdef ASSERT + bool is_on_free_list(HeapRegion* hr) { + return hr->containing_set() == &_free_list; + } - void prepend_region_list_on_unclean_list(UncleanRegionList* list); - void prepend_region_list_on_unclean_list_locked(UncleanRegionList* list); + bool is_on_humongous_set(HeapRegion* hr) { + return hr->containing_set() == &_humongous_set; +} +#endif // ASSERT - void set_unclean_regions_coming(bool b); - void set_unclean_regions_coming_locked(bool b); - // Wait for cleanup to be complete. - void wait_for_cleanup_complete(); - // Like above, but assumes that the calling thread owns the Heap_lock. - void wait_for_cleanup_complete_locked(); + // Wrapper for the region list operations that can be called from + // methods outside this class. - // Return the head of the unclean list. - HeapRegion* peek_unclean_region_list_locked(); - // Remove and return the head of the unclean list. - HeapRegion* pop_unclean_region_list_locked(); + void secondary_free_list_add_as_tail(FreeRegionList* list) { + _secondary_free_list.add_as_tail(list); + } - // List of regions which are zero filled and ready for allocation. - HeapRegion* _free_region_list; - // Number of elements on the free list. - size_t _free_region_list_size; + void append_secondary_free_list() { + _free_list.add_as_tail(&_secondary_free_list); + } - // If the head of the unclean list is ZeroFilled, move it to the free - // list. - bool move_cleaned_region_to_free_list_locked(); - bool move_cleaned_region_to_free_list(); + void append_secondary_free_list_if_not_empty() { + if (!_secondary_free_list.is_empty()) { + MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); + append_secondary_free_list(); + } + } - void put_free_region_on_list_locked(HeapRegion* r); - void put_free_region_on_list(HeapRegion* r); - - // Remove and return the head element of the free list. - HeapRegion* pop_free_region_list_locked(); - - // If "zero_filled" is true, we first try the free list, then we try the - // unclean list, zero-filling the result. If "zero_filled" is false, we - // first try the unclean list, then the zero-filled list. - HeapRegion* alloc_free_region_from_lists(bool zero_filled); - - // Verify the integrity of the region lists. - void remove_allocated_regions_from_lists(); - bool verify_region_lists(); - bool verify_region_lists_locked(); - size_t unclean_region_list_length(); - size_t free_region_list_length(); + void set_free_regions_coming(); + void reset_free_regions_coming(); + bool free_regions_coming() { return _free_regions_coming; } + void wait_while_free_regions_coming(); // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the @@ -1075,23 +1095,24 @@ public: // True iff a evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } - // Free a region if it is totally full of garbage. Returns the number of - // bytes freed (0 ==> didn't free it). - size_t free_region_if_totally_empty(HeapRegion *hr); - void free_region_if_totally_empty_work(HeapRegion *hr, - size_t& pre_used, - size_t& cleared_h_regions, - size_t& freed_regions, - UncleanRegionList* list, - bool par = false); - - // If we've done free region work that yields the given changes, update - // the relevant global variables. - void finish_free_region_work(size_t pre_used, - size_t cleared_h_regions, - size_t freed_regions, - UncleanRegionList* list); + // It will free a region if it has allocated objects in it that are + // all dead. It calls either free_region() or + // free_humongous_region() depending on the type of the region that + // is passed to it. + void free_region_if_totally_empty(HeapRegion* hr, + size_t* pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par); + // It appends the free list to the master free list and updates the + // master humongous list according to the contents of the proxy + // list. It also adjusts the total used bytes according to pre_used + // (if par is true, it will do so by taking the ParGCRareEvent_lock). + void update_sets_after_freeing_regions(size_t pre_used, + FreeRegionList* free_list, + HumongousRegionSet* humongous_proxy_set, + bool par); // Returns "TRUE" iff "p" points into the allocated area of the heap. virtual bool is_in(const void* p) const; @@ -1304,8 +1325,6 @@ public: return true; } - virtual bool allocs_are_zero_filled(); - // The boundary between a "large" and "small" array of primitives, in // words. virtual size_t large_typearray_limit(); @@ -1536,13 +1555,6 @@ public: protected: size_t _max_heap_capacity; - -public: - // Temporary: call to mark things unimplemented for the G1 heap (e.g., - // MemoryService). In productization, we can make this assert false - // to catch such places (as well as searching for calls to this...) - static void g1_unimplemented(); - }; #define use_local_bitmaps 1 diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 85812877f87..43c12272c7e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" -#include "gc_implementation/g1/heapRegionSeq.hpp" +#include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "utilities/taskqueue.hpp" // Inline functions for G1CollectedHeap @@ -63,10 +63,12 @@ inline bool G1CollectedHeap::obj_in_cs(oop obj) { // assumptions of this method (and other related ones). inline HeapWord* G1CollectedHeap::allocate_from_cur_alloc_region(HeapRegion* cur_alloc_region, - size_t word_size) { - assert_heap_locked_and_not_at_safepoint(); + size_t word_size, + bool with_heap_lock) { + assert_not_at_safepoint(); + assert(with_heap_lock == Heap_lock->owned_by_self(), + "with_heap_lock and Heap_lock->owned_by_self() should be a tautology"); assert(cur_alloc_region != NULL, "pre-condition of the method"); - assert(cur_alloc_region == _cur_alloc_region, "pre-condition of the method"); assert(cur_alloc_region->is_young(), "we only support young current alloc regions"); assert(!isHumongous(word_size), "allocate_from_cur_alloc_region() " @@ -76,20 +78,24 @@ G1CollectedHeap::allocate_from_cur_alloc_region(HeapRegion* cur_alloc_region, assert(!cur_alloc_region->is_empty(), err_msg("region ["PTR_FORMAT","PTR_FORMAT"] should not be empty", cur_alloc_region->bottom(), cur_alloc_region->end())); - // This allocate method does BOT updates and we don't need them in - // the young generation. This will be fixed in the near future by - // CR 6994297. - HeapWord* result = cur_alloc_region->allocate(word_size); + HeapWord* result = cur_alloc_region->par_allocate_no_bot_updates(word_size); if (result != NULL) { assert(is_in(result), "result should be in the heap"); - Heap_lock->unlock(); + if (with_heap_lock) { + Heap_lock->unlock(); + } + assert_heap_not_locked(); // Do the dirtying after we release the Heap_lock. dirty_young_block(result, word_size); return result; } - assert_heap_locked(); + if (with_heap_lock) { + assert_heap_locked(); + } else { + assert_heap_not_locked(); + } return NULL; } @@ -97,26 +103,75 @@ G1CollectedHeap::allocate_from_cur_alloc_region(HeapRegion* cur_alloc_region, // assumptions of this method (and other related ones). inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size) { - assert_heap_locked_and_not_at_safepoint(); + assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "attempt_allocation() should not be called " "for humongous allocation requests"); HeapRegion* cur_alloc_region = _cur_alloc_region; if (cur_alloc_region != NULL) { HeapWord* result = allocate_from_cur_alloc_region(cur_alloc_region, - word_size); + word_size, + false /* with_heap_lock */); + assert_heap_not_locked(); + if (result != NULL) { + return result; + } + } + + // Our attempt to allocate lock-free failed as the current + // allocation region is either NULL or full. So, we'll now take the + // Heap_lock and retry. + Heap_lock->lock(); + + HeapWord* result = attempt_allocation_locked(word_size); + if (result != NULL) { + assert_heap_not_locked(); + return result; + } + + assert_heap_locked(); + return NULL; +} + +inline void +G1CollectedHeap::retire_cur_alloc_region_common(HeapRegion* cur_alloc_region) { + assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); + assert(cur_alloc_region != NULL && cur_alloc_region == _cur_alloc_region, + "pre-condition of the call"); + assert(cur_alloc_region->is_young(), + "we only support young current alloc regions"); + + // The region is guaranteed to be young + g1_policy()->add_region_to_incremental_cset_lhs(cur_alloc_region); + _summary_bytes_used += cur_alloc_region->used(); + _cur_alloc_region = NULL; +} + +inline HeapWord* +G1CollectedHeap::attempt_allocation_locked(size_t word_size) { + assert_heap_locked_and_not_at_safepoint(); + assert(!isHumongous(word_size), "attempt_allocation_locked() " + "should not be called for humongous allocation requests"); + + // First, reread the current alloc region and retry the allocation + // in case somebody replaced it while we were waiting to get the + // Heap_lock. + HeapRegion* cur_alloc_region = _cur_alloc_region; + if (cur_alloc_region != NULL) { + HeapWord* result = allocate_from_cur_alloc_region( + cur_alloc_region, word_size, + true /* with_heap_lock */); if (result != NULL) { assert_heap_not_locked(); return result; } - assert_heap_locked(); - - // Since we couldn't successfully allocate into it, retire the - // current alloc region. + // We failed to allocate out of the current alloc region, so let's + // retire it before getting a new one. retire_cur_alloc_region(cur_alloc_region); } + assert_heap_locked(); // Try to get a new region and allocate out of it HeapWord* result = replace_cur_alloc_region_and_allocate(word_size, false, /* at_safepoint */ @@ -131,20 +186,6 @@ G1CollectedHeap::attempt_allocation(size_t word_size) { return NULL; } -inline void -G1CollectedHeap::retire_cur_alloc_region_common(HeapRegion* cur_alloc_region) { - assert_heap_locked_or_at_safepoint(); - assert(cur_alloc_region != NULL && cur_alloc_region == _cur_alloc_region, - "pre-condition of the call"); - assert(cur_alloc_region->is_young(), - "we only support young current alloc regions"); - - // The region is guaranteed to be young - g1_policy()->add_region_to_incremental_cset_lhs(cur_alloc_region); - _summary_bytes_used += cur_alloc_region->used(); - _cur_alloc_region = NULL; -} - // It dirties the cards that cover the block so that so that the post // write barrier never queues anything when updating objects on this // block. It is assumed (and in fact we assert) that the block diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 59f790c7225..63a5d63c780 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2875,8 +2875,6 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set( // Adjust for expansion and slop. max_live_bytes = max_live_bytes + expansion_bytes; - assert(_g1->regions_accounted_for(), "Region leakage!"); - HeapRegion* hr; if (in_young_gc_mode()) { double young_start_time_sec = os::elapsedTime(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index 765ef8bc62f..1c6c5df31c9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,6 +113,7 @@ void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, Threads::gc_epilogue(); CodeCache::gc_epilogue(); + JvmtiExport::gc_epilogue(); // refs processing: clean slate GenMarkSweep::_ref_processor = NULL; @@ -180,26 +181,46 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, } class G1PrepareCompactClosure: public HeapRegionClosure { + G1CollectedHeap* _g1h; ModRefBarrierSet* _mrbs; CompactPoint _cp; + size_t _pre_used; + FreeRegionList _free_list; + HumongousRegionSet _humongous_proxy_set; void free_humongous_region(HeapRegion* hr) { - HeapWord* bot = hr->bottom(); HeapWord* end = hr->end(); assert(hr->startsHumongous(), "Only the start of a humongous region should be freed."); - G1CollectedHeap::heap()->free_region(hr); + _g1h->free_humongous_region(hr, &_pre_used, &_free_list, + &_humongous_proxy_set, false /* par */); + // Do we also need to do this for the continues humongous regions + // we just collapsed? hr->prepare_for_compaction(&_cp); // Also clear the part of the card table that will be unused after // compaction. - _mrbs->clear(MemRegion(hr->compaction_top(), hr->end())); + _mrbs->clear(MemRegion(hr->compaction_top(), end)); } public: - G1PrepareCompactClosure(CompactibleSpace* cs) : + G1PrepareCompactClosure(CompactibleSpace* cs) + : _g1h(G1CollectedHeap::heap()), + _mrbs(G1CollectedHeap::heap()->mr_bs()), _cp(NULL, cs, cs->initialize_threshold()), - _mrbs(G1CollectedHeap::heap()->mr_bs()) - {} + _pre_used(0), + _free_list("Local Free List for G1MarkSweep"), + _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } + + void update_sets() { + // We'll recalculate total used bytes and recreate the free list + // at the end of the GC, so no point in updating those values here. + _g1h->update_sets_after_freeing_regions(0, /* pre_used */ + NULL, /* free_list */ + &_humongous_proxy_set, + false /* par */); + _free_list.remove_all(); + } + bool doHeapRegion(HeapRegion* hr) { if (hr->isHumongous()) { if (hr->startsHumongous()) { @@ -265,6 +286,7 @@ void G1MarkSweep::mark_sweep_phase2() { G1PrepareCompactClosure blk(sp); g1h->heap_region_iterate(&blk); + blk.update_sets(); CompactPoint perm_cp(pg, NULL, NULL); pg->prepare_for_compaction(&perm_cp); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index e9d908e4be2..b6fcf614fcc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,21 +75,12 @@ "(0 means do not periodically generate this info); " \ "it also requires -XX:+G1SummarizeRSetStats") \ \ - diagnostic(bool, G1SummarizeZFStats, false, \ - "Summarize zero-filling info") \ - \ diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ \ product(intx, G1MarkRegionStackSize, 1024 * 1024, \ "Size of the region stack for concurrent marking.") \ \ - develop(bool, G1ConcZeroFill, true, \ - "If true, run concurrent zero-filling thread") \ - \ - develop(intx, G1ConcZFMaxRegions, 1, \ - "Stop zero-filling when # of zf'd regions reaches") \ - \ develop(bool, G1SATBBarrierPrintNullPreVals, false, \ "If true, count frac of ptr writes with null pre-vals.") \ \ @@ -99,6 +90,13 @@ develop(intx, G1SATBProcessCompletedThreshold, 20, \ "Number of completed buffers that triggers log processing.") \ \ + product(uintx, G1SATBBufferEnqueueingThresholdPercent, 60, \ + "Before enqueueing them, each mutator thread tries to do some " \ + "filtering on the SATB buffers it generates. If post-filtering " \ + "the percentage of retained entries is over this threshold " \ + "the buffer will be enqueued for processing. A value of 0 " \ + "specifies that mutator threads should not do such filtering.") \ + \ develop(intx, G1ExtraRegionSurvRate, 33, \ "If the young survival rate is S, and there's room left in " \ "to-space, we will allow regions whose survival rate is up to " \ @@ -282,7 +280,20 @@ "Size of a work unit of cards claimed by a worker thread" \ "during RSet scanning.") \ \ - develop(bool, ReduceInitialCardMarksForG1, false, \ + develop(uintx, G1SecondaryFreeListAppendLength, 5, \ + "The number of regions we will add to the secondary free list " \ + "at every append operation") \ + \ + develop(bool, G1ConcRegionFreeingVerbose, false, \ + "Enables verboseness during concurrent region freeing") \ + \ + develop(bool, G1StressConcRegionFreeing, false, \ + "It stresses the concurrent region freeing operation") \ + \ + develop(uintx, G1StressConcRegionFreeingDelayMillis, 0, \ + "Artificial delay during concurrent region freeing") \ + \ + develop(bool, ReduceInitialCardMarksForG1, false, \ "When ReduceInitialCardMarks is true, this flag setting " \ " controls whether G1 allows the RICM optimization") diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index ab022668384..b25f7cf5290 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc_implementation/g1/concurrentZFThread.hpp" #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -348,22 +347,20 @@ HeapRegion::new_dcto_closure(OopClosure* cl, } void HeapRegion::hr_clear(bool par, bool clear_space) { - _humongous_type = NotHumongous; - _humongous_start_region = NULL; + assert(_humongous_type == NotHumongous, + "we should have already filtered out humongous regions"); + assert(_humongous_start_region == NULL, + "we should have already filtered out humongous regions"); + assert(_end == _orig_end, + "we should have already filtered out humongous regions"); + _in_collection_set = false; _is_gc_alloc_region = false; - // Age stuff (if parallel, this will be done separately, since it needs - // to be sequential). - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - set_young_index_in_cset(-1); uninstall_surv_rate_group(); set_young_type(NotYoung); - // In case it had been the start of a humongous sequence, reset its end. - set_end(_orig_end); - if (!par) { // If this is parallel, this will be done later. HeapRegionRemSet* hrrs = rem_set(); @@ -386,26 +383,49 @@ void HeapRegion::calc_gc_efficiency() { } // -void HeapRegion::set_startsHumongous(HeapWord* new_end) { +void HeapRegion::set_startsHumongous(HeapWord* new_top, HeapWord* new_end) { + assert(!isHumongous(), "sanity / pre-condition"); assert(end() == _orig_end, "Should be normal before the humongous object allocation"); assert(top() == bottom(), "should be empty"); + assert(bottom() <= new_top && new_top <= new_end, "pre-condition"); _humongous_type = StartsHumongous; _humongous_start_region = this; set_end(new_end); - _offsets.set_for_starts_humongous(new_end); + _offsets.set_for_starts_humongous(new_top); } -void HeapRegion::set_continuesHumongous(HeapRegion* start) { +void HeapRegion::set_continuesHumongous(HeapRegion* first_hr) { + assert(!isHumongous(), "sanity / pre-condition"); assert(end() == _orig_end, "Should be normal before the humongous object allocation"); assert(top() == bottom(), "should be empty"); - assert(start->startsHumongous(), "pre-condition"); + assert(first_hr->startsHumongous(), "pre-condition"); _humongous_type = ContinuesHumongous; - _humongous_start_region = start; + _humongous_start_region = first_hr; +} + +void HeapRegion::set_notHumongous() { + assert(isHumongous(), "pre-condition"); + + if (startsHumongous()) { + assert(top() <= end(), "pre-condition"); + set_end(_orig_end); + if (top() > end()) { + // at least one "continues humongous" region after it + set_top(end()); + } + } else { + // continues humongous + assert(end() == _orig_end, "sanity"); + } + + assert(capacity() == (size_t) HeapRegion::GrainBytes, "pre-condition"); + _humongous_type = NotHumongous; + _humongous_start_region = NULL; } bool HeapRegion::claimHeapRegion(jint claimValue) { @@ -442,15 +462,6 @@ HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) { return low; } -void HeapRegion::set_next_on_unclean_list(HeapRegion* r) { - assert(r == NULL || r->is_on_unclean_list(), "Malformed unclean list."); - _next_in_special_set = r; -} - -void HeapRegion::set_on_unclean_list(bool b) { - _is_on_unclean_list = b; -} - void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) { G1OffsetTableContigSpace::initialize(mr, false, mangle_space); hr_clear(false/*par*/, clear_space); @@ -468,15 +479,16 @@ HeapRegion(G1BlockOffsetSharedArray* sharedOffsetArray, _hrs_index(-1), _humongous_type(NotHumongous), _humongous_start_region(NULL), _in_collection_set(false), _is_gc_alloc_region(false), - _is_on_free_list(false), _is_on_unclean_list(false), _next_in_special_set(NULL), _orig_end(NULL), _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _sort_index(-1), _young_type(NotYoung), _next_young_region(NULL), - _next_dirty_cards_region(NULL), - _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), - _rem_set(NULL), _zfs(NotZeroFilled), - _recorded_rs_length(0), _predicted_elapsed_time_ms(0), + _next_dirty_cards_region(NULL), _next(NULL), _pending_removal(false), +#ifdef ASSERT + _containing_set(NULL), +#endif // ASSERT + _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), + _rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0), _predicted_bytes_to_copy(0) { _orig_end = mr.end(); @@ -551,86 +563,6 @@ void HeapRegion::oop_before_save_marks_iterate(OopClosure* cl) { oops_in_mr_iterate(MemRegion(bottom(), saved_mark_word()), cl); } -#ifdef DEBUG -HeapWord* HeapRegion::allocate(size_t size) { - jint state = zero_fill_state(); - assert(!G1CollectedHeap::heap()->allocs_are_zero_filled() || - zero_fill_is_allocated(), - "When ZF is on, only alloc in ZF'd regions"); - return G1OffsetTableContigSpace::allocate(size); -} -#endif - -void HeapRegion::set_zero_fill_state_work(ZeroFillState zfs) { - assert(ZF_mon->owned_by_self() || - Universe::heap()->is_gc_active(), - "Must hold the lock or be a full GC to modify."); -#ifdef ASSERT - if (top() != bottom() && zfs != Allocated) { - ResourceMark rm; - stringStream region_str; - print_on(®ion_str); - assert(top() == bottom() || zfs == Allocated, - err_msg("Region must be empty, or we must be setting it to allocated. " - "_zfs=%d, zfs=%d, region: %s", _zfs, zfs, region_str.as_string())); - } -#endif - _zfs = zfs; -} - -void HeapRegion::set_zero_fill_complete() { - set_zero_fill_state_work(ZeroFilled); - if (ZF_mon->owned_by_self()) { - ZF_mon->notify_all(); - } -} - - -void HeapRegion::ensure_zero_filled() { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - ensure_zero_filled_locked(); -} - -void HeapRegion::ensure_zero_filled_locked() { - assert(ZF_mon->owned_by_self(), "Precondition"); - bool should_ignore_zf = SafepointSynchronize::is_at_safepoint(); - assert(should_ignore_zf || Heap_lock->is_locked(), - "Either we're in a GC or we're allocating a region."); - switch (zero_fill_state()) { - case HeapRegion::NotZeroFilled: - set_zero_fill_in_progress(Thread::current()); - { - ZF_mon->unlock(); - Copy::fill_to_words(bottom(), capacity()/HeapWordSize); - ZF_mon->lock_without_safepoint_check(); - } - // A trap. - guarantee(zero_fill_state() == HeapRegion::ZeroFilling - && zero_filler() == Thread::current(), - "AHA! Tell Dave D if you see this..."); - set_zero_fill_complete(); - // gclog_or_tty->print_cr("Did sync ZF."); - ConcurrentZFThread::note_sync_zfs(); - break; - case HeapRegion::ZeroFilling: - if (should_ignore_zf) { - // We can "break" the lock and take over the work. - Copy::fill_to_words(bottom(), capacity()/HeapWordSize); - set_zero_fill_complete(); - ConcurrentZFThread::note_sync_zfs(); - break; - } else { - ConcurrentZFThread::wait_for_ZF_completed(this); - } - case HeapRegion::ZeroFilled: - // Nothing to do. - break; - case HeapRegion::Allocated: - guarantee(false, "Should not call on allocated regions."); - } - assert(zero_fill_state() == HeapRegion::ZeroFilled, "Post"); -} - HeapWord* HeapRegion::object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl) { @@ -782,9 +714,6 @@ void HeapRegion::verify(bool allow_dirty) const { verify(allow_dirty, /* use_prev_marking */ true, /* failures */ &dummy); } -#define OBJ_SAMPLE_INTERVAL 0 -#define BLOCK_SAMPLE_INTERVAL 100 - // This really ought to be commoned up into OffsetTableContigSpace somehow. // We would need a mechanism to make that code skip dead objects. @@ -795,83 +724,125 @@ void HeapRegion::verify(bool allow_dirty, *failures = false; HeapWord* p = bottom(); HeapWord* prev_p = NULL; - int objs = 0; - int blocks = 0; VerifyLiveClosure vl_cl(g1, use_prev_marking); bool is_humongous = isHumongous(); + bool do_bot_verify = !is_young(); size_t object_num = 0; while (p < top()) { - size_t size = oop(p)->size(); - if (is_humongous != g1->isHumongous(size)) { + oop obj = oop(p); + size_t obj_size = obj->size(); + object_num += 1; + + if (is_humongous != g1->isHumongous(obj_size)) { gclog_or_tty->print_cr("obj "PTR_FORMAT" is of %shumongous size (" SIZE_FORMAT" words) in a %shumongous region", - p, g1->isHumongous(size) ? "" : "non-", - size, is_humongous ? "" : "non-"); + p, g1->isHumongous(obj_size) ? "" : "non-", + obj_size, is_humongous ? "" : "non-"); *failures = true; + return; } - object_num += 1; - if (blocks == BLOCK_SAMPLE_INTERVAL) { - HeapWord* res = block_start_const(p + (size/2)); - if (p != res) { - gclog_or_tty->print_cr("offset computation 1 for "PTR_FORMAT" and " - SIZE_FORMAT" returned "PTR_FORMAT, - p, size, res); - *failures = true; - return; - } - blocks = 0; - } else { - blocks++; + + // If it returns false, verify_for_object() will output the + // appropriate messasge. + if (do_bot_verify && !_offsets.verify_for_object(p, obj_size)) { + *failures = true; + return; } - if (objs == OBJ_SAMPLE_INTERVAL) { - oop obj = oop(p); - if (!g1->is_obj_dead_cond(obj, this, use_prev_marking)) { - if (obj->is_oop()) { - klassOop klass = obj->klass(); - if (!klass->is_perm()) { - gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " - "not in perm", klass, obj); - *failures = true; - return; - } else if (!klass->is_klass()) { - gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " - "not a klass", klass, obj); - *failures = true; - return; - } else { - vl_cl.set_containing_obj(obj); - obj->oop_iterate(&vl_cl); - if (vl_cl.failures()) { - *failures = true; - } - if (G1MaxVerifyFailures >= 0 && - vl_cl.n_failures() >= G1MaxVerifyFailures) { - return; - } - } - } else { - gclog_or_tty->print_cr(PTR_FORMAT" no an oop", obj); + + if (!g1->is_obj_dead_cond(obj, this, use_prev_marking)) { + if (obj->is_oop()) { + klassOop klass = obj->klass(); + if (!klass->is_perm()) { + gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " + "not in perm", klass, obj); *failures = true; return; + } else if (!klass->is_klass()) { + gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " + "not a klass", klass, obj); + *failures = true; + return; + } else { + vl_cl.set_containing_obj(obj); + obj->oop_iterate(&vl_cl); + if (vl_cl.failures()) { + *failures = true; + } + if (G1MaxVerifyFailures >= 0 && + vl_cl.n_failures() >= G1MaxVerifyFailures) { + return; + } } - } - objs = 0; - } else { - objs++; - } - prev_p = p; - p += size; - } - HeapWord* rend = end(); - HeapWord* rtop = top(); - if (rtop < rend) { - HeapWord* res = block_start_const(rtop + (rend - rtop) / 2); - if (res != rtop) { - gclog_or_tty->print_cr("offset computation 2 for "PTR_FORMAT" and " - PTR_FORMAT" returned "PTR_FORMAT, - rtop, rend, res); + } else { + gclog_or_tty->print_cr(PTR_FORMAT" no an oop", obj); *failures = true; return; + } + } + prev_p = p; + p += obj_size; + } + + if (p != top()) { + gclog_or_tty->print_cr("end of last object "PTR_FORMAT" " + "does not match top "PTR_FORMAT, p, top()); + *failures = true; + return; + } + + HeapWord* the_end = end(); + assert(p == top(), "it should still hold"); + // Do some extra BOT consistency checking for addresses in the + // range [top, end). BOT look-ups in this range should yield + // top. No point in doing that if top == end (there's nothing there). + if (p < the_end) { + // Look up top + HeapWord* addr_1 = p; + HeapWord* b_start_1 = _offsets.block_start_const(addr_1); + if (b_start_1 != p) { + gclog_or_tty->print_cr("BOT look up for top: "PTR_FORMAT" " + " yielded "PTR_FORMAT", expecting "PTR_FORMAT, + addr_1, b_start_1, p); + *failures = true; + return; + } + + // Look up top + 1 + HeapWord* addr_2 = p + 1; + if (addr_2 < the_end) { + HeapWord* b_start_2 = _offsets.block_start_const(addr_2); + if (b_start_2 != p) { + gclog_or_tty->print_cr("BOT look up for top + 1: "PTR_FORMAT" " + " yielded "PTR_FORMAT", expecting "PTR_FORMAT, + addr_2, b_start_2, p); + *failures = true; + return; + } + } + + // Look up an address between top and end + size_t diff = pointer_delta(the_end, p) / 2; + HeapWord* addr_3 = p + diff; + if (addr_3 < the_end) { + HeapWord* b_start_3 = _offsets.block_start_const(addr_3); + if (b_start_3 != p) { + gclog_or_tty->print_cr("BOT look up for top + diff: "PTR_FORMAT" " + " yielded "PTR_FORMAT", expecting "PTR_FORMAT, + addr_3, b_start_3, p); + *failures = true; + return; + } + } + + // Loook up end - 1 + HeapWord* addr_4 = the_end - 1; + HeapWord* b_start_4 = _offsets.block_start_const(addr_4); + if (b_start_4 != p) { + gclog_or_tty->print_cr("BOT look up for end - 1: "PTR_FORMAT" " + " yielded "PTR_FORMAT", expecting "PTR_FORMAT, + addr_4, b_start_4, p); + *failures = true; + return; } } @@ -880,12 +851,6 @@ void HeapRegion::verify(bool allow_dirty, "but has "SIZE_FORMAT", objects", bottom(), end(), object_num); *failures = true; - } - - if (p != top()) { - gclog_or_tty->print_cr("end of last object "PTR_FORMAT" " - "does not match top "PTR_FORMAT, p, top()); - *failures = true; return; } } @@ -976,67 +941,3 @@ G1OffsetTableContigSpace(G1BlockOffsetSharedArray* sharedOffsetArray, _offsets.set_space(this); initialize(mr, !is_zeroed, SpaceDecorator::Mangle); } - -size_t RegionList::length() { - size_t len = 0; - HeapRegion* cur = hd(); - DEBUG_ONLY(HeapRegion* last = NULL); - while (cur != NULL) { - len++; - DEBUG_ONLY(last = cur); - cur = get_next(cur); - } - assert(last == tl(), "Invariant"); - return len; -} - -void RegionList::insert_before_head(HeapRegion* r) { - assert(well_formed(), "Inv"); - set_next(r, hd()); - _hd = r; - _sz++; - if (tl() == NULL) _tl = r; - assert(well_formed(), "Inv"); -} - -void RegionList::prepend_list(RegionList* new_list) { - assert(well_formed(), "Precondition"); - assert(new_list->well_formed(), "Precondition"); - HeapRegion* new_tl = new_list->tl(); - if (new_tl != NULL) { - set_next(new_tl, hd()); - _hd = new_list->hd(); - _sz += new_list->sz(); - if (tl() == NULL) _tl = new_list->tl(); - } else { - assert(new_list->hd() == NULL && new_list->sz() == 0, "Inv"); - } - assert(well_formed(), "Inv"); -} - -void RegionList::delete_after(HeapRegion* r) { - assert(well_formed(), "Precondition"); - HeapRegion* next = get_next(r); - assert(r != NULL, "Precondition"); - HeapRegion* next_tl = get_next(next); - set_next(r, next_tl); - dec_sz(); - if (next == tl()) { - assert(next_tl == NULL, "Inv"); - _tl = r; - } - assert(well_formed(), "Inv"); -} - -HeapRegion* RegionList::pop() { - assert(well_formed(), "Inv"); - HeapRegion* res = hd(); - if (res != NULL) { - _hd = get_next(res); - _sz--; - set_next(res, NULL); - if (sz() == 0) _tl = NULL; - } - assert(well_formed(), "Inv"); - return res; -} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index f11c6a3a3ec..e764ad4349c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,11 @@ class ContiguousSpace; class HeapRegionRemSet; class HeapRegionRemSetIterator; class HeapRegion; +class HeapRegionSetBase; + +#define HR_FORMAT "%d:["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]" +#define HR_FORMAT_PARAMS(__hr) (__hr)->hrs_index(), (__hr)->bottom(), \ + (__hr)->top(), (__hr)->end() // A dirty card to oop closure for heap regions. It // knows how to get the G1 heap and how to use the bitmap @@ -173,6 +178,19 @@ class G1OffsetTableContigSpace: public ContiguousSpace { virtual HeapWord* cross_threshold(HeapWord* start, HeapWord* end); virtual void print() const; + + void reset_bot() { + _offsets.zero_bottom_entry(); + _offsets.initialize_threshold(); + } + + void update_bot_for_object(HeapWord* start, size_t word_size) { + _offsets.alloc_block(start, word_size); + } + + void print_bot_on(outputStream* out) { + _offsets.print_on(out); + } }; class HeapRegion: public G1OffsetTableContigSpace { @@ -214,12 +232,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // True iff the region is in current collection_set. bool _in_collection_set; - // True iff the region is on the unclean list, waiting to be zero filled. - bool _is_on_unclean_list; - - // True iff the region is on the free list, ready for allocation. - bool _is_on_free_list; - // Is this or has it been an allocation region in the current collection // pause. bool _is_gc_alloc_region; @@ -241,6 +253,13 @@ class HeapRegion: public G1OffsetTableContigSpace { // Next region whose cards need cleaning HeapRegion* _next_dirty_cards_region; + // Fields used by the HeapRegionSetBase class and subclasses. + HeapRegion* _next; +#ifdef ASSERT + HeapRegionSetBase* _containing_set; +#endif // ASSERT + bool _pending_removal; + // For parallel heapRegion traversal. jint _claimed; @@ -292,10 +311,6 @@ class HeapRegion: public G1OffsetTableContigSpace { _top_at_conc_mark_count = bot; } - jint _zfs; // A member of ZeroFillState. Protected by ZF_lock. - Thread* _zero_filler; // If _zfs is ZeroFilling, the thread that (last) - // made it so. - void set_young_type(YoungType new_type) { //assert(_young_type != new_type, "setting the same type" ); // TODO: add more assertions here @@ -349,15 +364,14 @@ class HeapRegion: public G1OffsetTableContigSpace { RebuildRSClaimValue = 5 }; - // Concurrent refinement requires contiguous heap regions (in which TLABs - // might be allocated) to be zero-filled. Each region therefore has a - // zero-fill-state. - enum ZeroFillState { - NotZeroFilled, - ZeroFilling, - ZeroFilled, - Allocated - }; + inline HeapWord* par_allocate_no_bot_updates(size_t word_size) { + assert(is_young(), "we can only skip BOT updates on young regions"); + return ContiguousSpace::par_allocate(word_size); + } + inline HeapWord* allocate_no_bot_updates(size_t word_size) { + assert(is_young(), "we can only skip BOT updates on young regions"); + return ContiguousSpace::allocate(word_size); + } // If this region is a member of a HeapRegionSeq, the index in that // sequence, otherwise -1. @@ -404,13 +418,38 @@ class HeapRegion: public G1OffsetTableContigSpace { return _humongous_start_region; } - // Causes the current region to represent a humongous object spanning "n" - // regions. - void set_startsHumongous(HeapWord* new_end); + // Makes the current region be a "starts humongous" region, i.e., + // the first region in a series of one or more contiguous regions + // that will contain a single "humongous" object. The two parameters + // are as follows: + // + // new_top : The new value of the top field of this region which + // points to the end of the humongous object that's being + // allocated. If there is more than one region in the series, top + // will lie beyond this region's original end field and on the last + // region in the series. + // + // new_end : The new value of the end field of this region which + // points to the end of the last region in the series. If there is + // one region in the series (namely: this one) end will be the same + // as the original end of this region. + // + // Updating top and end as described above makes this region look as + // if it spans the entire space taken up by all the regions in the + // series and an single allocation moved its top to new_top. This + // ensures that the space (capacity / allocated) taken up by all + // humongous regions can be calculated by just looking at the + // "starts humongous" regions and by ignoring the "continues + // humongous" regions. + void set_startsHumongous(HeapWord* new_top, HeapWord* new_end); - // The regions that continue a humongous sequence should be added using - // this method, in increasing address order. - void set_continuesHumongous(HeapRegion* start); + // Makes the current region be a "continues humongous' + // region. first_hr is the "start humongous" region of the series + // which this region will be part of. + void set_continuesHumongous(HeapRegion* first_hr); + + // Unsets the humongous-related fields on the region. + void set_notHumongous(); // If the region has a remembered set, return a pointer to it. HeapRegionRemSet* rem_set() const { @@ -458,45 +497,56 @@ class HeapRegion: public G1OffsetTableContigSpace { _next_in_special_set = r; } - bool is_on_free_list() { - return _is_on_free_list; + // Methods used by the HeapRegionSetBase class and subclasses. + + // Getter and setter for the next field used to link regions into + // linked lists. + HeapRegion* next() { return _next; } + + void set_next(HeapRegion* next) { _next = next; } + + // Every region added to a set is tagged with a reference to that + // set. This is used for doing consistency checking to make sure that + // the contents of a set are as they should be and it's only + // available in non-product builds. +#ifdef ASSERT + void set_containing_set(HeapRegionSetBase* containing_set) { + assert((containing_set == NULL && _containing_set != NULL) || + (containing_set != NULL && _containing_set == NULL), + err_msg("containing_set: "PTR_FORMAT" " + "_containing_set: "PTR_FORMAT, + containing_set, _containing_set)); + + _containing_set = containing_set; +} + + HeapRegionSetBase* containing_set() { return _containing_set; } +#else // ASSERT + void set_containing_set(HeapRegionSetBase* containing_set) { } + + // containing_set() is only used in asserts so there's not reason + // to provide a dummy version of it. +#endif // ASSERT + + // If we want to remove regions from a list in bulk we can simply tag + // them with the pending_removal tag and call the + // remove_all_pending() method on the list. + + bool pending_removal() { return _pending_removal; } + + void set_pending_removal(bool pending_removal) { + // We can only set pending_removal to true, if it's false and the + // region belongs to a set. + assert(!pending_removal || + (!_pending_removal && containing_set() != NULL), "pre-condition"); + // We can only set pending_removal to false, if it's true and the + // region does not belong to a set. + assert( pending_removal || + ( _pending_removal && containing_set() == NULL), "pre-condition"); + + _pending_removal = pending_removal; } - void set_on_free_list(bool b) { - _is_on_free_list = b; - } - - HeapRegion* next_from_free_list() { - assert(is_on_free_list(), - "Should only invoke on free space."); - assert(_next_in_special_set == NULL || - _next_in_special_set->is_on_free_list(), - "Malformed Free List."); - return _next_in_special_set; - } - - void set_next_on_free_list(HeapRegion* r) { - assert(r == NULL || r->is_on_free_list(), "Malformed free list."); - _next_in_special_set = r; - } - - bool is_on_unclean_list() { - return _is_on_unclean_list; - } - - void set_on_unclean_list(bool b); - - HeapRegion* next_from_unclean_list() { - assert(is_on_unclean_list(), - "Should only invoke on unclean space."); - assert(_next_in_special_set == NULL || - _next_in_special_set->is_on_unclean_list(), - "Malformed unclean List."); - return _next_in_special_set; - } - - void set_next_on_unclean_list(HeapRegion* r); - HeapRegion* get_next_young_region() { return _next_young_region; } void set_next_young_region(HeapRegion* hr) { _next_young_region = hr; @@ -515,11 +565,6 @@ class HeapRegion: public G1OffsetTableContigSpace { void initialize(MemRegion mr, bool clear_space, bool mangle_space); - // Ensure that "this" is zero-filled. - void ensure_zero_filled(); - // This one requires that the calling thread holds ZF_mon. - void ensure_zero_filled_locked(); - // Get the start of the unmarked area in this region. HeapWord* prev_top_at_mark_start() const { return _prev_top_at_mark_start; } HeapWord* next_top_at_mark_start() const { return _next_top_at_mark_start; } @@ -754,36 +799,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // "end" of the region if there is no such block. HeapWord* next_block_start_careful(HeapWord* addr); - // Returns the zero-fill-state of the current region. - ZeroFillState zero_fill_state() { return (ZeroFillState)_zfs; } - bool zero_fill_is_allocated() { return _zfs == Allocated; } - Thread* zero_filler() { return _zero_filler; } - - // Indicate that the contents of the region are unknown, and therefore - // might require zero-filling. - void set_zero_fill_needed() { - set_zero_fill_state_work(NotZeroFilled); - } - void set_zero_fill_in_progress(Thread* t) { - set_zero_fill_state_work(ZeroFilling); - _zero_filler = t; - } - void set_zero_fill_complete(); - void set_zero_fill_allocated() { - set_zero_fill_state_work(Allocated); - } - - void set_zero_fill_state_work(ZeroFillState zfs); - - // This is called when a full collection shrinks the heap. - // We want to set the heap region to a value which says - // it is no longer part of the heap. For now, we'll let "NotZF" fill - // that role. - void reset_zero_fill() { - set_zero_fill_state_work(NotZeroFilled); - _zero_filler = NULL; - } - size_t recorded_rs_length() const { return _recorded_rs_length; } double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; } size_t predicted_bytes_to_copy() const { return _predicted_bytes_to_copy; } @@ -822,10 +837,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // Override; it uses the "prev" marking information virtual void verify(bool allow_dirty) const; - -#ifdef DEBUG - HeapWord* allocate(size_t size); -#endif }; // HeapRegionClosure is used for iterating over regions. @@ -848,113 +859,6 @@ class HeapRegionClosure : public StackObj { bool complete() { return _complete; } }; -// A linked lists of heap regions. It leaves the "next" field -// unspecified; that's up to subtypes. -class RegionList VALUE_OBJ_CLASS_SPEC { -protected: - virtual HeapRegion* get_next(HeapRegion* chr) = 0; - virtual void set_next(HeapRegion* chr, - HeapRegion* new_next) = 0; - - HeapRegion* _hd; - HeapRegion* _tl; - size_t _sz; - - // Protected constructor because this type is only meaningful - // when the _get/_set next functions are defined. - RegionList() : _hd(NULL), _tl(NULL), _sz(0) {} -public: - void reset() { - _hd = NULL; - _tl = NULL; - _sz = 0; - } - HeapRegion* hd() { return _hd; } - HeapRegion* tl() { return _tl; } - size_t sz() { return _sz; } - size_t length(); - - bool well_formed() { - return - ((hd() == NULL && tl() == NULL && sz() == 0) - || (hd() != NULL && tl() != NULL && sz() > 0)) - && (sz() == length()); - } - virtual void insert_before_head(HeapRegion* r); - void prepend_list(RegionList* new_list); - virtual HeapRegion* pop(); - void dec_sz() { _sz--; } - // Requires that "r" is an element of the list, and is not the tail. - void delete_after(HeapRegion* r); -}; - -class EmptyNonHRegionList: public RegionList { -protected: - // Protected constructor because this type is only meaningful - // when the _get/_set next functions are defined. - EmptyNonHRegionList() : RegionList() {} - -public: - void insert_before_head(HeapRegion* r) { - // assert(r->is_empty(), "Better be empty"); - assert(!r->isHumongous(), "Better not be humongous."); - RegionList::insert_before_head(r); - } - void prepend_list(EmptyNonHRegionList* new_list) { - // assert(new_list->hd() == NULL || new_list->hd()->is_empty(), - // "Better be empty"); - assert(new_list->hd() == NULL || !new_list->hd()->isHumongous(), - "Better not be humongous."); - // assert(new_list->tl() == NULL || new_list->tl()->is_empty(), - // "Better be empty"); - assert(new_list->tl() == NULL || !new_list->tl()->isHumongous(), - "Better not be humongous."); - RegionList::prepend_list(new_list); - } -}; - -class UncleanRegionList: public EmptyNonHRegionList { -public: - HeapRegion* get_next(HeapRegion* hr) { - return hr->next_from_unclean_list(); - } - void set_next(HeapRegion* hr, HeapRegion* new_next) { - hr->set_next_on_unclean_list(new_next); - } - - UncleanRegionList() : EmptyNonHRegionList() {} - - void insert_before_head(HeapRegion* r) { - assert(!r->is_on_free_list(), - "Better not already be on free list"); - assert(!r->is_on_unclean_list(), - "Better not already be on unclean list"); - r->set_zero_fill_needed(); - r->set_on_unclean_list(true); - EmptyNonHRegionList::insert_before_head(r); - } - void prepend_list(UncleanRegionList* new_list) { - assert(new_list->tl() == NULL || !new_list->tl()->is_on_free_list(), - "Better not already be on free list"); - assert(new_list->tl() == NULL || new_list->tl()->is_on_unclean_list(), - "Better already be marked as on unclean list"); - assert(new_list->hd() == NULL || !new_list->hd()->is_on_free_list(), - "Better not already be on free list"); - assert(new_list->hd() == NULL || new_list->hd()->is_on_unclean_list(), - "Better already be marked as on unclean list"); - EmptyNonHRegionList::prepend_list(new_list); - } - HeapRegion* pop() { - HeapRegion* res = RegionList::pop(); - if (res != NULL) res->set_on_unclean_list(false); - return res; - } -}; - -// Local Variables: *** -// c-indentation-style: gnu *** -// End: *** - #endif // SERIALGC #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index 336ba21c4f2..0363352af72 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,152 +65,6 @@ HeapRegionSeq::HeapRegionSeq(const size_t max_size) : // Private methods. -HeapWord* -HeapRegionSeq::alloc_obj_from_region_index(int ind, size_t word_size) { - assert(G1CollectedHeap::isHumongous(word_size), - "Allocation size should be humongous"); - int cur = ind; - int first = cur; - size_t sumSizes = 0; - while (cur < _regions.length() && sumSizes < word_size) { - // Loop invariant: - // For all i in [first, cur): - // _regions.at(i)->is_empty() - // && _regions.at(i) is contiguous with its predecessor, if any - // && sumSizes is the sum of the sizes of the regions in the interval - // [first, cur) - HeapRegion* curhr = _regions.at(cur); - if (curhr->is_empty() - && (first == cur - || (_regions.at(cur-1)->end() == - curhr->bottom()))) { - sumSizes += curhr->capacity() / HeapWordSize; - } else { - first = cur + 1; - sumSizes = 0; - } - cur++; - } - if (sumSizes >= word_size) { - _alloc_search_start = cur; - - // We need to initialize the region(s) we just discovered. This is - // a bit tricky given that it can happen concurrently with - // refinement threads refining cards on these regions and - // potentially wanting to refine the BOT as they are scanning - // those cards (this can happen shortly after a cleanup; see CR - // 6991377). So we have to set up the region(s) carefully and in - // a specific order. - - // Currently, allocs_are_zero_filled() returns false. The zero - // filling infrastructure will be going away soon (see CR 6977804). - // So no need to do anything else here. - bool zf = G1CollectedHeap::heap()->allocs_are_zero_filled(); - assert(!zf, "not supported"); - - // This will be the "starts humongous" region. - HeapRegion* first_hr = _regions.at(first); - { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - first_hr->set_zero_fill_allocated(); - } - // The header of the new object will be placed at the bottom of - // the first region. - HeapWord* new_obj = first_hr->bottom(); - // This will be the new end of the first region in the series that - // should also match the end of the last region in the seriers. - // (Note: sumSizes = "region size" x "number of regions we found"). - HeapWord* new_end = new_obj + sumSizes; - // This will be the new top of the first region that will reflect - // this allocation. - HeapWord* new_top = new_obj + word_size; - - // First, we need to zero the header of the space that we will be - // allocating. When we update top further down, some refinement - // threads might try to scan the region. By zeroing the header we - // ensure that any thread that will try to scan the region will - // come across the zero klass word and bail out. - // - // NOTE: It would not have been correct to have used - // CollectedHeap::fill_with_object() and make the space look like - // an int array. The thread that is doing the allocation will - // later update the object header to a potentially different array - // type and, for a very short period of time, the klass and length - // fields will be inconsistent. This could cause a refinement - // thread to calculate the object size incorrectly. - Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); - - // We will set up the first region as "starts humongous". This - // will also update the BOT covering all the regions to reflect - // that there is a single object that starts at the bottom of the - // first region. - first_hr->set_startsHumongous(new_end); - - // Then, if there are any, we will set up the "continues - // humongous" regions. - HeapRegion* hr = NULL; - for (int i = first + 1; i < cur; ++i) { - hr = _regions.at(i); - { - MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); - hr->set_zero_fill_allocated(); - } - hr->set_continuesHumongous(first_hr); - } - // If we have "continues humongous" regions (hr != NULL), then the - // end of the last one should match new_end. - assert(hr == NULL || hr->end() == new_end, "sanity"); - - // Up to this point no concurrent thread would have been able to - // do any scanning on any region in this series. All the top - // fields still point to bottom, so the intersection between - // [bottom,top] and [card_start,card_end] will be empty. Before we - // update the top fields, we'll do a storestore to make sure that - // no thread sees the update to top before the zeroing of the - // object header and the BOT initialization. - OrderAccess::storestore(); - - // Now that the BOT and the object header have been initialized, - // we can update top of the "starts humongous" region. - assert(first_hr->bottom() < new_top && new_top <= first_hr->end(), - "new_top should be in this region"); - first_hr->set_top(new_top); - - // Now, we will update the top fields of the "continues humongous" - // regions. The reason we need to do this is that, otherwise, - // these regions would look empty and this will confuse parts of - // G1. For example, the code that looks for a consecutive number - // of empty regions will consider them empty and try to - // re-allocate them. We can extend is_empty() to also include - // !continuesHumongous(), but it is easier to just update the top - // fields here. - hr = NULL; - for (int i = first + 1; i < cur; ++i) { - hr = _regions.at(i); - if ((i + 1) == cur) { - // last continues humongous region - assert(hr->bottom() < new_top && new_top <= hr->end(), - "new_top should fall on this region"); - hr->set_top(new_top); - } else { - // not last one - assert(new_top > hr->end(), "new_top should be above this region"); - hr->set_top(hr->end()); - } - } - // If we have continues humongous regions (hr != NULL), then the - // end of the last one should match new_end and its top should - // match new_top. - assert(hr == NULL || - (hr->end() == new_end && hr->top() == new_top), "sanity"); - - return new_obj; - } else { - // If we started from the beginning, we want to know why we can't alloc. - return NULL; - } -} - void HeapRegionSeq::print_empty_runs() { int empty_run = 0; int n_empty = 0; @@ -284,13 +138,67 @@ size_t HeapRegionSeq::free_suffix() { return res; } -HeapWord* HeapRegionSeq::obj_allocate(size_t word_size) { - int cur = _alloc_search_start; - // Make sure "cur" is a valid index. - assert(cur >= 0, "Invariant."); - HeapWord* res = alloc_obj_from_region_index(cur, word_size); - if (res == NULL) - res = alloc_obj_from_region_index(0, word_size); +int HeapRegionSeq::find_contiguous_from(int from, size_t num) { + assert(num > 1, "pre-condition"); + assert(0 <= from && from <= _regions.length(), + err_msg("from: %d should be valid and <= than %d", + from, _regions.length())); + + int curr = from; + int first = -1; + size_t num_so_far = 0; + while (curr < _regions.length() && num_so_far < num) { + HeapRegion* curr_hr = _regions.at(curr); + if (curr_hr->is_empty()) { + if (first == -1) { + first = curr; + num_so_far = 1; + } else { + num_so_far += 1; + } + } else { + first = -1; + num_so_far = 0; + } + curr += 1; + } + + assert(num_so_far <= num, "post-condition"); + if (num_so_far == num) { + // we find enough space for the humongous object + assert(from <= first && first < _regions.length(), "post-condition"); + assert(first < curr && (curr - first) == (int) num, "post-condition"); + for (int i = first; i < first + (int) num; ++i) { + assert(_regions.at(i)->is_empty(), "post-condition"); + } + return first; + } else { + // we failed to find enough space for the humongous object + return -1; + } +} + +int HeapRegionSeq::find_contiguous(size_t num) { + assert(num > 1, "otherwise we should not be calling this"); + assert(0 <= _alloc_search_start && _alloc_search_start <= _regions.length(), + err_msg("_alloc_search_start: %d should be valid and <= than %d", + _alloc_search_start, _regions.length())); + + int start = _alloc_search_start; + int res = find_contiguous_from(start, num); + if (res == -1 && start != 0) { + // Try starting from the beginning. If _alloc_search_start was 0, + // no point in doing this again. + res = find_contiguous_from(0, num); + } + if (res != -1) { + assert(0 <= res && res < _regions.length(), + err_msg("res: %d should be valid", res)); + _alloc_search_start = res + (int) num; + } + assert(0 < _alloc_search_start && _alloc_search_start <= _regions.length(), + err_msg("_alloc_search_start: %d should be valid", + _alloc_search_start)); return res; } @@ -376,6 +284,10 @@ void HeapRegionSeq::iterate_from(int idx, HeapRegionClosure* blk) { MemRegion HeapRegionSeq::shrink_by(size_t shrink_bytes, size_t& num_regions_deleted) { + // Reset this in case it's currently pointing into the regions that + // we just removed. + _alloc_search_start = 0; + assert(shrink_bytes % os::vm_page_size() == 0, "unaligned"); assert(shrink_bytes % HeapRegion::GrainBytes == 0, "unaligned"); @@ -395,7 +307,6 @@ MemRegion HeapRegionSeq::shrink_by(size_t shrink_bytes, } assert(cur == _regions.top(), "Should be top"); if (!cur->is_empty()) break; - cur->reset_zero_fill(); shrink_bytes -= cur->capacity(); num_regions_deleted++; _regions.pop(); @@ -410,7 +321,6 @@ MemRegion HeapRegionSeq::shrink_by(size_t shrink_bytes, return MemRegion(last_start, end); } - class PrintHeapRegionClosure : public HeapRegionClosure { public: bool doHeapRegion(HeapRegion* r) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp index 1a75a25301e..932b0cb9572 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,9 @@ class HeapRegionSeq: public CHeapObj { // (For efficiency only; private to obj_allocate after initialization.) int _alloc_search_start; - // Attempts to allocate a block of the (assumed humongous) word_size, - // starting at the region "ind". - HeapWord* alloc_obj_from_region_index(int ind, size_t word_size); + // Finds a contiguous set of empty regions of length num, starting + // from a given index. + int find_contiguous_from(int from, size_t num); // Currently, we're choosing collection sets in a round-robin fashion, // starting here. @@ -76,11 +76,8 @@ class HeapRegionSeq: public CHeapObj { // that are available for allocation. size_t free_suffix(); - // Requires "word_size" to be humongous (in the technical sense). If - // possible, allocates a contiguous subsequence of the heap regions to - // satisfy the allocation, and returns the address of the beginning of - // that sequence, otherwise returns NULL. - HeapWord* obj_allocate(size_t word_size); + // Finds a contiguous set of empty regions of length num. + int find_contiguous(size_t num); // Apply the "doHeapRegion" method of "blk" to all regions in "this", // in address order, terminating the iteration early @@ -106,7 +103,7 @@ class HeapRegionSeq: public CHeapObj { // If "addr" falls within a region in the sequence, return that region, // or else NULL. - HeapRegion* addr_to_region(const void* addr); + inline HeapRegion* addr_to_region(const void* addr); void print(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp new file mode 100644 index 00000000000..29fff5d8cf3 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" + +size_t HeapRegionSetBase::_unrealistically_long_length = 0; + +//////////////////// HeapRegionSetBase //////////////////// + +void HeapRegionSetBase::set_unrealistically_long_length(size_t len) { + guarantee(_unrealistically_long_length == 0, "should only be set once"); + _unrealistically_long_length = len; +} + +size_t HeapRegionSetBase::calculate_region_num(HeapRegion* hr) { + assert(hr->startsHumongous(), "pre-condition"); + assert(hr->capacity() % HeapRegion::GrainBytes == 0, "invariant"); + size_t region_num = hr->capacity() >> HeapRegion::LogOfHRGrainBytes; + assert(region_num > 0, "sanity"); + return region_num; +} + +void HeapRegionSetBase::fill_in_ext_msg(hrl_ext_msg* msg, const char* message) { + msg->append("[%s] %s " + "ln: "SIZE_FORMAT" rn: "SIZE_FORMAT" " + "cy: "SIZE_FORMAT" ud: "SIZE_FORMAT, + name(), message, length(), region_num(), + total_capacity_bytes(), total_used_bytes()); + fill_in_ext_msg_extra(msg); +} + +bool HeapRegionSetBase::verify_region(HeapRegion* hr, + HeapRegionSetBase* expected_containing_set) { + const char* error_message = NULL; + + if (!regions_humongous()) { + if (hr->isHumongous()) { + error_message = "the region should not be humongous"; + } + } else { + if (!hr->isHumongous() || !hr->startsHumongous()) { + error_message = "the region should be 'starts humongous'"; + } + } + + if (!regions_empty()) { + if (hr->is_empty()) { + error_message = "the region should not be empty"; + } + } else { + if (!hr->is_empty()) { + error_message = "the region should be empty"; + } + } + +#ifdef ASSERT + // The _containing_set field is only available when ASSERT is defined. + if (hr->containing_set() != expected_containing_set) { + error_message = "inconsistent containing set found"; + } +#endif // ASSERT + + const char* extra_error_message = verify_region_extra(hr); + if (extra_error_message != NULL) { + error_message = extra_error_message; + } + + if (error_message != NULL) { + outputStream* out = tty; + out->cr(); + out->print_cr("## [%s] %s", name(), error_message); + out->print_cr("## Offending Region: "PTR_FORMAT, hr); + out->print_cr(" "HR_FORMAT, HR_FORMAT_PARAMS(hr)); +#ifdef ASSERT + out->print_cr(" containing set: "PTR_FORMAT, hr->containing_set()); +#endif // ASSERT + out->print_cr("## Offending Region Set: "PTR_FORMAT, this); + print_on(out); + return false; + } else { + return true; + } +} + +void HeapRegionSetBase::verify() { + // It's important that we also observe the MT safety protocol even + // for the verification calls. If we do verification without the + // appropriate locks and the set changes underneath our feet + // verification might fail and send us on a wild goose chase. + hrl_assert_mt_safety_ok(this); + + guarantee(( is_empty() && length() == 0 && region_num() == 0 && + total_used_bytes() == 0 && total_capacity_bytes() == 0) || + (!is_empty() && length() >= 0 && region_num() >= 0 && + total_used_bytes() >= 0 && total_capacity_bytes() >= 0), + hrl_ext_msg(this, "invariant")); + + guarantee((!regions_humongous() && region_num() == length()) || + ( regions_humongous() && region_num() >= length()), + hrl_ext_msg(this, "invariant")); + + guarantee(!regions_empty() || total_used_bytes() == 0, + hrl_ext_msg(this, "invariant")); + + guarantee(total_used_bytes() <= total_capacity_bytes(), + hrl_ext_msg(this, "invariant")); +} + +void HeapRegionSetBase::verify_start() { + // See comment in verify() about MT safety and verification. + hrl_assert_mt_safety_ok(this); + assert(!_verify_in_progress, + hrl_ext_msg(this, "verification should not be in progress")); + + // Do the basic verification first before we do the checks over the regions. + HeapRegionSetBase::verify(); + + _calc_length = 0; + _calc_region_num = 0; + _calc_total_capacity_bytes = 0; + _calc_total_used_bytes = 0; + _verify_in_progress = true; +} + +void HeapRegionSetBase::verify_next_region(HeapRegion* hr) { + // See comment in verify() about MT safety and verification. + hrl_assert_mt_safety_ok(this); + assert(_verify_in_progress, + hrl_ext_msg(this, "verification should be in progress")); + + guarantee(verify_region(hr, this), hrl_ext_msg(this, "region verification")); + + _calc_length += 1; + if (!hr->isHumongous()) { + _calc_region_num += 1; + } else { + _calc_region_num += calculate_region_num(hr); + } + _calc_total_capacity_bytes += hr->capacity(); + _calc_total_used_bytes += hr->used(); +} + +void HeapRegionSetBase::verify_end() { + // See comment in verify() about MT safety and verification. + hrl_assert_mt_safety_ok(this); + assert(_verify_in_progress, + hrl_ext_msg(this, "verification should be in progress")); + + guarantee(length() == _calc_length, + hrl_err_msg("[%s] length: "SIZE_FORMAT" should be == " + "calc length: "SIZE_FORMAT, + name(), length(), _calc_length)); + + guarantee(region_num() == _calc_region_num, + hrl_err_msg("[%s] region num: "SIZE_FORMAT" should be == " + "calc region num: "SIZE_FORMAT, + name(), region_num(), _calc_region_num)); + + guarantee(total_capacity_bytes() == _calc_total_capacity_bytes, + hrl_err_msg("[%s] capacity bytes: "SIZE_FORMAT" should be == " + "calc capacity bytes: "SIZE_FORMAT, + name(), + total_capacity_bytes(), _calc_total_capacity_bytes)); + + guarantee(total_used_bytes() == _calc_total_used_bytes, + hrl_err_msg("[%s] used bytes: "SIZE_FORMAT" should be == " + "calc used bytes: "SIZE_FORMAT, + name(), total_used_bytes(), _calc_total_used_bytes)); + + _verify_in_progress = false; +} + +void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { + out->cr(); + out->print_cr("Set: %s ("PTR_FORMAT")", name(), this); + out->print_cr(" Region Assumptions"); + out->print_cr(" humongous : %s", BOOL_TO_STR(regions_humongous())); + out->print_cr(" empty : %s", BOOL_TO_STR(regions_empty())); + out->print_cr(" Attributes"); + out->print_cr(" length : "SIZE_FORMAT_W(14), length()); + out->print_cr(" region num : "SIZE_FORMAT_W(14), region_num()); + out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes", + total_capacity_bytes()); + out->print_cr(" total used : "SIZE_FORMAT_W(14)" bytes", + total_used_bytes()); +} + +void HeapRegionSetBase::clear() { + _length = 0; + _region_num = 0; + _total_used_bytes = 0; +} + +HeapRegionSetBase::HeapRegionSetBase(const char* name) + : _name(name), _verify_in_progress(false), + _calc_length(0), _calc_region_num(0), + _calc_total_capacity_bytes(0), _calc_total_used_bytes(0) { } + +//////////////////// HeapRegionSet //////////////////// + +void HeapRegionSet::update_from_proxy(HeapRegionSet* proxy_set) { + hrl_assert_mt_safety_ok(this); + hrl_assert_mt_safety_ok(proxy_set); + hrl_assert_sets_match(this, proxy_set); + + verify_optional(); + proxy_set->verify_optional(); + + if (proxy_set->is_empty()) return; + + assert(proxy_set->length() <= _length, + hrl_err_msg("[%s] proxy set length: "SIZE_FORMAT" " + "should be <= length: "SIZE_FORMAT, + name(), proxy_set->length(), _length)); + _length -= proxy_set->length(); + + assert(proxy_set->region_num() <= _region_num, + hrl_err_msg("[%s] proxy set region num: "SIZE_FORMAT" " + "should be <= region num: "SIZE_FORMAT, + name(), proxy_set->region_num(), _region_num)); + _region_num -= proxy_set->region_num(); + + assert(proxy_set->total_used_bytes() <= _total_used_bytes, + hrl_err_msg("[%s] proxy set used bytes: "SIZE_FORMAT" " + "should be <= used bytes: "SIZE_FORMAT, + name(), proxy_set->total_used_bytes(), + _total_used_bytes)); + _total_used_bytes -= proxy_set->total_used_bytes(); + + proxy_set->clear(); + + verify_optional(); + proxy_set->verify_optional(); +} + +//////////////////// HeapRegionLinkedList //////////////////// + +void HeapRegionLinkedList::fill_in_ext_msg_extra(hrl_ext_msg* msg) { + msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail()); +} + +void HeapRegionLinkedList::add_as_tail(HeapRegionLinkedList* from_list) { + hrl_assert_mt_safety_ok(this); + hrl_assert_mt_safety_ok(from_list); + + verify_optional(); + from_list->verify_optional(); + + if (from_list->is_empty()) return; + +#ifdef ASSERT + HeapRegionLinkedListIterator iter(from_list); + while (iter.more_available()) { + HeapRegion* hr = iter.get_next(); + // In set_containing_set() we check that we either set the value + // from NULL to non-NULL or vice versa to catch bugs. So, we have + // to NULL it first before setting it to the value. + hr->set_containing_set(NULL); + hr->set_containing_set(this); + } +#endif // ASSERT + + if (_tail != NULL) { + assert(length() > 0 && _head != NULL, hrl_ext_msg(this, "invariant")); + _tail->set_next(from_list->_head); + } else { + assert(length() == 0 && _head == NULL, hrl_ext_msg(this, "invariant")); + _head = from_list->_head; + } + _tail = from_list->_tail; + + _length += from_list->length(); + _region_num += from_list->region_num(); + _total_used_bytes += from_list->total_used_bytes(); + from_list->clear(); + + verify_optional(); + from_list->verify_optional(); +} + +void HeapRegionLinkedList::remove_all() { + hrl_assert_mt_safety_ok(this); + verify_optional(); + + HeapRegion* curr = _head; + while (curr != NULL) { + hrl_assert_region_ok(this, curr, this); + + HeapRegion* next = curr->next(); + curr->set_next(NULL); + curr->set_containing_set(NULL); + curr = next; + } + clear(); + + verify_optional(); +} + +void HeapRegionLinkedList::remove_all_pending(size_t target_count) { + hrl_assert_mt_safety_ok(this); + assert(target_count > 1, hrl_ext_msg(this, "pre-condition")); + assert(!is_empty(), hrl_ext_msg(this, "pre-condition")); + + verify_optional(); + DEBUG_ONLY(size_t old_length = length();) + + HeapRegion* curr = _head; + HeapRegion* prev = NULL; + size_t count = 0; + while (curr != NULL) { + hrl_assert_region_ok(this, curr, this); + HeapRegion* next = curr->next(); + + if (curr->pending_removal()) { + assert(count < target_count, + hrl_err_msg("[%s] should not come across more regions " + "pending for removal than target_count: "SIZE_FORMAT, + name(), target_count)); + + if (prev == NULL) { + assert(_head == curr, hrl_ext_msg(this, "invariant")); + _head = next; + } else { + assert(_head != curr, hrl_ext_msg(this, "invariant")); + prev->set_next(next); + } + if (next == NULL) { + assert(_tail == curr, hrl_ext_msg(this, "invariant")); + _tail = prev; + } else { + assert(_tail != curr, hrl_ext_msg(this, "invariant")); + } + + curr->set_next(NULL); + remove_internal(curr); + curr->set_pending_removal(false); + + count += 1; + + // If we have come across the target number of regions we can + // just bail out. However, for debugging purposes, we can just + // carry on iterating to make sure there are not more regions + // tagged with pending removal. + DEBUG_ONLY(if (count == target_count) break;) + } else { + prev = curr; + } + curr = next; + } + + assert(count == target_count, + hrl_err_msg("[%s] count: "SIZE_FORMAT" should be == " + "target_count: "SIZE_FORMAT, name(), count, target_count)); + assert(length() + target_count == old_length, + hrl_err_msg("[%s] new length should be consistent " + "new length: "SIZE_FORMAT" old length: "SIZE_FORMAT" " + "target_count: "SIZE_FORMAT, + name(), length(), old_length, target_count)); + + verify_optional(); +} + +void HeapRegionLinkedList::verify() { + // See comment in HeapRegionSetBase::verify() about MT safety and + // verification. + hrl_assert_mt_safety_ok(this); + + // This will also do the basic verification too. + verify_start(); + + HeapRegion* curr = _head; + HeapRegion* prev1 = NULL; + HeapRegion* prev0 = NULL; + size_t count = 0; + while (curr != NULL) { + verify_next_region(curr); + + count += 1; + guarantee(count < _unrealistically_long_length, + hrl_err_msg("[%s] the calculated length: "SIZE_FORMAT" " + "seems very long, is there maybe a cycle? " + "curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " + "prev1: "PTR_FORMAT" length: "SIZE_FORMAT, + name(), count, curr, prev0, prev1, length())); + + prev1 = prev0; + prev0 = curr; + curr = curr->next(); + } + + guarantee(_tail == prev0, hrl_ext_msg(this, "post-condition")); + + verify_end(); +} + +void HeapRegionLinkedList::clear() { + HeapRegionSetBase::clear(); + _head = NULL; + _tail = NULL; +} + +void HeapRegionLinkedList::print_on(outputStream* out, bool print_contents) { + HeapRegionSetBase::print_on(out, print_contents); + out->print_cr(" Linking"); + out->print_cr(" head : "PTR_FORMAT, _head); + out->print_cr(" tail : "PTR_FORMAT, _tail); + + if (print_contents) { + out->print_cr(" Contents"); + HeapRegionLinkedListIterator iter(this); + while (iter.more_available()) { + HeapRegion* hr = iter.get_next(); + hr->print_on(out); + } + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp new file mode 100644 index 00000000000..a973676ae78 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -0,0 +1,346 @@ +/* + * copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_HPP + +#include "gc_implementation/g1/heapRegion.hpp" + +// Large buffer for some cases where the output might be larger than normal. +#define HRL_ERR_MSG_BUFSZ 512 +typedef FormatBuffer hrl_err_msg; + +// Set verification will be forced either if someone defines +// HEAP_REGION_SET_FORCE_VERIFY to be 1, or in builds in which +// asserts are compiled in. +#ifndef HEAP_REGION_SET_FORCE_VERIFY +#define HEAP_REGION_SET_FORCE_VERIFY defined(ASSERT) +#endif // HEAP_REGION_SET_FORCE_VERIFY + +//////////////////// HeapRegionSetBase //////////////////// + +// Base class for all the classes that represent heap region sets. It +// contains the basic attributes that each set needs to maintain +// (e.g., length, region num, used bytes sum) plus any shared +// functionality (e.g., verification). + +class hrl_ext_msg; + +class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC { + friend class hrl_ext_msg; + +protected: + static size_t calculate_region_num(HeapRegion* hr); + + static size_t _unrealistically_long_length; + + // The number of regions added to the set. If the set contains + // only humongous regions, this reflects only 'starts humongous' + // regions and does not include 'continues humongous' ones. + size_t _length; + + // The total number of regions represented by the set. If the set + // does not contain humongous regions, this should be the same as + // _length. If the set contains only humongous regions, this will + // include the 'continues humongous' regions. + size_t _region_num; + + // We don't keep track of the total capacity explicitly, we instead + // recalculate it based on _region_num and the heap region size. + + // The sum of used bytes in the all the regions in the set. + size_t _total_used_bytes; + + const char* _name; + + bool _verify_in_progress; + size_t _calc_length; + size_t _calc_region_num; + size_t _calc_total_capacity_bytes; + size_t _calc_total_used_bytes; + + // verify_region() is used to ensure that the contents of a region + // added to / removed from a set are consistent. Different sets + // make different assumptions about the regions added to them. So + // each set can override verify_region_extra(), which is called + // from verify_region(), and do any extra verification it needs to + // perform in that. + virtual const char* verify_region_extra(HeapRegion* hr) { return NULL; } + bool verify_region(HeapRegion* hr, + HeapRegionSetBase* expected_containing_set); + + // Indicates whether all regions in the set should be humongous or + // not. Only used during verification. + virtual bool regions_humongous() = 0; + + // Indicates whether all regions in the set should be empty or + // not. Only used during verification. + virtual bool regions_empty() = 0; + + // Subclasses can optionally override this to do MT safety protocol + // checks. It is called in an assert from all methods that perform + // updates on the set (and subclasses should also call it too). + virtual bool check_mt_safety() { return true; } + + // fill_in_ext_msg() writes the the values of the set's attributes + // in the custom err_msg (hrl_ext_msg). fill_in_ext_msg_extra() + // allows subclasses to append further information. + virtual void fill_in_ext_msg_extra(hrl_ext_msg* msg) { } + void fill_in_ext_msg(hrl_ext_msg* msg, const char* message); + + // It updates the fields of the set to reflect hr being added to + // the set. + inline void update_for_addition(HeapRegion* hr); + + // It updates the fields of the set to reflect hr being added to + // the set and tags the region appropriately. + inline void add_internal(HeapRegion* hr); + + // It updates the fields of the set to reflect hr being removed + // from the set. + inline void update_for_removal(HeapRegion* hr); + + // It updates the fields of the set to reflect hr being removed + // from the set and tags the region appropriately. + inline void remove_internal(HeapRegion* hr); + + // It clears all the fields of the sets. Note: it will not iterate + // over the set and remove regions from it. It assumes that the + // caller has already done so. It will literally just clear the fields. + virtual void clear(); + + HeapRegionSetBase(const char* name); + +public: + static void set_unrealistically_long_length(size_t len); + + const char* name() { return _name; } + + size_t length() { return _length; } + + bool is_empty() { return _length == 0; } + + size_t region_num() { return _region_num; } + + size_t total_capacity_bytes() { + return region_num() << HeapRegion::LogOfHRGrainBytes; + } + + size_t total_used_bytes() { return _total_used_bytes; } + + virtual void verify(); + void verify_start(); + void verify_next_region(HeapRegion* hr); + void verify_end(); + +#if HEAP_REGION_SET_FORCE_VERIFY + void verify_optional() { + verify(); + } +#else // HEAP_REGION_SET_FORCE_VERIFY + void verify_optional() { } +#endif // HEAP_REGION_SET_FORCE_VERIFY + + virtual void print_on(outputStream* out, bool print_contents = false); +}; + +// Customized err_msg for heap region sets. Apart from a +// assert/guarantee-specific message it also prints out the values of +// the fields of the associated set. This can be very helpful in +// diagnosing failures. + +class hrl_ext_msg : public hrl_err_msg { +public: + hrl_ext_msg(HeapRegionSetBase* set, const char* message) : hrl_err_msg("") { + set->fill_in_ext_msg(this, message); + } +}; + +// These two macros are provided for convenience, to keep the uses of +// these two asserts a bit more concise. + +#define hrl_assert_mt_safety_ok(_set_) \ + do { \ + assert((_set_)->check_mt_safety(), hrl_ext_msg((_set_), "MT safety")); \ + } while (0) + +#define hrl_assert_region_ok(_set_, _hr_, _expected_) \ + do { \ + assert((_set_)->verify_region((_hr_), (_expected_)), \ + hrl_ext_msg((_set_), "region verification")); \ + } while (0) + +//////////////////// HeapRegionSet //////////////////// + +#define hrl_assert_sets_match(_set1_, _set2_) \ + do { \ + assert(((_set1_)->regions_humongous() == \ + (_set2_)->regions_humongous()) && \ + ((_set1_)->regions_empty() == (_set2_)->regions_empty()), \ + hrl_err_msg("the contents of set %s and set %s should match", \ + (_set1_)->name(), (_set2_)->name())); \ + } while (0) + +// This class represents heap region sets whose members are not +// explicitly tracked. It's helpful to group regions using such sets +// so that we can reason about all the region groups in the heap using +// the same interface (namely, the HeapRegionSetBase API). + +class HeapRegionSet : public HeapRegionSetBase { +protected: + virtual const char* verify_region_extra(HeapRegion* hr) { + if (hr->next() != NULL) { + return "next() should always be NULL as we do not link the regions"; + } + + return HeapRegionSetBase::verify_region_extra(hr); + } + + HeapRegionSet(const char* name) : HeapRegionSetBase(name) { + clear(); + } + +public: + // It adds hr to the set. The region should not be a member of + // another set. + inline void add(HeapRegion* hr); + + // It removes hr from the set. The region should be a member of + // this set. + inline void remove(HeapRegion* hr); + + // It removes a region from the set. Instead of updating the fields + // of the set to reflect this removal, it accumulates the updates + // in proxy_set. The idea is that proxy_set is thread-local to + // avoid multiple threads updating the fields of the set + // concurrently and having to synchronize. The method + // update_from_proxy() will update the fields of the set from the + // proxy_set. + inline void remove_with_proxy(HeapRegion* hr, HeapRegionSet* proxy_set); + + // After multiple calls to remove_with_proxy() the updates to the + // fields of the set are accumulated in proxy_set. This call + // updates the fields of the set from proxy_set. + void update_from_proxy(HeapRegionSet* proxy_set); +}; + +//////////////////// HeapRegionLinkedList //////////////////// + +// A set that links all the regions added to it in a singly-linked +// list. We should try to avoid doing operations that iterate over +// such lists in performance critical paths. Typically we should +// add / remove one region at a time or concatenate two lists. All +// those operations are done in constant time. + +class HeapRegionLinkedListIterator; + +class HeapRegionLinkedList : public HeapRegionSetBase { + friend class HeapRegionLinkedListIterator; + +private: + HeapRegion* _head; + HeapRegion* _tail; + + // These are provided for use by the friend classes. + HeapRegion* head() { return _head; } + HeapRegion* tail() { return _tail; } + +protected: + virtual void fill_in_ext_msg_extra(hrl_ext_msg* msg); + + // See the comment for HeapRegionSetBase::clear() + virtual void clear(); + + HeapRegionLinkedList(const char* name) : HeapRegionSetBase(name) { + clear(); + } + +public: + // It adds hr to the list as the new tail. The region should not be + // a member of another set. + inline void add_as_tail(HeapRegion* hr); + + // It removes and returns the head of the list. It assumes that the + // list is not empty so it will return a non-NULL value. + inline HeapRegion* remove_head(); + + // Convenience method. + inline HeapRegion* remove_head_or_null(); + + // It moves the regions from from_list to this list and empties + // from_list. The new regions will appear in the same order as they + // were in from_list and be linked in the end of this list. + void add_as_tail(HeapRegionLinkedList* from_list); + + // It empties the list by removing all regions from it. + void remove_all(); + + // It removes all regions in the list that are pending for removal + // (i.e., they have been tagged with "pending_removal"). The list + // must not be empty, target_count should reflect the exact number + // of regions that are pending for removal in the list, and + // target_count should be > 1 (currently, we never need to remove a + // single region using this). + void remove_all_pending(size_t target_count); + + virtual void verify(); + + virtual void print_on(outputStream* out, bool print_contents = false); +}; + +//////////////////// HeapRegionLinkedList //////////////////// + +// Iterator class that provides a convenient way to iterator over the +// regions in a HeapRegionLinkedList instance. + +class HeapRegionLinkedListIterator : public StackObj { +private: + HeapRegionLinkedList* _list; + HeapRegion* _curr; + +public: + bool more_available() { + return _curr != NULL; + } + + HeapRegion* get_next() { + assert(more_available(), + "get_next() should be called when more regions are available"); + + // If we are going to introduce a count in the iterator we should + // do the "cycle" check. + + HeapRegion* hr = _curr; + assert(_list->verify_region(hr, _list), "region verification"); + _curr = hr->next(); + return hr; + } + + HeapRegionLinkedListIterator(HeapRegionLinkedList* list) + : _curr(NULL), _list(list) { + _curr = list->head(); + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp new file mode 100644 index 00000000000..44f7335f48f --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp @@ -0,0 +1,159 @@ +/* + * copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP + +#include "gc_implementation/g1/heapRegionSet.hpp" + +//////////////////// HeapRegionSetBase //////////////////// + +inline void HeapRegionSetBase::update_for_addition(HeapRegion* hr) { + // Assumes the caller has already verified the region. + + _length += 1; + if (!hr->isHumongous()) { + _region_num += 1; + } else { + _region_num += calculate_region_num(hr); + } + _total_used_bytes += hr->used(); +} + +inline void HeapRegionSetBase::add_internal(HeapRegion* hr) { + hrl_assert_region_ok(this, hr, NULL); + assert(hr->next() == NULL, hrl_ext_msg(this, "should not already be linked")); + + update_for_addition(hr); + hr->set_containing_set(this); +} + +inline void HeapRegionSetBase::update_for_removal(HeapRegion* hr) { + // Assumes the caller has already verified the region. + assert(_length > 0, hrl_ext_msg(this, "pre-condition")); + _length -= 1; + + size_t region_num_diff; + if (!hr->isHumongous()) { + region_num_diff = 1; + } else { + region_num_diff = calculate_region_num(hr); + } + assert(region_num_diff <= _region_num, + hrl_err_msg("[%s] region's region num: "SIZE_FORMAT" " + "should be <= region num: "SIZE_FORMAT, + name(), region_num_diff, _region_num)); + _region_num -= region_num_diff; + + size_t used_bytes = hr->used(); + assert(used_bytes <= _total_used_bytes, + hrl_err_msg("[%s] region's used bytes: "SIZE_FORMAT" " + "should be <= used bytes: "SIZE_FORMAT, + name(), used_bytes, _total_used_bytes)); + _total_used_bytes -= used_bytes; +} + +inline void HeapRegionSetBase::remove_internal(HeapRegion* hr) { + hrl_assert_region_ok(this, hr, this); + assert(hr->next() == NULL, hrl_ext_msg(this, "should already be unlinked")); + + hr->set_containing_set(NULL); + update_for_removal(hr); +} + +//////////////////// HeapRegionSet //////////////////// + +inline void HeapRegionSet::add(HeapRegion* hr) { + hrl_assert_mt_safety_ok(this); + // add_internal() will verify the region. + add_internal(hr); +} + +inline void HeapRegionSet::remove(HeapRegion* hr) { + hrl_assert_mt_safety_ok(this); + // remove_internal() will verify the region. + remove_internal(hr); +} + +inline void HeapRegionSet::remove_with_proxy(HeapRegion* hr, + HeapRegionSet* proxy_set) { + // No need to fo the MT safety check here given that this method + // does not update the contents of the set but instead accumulates + // the changes in proxy_set which is assumed to be thread-local. + hrl_assert_sets_match(this, proxy_set); + hrl_assert_region_ok(this, hr, this); + + hr->set_containing_set(NULL); + proxy_set->update_for_addition(hr); +} + +//////////////////// HeapRegionLinkedList //////////////////// + +inline void HeapRegionLinkedList::add_as_tail(HeapRegion* hr) { + hrl_assert_mt_safety_ok(this); + assert((length() == 0 && _head == NULL && _tail == NULL) || + (length() > 0 && _head != NULL && _tail != NULL), + hrl_ext_msg(this, "invariant")); + // add_internal() will verify the region. + add_internal(hr); + + // Now link the region. + if (_tail != NULL) { + _tail->set_next(hr); + } else { + _head = hr; + } + _tail = hr; +} + +inline HeapRegion* HeapRegionLinkedList::remove_head() { + hrl_assert_mt_safety_ok(this); + assert(!is_empty(), hrl_ext_msg(this, "the list should not be empty")); + assert(length() > 0 && _head != NULL && _tail != NULL, + hrl_ext_msg(this, "invariant")); + + // We need to unlink it first. + HeapRegion* hr = _head; + _head = hr->next(); + if (_head == NULL) { + _tail = NULL; + } + hr->set_next(NULL); + + // remove_internal() will verify the region. + remove_internal(hr); + return hr; +} + +inline HeapRegion* HeapRegionLinkedList::remove_head_or_null() { + hrl_assert_mt_safety_ok(this); + + if (!is_empty()) { + return remove_head(); + } else { + return NULL; + } +} + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp new file mode 100644 index 00000000000..c5f58cb87af --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/heapRegionSets.hpp" + +//////////////////// FreeRegionList //////////////////// + +const char* FreeRegionList::verify_region_extra(HeapRegion* hr) { + if (hr->is_young()) { + return "the region should not be young"; + } + // The superclass will check that the region is empty and + // not-humongous. + return HeapRegionLinkedList::verify_region_extra(hr); +} + +//////////////////// MasterFreeRegionList //////////////////// + +bool MasterFreeRegionList::check_mt_safety() { + // Master Free List MT safety protocol: + // (a) If we're at a safepoint, operations on the master free list + // should be invoked by either the VM thread (which will serialize + // them) or by the GC workers while holding the + // FreeList_lock. + // (b) If we're not at a safepoint, operations on the master free + // list should be invoked while holding the Heap_lock. + + guarantee((SafepointSynchronize::is_at_safepoint() && + (Thread::current()->is_VM_thread() || + FreeList_lock->owned_by_self())) || + (!SafepointSynchronize::is_at_safepoint() && + Heap_lock->owned_by_self()), + hrl_ext_msg(this, "master free list MT safety protocol")); + + return FreeRegionList::check_mt_safety(); +} + +//////////////////// SecondaryFreeRegionList //////////////////// + +bool SecondaryFreeRegionList::check_mt_safety() { + // Secondary Free List MT safety protocol: + // Operations on the secondary free list should always be invoked + // while holding the SecondaryFreeList_lock. + + guarantee(SecondaryFreeList_lock->owned_by_self(), + hrl_ext_msg(this, "secondary free list MT safety protocol")); + + return FreeRegionList::check_mt_safety(); +} + +//////////////////// HumongousRegionSet //////////////////// + +const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) { + if (hr->is_young()) { + return "the region should not be young"; + } + // The superclass will check that the region is not empty and + // humongous. + return HeapRegionSet::verify_region_extra(hr); +} + +//////////////////// HumongousRegionSet //////////////////// + +bool MasterHumongousRegionSet::check_mt_safety() { + // Master Humongous Set MT safety protocol: + // (a) If we're at a safepoint, operations on the master humongous + // set should be invoked by either the VM thread (which will + // serialize them) or by the GC workers while holding the + // OldSets_lock. + // (b) If we're not at a safepoint, operations on the master + // humongous set should be invoked while holding the Heap_lock. + + guarantee((SafepointSynchronize::is_at_safepoint() && + (Thread::current()->is_VM_thread() || + OldSets_lock->owned_by_self())) || + (!SafepointSynchronize::is_at_safepoint() && + Heap_lock->owned_by_self()), + hrl_ext_msg(this, "master humongous set MT safety protocol")); + return HumongousRegionSet::check_mt_safety(); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp new file mode 100644 index 00000000000..c00327c578f --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp @@ -0,0 +1,86 @@ +/* + * copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP + +#include "gc_implementation/g1/heapRegionSet.inline.hpp" + +//////////////////// FreeRegionList //////////////////// + +class FreeRegionList : public HeapRegionLinkedList { +protected: + virtual const char* verify_region_extra(HeapRegion* hr); + + virtual bool regions_humongous() { return false; } + virtual bool regions_empty() { return true; } + +public: + FreeRegionList(const char* name) : HeapRegionLinkedList(name) { } +}; + +//////////////////// MasterFreeRegionList //////////////////// + +class MasterFreeRegionList : public FreeRegionList { +protected: + virtual bool check_mt_safety(); + +public: + MasterFreeRegionList(const char* name) : FreeRegionList(name) { } +}; + +//////////////////// SecondaryFreeRegionList //////////////////// + +class SecondaryFreeRegionList : public FreeRegionList { +protected: + virtual bool check_mt_safety(); + +public: + SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { } +}; + +//////////////////// HumongousRegionSet //////////////////// + +class HumongousRegionSet : public HeapRegionSet { +protected: + virtual const char* verify_region_extra(HeapRegion* hr); + + virtual bool regions_humongous() { return true; } + virtual bool regions_empty() { return false; } + +public: + HumongousRegionSet(const char* name) : HeapRegionSet(name) { } +}; + +//////////////////// MasterHumongousRegionSet //////////////////// + +class MasterHumongousRegionSet : public HumongousRegionSet { +protected: + virtual bool check_mt_safety(); + +public: + MasterHumongousRegionSet(const char* name) : HumongousRegionSet(name) { } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp index dac9fc36415..4186b42b788 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,8 @@ # include "thread_windows.inline.hpp" #endif -PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm, bool active) : - _qset(qset_), _buf(NULL), _index(0), _active(active), +PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) : + _qset(qset), _buf(NULL), _index(0), _active(active), _perm(perm), _lock(NULL) {} @@ -153,10 +153,16 @@ void PtrQueueSet::reduce_free_list() { } void PtrQueue::handle_zero_index() { - assert(0 == _index, "Precondition."); + assert(_index == 0, "Precondition."); + // This thread records the full buffer and allocates a new one (while // holding the lock if there is one). if (_buf != NULL) { + if (!should_enqueue_buffer()) { + assert(_index > 0, "the buffer can only be re-used if it's not full"); + return; + } + if (_lock) { assert(_lock->owned_by_self(), "Required."); diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp index d5a128240d8..55a96fce129 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ protected: public: // Initialize this queue to contain a null buffer, and be part of the // given PtrQueueSet. - PtrQueue(PtrQueueSet*, bool perm = false, bool active = false); + PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false); // Release any contained resources. void flush(); // Calls flush() when destroyed. @@ -85,6 +85,14 @@ public: else enqueue_known_active(ptr); } + // This method is called when we're doing the zero index handling + // and gives a chance to the queues to do any pre-enqueueing + // processing they might want to do on the buffer. It should return + // true if the buffer should be enqueued, or false if enough + // entries were cleared from it so that it can be re-used. It should + // not return false if the buffer is still full (otherwise we can + // get into an infinite loop). + virtual bool should_enqueue_buffer() { return true; } void handle_zero_index(); void locking_enqueue_completed_buffer(void** buf); diff --git a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp index b6b15e13469..5a7a7b694e8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,98 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/satbQueue.hpp" #include "memory/allocation.inline.hpp" #include "memory/sharedHeap.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.hpp" +// This method removes entries from an SATB buffer that will not be +// useful to the concurrent marking threads. An entry is removed if it +// satisfies one of the following conditions: +// +// * it points to an object outside the G1 heap (G1's concurrent +// marking only visits objects inside the G1 heap), +// * it points to an object that has been allocated since marking +// started (according to SATB those objects do not need to be +// visited during marking), or +// * it points to an object that has already been marked (no need to +// process it again). +// +// The rest of the entries will be retained and are compacted towards +// the top of the buffer. If with this filtering we clear a large +// enough chunk of the buffer we can re-use it (instead of enqueueing +// it) and we can just allow the mutator to carry on executing. + +bool ObjPtrQueue::should_enqueue_buffer() { + assert(_lock == NULL || _lock->owned_by_self(), + "we should have taken the lock before calling this"); + + // A value of 0 means "don't filter SATB buffers". + if (G1SATBBufferEnqueueingThresholdPercent == 0) { + return true; + } + + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + // This method should only be called if there is a non-NULL buffer + // that is full. + assert(_index == 0, "pre-condition"); + assert(_buf != NULL, "pre-condition"); + + void** buf = _buf; + size_t sz = _sz; + + // Used for sanity checking at the end of the loop. + debug_only(size_t entries = 0; size_t retained = 0;) + + size_t i = sz; + size_t new_index = sz; + + // Given that we are expecting _index == 0, we could have changed + // the loop condition to (i > 0). But we are using _index for + // generality. + while (i > _index) { + assert(i > 0, "we should have at least one more entry to process"); + i -= oopSize; + debug_only(entries += 1;) + oop* p = (oop*) &buf[byte_index_to_index((int) i)]; + oop obj = *p; + // NULL the entry so that unused parts of the buffer contain NULLs + // at the end. If we are going to retain it we will copy it to its + // final place. If we have retained all entries we have visited so + // far, we'll just end up copying it to the same place. + *p = NULL; + + bool retain = g1h->is_obj_ill(obj); + if (retain) { + assert(new_index > 0, "we should not have already filled up the buffer"); + new_index -= oopSize; + assert(new_index >= i, + "new_index should never be below i, as we alwaysr compact 'up'"); + oop* new_p = (oop*) &buf[byte_index_to_index((int) new_index)]; + assert(new_p >= p, "the destination location should never be below " + "the source as we always compact 'up'"); + assert(*new_p == NULL, + "we should have already cleared the destination location"); + *new_p = obj; + debug_only(retained += 1;) + } + } + size_t entries_calc = (sz - _index) / oopSize; + assert(entries == entries_calc, "the number of entries we counted " + "should match the number of entries we calculated"); + size_t retained_calc = (sz - new_index) / oopSize; + assert(retained == retained_calc, "the number of retained entries we counted " + "should match the number of retained entries we calculated"); + size_t perc = retained_calc * 100 / entries_calc; + bool should_enqueue = perc > (size_t) G1SATBBufferEnqueueingThresholdPercent; + _index = new_index; + + return should_enqueue; +} + void ObjPtrQueue::apply_closure(ObjectClosure* cl) { if (_buf != NULL) { apply_closure_to_buffer(cl, _buf, _index, _sz); diff --git a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp index a183642368c..5a44b1695e1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,13 +33,18 @@ class JavaThread; // A ptrQueue whose elements are "oops", pointers to object heads. class ObjPtrQueue: public PtrQueue { public: - ObjPtrQueue(PtrQueueSet* qset_, bool perm = false) : + ObjPtrQueue(PtrQueueSet* qset, bool perm = false) : // SATB queues are only active during marking cycles. We create // them with their active field set to false. If a thread is // created during a cycle and its SATB queue needs to be activated // before the thread starts running, we'll need to set its active // field to true. This is done in JavaThread::initialize_queues(). - PtrQueue(qset_, perm, false /* active */) { } + PtrQueue(qset, perm, false /* active */) { } + + // Overrides PtrQueue::should_enqueue_buffer(). See the method's + // definition for more information. + virtual bool should_enqueue_buffer(); + // Apply the closure to all elements, and reset the index to make the // buffer empty. void apply_closure(ObjectClosure* cl); diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index 1ceeead58ff..aaf44b02d3f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -38,7 +38,6 @@ VM_G1CollectForAllocation::VM_G1CollectForAllocation( } void VM_G1CollectForAllocation::doit() { - JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); _result = g1h->satisfy_failed_allocation(_word_size, &_pause_succeeded); assert(_result == NULL || _pause_succeeded, @@ -46,7 +45,6 @@ void VM_G1CollectForAllocation::doit() { } void VM_G1CollectFull::doit() { - JvmtiGCFullMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCCauseSetter x(g1h, _gc_cause); g1h->do_full_collection(false /* clear_all_soft_refs */); @@ -72,7 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause( } void VM_G1IncCollectionPause::doit() { - JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); assert(!_should_initiate_conc_mark || ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index 3efa4ceaeae..4c96c3d41d0 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -258,6 +258,7 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { BiasedLocking::restore_marks(); Threads::gc_epilogue(); CodeCache::gc_epilogue(); + JvmtiExport::gc_epilogue(); COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 79e269dc7f3..87ba37e496b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -1054,6 +1054,7 @@ void PSParallelCompact::post_compact() Threads::gc_epilogue(); CodeCache::gc_epilogue(); + JvmtiExport::gc_epilogue(); COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp index 453c791621b..0f122a97b57 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp @@ -42,8 +42,7 @@ VM_ParallelGCFailedAllocation::VM_ParallelGCFailedAllocation(size_t size, } void VM_ParallelGCFailedAllocation::doit() { - JvmtiGCForAllocationMarker jgcm; - notify_gc_begin(false); + SvcGCMarker sgcm(SvcGCMarker::MINOR); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "must be a ParallelScavengeHeap"); @@ -54,8 +53,6 @@ void VM_ParallelGCFailedAllocation::doit() { if (_result == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } - - notify_gc_end(); } VM_ParallelGCFailedPermanentAllocation::VM_ParallelGCFailedPermanentAllocation(size_t size, @@ -67,8 +64,7 @@ VM_ParallelGCFailedPermanentAllocation::VM_ParallelGCFailedPermanentAllocation(s } void VM_ParallelGCFailedPermanentAllocation::doit() { - JvmtiGCFullMarker jgcm; - notify_gc_begin(true); + SvcGCMarker sgcm(SvcGCMarker::FULL); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "must be a ParallelScavengeHeap"); @@ -78,7 +74,6 @@ void VM_ParallelGCFailedPermanentAllocation::doit() { if (_result == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } - notify_gc_end(); } // Only used for System.gc() calls @@ -91,8 +86,7 @@ VM_ParallelGCSystemGC::VM_ParallelGCSystemGC(unsigned int gc_count, } void VM_ParallelGCSystemGC::doit() { - JvmtiGCFullMarker jgcm; - notify_gc_begin(true); + SvcGCMarker sgcm(SvcGCMarker::FULL); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, @@ -106,5 +100,4 @@ void VM_ParallelGCSystemGC::doit() { } else { heap->invoke_full_gc(false); } - notify_gc_end(); } diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index 350d6dbacb6..5799550d114 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -31,7 +31,6 @@ #include "memory/oopFactory.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceRefKlass.hpp" -#include "prims/jvmtiExport.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -40,6 +39,7 @@ #ifndef SERIALGC #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #endif + HS_DTRACE_PROBE_DECL1(hotspot, gc__begin, bool); HS_DTRACE_PROBE_DECL(hotspot, gc__end); @@ -158,8 +158,7 @@ void VM_GC_HeapInspection::doit() { void VM_GenCollectForAllocation::doit() { - JvmtiGCForAllocationMarker jgcm; - notify_gc_begin(false); + SvcGCMarker sgcm(SvcGCMarker::MINOR); GenCollectedHeap* gch = GenCollectedHeap::heap(); GCCauseSetter gccs(gch, _gc_cause); @@ -169,22 +168,19 @@ void VM_GenCollectForAllocation::doit() { if (_res == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } - notify_gc_end(); } void VM_GenCollectFull::doit() { - JvmtiGCFullMarker jgcm; - notify_gc_begin(true); + SvcGCMarker sgcm(SvcGCMarker::FULL); GenCollectedHeap* gch = GenCollectedHeap::heap(); GCCauseSetter gccs(gch, _gc_cause); gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level); - notify_gc_end(); } void VM_GenCollectForPermanentAllocation::doit() { - JvmtiGCForAllocationMarker jgcm; - notify_gc_begin(true); + SvcGCMarker sgcm(SvcGCMarker::FULL); + SharedHeap* heap = (SharedHeap*)Universe::heap(); GCCauseSetter gccs(heap, _gc_cause); switch (heap->kind()) { @@ -209,5 +205,4 @@ void VM_GenCollectForPermanentAllocation::doit() { if (_res == NULL && GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } - notify_gc_end(); } diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp index c7ee95f445b..1a828facadc 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp @@ -30,6 +30,7 @@ #include "runtime/jniHandles.hpp" #include "runtime/synchronizer.hpp" #include "runtime/vm_operations.hpp" +#include "prims/jvmtiExport.hpp" // The following class hierarchy represents // a set of operations (VM_Operation) related to GC. @@ -209,13 +210,17 @@ class VM_GenCollectForPermanentAllocation: public VM_GC_Operation { HeapWord* result() const { return _res; } }; -class DTraceGCProbeMarker : public StackObj { -public: - DTraceGCProbeMarker(bool full) { - VM_GC_Operation::notify_gc_begin(full); +class SvcGCMarker : public StackObj { + private: + JvmtiGCMarker _jgcm; + public: + typedef enum { MINOR, FULL, OTHER } reason_type; + + SvcGCMarker(reason_type reason ) { + VM_GC_Operation::notify_gc_begin(reason == FULL); } - ~DTraceGCProbeMarker() { + ~SvcGCMarker() { VM_GC_Operation::notify_gc_end(); } }; diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp index badfc322e82..b204a4f2691 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.cpp +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,30 +34,6 @@ // Implementation of Bytecode -bool Bytecode::check_must_rewrite(Bytecodes::Code code) const { - assert(Bytecodes::can_rewrite(code), "post-check only"); - - // Some codes are conditionally rewriting. Look closely at them. - switch (code) { - case Bytecodes::_aload_0: - // Even if RewriteFrequentPairs is turned on, - // the _aload_0 code might delay its rewrite until - // a following _getfield rewrites itself. - return false; - - case Bytecodes::_lookupswitch: - return false; // the rewrite is not done by the interpreter - - case Bytecodes::_new: - // (Could actually look at the class here, but the profit would be small.) - return false; // the rewrite is not always done - } - - // No other special cases. - return true; -} - - #ifdef ASSERT void Bytecode::assert_same_format_as(Bytecodes::Code testbc, bool is_wide) const { @@ -188,17 +164,16 @@ int Bytecode_member_ref::index() const { // Note: Rewriter::rewrite changes the Java_u2 of an invokedynamic to a native_u4, // at the same time it allocates per-call-site CP cache entries. Bytecodes::Code rawc = code(); - Bytecode* invoke = bytecode(); - if (invoke->has_index_u4(rawc)) - return invoke->get_index_u4(rawc); + if (has_index_u4(rawc)) + return get_index_u4(rawc); else - return invoke->get_index_u2_cpcache(rawc); + return get_index_u2_cpcache(rawc); } int Bytecode_member_ref::pool_index() const { int index = this->index(); DEBUG_ONLY({ - if (!bytecode()->has_index_u4(code())) + if (!has_index_u4(code())) index -= constantPoolOopDesc::CPCACHE_INDEX_TAG; }); return _method->constants()->cache()->entry_at(index)->constant_pool_index(); @@ -214,13 +189,12 @@ void Bytecode_field::verify() const { // Implementation of Bytecode_loadconstant int Bytecode_loadconstant::raw_index() const { - Bytecode* bcp = bytecode(); - Bytecodes::Code rawc = bcp->code(); + Bytecodes::Code rawc = code(); assert(rawc != Bytecodes::_wide, "verifier prevents this"); if (Bytecodes::java_code(rawc) == Bytecodes::_ldc) - return bcp->get_index_u1(rawc); + return get_index_u1(rawc); else - return bcp->get_index_u2(rawc, false); + return get_index_u2(rawc, false); } int Bytecode_loadconstant::pool_index() const { @@ -258,7 +232,7 @@ void Bytecode_lookupswitch::verify() const { case Bytecodes::_lookupswitch: { int i = number_of_pairs() - 1; while (i-- > 0) { - assert(pair_at(i)->match() < pair_at(i+1)->match(), "unsorted table entries"); + assert(pair_at(i).match() < pair_at(i+1).match(), "unsorted table entries"); } } break; diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp index ae27187aa14..8ef4031c9f5 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.hpp +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,14 +38,20 @@ # include "bytes_zero.hpp" #endif -// Base class for different kinds of abstractions working -// relative to an objects 'this' pointer. +class ciBytecodeStream; + +// The base class for different kinds of bytecode abstractions. +// Provides the primitive operations to manipulate code relative +// to the bcp. + +class Bytecode: public StackObj { + protected: + const address _bcp; + const Bytecodes::Code _code; -class ThisRelativeObj VALUE_OBJ_CLASS_SPEC { - public: // Address computation - address addr_at (int offset) const { return (address)this + offset; } - int byte_at (int offset) const { return *(addr_at(offset)); } + address addr_at (int offset) const { return (address)_bcp + offset; } + u_char byte_at(int offset) const { return *addr_at(offset); } address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } @@ -54,31 +60,20 @@ class ThisRelativeObj VALUE_OBJ_CLASS_SPEC { int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); } int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); } -}; - - -// The base class for different kinds of bytecode abstractions. -// Provides the primitive operations to manipulate code relative -// to an objects 'this' pointer. -// FIXME: Make this a ResourceObj, include the enclosing methodOop, and cache the opcode. - -class Bytecode: public ThisRelativeObj { - protected: - u_char byte_at(int offset) const { return *addr_at(offset); } - bool check_must_rewrite(Bytecodes::Code bc) const; public: + Bytecode(methodOop method, address bcp): _bcp(bcp), _code(Bytecodes::code_at(method, addr_at(0))) { + assert(method != NULL, "this form requires a valid methodOop"); + } + // Defined in ciStreams.hpp + inline Bytecode(const ciBytecodeStream* stream, address bcp = NULL); + // Attributes - address bcp() const { return addr_at(0); } - int instruction_size() const { return Bytecodes::length_at(bcp()); } + address bcp() const { return _bcp; } + int instruction_size() const { return Bytecodes::length_for_code_at(_code, bcp()); } - // Warning: Use code() with caution on live bytecode streams. 4926272 - Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); } + Bytecodes::Code code() const { return _code; } Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } - bool must_rewrite(Bytecodes::Code code) const { return Bytecodes::can_rewrite(code) && check_must_rewrite(code); } - - // Creation - inline friend Bytecode* Bytecode_at(address bcp); // Static functions for parsing bytecodes in place. int get_index_u1(Bytecodes::Code bc) const { @@ -89,7 +84,7 @@ class Bytecode: public ThisRelativeObj { assert_same_format_as(bc, is_wide); assert_index_size(2, bc, is_wide); address p = addr_at(is_wide ? 2 : 1); if (can_use_native_byte_order(bc, is_wide)) - return Bytes::get_native_u2(p); + return Bytes::get_native_u2(p); else return Bytes::get_Java_u2(p); } int get_index_u1_cpcache(Bytecodes::Code bc) const { @@ -138,20 +133,17 @@ class Bytecode: public ThisRelativeObj { } }; -inline Bytecode* Bytecode_at(address bcp) { - // Warning: Use with caution on live bytecode streams. 4926272 - return (Bytecode*)bcp; -} - // Abstractions for lookupswitch bytecode - -class LookupswitchPair: ThisRelativeObj { +class LookupswitchPair VALUE_OBJ_CLASS_SPEC { private: - int _match; - int _offset; + const address _bcp; + + address addr_at (int offset) const { return _bcp + offset; } + int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } public: + LookupswitchPair(address bcp): _bcp(bcp) {} int match() const { return get_Java_u4_at(0 * jintSize); } int offset() const { return get_Java_u4_at(1 * jintSize); } }; @@ -159,26 +151,25 @@ class LookupswitchPair: ThisRelativeObj { class Bytecode_lookupswitch: public Bytecode { public: + Bytecode_lookupswitch(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } + // Defined in ciStreams.hpp + inline Bytecode_lookupswitch(const ciBytecodeStream* stream); void verify() const PRODUCT_RETURN; // Attributes int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } - LookupswitchPair* pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); - return (LookupswitchPair*)aligned_addr_at(1 + (1 + i)*2*jintSize); } - // Creation - inline friend Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp); + LookupswitchPair pair_at(int i) const { + assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); + return LookupswitchPair(aligned_addr_at(1 + (1 + i)*2*jintSize)); + } }; -inline Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp) { - Bytecode_lookupswitch* b = (Bytecode_lookupswitch*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - class Bytecode_tableswitch: public Bytecode { public: + Bytecode_tableswitch(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } + // Defined in ciStreams.hpp + inline Bytecode_tableswitch(const ciBytecodeStream* stream); void verify() const PRODUCT_RETURN; // Attributes @@ -187,52 +178,36 @@ class Bytecode_tableswitch: public Bytecode { int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); } int dest_offset_at(int i) const; int length() { return high_key()-low_key()+1; } - - // Creation - inline friend Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp); }; -inline Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp) { - Bytecode_tableswitch* b = (Bytecode_tableswitch*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - // Common code for decoding invokes and field references. -class Bytecode_member_ref: public ResourceObj { +class Bytecode_member_ref: public Bytecode { protected: - methodHandle _method; // method containing the bytecode - int _bci; // position of the bytecode + const methodHandle _method; // method containing the bytecode - Bytecode_member_ref(methodHandle method, int bci) : _method(method), _bci(bci) {} + Bytecode_member_ref(methodHandle method, int bci) : Bytecode(method(), method()->bcp_from(bci)), _method(method) {} + + methodHandle method() const { return _method; } public: - // Attributes - methodHandle method() const { return _method; } - int bci() const { return _bci; } - address bcp() const { return _method->bcp_from(bci()); } - Bytecode* bytecode() const { return Bytecode_at(bcp()); } - int index() const; // cache index (loaded from instruction) int pool_index() const; // constant pool index symbolOop name() const; // returns the name of the method or field symbolOop signature() const; // returns the signature of the method or field BasicType result_type(Thread* thread) const; // returns the result type of the getfield or invoke - - Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); } - Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } }; // Abstraction for invoke_{virtual, static, interface, special} class Bytecode_invoke: public Bytecode_member_ref { protected: - Bytecode_invoke(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} + // Constructor that skips verification + Bytecode_invoke(methodHandle method, int bci, bool unused) : Bytecode_member_ref(method, bci) {} public: + Bytecode_invoke(methodHandle method, int bci) : Bytecode_member_ref(method, bci) { verify(); } void verify() const; // Attributes @@ -253,31 +228,20 @@ class Bytecode_invoke: public Bytecode_member_ref { is_invokespecial() || is_invokedynamic(); } - // Creation - inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci); - - // Like Bytecode_invoke_at. Instead it returns NULL if the bci is not at an invoke. - inline friend Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci); + // Helper to skip verification. Used is_valid() to check if the result is really an invoke + inline friend Bytecode_invoke Bytecode_invoke_check(methodHandle method, int bci); }; -inline Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci) { - Bytecode_invoke* b = new Bytecode_invoke(method, bci); - DEBUG_ONLY(b->verify()); - return b; -} - -inline Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci) { - Bytecode_invoke* b = new Bytecode_invoke(method, bci); - return b->is_valid() ? b : NULL; +inline Bytecode_invoke Bytecode_invoke_check(methodHandle method, int bci) { + return Bytecode_invoke(method, bci, false); } // Abstraction for all field accesses (put/get field/static) class Bytecode_field: public Bytecode_member_ref { - protected: - Bytecode_field(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} - public: + Bytecode_field(methodHandle method, int bci) : Bytecode_member_ref(method, bci) { verify(); } + // Testers bool is_getfield() const { return java_code() == Bytecodes::_getfield; } bool is_putfield() const { return java_code() == Bytecodes::_putfield; } @@ -292,131 +256,64 @@ class Bytecode_field: public Bytecode_member_ref { is_getstatic() || is_putstatic(); } void verify() const; - - // Creation - inline friend Bytecode_field* Bytecode_field_at(methodHandle method, int bci); }; -inline Bytecode_field* Bytecode_field_at(methodHandle method, int bci) { - Bytecode_field* b = new Bytecode_field(method, bci); - DEBUG_ONLY(b->verify()); - return b; -} - - // Abstraction for checkcast - class Bytecode_checkcast: public Bytecode { public: + Bytecode_checkcast(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } void verify() const { assert(Bytecodes::java_code(code()) == Bytecodes::_checkcast, "check checkcast"); } // Returns index long index() const { return get_index_u2(Bytecodes::_checkcast); }; - - // Creation - inline friend Bytecode_checkcast* Bytecode_checkcast_at(address bcp); }; -inline Bytecode_checkcast* Bytecode_checkcast_at(address bcp) { - Bytecode_checkcast* b = (Bytecode_checkcast*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - // Abstraction for instanceof - class Bytecode_instanceof: public Bytecode { public: + Bytecode_instanceof(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } void verify() const { assert(code() == Bytecodes::_instanceof, "check instanceof"); } // Returns index long index() const { return get_index_u2(Bytecodes::_instanceof); }; - - // Creation - inline friend Bytecode_instanceof* Bytecode_instanceof_at(address bcp); }; -inline Bytecode_instanceof* Bytecode_instanceof_at(address bcp) { - Bytecode_instanceof* b = (Bytecode_instanceof*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - class Bytecode_new: public Bytecode { public: + Bytecode_new(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } void verify() const { assert(java_code() == Bytecodes::_new, "check new"); } // Returns index long index() const { return get_index_u2(Bytecodes::_new); }; - - // Creation - inline friend Bytecode_new* Bytecode_new_at(address bcp); }; -inline Bytecode_new* Bytecode_new_at(address bcp) { - Bytecode_new* b = (Bytecode_new*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - class Bytecode_multianewarray: public Bytecode { public: + Bytecode_multianewarray(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } void verify() const { assert(java_code() == Bytecodes::_multianewarray, "check new"); } // Returns index long index() const { return get_index_u2(Bytecodes::_multianewarray); }; - - // Creation - inline friend Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp); }; -inline Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp) { - Bytecode_multianewarray* b = (Bytecode_multianewarray*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - class Bytecode_anewarray: public Bytecode { public: + Bytecode_anewarray(methodOop method, address bcp): Bytecode(method, bcp) { verify(); } void verify() const { assert(java_code() == Bytecodes::_anewarray, "check anewarray"); } // Returns index long index() const { return get_index_u2(Bytecodes::_anewarray); }; - - // Creation - inline friend Bytecode_anewarray* Bytecode_anewarray_at(address bcp); }; -inline Bytecode_anewarray* Bytecode_anewarray_at(address bcp) { - Bytecode_anewarray* b = (Bytecode_anewarray*)bcp; - DEBUG_ONLY(b->verify()); - return b; -} - - // Abstraction for ldc, ldc_w and ldc2_w - -class Bytecode_loadconstant: public ResourceObj { +class Bytecode_loadconstant: public Bytecode { private: - int _bci; - methodHandle _method; - - Bytecodes::Code code() const { return bytecode()->code(); } + const methodHandle _method; int raw_index() const; - Bytecode_loadconstant(methodHandle method, int bci) : _method(method), _bci(bci) {} - public: - // Attributes - methodHandle method() const { return _method; } - int bci() const { return _bci; } - address bcp() const { return _method->bcp_from(bci()); } - Bytecode* bytecode() const { return Bytecode_at(bcp()); } + Bytecode_loadconstant(methodHandle method, int bci): Bytecode(method(), method->bcp_from(bci)), _method(method) { verify(); } void verify() const { assert(_method.not_null(), "must supply method"); @@ -437,15 +334,6 @@ class Bytecode_loadconstant: public ResourceObj { BasicType result_type() const; // returns the result type of the ldc oop resolve_constant(TRAPS) const; - - // Creation - inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci); }; -inline Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci) { - Bytecode_loadconstant* b = new Bytecode_loadconstant(method, bci); - DEBUG_ONLY(b->verify()); - return b; -} - #endif // SHARE_VM_INTERPRETER_BYTECODE_HPP diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 16ec3ff6081..c214457b4f4 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -831,11 +831,11 @@ BytecodeInterpreter::run(interpreterState istate) { // much like trying to deopt at a poll return. In that has we simply // get out of here // - if ( Bytecodes::code_at(pc, METHOD) == Bytecodes::_return_register_finalizer) { + if ( Bytecodes::code_at(METHOD, pc) == Bytecodes::_return_register_finalizer) { // this will do the right thing even if an exception is pending. goto handle_return; } - UPDATE_PC(Bytecodes::length_at(pc)); + UPDATE_PC(Bytecodes::length_at(METHOD, pc)); if (THREAD->has_pending_exception()) goto handle_exception; goto run; } diff --git a/hotspot/src/share/vm/interpreter/bytecodeStream.cpp b/hotspot/src/share/vm/interpreter/bytecodeStream.cpp index 65fd7ecf575..bf03c08c2bf 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeStream.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ void BaseBytecodeStream::assert_raw_index_size(int size) const { // in raw mode, pretend indy is "bJJ__" assert(size == 2, "raw invokedynamic instruction has 2-byte index only"); } else { - bytecode()->assert_index_size(size, raw_code(), is_wide()); + bytecode().assert_index_size(size, raw_code(), is_wide()); } } diff --git a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp index f3b5a787b3f..05e4e64d088 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,14 +105,14 @@ class BaseBytecodeStream: StackObj { bool is_last_bytecode() const { return _next_bci >= _end_bci; } address bcp() const { return method()->code_base() + _bci; } - Bytecode* bytecode() const { return Bytecode_at(bcp()); } + Bytecode bytecode() const { return Bytecode(_method(), bcp()); } // State changes void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; } // Bytecode-specific attributes - int dest() const { return bci() + bytecode()->get_offset_s2(raw_code()); } - int dest_w() const { return bci() + bytecode()->get_offset_s4(raw_code()); } + int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); } + int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); } // One-byte indices. int get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); } @@ -189,7 +189,7 @@ class BytecodeStream: public BaseBytecodeStream { } else { // get bytecode address bcp = this->bcp(); - raw_code = Bytecodes::code_at(bcp); + raw_code = Bytecodes::code_at(_method(), bcp); code = Bytecodes::java_code(raw_code); // set next bytecode position // @@ -197,7 +197,7 @@ class BytecodeStream: public BaseBytecodeStream { // tty bytecode otherwise the stepping is wrong! // (carefull: length_for(...) must be used first!) int l = Bytecodes::length_for(code); - if (l == 0) l = Bytecodes::length_at(bcp); + if (l == 0) l = Bytecodes::length_at(_method(), bcp); _next_bci += l; assert(_bci < _next_bci, "length must be > 0"); // set attributes @@ -219,16 +219,16 @@ class BytecodeStream: public BaseBytecodeStream { Bytecodes::Code code() const { return _code; } // Unsigned indices, widening - int get_index() const { return is_wide() ? bytecode()->get_index_u2(raw_code(), true) : get_index_u1(); } + int get_index() const { return is_wide() ? bytecode().get_index_u2(raw_code(), true) : get_index_u1(); } // Get an unsigned 2-byte index, swapping the bytes if necessary. int get_index_u2() const { assert_raw_stream(false); - return bytecode()->get_index_u2(raw_code(), false); } + return bytecode().get_index_u2(raw_code(), false); } // Get an unsigned 2-byte index in native order. int get_index_u2_cpcache() const { assert_raw_stream(false); - return bytecode()->get_index_u2_cpcache(raw_code()); } + return bytecode().get_index_u2_cpcache(raw_code()); } int get_index_u4() const { assert_raw_stream(false); - return bytecode()->get_index_u4(raw_code()); } - bool has_index_u4() const { return bytecode()->has_index_u4(raw_code()); } + return bytecode().get_index_u4(raw_code()); } + bool has_index_u4() const { return bytecode().has_index_u4(raw_code()); } }; #endif // SHARE_VM_INTERPRETER_BYTECODESTREAM_HPP diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index d5f19449f8f..97f6ca47488 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,9 +100,9 @@ class BytecodePrinter: public BytecodeClosure { Bytecodes::Code code; if (is_wide()) { // bcp wasn't advanced if previous bytecode was _wide. - code = Bytecodes::code_at(bcp+1); + code = Bytecodes::code_at(method(), bcp+1); } else { - code = Bytecodes::code_at(bcp); + code = Bytecodes::code_at(method(), bcp); } _code = code; int bci = bcp - method->code_base(); @@ -127,11 +127,11 @@ class BytecodePrinter: public BytecodeClosure { void trace(methodHandle method, address bcp, outputStream* st) { _current_method = method(); ResourceMark rm; - Bytecodes::Code code = Bytecodes::code_at(bcp); + Bytecodes::Code code = Bytecodes::code_at(method(), bcp); // Set is_wide _is_wide = (code == Bytecodes::_wide); if (is_wide()) { - code = Bytecodes::code_at(bcp+1); + code = Bytecodes::code_at(method(), bcp+1); } _code = code; int bci = bcp - method->code_base(); diff --git a/hotspot/src/share/vm/interpreter/bytecodes.cpp b/hotspot/src/share/vm/interpreter/bytecodes.cpp index 0601d3fbea1..45c42bb592e 100644 --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,18 +54,46 @@ u_char Bytecodes::_lengths [Bytecodes::number_of_codes]; Bytecodes::Code Bytecodes::_java_code [Bytecodes::number_of_codes]; u_short Bytecodes::_flags [(1<contains(bcp); +} +#endif -Bytecodes::Code Bytecodes::code_at(methodOop method, int bci) { - return code_at(method->bcp_from(bci), method); +bool Bytecodes::check_must_rewrite(Bytecodes::Code code) { + assert(can_rewrite(code), "post-check only"); + + // Some codes are conditionally rewriting. Look closely at them. + switch (code) { + case Bytecodes::_aload_0: + // Even if RewriteFrequentPairs is turned on, + // the _aload_0 code might delay its rewrite until + // a following _getfield rewrites itself. + return false; + + case Bytecodes::_lookupswitch: + return false; // the rewrite is not done by the interpreter + + case Bytecodes::_new: + // (Could actually look at the class here, but the profit would be small.) + return false; // the rewrite is not always done + } + + // No other special cases. + return true; } -Bytecodes::Code Bytecodes::non_breakpoint_code_at(address bcp, methodOop method) { - if (method == NULL) method = methodOopDesc::method_from_bcp(bcp); +Bytecodes::Code Bytecodes::code_at(methodOop method, int bci) { + return code_at(method, method->bcp_from(bci)); +} + +Bytecodes::Code Bytecodes::non_breakpoint_code_at(const methodOopDesc* method, address bcp) { + assert(method != NULL, "must have the method for breakpoint conversion"); + assert(method->contains(bcp), "must be valid bcp in method"); return method->orig_bytecode_at(method->bci_from(bcp)); } -int Bytecodes::special_length_at(address bcp, address end) { - Code code = code_at(bcp); +int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) { switch (code) { case _wide: if (end != NULL && bcp + 1 >= end) { @@ -120,7 +148,7 @@ int Bytecodes::raw_special_length_at(address bcp, address end) { if (code == _breakpoint) { return 1; } else { - return special_length_at(bcp, end); + return special_length_at(code, bcp, end); } } diff --git a/hotspot/src/share/vm/interpreter/bytecodes.hpp b/hotspot/src/share/vm/interpreter/bytecodes.hpp index 91e456f7a1c..29313cd44b6 100644 --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -342,6 +342,12 @@ class Bytecodes: AllStatic { static void pd_initialize(); // platform specific initialization static Code pd_base_code_for(Code code); // platform specific base_code_for implementation + // Verify that bcp points into method +#ifdef ASSERT + static bool check_method(const methodOopDesc* method, address bcp); +#endif + static bool check_must_rewrite(Bytecodes::Code bc); + public: // Conversion static void check (Code code) { assert(is_defined(code), "illegal code"); } @@ -349,22 +355,30 @@ class Bytecodes: AllStatic { static Code cast (int code) { return (Code)code; } - // Fetch a bytecode, hiding breakpoints as necessary: - static Code code_at(address bcp, methodOop method = NULL) { - Code code = cast(*bcp); return (code != _breakpoint) ? code : non_breakpoint_code_at(bcp, method); - } - static Code java_code_at(address bcp, methodOop method = NULL) { - return java_code(code_at(bcp, method)); - } + // Fetch a bytecode, hiding breakpoints as necessary. The method + // argument is used for conversion of breakpoints into the original + // bytecode. The CI uses these methods but guarantees that + // breakpoints are hidden so the method argument should be passed as + // NULL since in that case the bcp and methodOop are unrelated + // memory. + static Code code_at(const methodOopDesc* method, address bcp) { + assert(method == NULL || check_method(method, bcp), "bcp must point into method"); + Code code = cast(*bcp); + assert(code != _breakpoint || method != NULL, "need methodOop to decode breakpoint"); + return (code != _breakpoint) ? code : non_breakpoint_code_at(method, bcp); + } + static Code java_code_at(const methodOopDesc* method, address bcp) { + return java_code(code_at(method, bcp)); + } - // Fetch a bytecode or a breakpoint: - static Code code_or_bp_at(address bcp) { return (Code)cast(*bcp); } + // Fetch a bytecode or a breakpoint: + static Code code_or_bp_at(address bcp) { return (Code)cast(*bcp); } - static Code code_at(methodOop method, int bci); - static bool is_active_breakpoint_at(address bcp) { return (Code)*bcp == _breakpoint; } + static Code code_at(methodOop method, int bci); + static bool is_active_breakpoint_at(address bcp) { return (Code)*bcp == _breakpoint; } - // find a bytecode, behind a breakpoint if necessary: - static Code non_breakpoint_code_at(address bcp, methodOop method = NULL); + // find a bytecode, behind a breakpoint if necessary: + static Code non_breakpoint_code_at(const methodOopDesc* method, address bcp); // Bytecode attributes static bool is_defined (int code) { return 0 <= code && code < number_of_codes && flags(code, false) != 0; } @@ -379,14 +393,17 @@ class Bytecodes: AllStatic { static bool can_trap (Code code) { check(code); return has_all_flags(code, _bc_can_trap, false); } static Code java_code (Code code) { check(code); return _java_code [code]; } static bool can_rewrite (Code code) { check(code); return has_all_flags(code, _bc_can_rewrite, false); } + static bool must_rewrite(Bytecodes::Code code) { return can_rewrite(code) && check_must_rewrite(code); } static bool native_byte_order(Code code) { check(code); return has_all_flags(code, _fmt_has_nbo, false); } static bool uses_cp_cache (Code code) { check(code); return has_all_flags(code, _fmt_has_j, false); } // if 'end' is provided, it indicates the end of the code buffer which // should not be read past when parsing. - static int special_length_at(address bcp, address end = NULL); + static int special_length_at(Bytecodes::Code code, address bcp, address end = NULL); + static int special_length_at(methodOop method, address bcp, address end = NULL) { return special_length_at(code_at(method, bcp), bcp, end); } static int raw_special_length_at(address bcp, address end = NULL); - static int length_at (address bcp) { int l = length_for(code_at(bcp)); return l > 0 ? l : special_length_at(bcp); } - static int java_length_at (address bcp) { int l = length_for(java_code_at(bcp)); return l > 0 ? l : special_length_at(bcp); } + static int length_for_code_at(Bytecodes::Code code, address bcp) { int l = length_for(code); return l > 0 ? l : special_length_at(code, bcp); } + static int length_at (methodOop method, address bcp) { return length_for_code_at(code_at(method, bcp), bcp); } + static int java_length_at (methodOop method, address bcp) { return length_for_code_at(java_code_at(method, bcp), bcp); } static bool is_java_code (Code code) { return 0 <= code && code < number_of_java_codes; } static bool is_aload (Code code) { return (code == _aload || code == _aload_0 || code == _aload_1 diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index 2c389b1d2ec..3edcc6cd9d8 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,10 +237,9 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) // Return true if the interpreter can prove that the given bytecode has // not yet been executed (in Java semantics, not in actual operation). bool AbstractInterpreter::is_not_reached(methodHandle method, int bci) { - address bcp = method->bcp_from(bci); - Bytecodes::Code code = Bytecodes::code_at(bcp, method()); + Bytecodes::Code code = method()->code_at(bci); - if (!Bytecode_at(bcp)->must_rewrite(code)) { + if (!Bytecodes::must_rewrite(code)) { // might have been reached return false; } @@ -286,12 +285,12 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) { // If deoptimization happens, this function returns the point of next bytecode to continue execution address AbstractInterpreter::deopt_continue_after_entry(methodOop method, address bcp, int callee_parameters, bool is_top_frame) { assert(method->contains(bcp), "just checkin'"); - Bytecodes::Code code = Bytecodes::java_code_at(bcp); + Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); assert(!Interpreter::bytecode_should_reexecute(code), "should not reexecute"); int bci = method->bci_from(bcp); int length = -1; // initial value for debugging // compute continuation length - length = Bytecodes::length_at(bcp); + length = Bytecodes::length_at(method, bcp); // compute result type BasicType type = T_ILLEGAL; @@ -303,7 +302,7 @@ address AbstractInterpreter::deopt_continue_after_entry(methodOop method, addres Thread *thread = Thread::current(); ResourceMark rm(thread); methodHandle mh(thread, method); - type = Bytecode_invoke_at(mh, bci)->result_type(thread); + type = Bytecode_invoke(mh, bci).result_type(thread); // since the cache entry might not be initialized: // (NOT needed for the old calling convension) if (!is_top_frame) { @@ -317,7 +316,7 @@ address AbstractInterpreter::deopt_continue_after_entry(methodOop method, addres Thread *thread = Thread::current(); ResourceMark rm(thread); methodHandle mh(thread, method); - type = Bytecode_invoke_at(mh, bci)->result_type(thread); + type = Bytecode_invoke(mh, bci).result_type(thread); // since the cache entry might not be initialized: // (NOT needed for the old calling convension) if (!is_top_frame) { @@ -334,7 +333,7 @@ address AbstractInterpreter::deopt_continue_after_entry(methodOop method, addres Thread *thread = Thread::current(); ResourceMark rm(thread); methodHandle mh(thread, method); - type = Bytecode_loadconstant_at(mh, bci)->result_type(); + type = Bytecode_loadconstant(mh, bci).result_type(); break; } @@ -356,7 +355,7 @@ address AbstractInterpreter::deopt_continue_after_entry(methodOop method, addres // Interpreter::deopt_entry(vtos, 0) like others address AbstractInterpreter::deopt_reexecute_entry(methodOop method, address bcp) { assert(method->contains(bcp), "just checkin'"); - Bytecodes::Code code = Bytecodes::java_code_at(bcp); + Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); #ifdef COMPILER1 if(code == Bytecodes::_athrow ) { return Interpreter::rethrow_exception_entry(); diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 494ba1fccbf..80947a00ab5 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,9 +132,9 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* thread, Bytecodes::C bytecode == Bytecodes::_fast_aldc_w, "wrong bc"); ResourceMark rm(thread); methodHandle m (thread, method(thread)); - Bytecode_loadconstant* ldc = Bytecode_loadconstant_at(m, bci(thread)); - oop result = ldc->resolve_constant(THREAD); - DEBUG_ONLY(ConstantPoolCacheEntry* cpce = m->constants()->cache()->entry_at(ldc->cache_index())); + Bytecode_loadconstant ldc(m, bci(thread)); + oop result = ldc.resolve_constant(THREAD); + DEBUG_ONLY(ConstantPoolCacheEntry* cpce = m->constants()->cache()->entry_at(ldc.cache_index())); assert(result == cpce->f1(), "expected result for assembly code"); } IRT_END @@ -672,8 +672,8 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) { ResourceMark rm(thread); methodHandle m (thread, method(thread)); - Bytecode_invoke* call = Bytecode_invoke_at(m, bci(thread)); - symbolHandle signature (thread, call->signature()); + Bytecode_invoke call(m, bci(thread)); + symbolHandle signature (thread, call.signature()); receiver = Handle(thread, thread->last_frame().interpreter_callee_receiver(signature)); assert(Universe::heap()->is_in_reserved_or_null(receiver()), @@ -756,7 +756,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { caller_bci = caller_method->bci_from(caller_bcp); site_index = Bytes::get_native_u4(caller_bcp+1); } - assert(site_index == InterpreterRuntime::bytecode(thread)->get_index_u4(bytecode), ""); + assert(site_index == InterpreterRuntime::bytecode(thread).get_index_u4(bytecode), ""); assert(constantPoolCacheOopDesc::is_secondary_index(site_index), "proper format"); // there is a second CPC entries that is of interest; it caches signature info: int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index(); @@ -884,7 +884,7 @@ IRT_LEAF(jint, InterpreterRuntime::bcp_to_di(methodOopDesc* method, address cur_ return mdo->bci_to_di(bci); IRT_END -IRT_ENTRY(jint, InterpreterRuntime::profile_method(JavaThread* thread, address cur_bcp)) +IRT_ENTRY(void, InterpreterRuntime::profile_method(JavaThread* thread)) // use UnlockFlagSaver to clear and restore the _do_not_unlock_if_synchronized // flag, in case this method triggers classloading which will call into Java. UnlockFlagSaver fs(thread); @@ -893,16 +893,12 @@ IRT_ENTRY(jint, InterpreterRuntime::profile_method(JavaThread* thread, address c frame fr = thread->last_frame(); assert(fr.is_interpreted_frame(), "must come from interpreter"); methodHandle method(thread, fr.interpreter_frame_method()); - int bci = method->bci_from(cur_bcp); methodOopDesc::build_interpreter_method_data(method, THREAD); if (HAS_PENDING_EXCEPTION) { assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); CLEAR_PENDING_EXCEPTION; // and fall through... } - methodDataOop mdo = method->method_data(); - if (mdo == NULL) return 0; - return mdo->bci_to_di(bci); IRT_END @@ -1245,9 +1241,9 @@ IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* threa assert(fr.is_interpreted_frame(), ""); jint bci = fr.interpreter_frame_bci(); methodHandle mh(thread, fr.interpreter_frame_method()); - Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci); - ArgumentSizeComputer asc(invoke->signature()); - int size_of_arguments = (asc.size() + (invoke->has_receiver() ? 1 : 0)); // receiver + Bytecode_invoke invoke(mh, bci); + ArgumentSizeComputer asc(invoke.signature()); + int size_of_arguments = (asc.size() + (invoke.has_receiver() ? 1 : 0)); // receiver Copy::conjoint_jbytes(src_address, dest_address, size_of_arguments * Interpreter::stackElementSize); IRT_END diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp index 0a48ce16dc8..84b3910224b 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,16 +58,16 @@ class InterpreterRuntime: AllStatic { static void set_bcp_and_mdp(address bcp, JavaThread*thread); static Bytecodes::Code code(JavaThread *thread) { // pass method to avoid calling unsafe bcp_to_method (partial fix 4926272) - return Bytecodes::code_at(bcp(thread), method(thread)); + return Bytecodes::code_at(method(thread), bcp(thread)); } static bool already_resolved(JavaThread *thread) { return cache_entry(thread)->is_resolved(code(thread)); } - static Bytecode* bytecode(JavaThread *thread) { return Bytecode_at(bcp(thread)); } + static Bytecode bytecode(JavaThread *thread) { return Bytecode(method(thread), bcp(thread)); } static int get_index_u1(JavaThread *thread, Bytecodes::Code bc) - { return bytecode(thread)->get_index_u1(bc); } + { return bytecode(thread).get_index_u1(bc); } static int get_index_u2(JavaThread *thread, Bytecodes::Code bc) - { return bytecode(thread)->get_index_u2(bc); } + { return bytecode(thread).get_index_u2(bc); } static int get_index_u2_cpcache(JavaThread *thread, Bytecodes::Code bc) - { return bytecode(thread)->get_index_u2_cpcache(bc); } + { return bytecode(thread).get_index_u2_cpcache(bc); } static int number_of_dimensions(JavaThread *thread) { return bcp(thread)[3]; } static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i) { return method(thread)->constants()->cache()->entry_at(i); } @@ -164,7 +164,7 @@ class InterpreterRuntime: AllStatic { // Interpreter profiling support static jint bcp_to_di(methodOopDesc* method, address cur_bcp); - static jint profile_method(JavaThread* thread, address cur_bcp); + static void profile_method(JavaThread* thread); static void update_mdp_for_ret(JavaThread* thread, int bci); #ifdef ASSERT static void verify_mdp(methodOopDesc* method, address bcp, address mdp); diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 83ef8859a48..e80216c79c1 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,7 @@ void Rewriter::scan_method(methodOop method) { // call to calculate the length. bc_length = Bytecodes::length_for(c); if (bc_length == 0) { - bc_length = Bytecodes::length_at(bcp); + bc_length = Bytecodes::length_at(method, bcp); // length_at will put us at the bytecode after the one modified // by 'wide'. We don't currently examine any of the bytecodes @@ -237,9 +237,9 @@ void Rewriter::scan_method(methodOop method) { switch (c) { case Bytecodes::_lookupswitch : { #ifndef CC_INTERP - Bytecode_lookupswitch* bc = Bytecode_lookupswitch_at(bcp); + Bytecode_lookupswitch bc(method, bcp); (*bcp) = ( - bc->number_of_pairs() < BinarySwitchThreshold + bc.number_of_pairs() < BinarySwitchThreshold ? Bytecodes::_fast_linearswitch : Bytecodes::_fast_binaryswitch ); diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 7e09cfcc2ce..0d1125ecb38 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -592,7 +592,7 @@ address TemplateInterpreter::deopt_continue_after_entry(methodOop method, addres // that do not return "Interpreter::deopt_entry(vtos, 0)" address TemplateInterpreter::deopt_reexecute_entry(methodOop method, address bcp) { assert(method->contains(bcp), "just checkin'"); - Bytecodes::Code code = Bytecodes::java_code_at(bcp); + Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); if (code == Bytecodes::_return) { // This is used for deopt during registration of finalizers // during Object.. We simply need to resume execution at diff --git a/hotspot/src/share/vm/memory/genMarkSweep.cpp b/hotspot/src/share/vm/memory/genMarkSweep.cpp index 95056cd8f42..44b958d1e23 100644 --- a/hotspot/src/share/vm/memory/genMarkSweep.cpp +++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp @@ -158,6 +158,7 @@ void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp, Threads::gc_epilogue(); CodeCache::gc_epilogue(); + JvmtiExport::gc_epilogue(); if (PrintGC && !PrintGCDetails) { gch->print_heap_change(gch_prev_used); diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index 4b504ec476d..dff8363b2f0 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,8 +36,8 @@ class arrayKlass: public Klass { friend class VMStructs; private: int _dimension; // This is n'th-dimensional array. - klassOop _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). - klassOop _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). + volatile klassOop _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). + volatile klassOop _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). int _vtable_len; // size of vtable for this klass juint _alloc_size; // allocation profiling support oop _component_mirror; // component type, as a java/lang/Class diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index 4d78ca2a87b..66ed440a3fc 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -535,23 +535,23 @@ bool GenerateOopMap::jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, int * (*jmpFct)(this, bcs->dest_w(), data); break; case Bytecodes::_tableswitch: - { Bytecode_tableswitch *tableswitch = Bytecode_tableswitch_at(bcs->bcp()); - int len = tableswitch->length(); + { Bytecode_tableswitch tableswitch(method(), bcs->bcp()); + int len = tableswitch.length(); - (*jmpFct)(this, bci + tableswitch->default_offset(), data); /* Default. jump address */ + (*jmpFct)(this, bci + tableswitch.default_offset(), data); /* Default. jump address */ while (--len >= 0) { - (*jmpFct)(this, bci + tableswitch->dest_offset_at(len), data); + (*jmpFct)(this, bci + tableswitch.dest_offset_at(len), data); } break; } case Bytecodes::_lookupswitch: - { Bytecode_lookupswitch *lookupswitch = Bytecode_lookupswitch_at(bcs->bcp()); - int npairs = lookupswitch->number_of_pairs(); - (*jmpFct)(this, bci + lookupswitch->default_offset(), data); /* Default. */ + { Bytecode_lookupswitch lookupswitch(method(), bcs->bcp()); + int npairs = lookupswitch.number_of_pairs(); + (*jmpFct)(this, bci + lookupswitch.default_offset(), data); /* Default. */ while(--npairs >= 0) { - LookupswitchPair *pair = lookupswitch->pair_at(npairs); - (*jmpFct)(this, bci + pair->offset(), data); + LookupswitchPair pair = lookupswitch.pair_at(npairs); + (*jmpFct)(this, bci + pair.offset(), data); } break; } @@ -977,7 +977,7 @@ void GenerateOopMap::init_basic_blocks() { #ifdef ASSERT if (blockNum + 1 < bbNo) { address bcp = _method->bcp_from(bb->_end_bci); - int bc_len = Bytecodes::java_length_at(bcp); + int bc_len = Bytecodes::java_length_at(_method(), bcp); assert(bb->_end_bci + bc_len == bb[1]._bci, "unmatched bci info in basicblock"); } #endif @@ -985,7 +985,7 @@ void GenerateOopMap::init_basic_blocks() { #ifdef ASSERT { BasicBlock *bb = &_basic_blocks[bbNo-1]; address bcp = _method->bcp_from(bb->_end_bci); - int bc_len = Bytecodes::java_length_at(bcp); + int bc_len = Bytecodes::java_length_at(_method(), bcp); assert(bb->_end_bci + bc_len == _method->code_size(), "wrong end bci"); } #endif @@ -1837,14 +1837,14 @@ void GenerateOopMap::do_jsr(int targ_bci) { void GenerateOopMap::do_ldc(int bci) { - Bytecode_loadconstant* ldc = Bytecode_loadconstant_at(method(), bci); + Bytecode_loadconstant ldc(method(), bci); constantPoolOop cp = method()->constants(); - BasicType bt = ldc->result_type(); + BasicType bt = ldc.result_type(); CellTypeState cts = (bt == T_OBJECT) ? CellTypeState::make_line_ref(bci) : valCTS; // Make sure bt==T_OBJECT is the same as old code (is_pointer_entry). // Note that CONSTANT_MethodHandle entries are u2 index pairs, not pointer-entries, // and they are processed by _fast_aldc and the CP cache. - assert((ldc->has_cache_index() || cp->is_pointer_entry(ldc->pool_index())) + assert((ldc.has_cache_index() || cp->is_pointer_entry(ldc.pool_index())) ? (bt == T_OBJECT) : true, "expected object type"); ppush1(cts); } @@ -2343,7 +2343,7 @@ bool GenerateOopMap::rewrite_refval_conflict_inst(BytecodeStream *itr, int from, bool GenerateOopMap::rewrite_load_or_store(BytecodeStream *bcs, Bytecodes::Code bcN, Bytecodes::Code bc0, unsigned int varNo) { assert(bcN == Bytecodes::_astore || bcN == Bytecodes::_aload, "wrong argument (bcN)"); assert(bc0 == Bytecodes::_astore_0 || bc0 == Bytecodes::_aload_0, "wrong argument (bc0)"); - int ilen = Bytecodes::length_at(bcs->bcp()); + int ilen = Bytecodes::length_at(_method(), bcs->bcp()); int newIlen; if (ilen == 4) { diff --git a/hotspot/src/share/vm/oops/methodDataOop.cpp b/hotspot/src/share/vm/oops/methodDataOop.cpp index c69ab0af49b..b0856dbca46 100644 --- a/hotspot/src/share/vm/oops/methodDataOop.cpp +++ b/hotspot/src/share/vm/oops/methodDataOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -417,11 +417,11 @@ void BranchData::print_data_on(outputStream* st) { int MultiBranchData::compute_cell_count(BytecodeStream* stream) { int cell_count = 0; if (stream->code() == Bytecodes::_tableswitch) { - Bytecode_tableswitch* sw = Bytecode_tableswitch_at(stream->bcp()); - cell_count = 1 + per_case_cell_count * (1 + sw->length()); // 1 for default + Bytecode_tableswitch sw(stream->method()(), stream->bcp()); + cell_count = 1 + per_case_cell_count * (1 + sw.length()); // 1 for default } else { - Bytecode_lookupswitch* sw = Bytecode_lookupswitch_at(stream->bcp()); - cell_count = 1 + per_case_cell_count * (sw->number_of_pairs() + 1); // 1 for default + Bytecode_lookupswitch sw(stream->method()(), stream->bcp()); + cell_count = 1 + per_case_cell_count * (sw.number_of_pairs() + 1); // 1 for default } return cell_count; } @@ -434,35 +434,35 @@ void MultiBranchData::post_initialize(BytecodeStream* stream, int target_di; int offset; if (stream->code() == Bytecodes::_tableswitch) { - Bytecode_tableswitch* sw = Bytecode_tableswitch_at(stream->bcp()); - int len = sw->length(); + Bytecode_tableswitch sw(stream->method()(), stream->bcp()); + int len = sw.length(); assert(array_len() == per_case_cell_count * (len + 1), "wrong len"); for (int count = 0; count < len; count++) { - target = sw->dest_offset_at(count) + bci(); + target = sw.dest_offset_at(count) + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_displacement_at(count, offset); } - target = sw->default_offset() + bci(); + target = sw.default_offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_default_displacement(offset); } else { - Bytecode_lookupswitch* sw = Bytecode_lookupswitch_at(stream->bcp()); - int npairs = sw->number_of_pairs(); + Bytecode_lookupswitch sw(stream->method()(), stream->bcp()); + int npairs = sw.number_of_pairs(); assert(array_len() == per_case_cell_count * (npairs + 1), "wrong len"); for (int count = 0; count < npairs; count++) { - LookupswitchPair *pair = sw->pair_at(count); - target = pair->offset() + bci(); + LookupswitchPair pair = sw.pair_at(count); + target = pair.offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_displacement_at(count, offset); } - target = sw->default_offset() + bci(); + target = sw.default_offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index d10c2ea02cc..1dab0cbd6d8 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,17 +150,6 @@ int methodOopDesc::fast_exception_handler_bci_for(KlassHandle ex_klass, int thr return -1; } -methodOop methodOopDesc::method_from_bcp(address bcp) { - debug_only(static int count = 0; count++); - assert(Universe::heap()->is_in_permanent(bcp), "bcp not in perm_gen"); - // TO DO: this may be unsafe in some configurations - HeapWord* p = Universe::heap()->block_start(bcp); - assert(Universe::heap()->block_is_obj(p), "must be obj"); - assert(oop(p)->is_constMethod(), "not a method"); - return constMethodOop(p)->method(); -} - - void methodOopDesc::mask_for(int bci, InterpreterOopMap* mask) { Thread* myThread = Thread::current(); @@ -469,11 +458,10 @@ bool methodOopDesc::can_be_statically_bound() const { bool methodOopDesc::is_accessor() const { if (code_size() != 5) return false; if (size_of_parameters() != 1) return false; - methodOop m = (methodOop)this; // pass to code_at() to avoid method_from_bcp - if (Bytecodes::java_code_at(code_base()+0, m) != Bytecodes::_aload_0 ) return false; - if (Bytecodes::java_code_at(code_base()+1, m) != Bytecodes::_getfield) return false; - if (Bytecodes::java_code_at(code_base()+4, m) != Bytecodes::_areturn && - Bytecodes::java_code_at(code_base()+4, m) != Bytecodes::_ireturn ) return false; + if (java_code_at(0) != Bytecodes::_aload_0 ) return false; + if (java_code_at(1) != Bytecodes::_getfield) return false; + if (java_code_at(4) != Bytecodes::_areturn && + java_code_at(4) != Bytecodes::_ireturn ) return false; return true; } @@ -1414,7 +1402,7 @@ bool CompressedLineNumberReadStream::read_pair() { } -Bytecodes::Code methodOopDesc::orig_bytecode_at(int bci) { +Bytecodes::Code methodOopDesc::orig_bytecode_at(int bci) const { BreakpointInfo* bp = instanceKlass::cast(method_holder())->breakpoints(); for (; bp != NULL; bp = bp->next()) { if (bp->match(this, bci)) { diff --git a/hotspot/src/share/vm/oops/methodOop.hpp b/hotspot/src/share/vm/oops/methodOop.hpp index 84029431c12..9f74b8fe8e4 100644 --- a/hotspot/src/share/vm/oops/methodOop.hpp +++ b/hotspot/src/share/vm/oops/methodOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -196,8 +196,15 @@ class methodOopDesc : public oopDesc { static char* name_and_sig_as_C_string(Klass* klass, symbolOop method_name, symbolOop signature); static char* name_and_sig_as_C_string(Klass* klass, symbolOop method_name, symbolOop signature, char* buf, int size); + Bytecodes::Code java_code_at(int bci) const { + return Bytecodes::java_code_at(this, bcp_from(bci)); + } + Bytecodes::Code code_at(int bci) const { + return Bytecodes::code_at(this, bcp_from(bci)); + } + // JVMTI breakpoints - Bytecodes::Code orig_bytecode_at(int bci); + Bytecodes::Code orig_bytecode_at(int bci) const; void set_orig_bytecode_at(int bci, Bytecodes::Code code); void set_breakpoint(int bci); void clear_breakpoint(int bci); @@ -655,8 +662,6 @@ class methodOopDesc : public oopDesc { void set_queued_for_compilation() { _access_flags.set_queued_for_compilation(); } void clear_queued_for_compilation() { _access_flags.clear_queued_for_compilation(); } - static methodOop method_from_bcp(address bcp); - // Resolve all classes in signature, return 'true' if successful static bool load_signature_classes(methodHandle m, TRAPS); @@ -787,11 +792,11 @@ class BreakpointInfo : public CHeapObj { void set_next(BreakpointInfo* n) { _next = n; } // helps for searchers - bool match(methodOop m, int bci) { + bool match(const methodOopDesc* m, int bci) { return bci == _bci && match(m); } - bool match(methodOop m) { + bool match(const methodOopDesc* m) { return _name_index == m->name_index() && _signature_index == m->signature_index(); } diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 3233a4d225c..d31d710bc63 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -235,8 +235,9 @@ klassOop objArrayKlass::array_klass_impl(objArrayKlassHandle this_oop, bool or_n objArrayKlassKlass::cast(Universe::objArrayKlassKlassObj())-> allocate_objArray_klass(dimension + 1, this_oop, CHECK_NULL); ak = objArrayKlassHandle(THREAD, new_klass); - this_oop->set_higher_dimension(ak()); ak->set_lower_dimension(this_oop()); + OrderAccess::storestore(); + this_oop->set_higher_dimension(ak()); assert(ak->oop_is_objArray(), "incorrect initialization of objArrayKlass"); } } diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index 8d317dff9af..99d3f65cb80 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -179,6 +179,7 @@ klassOop typeArrayKlass::array_klass_impl(typeArrayKlassHandle h_this, bool or_n dimension + 1, h_this, CHECK_NULL); h_ak = objArrayKlassHandle(THREAD, oak); h_ak->set_lower_dimension(h_this()); + OrderAccess::storestore(); h_this->set_higher_dimension(h_ak()); assert(h_ak->oop_is_objArray(), "incorrect initialization of objArrayKlass"); } diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index ac09b95c974..5f6550a6795 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2187,8 +2187,11 @@ const TypePtr *TypeRawPtr::add_offset( intptr_t offset ) const { case TypePtr::NotNull: return this; case TypePtr::Null: - case TypePtr::Constant: - return make( _bits+offset ); + case TypePtr::Constant: { + address bits = _bits+offset; + if ( bits == 0 ) return TypePtr::NULL_PTR; + return make( bits ); + } default: ShouldNotReachHere(); } return NULL; // Lint noise diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 1c5000af4eb..ec8ca4049a6 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1649,7 +1649,8 @@ typedef struct { * the new bit is also added in the main/baseline. */ unsigned int thread_park_blocker : 1; - unsigned int : 31; + unsigned int post_vm_init_hook_enabled : 1; + unsigned int : 30; unsigned int : 32; unsigned int : 32; } jdk_version_info; diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 9e24fb64b1c..0d845050ac9 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -13048,8 +13048,8 @@ myInit() { - A Garbage Collection Start event is sent when a full cycle - garbage collection begins. + A Garbage Collection Start event is sent when a + garbage collection pause begins. Only stop-the-world collections are reported--that is, collections during which all threads cease to modify the state of the Java virtual machine. This means that some collectors will never generate these events. @@ -13075,8 +13075,8 @@ myInit() { - A Garbage Collection Finish event is sent when a full - garbage collection cycle ends. + A Garbage Collection Finish event is sent when a + garbage collection pause ends. This event is sent while the VM is still stopped, thus the event handler must not use JNI functions and must not use functions except those which diff --git a/hotspot/src/share/vm/prims/jvmtiEventController.cpp b/hotspot/src/share/vm/prims/jvmtiEventController.cpp index 0e32f85c141..ccb22b550b8 100644 --- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEventController.cpp @@ -667,14 +667,13 @@ void JvmtiEventControllerPrivate::thread_ended(JavaThread *thread) { // Removes the JvmtiThreadState associated with the specified thread. // May be called after all environments have been disposed. + assert(JvmtiThreadState_lock->is_locked(), "sanity check"); EC_TRACE(("JVMTI [%s] # thread ended", JvmtiTrace::safe_get_thread_name(thread))); JvmtiThreadState *state = thread->jvmti_thread_state(); - if (state != NULL) { - MutexLocker mu(JvmtiThreadState_lock); - delete state; - } + assert(state != NULL, "else why are we here?"); + delete state; } void JvmtiEventControllerPrivate::set_event_callbacks(JvmtiEnvBase *env, diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index ab5ced93ba4..5fc3281400c 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -2253,12 +2253,14 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { void JvmtiExport::cleanup_thread(JavaThread* thread) { assert(JavaThread::current() == thread, "thread is not current"); + MutexLocker mu(JvmtiThreadState_lock); - - // This has to happen after the thread state is removed, which is - // why it is not in post_thread_end_event like its complement - // Maybe both these functions should be rolled into the posts? - JvmtiEventController::thread_ended(thread); + if (thread->jvmti_thread_state() != NULL) { + // This has to happen after the thread state is removed, which is + // why it is not in post_thread_end_event like its complement + // Maybe both these functions should be rolled into the posts? + JvmtiEventController::thread_ended(thread); + } } void JvmtiExport::oops_do(OopClosure* f) { @@ -2266,6 +2268,14 @@ void JvmtiExport::oops_do(OopClosure* f) { JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(f); } +void JvmtiExport::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { + JvmtiTagMap::weak_oops_do(is_alive, f); +} + +void JvmtiExport::gc_epilogue() { + JvmtiCurrentBreakpoints::gc_epilogue(); +} + // Onload raw monitor transition. void JvmtiExport::transition_pending_onload_raw_monitors() { JvmtiPendingMonitors::transition_raw_monitors(); @@ -2358,15 +2368,6 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { } #endif // SERVICES_KERNEL -// CMS has completed referencing processing so may need to update -// tag maps. -void JvmtiExport::cms_ref_processing_epilogue() { - if (JvmtiEnv::environments_might_exist()) { - JvmtiTagMap::cms_ref_processing_epilogue(); - } -} - - //////////////////////////////////////////////////////////////////////////////////////////////// // Setup current current thread for event collection. @@ -2536,36 +2537,20 @@ NoJvmtiVMObjectAllocMark::~NoJvmtiVMObjectAllocMark() { } }; -JvmtiGCMarker::JvmtiGCMarker(bool full) : _full(full), _invocation_count(0) { - assert(Thread::current()->is_VM_thread(), "wrong thread"); - +JvmtiGCMarker::JvmtiGCMarker() { // if there aren't any JVMTI environments then nothing to do if (!JvmtiEnv::environments_might_exist()) { return; } - if (ForceFullGCJVMTIEpilogues) { - // force 'Full GC' was done semantics for JVMTI GC epilogues - _full = true; - } - - // GarbageCollectionStart event posted from VM thread - okay because - // JVMTI is clear that the "world is stopped" and callback shouldn't - // try to call into the VM. if (JvmtiExport::should_post_garbage_collection_start()) { JvmtiExport::post_garbage_collection_start(); } - // if "full" is false it probably means this is a scavenge of the young - // generation. However it could turn out that a "full" GC is required - // so we record the number of collections so that it can be checked in - // the destructor. - if (!_full) { - _invocation_count = Universe::heap()->total_full_collections(); + if (SafepointSynchronize::is_at_safepoint()) { + // Do clean up tasks that need to be done at a safepoint + JvmtiEnvBase::check_for_periodic_clean_up(); } - - // Do clean up tasks that need to be done at a safepoint - JvmtiEnvBase::check_for_periodic_clean_up(); } JvmtiGCMarker::~JvmtiGCMarker() { @@ -2578,21 +2563,5 @@ JvmtiGCMarker::~JvmtiGCMarker() { if (JvmtiExport::should_post_garbage_collection_finish()) { JvmtiExport::post_garbage_collection_finish(); } - - // we might have initially started out doing a scavenge of the young - // generation but could have ended up doing a "full" GC - check the - // GC count to see. - if (!_full) { - _full = (_invocation_count != Universe::heap()->total_full_collections()); - } - - // Full collection probably means the perm generation has been GC'ed - // so we clear the breakpoint cache. - if (_full) { - JvmtiCurrentBreakpoints::gc_epilogue(); - } - - // Notify heap/object tagging support - JvmtiTagMap::gc_epilogue(_full); } #endif // JVMTI_KERNEL diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp index 88a23383116..31b4e1ba91a 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.hpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp @@ -346,6 +346,8 @@ class JvmtiExport : public AllStatic { static void cleanup_thread (JavaThread* thread) KERNEL_RETURN; static void oops_do(OopClosure* f) KERNEL_RETURN; + static void weak_oops_do(BoolObjectClosure* b, OopClosure* f) KERNEL_RETURN; + static void gc_epilogue() KERNEL_RETURN; static void transition_pending_onload_raw_monitors() KERNEL_RETURN; @@ -356,9 +358,6 @@ class JvmtiExport : public AllStatic { // SetNativeMethodPrefix support static char** get_all_native_method_prefixes(int* count_ptr); - - // call after CMS has completed referencing processing - static void cms_ref_processing_epilogue() KERNEL_RETURN; }; // Support class used by JvmtiDynamicCodeEventCollector and others. It @@ -492,55 +491,11 @@ class NoJvmtiVMObjectAllocMark : public StackObj { // Base class for reporting GC events to JVMTI. class JvmtiGCMarker : public StackObj { - private: - bool _full; // marks a "full" GC - unsigned int _invocation_count; // GC invocation count - protected: - JvmtiGCMarker(bool full) KERNEL_RETURN; // protected - ~JvmtiGCMarker() KERNEL_RETURN; // protected -}; - - -// Support class used to report GC events to JVMTI. The class is stack -// allocated and should be placed in the doit() implementation of all -// vm operations that do a stop-the-world GC for failed allocation. -// -// Usage :- -// -// void VM_GenCollectForAllocation::doit() { -// JvmtiGCForAllocationMarker jgcm; -// : -// } -// -// If jvmti is not enabled the constructor and destructor is essentially -// a no-op (no overhead). -// -class JvmtiGCForAllocationMarker : public JvmtiGCMarker { public: - JvmtiGCForAllocationMarker() : JvmtiGCMarker(false) { - } + JvmtiGCMarker() KERNEL_RETURN; + ~JvmtiGCMarker() KERNEL_RETURN; }; -// Support class used to report GC events to JVMTI. The class is stack -// allocated and should be placed in the doit() implementation of all -// vm operations that do a "full" stop-the-world GC. This class differs -// from JvmtiGCForAllocationMarker in that this class assumes that a -// "full" GC will happen. -// -// Usage :- -// -// void VM_GenCollectFull::doit() { -// JvmtiGCFullMarker jgcm; -// : -// } -// -class JvmtiGCFullMarker : public JvmtiGCMarker { - public: - JvmtiGCFullMarker() : JvmtiGCMarker(true) { - } -}; - - // JvmtiHideSingleStepping is a helper class for hiding // internal single step events. class JvmtiHideSingleStepping : public StackObj { diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp index 90864b68abe..f8f94c8445a 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp @@ -217,7 +217,6 @@ void GrowableCache::oops_do(OopClosure* f) { void GrowableCache::gc_epilogue() { int len = _elements->length(); - // recompute the new cache value after GC for (int i=0; iat(i)->getCacheValue(); } @@ -401,7 +400,7 @@ void JvmtiBreakpoints::oops_do(OopClosure* f) { _bps.oops_do(f); } -void JvmtiBreakpoints::gc_epilogue() { +void JvmtiBreakpoints::gc_epilogue() { _bps.gc_epilogue(); } @@ -540,7 +539,6 @@ void JvmtiCurrentBreakpoints::gc_epilogue() { } } - /////////////////////////////////////////////////////////////// // // class VM_GetOrSetLocal diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.hpp b/hotspot/src/share/vm/prims/jvmtiImpl.hpp index df28abf7d72..4f543cc4322 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp @@ -117,6 +117,7 @@ public: void clear(); // apply f to every element and update the cache void oops_do(OopClosure* f); + // update the cache after a full gc void gc_epilogue(); }; @@ -278,13 +279,13 @@ public: int length(); void oops_do(OopClosure* f); - void gc_epilogue(); void print(); int set(JvmtiBreakpoint& bp); int clear(JvmtiBreakpoint& bp); void clearall_in_class_at_safepoint(klassOop klass); void clearall(); + void gc_epilogue(); }; diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index a4c31778cf0..68fc8fe7e81 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1458,7 +1458,7 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, if (bc_length == 0) { // More complicated bytecodes report a length of zero so // we have to try again a slightly different way. - bc_length = Bytecodes::length_at(bcp); + bc_length = Bytecodes::length_at(method(), bcp); } assert(bc_length != 0, "impossible bytecode length"); diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 085952af565..a5edc2bed44 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -50,7 +50,7 @@ // JvmtiTagHashmapEntry // -// Each entry encapsulates a JNI weak reference to the tagged object +// Each entry encapsulates a reference to the tagged object // and the tag value. In addition an entry includes a next pointer which // is used to chain entries together. @@ -58,24 +58,25 @@ class JvmtiTagHashmapEntry : public CHeapObj { private: friend class JvmtiTagMap; - jweak _object; // JNI weak ref to tagged object + oop _object; // tagged object jlong _tag; // the tag JvmtiTagHashmapEntry* _next; // next on the list - inline void init(jweak object, jlong tag) { + inline void init(oop object, jlong tag) { _object = object; _tag = tag; _next = NULL; } // constructor - JvmtiTagHashmapEntry(jweak object, jlong tag) { init(object, tag); } + JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); } public: // accessor methods - inline jweak object() const { return _object; } - inline jlong tag() const { return _tag; } + inline oop object() const { return _object; } + inline oop* object_addr() { return &_object; } + inline jlong tag() const { return _tag; } inline void set_tag(jlong tag) { assert(tag != 0, "can't be zero"); @@ -92,9 +93,7 @@ class JvmtiTagHashmapEntry : public CHeapObj { // A hashmap is essentially a table of pointers to entries. Entries // are hashed to a location, or position in the table, and then // chained from that location. The "key" for hashing is address of -// the object, or oop. The "value" is the JNI weak reference to the -// object and the tag value. Keys are not stored with the entry. -// Instead the weak reference is resolved to obtain the key. +// the object, or oop. The "value" is the tag value. // // A hashmap maintains a count of the number entries in the hashmap // and resizes if the number of entries exceeds a given threshold. @@ -206,7 +205,7 @@ class JvmtiTagHashmap : public CHeapObj { JvmtiTagHashmapEntry* entry = _table[i]; while (entry != NULL) { JvmtiTagHashmapEntry* next = entry->next(); - oop key = JNIHandles::resolve(entry->object()); + oop key = entry->object(); assert(key != NULL, "jni weak reference cleared!!"); unsigned int h = hash(key, new_size); JvmtiTagHashmapEntry* anchor = new_table[h]; @@ -299,14 +298,12 @@ class JvmtiTagHashmap : public CHeapObj { unsigned int h = hash(key); JvmtiTagHashmapEntry* entry = _table[h]; while (entry != NULL) { - oop orig_key = JNIHandles::resolve(entry->object()); - assert(orig_key != NULL, "jni weak reference cleared!!"); - if (key == orig_key) { - break; + if (entry->object() == key) { + return entry; } entry = entry->next(); } - return entry; + return NULL; } @@ -343,9 +340,7 @@ class JvmtiTagHashmap : public CHeapObj { JvmtiTagHashmapEntry* entry = _table[h]; JvmtiTagHashmapEntry* prev = NULL; while (entry != NULL) { - oop orig_key = JNIHandles::resolve(entry->object()); - assert(orig_key != NULL, "jni weak reference cleared!!"); - if (key == orig_key) { + if (key == entry->object()) { break; } prev = entry; @@ -418,54 +413,6 @@ void JvmtiTagHashmap::compute_next_trace_threshold() { } } -// memory region for young generation -MemRegion JvmtiTagMap::_young_gen; - -// get the memory region used for the young generation -void JvmtiTagMap::get_young_generation() { - CollectedHeap* ch = Universe::heap(); - switch (ch->kind()) { - case (CollectedHeap::GenCollectedHeap): { - _young_gen = ((GenCollectedHeap*)ch)->get_gen(0)->reserved(); - break; - } -#ifndef SERIALGC - case (CollectedHeap::ParallelScavengeHeap): { - _young_gen = ((ParallelScavengeHeap*)ch)->young_gen()->reserved(); - break; - } - case (CollectedHeap::G1CollectedHeap): { - // Until a more satisfactory solution is implemented, all - // oops in the tag map will require rehash at each gc. - // This is a correct, if extremely inefficient solution. - // See RFE 6621729 for related commentary. - _young_gen = ch->reserved_region(); - break; - } -#endif // !SERIALGC - default: - ShouldNotReachHere(); - } -} - -// returns true if oop is in the young generation -inline bool JvmtiTagMap::is_in_young(oop o) { - assert(_young_gen.start() != NULL, "checking"); - void* p = (void*)o; - bool in_young = _young_gen.contains(p); - return in_young; -} - -// returns the appropriate hashmap for a given object -inline JvmtiTagHashmap* JvmtiTagMap::hashmap_for(oop o) { - if (is_in_young(o)) { - return _hashmap[0]; - } else { - return _hashmap[1]; - } -} - - // create a JvmtiTagMap JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : _env(env), @@ -476,13 +423,7 @@ JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : assert(JvmtiThreadState_lock->is_locked(), "sanity check"); assert(((JvmtiEnvBase *)env)->tag_map() == NULL, "tag map already exists for environment"); - // create the hashmaps - for (int i=0; iset_tag_map(this); @@ -496,25 +437,20 @@ JvmtiTagMap::~JvmtiTagMap() { // also being destroryed. ((JvmtiEnvBase *)_env)->set_tag_map(NULL); - // iterate over the hashmaps and destroy each of the entries - for (int i=0; itable(); - for (int j=0; jsize(); j++) { - JvmtiTagHashmapEntry *entry = table[j]; - while (entry != NULL) { - JvmtiTagHashmapEntry* next = entry->next(); - jweak ref = entry->object(); - JNIHandles::destroy_weak_global(ref); - delete entry; - entry = next; - } + JvmtiTagHashmapEntry** table = _hashmap->table(); + for (int j = 0; j < _hashmap->size(); j++) { + JvmtiTagHashmapEntry* entry = table[j]; + while (entry != NULL) { + JvmtiTagHashmapEntry* next = entry->next(); + delete entry; + entry = next; } - - // finally destroy the hashmap - delete hashmap; } + // finally destroy the hashmap + delete _hashmap; + _hashmap = NULL; + // remove any entries on the free list JvmtiTagHashmapEntry* entry = _free_entries; while (entry != NULL) { @@ -522,12 +458,13 @@ JvmtiTagMap::~JvmtiTagMap() { delete entry; entry = next; } + _free_entries = NULL; } // create a hashmap entry // - if there's an entry on the (per-environment) free list then this // is returned. Otherwise an new entry is allocated. -JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(jweak ref, jlong tag) { +JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(oop ref, jlong tag) { assert(Thread::current()->is_VM_thread() || is_locked(), "checking"); JvmtiTagHashmapEntry* entry; if (_free_entries == NULL) { @@ -558,10 +495,10 @@ void JvmtiTagMap::destroy_entry(JvmtiTagHashmapEntry* entry) { // returns the tag map for the given environments. If the tag map // doesn't exist then it is created. JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) { - JvmtiTagMap* tag_map = ((JvmtiEnvBase *)env)->tag_map(); + JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->tag_map(); if (tag_map == NULL) { MutexLocker mu(JvmtiThreadState_lock); - tag_map = ((JvmtiEnvBase *)env)->tag_map(); + tag_map = ((JvmtiEnvBase*)env)->tag_map(); if (tag_map == NULL) { tag_map = new JvmtiTagMap(env); } @@ -573,17 +510,13 @@ JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) { // iterate over all entries in the tag map. void JvmtiTagMap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) { - for (int i=0; ientry_iterate(closure); - } + hashmap()->entry_iterate(closure); } // returns true if the hashmaps are empty bool JvmtiTagMap::is_empty() { assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking"); - assert(n_hashmaps == 2, "not implemented"); - return ((_hashmap[0]->entry_count() == 0) && (_hashmap[1]->entry_count() == 0)); + return hashmap()->entry_count() == 0; } @@ -591,7 +524,7 @@ bool JvmtiTagMap::is_empty() { // not tagged // static inline jlong tag_for(JvmtiTagMap* tag_map, oop o) { - JvmtiTagHashmapEntry* entry = tag_map->hashmap_for(o)->find(o); + JvmtiTagHashmapEntry* entry = tag_map->hashmap()->find(o); if (entry == NULL) { return 0; } else { @@ -655,7 +588,7 @@ class CallbackWrapper : public StackObj { // record the context _tag_map = tag_map; - _hashmap = tag_map->hashmap_for(_o); + _hashmap = tag_map->hashmap(); _entry = _hashmap->find(_o); // get object tag @@ -694,23 +627,18 @@ void inline CallbackWrapper::post_callback_tag_update(oop o, if (obj_tag != 0) { // callback has tagged the object assert(Thread::current()->is_VM_thread(), "must be VMThread"); - HandleMark hm; - Handle h(o); - jweak ref = JNIHandles::make_weak_global(h); - entry = tag_map()->create_entry(ref, obj_tag); + entry = tag_map()->create_entry(o, obj_tag); hashmap->add(o, entry); } } else { // object was previously tagged - the callback may have untagged // the object or changed the tag value if (obj_tag == 0) { - jweak ref = entry->object(); JvmtiTagHashmapEntry* entry_removed = hashmap->remove(o); assert(entry_removed == entry, "checking"); tag_map()->destroy_entry(entry); - JNIHandles::destroy_weak_global(ref); } else { if (obj_tag != entry->tag()) { entry->set_tag(obj_tag); @@ -760,7 +688,7 @@ class TwoOopCallbackWrapper : public CallbackWrapper { // for Classes the klassOop is tagged _referrer = klassOop_if_java_lang_Class(referrer); // record the context - _referrer_hashmap = tag_map->hashmap_for(_referrer); + _referrer_hashmap = tag_map->hashmap(); _referrer_entry = _referrer_hashmap->find(_referrer); // get object tag @@ -796,8 +724,7 @@ class TwoOopCallbackWrapper : public CallbackWrapper { // // This function is performance critical. If many threads attempt to tag objects // around the same time then it's possible that the Mutex associated with the -// tag map will be a hot lock. Eliminating this lock will not eliminate the issue -// because creating a JNI weak reference requires acquiring a global lock also. +// tag map will be a hot lock. void JvmtiTagMap::set_tag(jobject object, jlong tag) { MutexLocker ml(lock()); @@ -808,22 +735,14 @@ void JvmtiTagMap::set_tag(jobject object, jlong tag) { o = klassOop_if_java_lang_Class(o); // see if the object is already tagged - JvmtiTagHashmap* hashmap = hashmap_for(o); + JvmtiTagHashmap* hashmap = _hashmap; JvmtiTagHashmapEntry* entry = hashmap->find(o); // if the object is not already tagged then we tag it if (entry == NULL) { if (tag != 0) { - HandleMark hm; - Handle h(o); - jweak ref = JNIHandles::make_weak_global(h); - - // the object may have moved because make_weak_global may - // have blocked - thus it is necessary resolve the handle - // and re-hash the object. - o = h(); - entry = create_entry(ref, tag); - hashmap_for(o)->add(o, entry); + entry = create_entry(o, tag); + hashmap->add(o, entry); } else { // no-op } @@ -831,13 +750,9 @@ void JvmtiTagMap::set_tag(jobject object, jlong tag) { // if the object is already tagged then we either update // the tag (if a new tag value has been provided) // or remove the object if the new tag value is 0. - // Removing the object requires that we also delete the JNI - // weak ref to the object. if (tag == 0) { - jweak ref = entry->object(); hashmap->remove(o); destroy_entry(entry); - JNIHandles::destroy_weak_global(ref); } else { entry->set_tag(tag); } @@ -1626,8 +1541,8 @@ class TagObjectCollector : public JvmtiTagHashmapEntryClosure { void do_entry(JvmtiTagHashmapEntry* entry) { for (int i=0; i<_tag_count; i++) { if (_tags[i] == entry->tag()) { - oop o = JNIHandles::resolve(entry->object()); - assert(o != NULL && o != JNIHandles::deleted_handle(), "sanity check"); + oop o = entry->object(); + assert(o != NULL, "sanity check"); // the mirror is tagged if (o->is_klass()) { @@ -3374,62 +3289,25 @@ void JvmtiTagMap::follow_references(jint heap_filter, } -// called post-GC -// - for each JVMTI environment with an object tag map, call its rehash -// function to re-sync with the new object locations. -void JvmtiTagMap::gc_epilogue(bool full) { - assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); +void JvmtiTagMap::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { + // No locks during VM bring-up (0 threads) and no safepoints after main + // thread creation and before VMThread creation (1 thread); initial GC + // verification can happen in that window which gets to here. + assert(Threads::number_of_threads() <= 1 || + SafepointSynchronize::is_at_safepoint(), + "must be executed at a safepoint"); if (JvmtiEnv::environments_might_exist()) { - // re-obtain the memory region for the young generation (might - // changed due to adaptive resizing policy) - get_young_generation(); - JvmtiEnvIterator it; for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { JvmtiTagMap* tag_map = env->tag_map(); if (tag_map != NULL && !tag_map->is_empty()) { - TraceTime t(full ? "JVMTI Full Rehash " : "JVMTI Rehash ", TraceJVMTIObjectTagging); - if (full) { - tag_map->rehash(0, n_hashmaps); - } else { - tag_map->rehash(0, 0); // tag map for young gen only - } + tag_map->do_weak_oops(is_alive, f); } } } } -// CMS has completed referencing processing so we may have JNI weak refs -// to objects in the CMS generation that have been GC'ed. -void JvmtiTagMap::cms_ref_processing_epilogue() { - assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); - assert(UseConcMarkSweepGC, "should only be used with CMS"); - if (JvmtiEnv::environments_might_exist()) { - JvmtiEnvIterator it; - for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { - JvmtiTagMap* tag_map = ((JvmtiEnvBase *)env)->tag_map(); - if (tag_map != NULL && !tag_map->is_empty()) { - TraceTime t("JVMTI Rehash (CMS) ", TraceJVMTIObjectTagging); - tag_map->rehash(1, n_hashmaps); // assume CMS not used in young gen - } - } - } -} - - -// For each entry in the hashmaps 'start' to 'end' : -// -// 1. resolve the JNI weak reference -// -// 2. If it resolves to NULL it means the object has been freed so the entry -// is removed, the weak reference destroyed, and the object free event is -// posted (if enabled). -// -// 3. If the weak reference resolves to an object then we re-hash the object -// to see if it has moved or has been promoted (from the young to the old -// generation for example). -// -void JvmtiTagMap::rehash(int start, int end) { +void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) { // does this environment have the OBJECT_FREE event enabled bool post_object_free = env()->is_enabled(JVMTI_EVENT_OBJECT_FREE); @@ -3437,143 +3315,98 @@ void JvmtiTagMap::rehash(int start, int end) { // counters used for trace message int freed = 0; int moved = 0; - int promoted = 0; - // we assume there are two hashmaps - one for the young generation - // and the other for all other spaces. - assert(n_hashmaps == 2, "not implemented"); - JvmtiTagHashmap* young_hashmap = _hashmap[0]; - JvmtiTagHashmap* other_hashmap = _hashmap[1]; + JvmtiTagHashmap* hashmap = this->hashmap(); // reenable sizing (if disabled) - young_hashmap->set_resizing_enabled(true); - other_hashmap->set_resizing_enabled(true); + hashmap->set_resizing_enabled(true); - // when re-hashing the hashmap corresponding to the young generation we - // collect the entries corresponding to objects that have been promoted. - JvmtiTagHashmapEntry* promoted_entries = NULL; - - if (end >= n_hashmaps) { - end = n_hashmaps - 1; + // if the hashmap is empty then we can skip it + if (hashmap->_entry_count == 0) { + return; } - for (int i=start; i <= end; i++) { - JvmtiTagHashmap* hashmap = _hashmap[i]; + // now iterate through each entry in the table - // if the hashmap is empty then we can skip it - if (hashmap->_entry_count == 0) { - continue; - } + JvmtiTagHashmapEntry** table = hashmap->table(); + int size = hashmap->size(); - // now iterate through each entry in the table + JvmtiTagHashmapEntry* delayed_add = NULL; - JvmtiTagHashmapEntry** table = hashmap->table(); - int size = hashmap->size(); + for (int pos = 0; pos < size; ++pos) { + JvmtiTagHashmapEntry* entry = table[pos]; + JvmtiTagHashmapEntry* prev = NULL; - for (int pos=0; posnext(); - while (entry != NULL) { - JvmtiTagHashmapEntry* next = entry->next(); + oop* obj = entry->object_addr(); - jweak ref = entry->object(); - oop oop = JNIHandles::resolve(ref); + // has object been GC'ed + if (!is_alive->do_object_b(entry->object())) { + // grab the tag + jlong tag = entry->tag(); + guarantee(tag != 0, "checking"); - // has object been GC'ed - if (oop == NULL) { - // grab the tag - jlong tag = entry->tag(); - guarantee(tag != 0, "checking"); + // remove GC'ed entry from hashmap and return the + // entry to the free list + hashmap->remove(prev, pos, entry); + destroy_entry(entry); - // remove GC'ed entry from hashmap and return the - // entry to the free list - hashmap->remove(prev, pos, entry); - destroy_entry(entry); + // post the event to the profiler + if (post_object_free) { + JvmtiExport::post_object_free(env(), tag); + } - // destroy the weak ref - JNIHandles::destroy_weak_global(ref); + ++freed; + } else { + f->do_oop(entry->object_addr()); + oop new_oop = entry->object(); - // post the event to the profiler - if (post_object_free) { - JvmtiExport::post_object_free(env(), tag); + // if the object has moved then re-hash it and move its + // entry to its new location. + unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size); + if (new_pos != (unsigned int)pos) { + if (prev == NULL) { + table[pos] = next; + } else { + prev->set_next(next); } - - freed++; - entry = next; - continue; - } - - // if this is the young hashmap then the object is either promoted - // or moved. - // if this is the other hashmap then the object is moved. - - bool same_gen; - if (i == 0) { - assert(hashmap == young_hashmap, "checking"); - same_gen = is_in_young(oop); - } else { - same_gen = true; - } - - - if (same_gen) { - // if the object has moved then re-hash it and move its - // entry to its new location. - unsigned int new_pos = JvmtiTagHashmap::hash(oop, size); - if (new_pos != (unsigned int)pos) { - if (prev == NULL) { - table[pos] = next; - } else { - prev->set_next(next); - } + if (new_pos < (unsigned int)pos) { entry->set_next(table[new_pos]); table[new_pos] = entry; - moved++; } else { - // object didn't move - prev = entry; + // Delay adding this entry to it's new position as we'd end up + // hitting it again during this iteration. + entry->set_next(delayed_add); + delayed_add = entry; } + moved++; } else { - // object has been promoted so remove the entry from the - // young hashmap - assert(hashmap == young_hashmap, "checking"); - hashmap->remove(prev, pos, entry); - - // move the entry to the promoted list - entry->set_next(promoted_entries); - promoted_entries = entry; + // object didn't move + prev = entry; } - - entry = next; } + + entry = next; } } - - // add the entries, corresponding to the promoted objects, to the - // other hashmap. - JvmtiTagHashmapEntry* entry = promoted_entries; - while (entry != NULL) { - oop o = JNIHandles::resolve(entry->object()); - assert(hashmap_for(o) == other_hashmap, "checking"); - JvmtiTagHashmapEntry* next = entry->next(); - other_hashmap->add(o, entry); - entry = next; - promoted++; + // Re-add all the entries which were kept aside + while (delayed_add != NULL) { + JvmtiTagHashmapEntry* next = delayed_add->next(); + unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size); + delayed_add->set_next(table[pos]); + table[pos] = delayed_add; + delayed_add = next; } // stats if (TraceJVMTIObjectTagging) { - int total_moves = promoted + moved; - - int post_total = 0; - for (int i=0; i_entry_count; - } + int post_total = hashmap->_entry_count; int pre_total = post_total + freed; - tty->print("(%d->%d, %d freed, %d promoted, %d total moves)", - pre_total, post_total, freed, promoted, total_moves); + tty->print_cr("(%d->%d, %d freed, %d total moves)", + pre_total, post_total, freed, moved); } } diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.hpp b/hotspot/src/share/vm/prims/jvmtiTagMap.hpp index f94e74f71c2..9abdd9b37a1 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.hpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.hpp @@ -45,17 +45,12 @@ class JvmtiTagMap : public CHeapObj { private: enum{ - n_hashmaps = 2, // encapsulates 2 hashmaps - max_free_entries = 4096 // maximum number of free entries per env + max_free_entries = 4096 // maximum number of free entries per env }; - // memory region for young generation - static MemRegion _young_gen; - static void get_young_generation(); - JvmtiEnv* _env; // the jvmti environment Mutex _lock; // lock for this tag map - JvmtiTagHashmap* _hashmap[n_hashmaps]; // the hashmaps + JvmtiTagHashmap* _hashmap; // the hashmap JvmtiTagHashmapEntry* _free_entries; // free list for this environment int _free_entries_count; // number of entries on the free list @@ -67,11 +62,7 @@ class JvmtiTagMap : public CHeapObj { inline Mutex* lock() { return &_lock; } inline JvmtiEnv* env() const { return _env; } - // rehash tags maps for generation start to end - void rehash(int start, int end); - - // indicates if the object is in the young generation - static bool is_in_young(oop o); + void do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f); // iterate over all entries in this tag map void entry_iterate(JvmtiTagHashmapEntryClosure* closure); @@ -81,11 +72,10 @@ class JvmtiTagMap : public CHeapObj { // indicates if this tag map is locked bool is_locked() { return lock()->is_locked(); } - // return the appropriate hashmap for a given object - JvmtiTagHashmap* hashmap_for(oop o); + JvmtiTagHashmap* hashmap() { return _hashmap; } // create/destroy entries - JvmtiTagHashmapEntry* create_entry(jweak ref, jlong tag); + JvmtiTagHashmapEntry* create_entry(oop ref, jlong tag); void destroy_entry(JvmtiTagHashmapEntry* entry); // returns true if the hashmaps are empty @@ -134,11 +124,8 @@ class JvmtiTagMap : public CHeapObj { jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr); - // call post-GC to rehash the tag maps. - static void gc_epilogue(bool full); - - // call after referencing processing has completed (CMS) - static void cms_ref_processing_epilogue(); + static void weak_oops_do( + BoolObjectClosure* is_alive, OopClosure* f) KERNEL_RETURN; }; #endif // SHARE_VM_PRIMS_JVMTITAGMAP_HPP diff --git a/hotspot/src/share/vm/prims/methodComparator.cpp b/hotspot/src/share/vm/prims/methodComparator.cpp index 6223c87797e..184979d9911 100644 --- a/hotspot/src/share/vm/prims/methodComparator.cpp +++ b/hotspot/src/share/vm/prims/methodComparator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,10 +194,10 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) { case Bytecodes::_ldc : // fall through case Bytecodes::_ldc_w : { - Bytecode_loadconstant* ldc_old = Bytecode_loadconstant_at(_s_old->method(), _s_old->bci()); - Bytecode_loadconstant* ldc_new = Bytecode_loadconstant_at(_s_new->method(), _s_new->bci()); - int cpi_old = ldc_old->pool_index(); - int cpi_new = ldc_new->pool_index(); + Bytecode_loadconstant ldc_old(_s_old->method(), _s_old->bci()); + Bytecode_loadconstant ldc_new(_s_new->method(), _s_new->bci()); + int cpi_old = ldc_old.pool_index(); + int cpi_new = ldc_new.pool_index(); if (!pool_constants_same(cpi_old, cpi_new)) return false; break; @@ -267,8 +267,8 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) { case Bytecodes::_ifnonnull : // fall through case Bytecodes::_ifnull : // fall through case Bytecodes::_jsr : { - int old_ofs = _s_old->bytecode()->get_offset_s2(c_old); - int new_ofs = _s_new->bytecode()->get_offset_s2(c_new); + int old_ofs = _s_old->bytecode().get_offset_s2(c_old); + int new_ofs = _s_new->bytecode().get_offset_s2(c_new); if (_switchable_test) { int old_dest = _s_old->bci() + old_ofs; int new_dest = _s_new->bci() + new_ofs; @@ -304,8 +304,8 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) { case Bytecodes::_goto_w : // fall through case Bytecodes::_jsr_w : { - int old_ofs = _s_old->bytecode()->get_offset_s4(c_old); - int new_ofs = _s_new->bytecode()->get_offset_s4(c_new); + int old_ofs = _s_old->bytecode().get_offset_s4(c_old); + int new_ofs = _s_new->bytecode().get_offset_s4(c_new); if (_switchable_test) { int old_dest = _s_old->bci() + old_ofs; int new_dest = _s_new->bci() + new_ofs; diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.cpp b/hotspot/src/share/vm/prims/methodHandleWalk.cpp index f20859dac8c..4552410944f 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,6 @@ BasicType MethodHandleChain::compute_bound_arg_type(oop target, methodOop m, int void MethodHandleChain::lose(const char* msg, TRAPS) { - assert(false, "lose"); _lose_message = msg; if (!THREAD->is_Java_thread() || ((JavaThread*)THREAD)->thread_state() != _thread_in_vm) { // throw a preallocated exception diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 1b2c3c60d4a..f77f0b625d5 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,7 @@ bool MethodHandles::spot_check_entry_names() { //------------------------------------------------------------------------------ // MethodHandles::generate_adapters // -void MethodHandles::generate_adapters(TRAPS) { +void MethodHandles::generate_adapters() { if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; assert(_adapter_code == NULL, "generate only once"); @@ -123,20 +123,20 @@ void MethodHandles::generate_adapters(TRAPS) { vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); - g.generate(CHECK); + g.generate(); } //------------------------------------------------------------------------------ // MethodHandlesAdapterGenerator::generate // -void MethodHandlesAdapterGenerator::generate(TRAPS) { +void MethodHandlesAdapterGenerator::generate() { // Generate generic method handle adapters. for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; ek < MethodHandles::_EK_LIMIT; ek = MethodHandles::EntryKind(1 + (int)ek)) { StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek, CHECK); + MethodHandles::generate_method_handle_stub(_masm, ek); } } @@ -2621,10 +2621,20 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); enable_MH = false; } + } else { + enable_MH = false; } } if (enable_MH) { + // We need to link the MethodHandleImpl klass before we generate + // the method handle adapters as the _raise_exception adapter uses + // one of its methods (and its c2i-adapter). + KlassHandle k = SystemDictionaryHandles::MethodHandleImpl_klass(); + instanceKlass* ik = instanceKlass::cast(k()); + ik->link_class(CHECK); + + MethodHandles::generate_adapters(); MethodHandles::set_enabled(true); } @@ -2645,10 +2655,5 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) MethodHandles::set_enabled(true); } } - - // Generate method handles adapters if enabled. - if (MethodHandles::enabled()) { - MethodHandles::generate_adapters(CHECK); - } } JVM_END diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp index f66f0e026d2..cf9c25a5ae9 100644 --- a/hotspot/src/share/vm/prims/methodHandles.hpp +++ b/hotspot/src/share/vm/prims/methodHandles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -294,11 +294,11 @@ class MethodHandles: AllStatic { enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; // Generate MethodHandles adapters. - static void generate_adapters(TRAPS); + static void generate_adapters(); // Called from InterpreterGenerator and MethodHandlesAdapterGenerator. static address generate_method_handle_interpreter_entry(MacroAssembler* _masm); - static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek, TRAPS); + static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek); // argument list parsing static int argument_slot(oop method_type, int arg); @@ -530,7 +530,7 @@ class MethodHandlesAdapterGenerator : public StubCodeGenerator { public: MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {} - void generate(TRAPS); + void generate(); }; #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 4444fc67a25..7c64262d86f 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,12 +154,11 @@ jint Unsafe_invocation_key_to_method_slot(jint key) { #define GET_FIELD_VOLATILE(obj, offset, type_name, v) \ oop p = JNIHandles::resolve(obj); \ - volatile type_name v = *(volatile type_name*)index_oop_from_field_offset_long(p, offset) + volatile type_name v = OrderAccess::load_acquire((volatile type_name*)index_oop_from_field_offset_long(p, offset)); #define SET_FIELD_VOLATILE(obj, offset, type_name, x) \ oop p = JNIHandles::resolve(obj); \ - *(volatile type_name*)index_oop_from_field_offset_long(p, offset) = x; \ - OrderAccess::fence(); + OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x); // Macros for oops that check UseCompressedOops @@ -181,7 +180,8 @@ jint Unsafe_invocation_key_to_method_slot(jint key) { v = oopDesc::decode_heap_oop(n); \ } else { \ v = *(volatile oop*)index_oop_from_field_offset_long(p, offset); \ - } + } \ + OrderAccess::acquire(); // Get/SetObject must be special-cased, since it works with handles. @@ -248,14 +248,22 @@ UNSAFE_ENTRY(void, Unsafe_SetObjectVolatile(JNIEnv *env, jobject unsafe, jobject UnsafeWrapper("Unsafe_SetObjectVolatile"); oop x = JNIHandles::resolve(x_h); oop p = JNIHandles::resolve(obj); + void* addr = index_oop_from_field_offset_long(p, offset); + OrderAccess::release(); if (UseCompressedOops) { - oop_store((narrowOop*)index_oop_from_field_offset_long(p, offset), x); + oop_store((narrowOop*)addr, x); } else { - oop_store((oop*)index_oop_from_field_offset_long(p, offset), x); + oop_store((oop*)addr, x); } OrderAccess::fence(); UNSAFE_END +#if defined(SPARC) || defined(X86) +// Sparc and X86 have atomic jlong (8 bytes) instructions + +#else +// Keep old code for platforms which may not have atomic jlong (8 bytes) instructions + // Volatile long versions must use locks if !VM_Version::supports_cx8(). // support_cx8 is a surrogate for 'supports atomic long memory ops'. @@ -291,6 +299,7 @@ UNSAFE_ENTRY(void, Unsafe_SetLongVolatile(JNIEnv *env, jobject unsafe, jobject o } UNSAFE_END +#endif // not SPARC and not X86 #define DEFINE_GETSETOOP(jboolean, Boolean) \ \ @@ -320,6 +329,16 @@ UNSAFE_END \ \ // END DEFINE_GETSETOOP. +DEFINE_GETSETOOP(jboolean, Boolean) +DEFINE_GETSETOOP(jbyte, Byte) +DEFINE_GETSETOOP(jshort, Short); +DEFINE_GETSETOOP(jchar, Char); +DEFINE_GETSETOOP(jint, Int); +DEFINE_GETSETOOP(jlong, Long); +DEFINE_GETSETOOP(jfloat, Float); +DEFINE_GETSETOOP(jdouble, Double); + +#undef DEFINE_GETSETOOP #define DEFINE_GETSETOOP_VOLATILE(jboolean, Boolean) \ \ @@ -336,47 +355,49 @@ UNSAFE_END \ \ // END DEFINE_GETSETOOP_VOLATILE. -DEFINE_GETSETOOP(jboolean, Boolean) -DEFINE_GETSETOOP(jbyte, Byte) -DEFINE_GETSETOOP(jshort, Short); -DEFINE_GETSETOOP(jchar, Char); -DEFINE_GETSETOOP(jint, Int); -DEFINE_GETSETOOP(jlong, Long); -DEFINE_GETSETOOP(jfloat, Float); -DEFINE_GETSETOOP(jdouble, Double); - DEFINE_GETSETOOP_VOLATILE(jboolean, Boolean) DEFINE_GETSETOOP_VOLATILE(jbyte, Byte) DEFINE_GETSETOOP_VOLATILE(jshort, Short); DEFINE_GETSETOOP_VOLATILE(jchar, Char); DEFINE_GETSETOOP_VOLATILE(jint, Int); -// no long -- handled specially DEFINE_GETSETOOP_VOLATILE(jfloat, Float); DEFINE_GETSETOOP_VOLATILE(jdouble, Double); -#undef DEFINE_GETSETOOP +#if defined(SPARC) || defined(X86) +// Sparc and X86 have atomic jlong (8 bytes) instructions +DEFINE_GETSETOOP_VOLATILE(jlong, Long); +#endif + +#undef DEFINE_GETSETOOP_VOLATILE // The non-intrinsified versions of setOrdered just use setVolatile -UNSAFE_ENTRY(void, Unsafe_SetOrderedInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint x)) \ - UnsafeWrapper("Unsafe_SetOrderedInt"); \ - SET_FIELD_VOLATILE(obj, offset, jint, x); \ +UNSAFE_ENTRY(void, Unsafe_SetOrderedInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint x)) + UnsafeWrapper("Unsafe_SetOrderedInt"); + SET_FIELD_VOLATILE(obj, offset, jint, x); UNSAFE_END UNSAFE_ENTRY(void, Unsafe_SetOrderedObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) UnsafeWrapper("Unsafe_SetOrderedObject"); oop x = JNIHandles::resolve(x_h); oop p = JNIHandles::resolve(obj); + void* addr = index_oop_from_field_offset_long(p, offset); + OrderAccess::release(); if (UseCompressedOops) { - oop_store((narrowOop*)index_oop_from_field_offset_long(p, offset), x); + oop_store((narrowOop*)addr, x); } else { - oop_store((oop*)index_oop_from_field_offset_long(p, offset), x); + oop_store((oop*)addr, x); } OrderAccess::fence(); UNSAFE_END UNSAFE_ENTRY(void, Unsafe_SetOrderedLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x)) UnsafeWrapper("Unsafe_SetOrderedLong"); +#if defined(SPARC) || defined(X86) + // Sparc and X86 have atomic jlong (8 bytes) instructions + SET_FIELD_VOLATILE(obj, offset, jlong, x); +#else + // Keep old code for platforms which may not have atomic long (8 bytes) instructions { if (VM_Version::supports_cx8()) { SET_FIELD_VOLATILE(obj, offset, jlong, x); @@ -388,6 +409,7 @@ UNSAFE_ENTRY(void, Unsafe_SetOrderedLong(JNIEnv *env, jobject unsafe, jobject ob *addr = x; } } +#endif UNSAFE_END ////// Data in the C heap. diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 09b41b5b0b1..b106d08fc60 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -918,9 +918,7 @@ bool Arguments::add_property(const char* prop) { } else if (strcmp(key, "sun.java.command") == 0) { _java_command = value; - // don't add this property to the properties exposed to the java application - FreeHeap(key); - return true; + // Record value in Arguments, but let it get passed to Java. } else if (strcmp(key, "sun.java.launcher.pid") == 0) { // launcher.pid property is private and is processed // in process_sun_java_launcher_properties(); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index dee481a084a..de431174da7 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -395,8 +395,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread { HandleMark hm; methodHandle method(thread, array->element(0)->method()); - Bytecode_invoke* invoke = Bytecode_invoke_at_check(method, array->element(0)->bci()); - return_type = (invoke != NULL) ? invoke->result_type(thread) : T_ILLEGAL; + Bytecode_invoke invoke = Bytecode_invoke_check(method, array->element(0)->bci()); + return_type = invoke.is_valid() ? invoke.result_type(thread) : T_ILLEGAL; } // Compute information for handling adapters and adjusting the frame size of the caller. @@ -600,8 +600,8 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m cur_code == Bytecodes::_invokespecial || cur_code == Bytecodes::_invokestatic || cur_code == Bytecodes::_invokeinterface) { - Bytecode_invoke* invoke = Bytecode_invoke_at(mh, iframe->interpreter_frame_bci()); - symbolHandle signature(thread, invoke->signature()); + Bytecode_invoke invoke(mh, iframe->interpreter_frame_bci()); + symbolHandle signature(thread, invoke.signature()); ArgumentSizeComputer asc(signature); cur_invoke_parameter_size = asc.size(); if (cur_code != Bytecodes::_invokestatic) { @@ -963,7 +963,7 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re if (bci == SynchronizationEntryBCI) { code_name = "sync entry"; } else { - Bytecodes::Code code = Bytecodes::code_at(vf->method(), bci); + Bytecodes::Code code = vf->method()->code_at(bci); code_name = Bytecodes::name(code); } tty->print(" - %s", code_name); @@ -1224,7 +1224,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra ScopeDesc* trap_scope = cvf->scope(); methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); - Bytecodes::Code trap_bc = Bytecode_at(trap_method->bcp_from(trap_bci))->java_code(); + Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); // Record this event in the histogram. gather_statistics(reason, action, trap_bc); diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 5f5ccd4798f..91f0292b476 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -930,10 +930,10 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer // This is used sometimes for calling into the VM, not for another // interpreted or compiled frame. if (!m->is_native()) { - Bytecode_invoke *call = Bytecode_invoke_at_check(m, bci); - if (call != NULL) { - signature = symbolHandle(thread, call->signature()); - has_receiver = call->has_receiver(); + Bytecode_invoke call = Bytecode_invoke_check(m, bci); + if (call.is_valid()) { + signature = symbolHandle(thread, call.signature()); + has_receiver = call.has_receiver(); if (map->include_argument_oops() && interpreter_frame_expression_stack_size() > 0) { ResourceMark rm(thread); // is this right ??? diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 07bda32a07f..7024dacb9bc 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1198,9 +1198,6 @@ class CommandLineFlags { product(ccstr, TraceJVMTI, NULL, \ "Trace flags for JVMTI functions and events") \ \ - product(bool, ForceFullGCJVMTIEpilogues, false, \ - "Force 'Full GC' was done semantics for JVMTI GC epilogues") \ - \ /* This option can change an EMCP method into an obsolete method. */ \ /* This can affect tests that except specific methods to be EMCP. */ \ /* This option should be used with caution. */ \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index f6b20a7b79e..42cfd6a0018 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -663,7 +663,8 @@ void JDK_Version::initialize() { } _current = JDK_Version(major, minor, micro, info.update_version, info.special_update_version, build, - info.thread_park_blocker == 1); + info.thread_park_blocker == 1, + info.post_vm_init_hook_enabled == 1); } } diff --git a/hotspot/src/share/vm/runtime/java.hpp b/hotspot/src/share/vm/runtime/java.hpp index b6062da448b..aabc63116c1 100644 --- a/hotspot/src/share/vm/runtime/java.hpp +++ b/hotspot/src/share/vm/runtime/java.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,6 +92,7 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC { bool _partially_initialized; bool _thread_park_blocker; + bool _post_vm_init_hook_enabled; bool is_valid() const { return (_major != 0 || _partially_initialized); @@ -113,14 +114,15 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC { JDK_Version() : _major(0), _minor(0), _micro(0), _update(0), _special(0), _build(0), _partially_initialized(false), - _thread_park_blocker(false) {} + _thread_park_blocker(false), _post_vm_init_hook_enabled(false) {} JDK_Version(uint8_t major, uint8_t minor = 0, uint8_t micro = 0, uint8_t update = 0, uint8_t special = 0, uint8_t build = 0, - bool thread_park_blocker = false) : + bool thread_park_blocker = false, bool post_vm_init_hook_enabled = false) : _major(major), _minor(minor), _micro(micro), _update(update), _special(special), _build(build), _partially_initialized(false), - _thread_park_blocker(thread_park_blocker) {} + _thread_park_blocker(thread_park_blocker), + _post_vm_init_hook_enabled(post_vm_init_hook_enabled) {} // Returns the current running JDK version static JDK_Version current() { return _current; } @@ -144,6 +146,9 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC { bool supports_thread_park_blocker() const { return _thread_park_blocker; } + bool post_vm_init_hook_enabled() const { + return _post_vm_init_hook_enabled; + } // Performs a full ordering comparison using all fields (update, build, etc.) int compare(const JDK_Version& other) const; diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 357061f3ea0..31595688fe5 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #ifdef TARGET_OS_FAMILY_linux @@ -428,6 +429,12 @@ void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive, break; } } + + /* + * JVMTI data structures may also contain weak oops. The iteration of them + * is placed here so that we don't need to add it to each of the collectors. + */ + JvmtiExport::weak_oops_do(is_alive, f); } diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 5b825aee68b..25b0c339d01 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,8 +80,6 @@ Monitor* SLT_lock = NULL; Monitor* iCMS_lock = NULL; Monitor* FullGCCount_lock = NULL; Monitor* CMark_lock = NULL; -Monitor* ZF_mon = NULL; -Monitor* Cleanup_mon = NULL; Mutex* CMRegionStack_lock = NULL; Mutex* SATB_Q_FL_lock = NULL; Monitor* SATB_Q_CBL_mon = NULL; @@ -122,6 +120,9 @@ Mutex* PerfDataMemAlloc_lock = NULL; Mutex* PerfDataManager_lock = NULL; Mutex* OopMapCacheAlloc_lock = NULL; +Mutex* FreeList_lock = NULL; +Monitor* SecondaryFreeList_lock = NULL; +Mutex* OldSets_lock = NULL; Mutex* MMUTracker_lock = NULL; Mutex* HotCardCache_lock = NULL; @@ -177,8 +178,6 @@ void mutex_init() { } if (UseG1GC) { def(CMark_lock , Monitor, nonleaf, true ); // coordinate concurrent mark thread - def(ZF_mon , Monitor, leaf, true ); - def(Cleanup_mon , Monitor, nonleaf, true ); def(CMRegionStack_lock , Mutex, leaf, true ); def(SATB_Q_FL_lock , Mutex , special, true ); def(SATB_Q_CBL_mon , Monitor, nonleaf, true ); @@ -188,6 +187,9 @@ void mutex_init() { def(DirtyCardQ_CBL_mon , Monitor, nonleaf, true ); def(Shared_DirtyCardQ_lock , Mutex, nonleaf, true ); + def(FreeList_lock , Mutex, leaf , true ); + def(SecondaryFreeList_lock , Monitor, leaf , true ); + def(OldSets_lock , Mutex , leaf , true ); def(MMUTracker_lock , Mutex , leaf , true ); def(HotCardCache_lock , Mutex , special , true ); def(EvacFailureStack_lock , Mutex , nonleaf , true ); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index c4a9ce1bbdf..ad3c24ca8a5 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,8 +76,6 @@ extern Monitor* SLT_lock; // used in CMS GC for acquiring extern Monitor* iCMS_lock; // CMS incremental mode start/stop notification extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc extern Monitor* CMark_lock; // used for concurrent mark thread coordination -extern Monitor* ZF_mon; // used for G1 conc zero-fill. -extern Monitor* Cleanup_mon; // used for G1 conc cleanup. extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack extern Mutex* SATB_Q_FL_lock; // Protects SATB Q // buffer free list. @@ -125,6 +123,9 @@ extern Mutex* PerfDataManager_lock; // a long on access to PerfData extern Mutex* ParkerFreeList_lock; extern Mutex* OopMapCacheAlloc_lock; // protects allocation of oop_map caches +extern Mutex* FreeList_lock; // protects the free region list during safepoints +extern Monitor* SecondaryFreeList_lock; // protects the secondary free region list +extern Mutex* OldSets_lock; // protects the old region sets extern Mutex* MMUTracker_lock; // protects the MMU // tracker data structures extern Mutex* HotCardCache_lock; // protects the hot card cache diff --git a/hotspot/src/share/vm/runtime/relocator.hpp b/hotspot/src/share/vm/runtime/relocator.hpp index f1c8c67f74e..7fc4241c800 100644 --- a/hotspot/src/share/vm/runtime/relocator.hpp +++ b/hotspot/src/share/vm/runtime/relocator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,7 +106,7 @@ class Relocator : public ResourceObj { // get the address of in the code_array inline char* addr_at(int bci) const { return (char*) &code_array()[bci]; } - int instruction_length_at(int bci) { return Bytecodes::length_at(code_array() + bci); } + int instruction_length_at(int bci) { return Bytecodes::length_at(NULL, code_array() + bci); } // Helper methods int align(int n) const { return (n+3) & ~3; } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 46305fe871d..b22d99d146f 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -944,9 +944,9 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, int bci = vfst.bci(); // Find bytecode - Bytecode_invoke* bytecode = Bytecode_invoke_at(caller, bci); - bc = bytecode->java_code(); - int bytecode_index = bytecode->index(); + Bytecode_invoke bytecode(caller, bci); + bc = bytecode.java_code(); + int bytecode_index = bytecode.index(); // Find receiver for non-static call if (bc != Bytecodes::_invokestatic) { @@ -957,7 +957,7 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, // Caller-frame is a compiled frame frame callerFrame = stubFrame.sender(®_map2); - methodHandle callee = bytecode->static_target(CHECK_(nullHandle)); + methodHandle callee = bytecode.static_target(CHECK_(nullHandle)); if (callee.is_null()) { THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle); } @@ -1674,10 +1674,9 @@ char* SharedRuntime::generate_class_cast_message( // Get target class name from the checkcast instruction vframeStream vfst(thread, true); assert(!vfst.at_end(), "Java frame must exist"); - Bytecode_checkcast* cc = Bytecode_checkcast_at( - vfst.method()->bcp_from(vfst.bci())); + Bytecode_checkcast cc(vfst.method(), vfst.method()->bcp_from(vfst.bci())); Klass* targetKlass = Klass::cast(vfst.method()->constants()->klass_at( - cc->index(), thread)); + cc.index(), thread)); return generate_class_cast_message(objName, targetKlass->external_name()); } @@ -1711,11 +1710,11 @@ char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread, const char* targetType = "the required signature"; vframeStream vfst(thread, true); if (!vfst.at_end()) { - Bytecode_invoke* call = Bytecode_invoke_at(vfst.method(), vfst.bci()); + Bytecode_invoke call(vfst.method(), vfst.bci()); methodHandle target; { EXCEPTION_MARK; - target = call->static_target(THREAD); + target = call.static_target(THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; } } if (target.not_null() diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index fbb6ca93b5c..0349c658495 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -31,6 +31,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" +#include "jvmtifiles/jvmtiEnv.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" @@ -977,6 +978,19 @@ static void set_jkernel_boot_classloader_hook(TRAPS) { } #endif // KERNEL +// General purpose hook into Java code, run once when the VM is initialized. +// The Java library method itself may be changed independently from the VM. +static void call_postVMInitHook(TRAPS) { + klassOop k = SystemDictionary::sun_misc_PostVMInitHook_klass(); + instanceKlassHandle klass (THREAD, k); + if (klass.not_null()) { + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbolHandles::run_method_name(), + vmSymbolHandles::void_method_signature(), + CHECK); + } +} + static void reset_vm_info_property(TRAPS) { // the vm info string ResourceMark rm(THREAD); @@ -1699,7 +1713,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { tlab().make_parsable(true); // retire TLAB } - if (jvmti_thread_state() != NULL) { + if (JvmtiEnv::environments_might_exist()) { JvmtiExport::cleanup_thread(this); } @@ -3345,6 +3359,14 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { BiasedLocking::init(); + if (JDK_Version::current().post_vm_init_hook_enabled()) { + call_postVMInitHook(THREAD); + // The Java side of PostVMInitHook.run must deal with all + // exceptions and provide means of diagnosis. + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } + } // Start up the WatcherThread if there are any periodic tasks // NOTE: All PeriodicTasks should be registered by now. If they diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index a0ca83c56c5..acdc227bdcc 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -809,7 +809,7 @@ class JavaThread: public Thread { // // _vm_exited is a special value to cover the case of a JavaThread // executing native code after the VM itself is terminated. - TerminatedTypes _terminated; + volatile TerminatedTypes _terminated; // suspend/resume support volatile bool _suspend_equivalent; // Suspend equivalent condition jint _in_deopt_handler; // count of deoptimization diff --git a/hotspot/src/share/vm/runtime/vframeArray.cpp b/hotspot/src/share/vm/runtime/vframeArray.cpp index b2e666db3d4..2a16535310a 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.cpp +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -399,7 +399,7 @@ void vframeArrayElement::unpack_on_stack(int callee_parameters, } else if (TraceDeoptimization) { tty->print(" "); method()->print_value(); - Bytecodes::Code code = Bytecodes::java_code_at(bcp); + Bytecodes::Code code = Bytecodes::java_code_at(method(), bcp); int bci = method()->bci_from(bcp); tty->print(" - %s", Bytecodes::name(code)); tty->print(" @ bci %d ", bci); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 2d440e58f3c..30973292d2a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,8 +219,8 @@ static inline uint64_t cast_uint64_t(size_t x) volatile_nonstatic_field(oopDesc, _metadata._compressed_klass, narrowOop) \ static_field(oopDesc, _bs, BarrierSet*) \ nonstatic_field(arrayKlass, _dimension, int) \ - nonstatic_field(arrayKlass, _higher_dimension, klassOop) \ - nonstatic_field(arrayKlass, _lower_dimension, klassOop) \ + volatile_nonstatic_field(arrayKlass, _higher_dimension, klassOop) \ + volatile_nonstatic_field(arrayKlass, _lower_dimension, klassOop) \ nonstatic_field(arrayKlass, _vtable_len, int) \ nonstatic_field(arrayKlass, _alloc_size, juint) \ nonstatic_field(arrayKlass, _component_mirror, oop) \ diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 37a11ca9814..e30e62d1a17 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -453,7 +453,7 @@ DumpWriter::DumpWriter(const char* path) { DumpWriter::~DumpWriter() { // flush and close dump file - if (file_descriptor() >= 0) { + if (is_open()) { close(); } if (_buffer != NULL) os::free(_buffer); @@ -463,9 +463,10 @@ DumpWriter::~DumpWriter() { // closes dump file (if open) void DumpWriter::close() { // flush and close dump file - if (file_descriptor() >= 0) { + if (is_open()) { flush(); ::close(file_descriptor()); + set_file_descriptor(-1); } } @@ -1935,18 +1936,32 @@ void HeapDumper::dump_heap() { void HeapDumper::dump_heap(bool oome) { static char base_path[JVM_MAXPATHLEN] = {'\0'}; static uint dump_file_seq = 0; - char my_path[JVM_MAXPATHLEN] = {'\0'}; + char* my_path; + const int max_digit_chars = 20; + + const char* dump_file_name = "java_pid"; + const char* dump_file_ext = ".hprof"; // The dump file defaults to java_pid.hprof in the current working // directory. HeapDumpPath= can be used to specify an alternative // dump file name or a directory where dump file is created. if (dump_file_seq == 0) { // first time in, we initialize base_path + // Calculate potentially longest base path and check if we have enough + // allocated statically. + const size_t total_length = + (HeapDumpPath == NULL ? 0 : strlen(HeapDumpPath)) + + strlen(os::file_separator()) + max_digit_chars + + strlen(dump_file_name) + strlen(dump_file_ext) + 1; + if (total_length > sizeof(base_path)) { + warning("Cannot create heap dump file. HeapDumpPath is too long."); + return; + } + bool use_default_filename = true; if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { // HeapDumpPath= not specified } else { - assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long"); - strcpy(base_path, HeapDumpPath); + strncpy(base_path, HeapDumpPath, sizeof(base_path)); // check if the path is a directory (must exist) DIR* dir = os::opendir(base_path); if (dir == NULL) { @@ -1960,8 +1975,6 @@ void HeapDumper::dump_heap(bool oome) { char* end = base_path; end += (strlen(base_path) - fs_len); if (strcmp(end, os::file_separator()) != 0) { - assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path), - "HeapDumpPath too long"); strcat(base_path, os::file_separator()); } } @@ -1969,21 +1982,26 @@ void HeapDumper::dump_heap(bool oome) { } // If HeapDumpPath wasn't a file name then we append the default name if (use_default_filename) { - char fn[32]; - sprintf(fn, "java_pid%d", os::current_process_id()); - assert(strlen(base_path) + strlen(fn) + strlen(".hprof") < sizeof(base_path), "HeapDumpPath too long"); - strcat(base_path, fn); - strcat(base_path, ".hprof"); + const size_t dlen = strlen(base_path); // if heap dump dir specified + jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s", + dump_file_name, os::current_process_id(), dump_file_ext); } - assert(strlen(base_path) < sizeof(my_path), "Buffer too small"); - strcpy(my_path, base_path); + const size_t len = strlen(base_path) + 1; + my_path = (char*)os::malloc(len); + if (my_path == NULL) { + warning("Cannot create heap dump file. Out of system memory."); + return; + } + strncpy(my_path, base_path, len); } else { // Append a sequence number id for dumps following the first - char fn[33]; - sprintf(fn, ".%d", dump_file_seq); - assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long"); - strcpy(my_path, base_path); - strcat(my_path, fn); + const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0 + my_path = (char*)os::malloc(len); + if (my_path == NULL) { + warning("Cannot create heap dump file. Out of system memory."); + return; + } + jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq); } dump_file_seq++; // increment seq number for next time we dump @@ -1991,4 +2009,5 @@ void HeapDumper::dump_heap(bool oome) { true /* send to tty */, oome /* pass along out-of-memory-error flag */); dumper.dump(my_path); + os::free(my_path); } diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index 54bfc777c64..bb92bbe90e2 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -34,6 +34,7 @@ template class FormatBuffer { public: inline FormatBuffer(const char * format, ...); + inline void append(const char* format, ...); operator const char *() const { return _buf; } private: @@ -51,6 +52,19 @@ FormatBuffer::FormatBuffer(const char * format, ...) { va_end(argp); } +template +void FormatBuffer::append(const char* format, ...) { + // Given that the constructor does a vsnprintf we can assume that + // _buf is already initialized. + size_t len = strlen(_buf); + char* buf_end = _buf + len; + + va_list argp; + va_start(argp, format); + vsnprintf(buf_end, bufsz - len, format, argp); + va_end(argp); +} + // Used to format messages for assert(), guarantee(), fatal(), etc. typedef FormatBuffer<> err_msg; diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 0499aaeb660..56a9043e546 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1179,6 +1179,8 @@ inline int build_int_from_shorts( jushort low, jushort high ) { // '%d' formats to indicate a 64-bit quantity; commonly "l" (in LP64) or "ll" // (in ILP32). +#define BOOL_TO_STR(__b) (__b) ? "true" : "false" + // Format 32-bit quantities. #define INT32_FORMAT "%d" #define UINT32_FORMAT "%u" diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 4b8e055d496..662e5a7c91a 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -874,11 +874,13 @@ void VMError::report_and_die() { } if (fd == -1) { - // try temp directory const char * tmpdir = os::get_temp_directory(); - jio_snprintf(buffer, sizeof(buffer), "%s%shs_err_pid%u.log", - tmpdir, os::file_separator(), os::current_process_id()); - fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666); + // try temp directory if it exists. + if (tmpdir != NULL && tmpdir[0] != '\0') { + jio_snprintf(buffer, sizeof(buffer), "%s%shs_err_pid%u.log", + tmpdir, os::file_separator(), os::current_process_id()); + fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666); + } } if (fd != -1) { diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 820c05234b5..8078946bf78 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -100,3 +100,5 @@ b2f6d9c4f12ffd307a5de40455b2b61b31a5cb79 jdk7-b118 e2aedea6495d61557326928de20dbb2d78fdd9aa jdk7-b123 57ed1f3bec72924cdad102f9bf90f7449ea7bb83 jdk7-b124 6c9bdee0cc3a8912acc5189cc092b8cba6851f9d jdk7-b125 +2fde639439c1fb3fbc44f533d48bb2916e813312 jdk7-b126 +c532d6dbc8d18d55b5d693599ee5cd8250e16eb4 jdk7-b127 diff --git a/jaxws/.hgtags b/jaxws/.hgtags index ee5ac8a4728..3f097d53596 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -100,3 +100,5 @@ a4f2e1ca67163ef79555082809d7cd719893c338 jdk7-b120 5a8e43bcce56b7cd5576419067a929b74575ae71 jdk7-b123 86f60e5b3975840968f3147ddce047a27a9fc83e jdk7-b124 d72eea121c3bc2b649272a37b80d9417855b7146 jdk7-b125 +6d772c5119d5e247bc98a57ce8b1be121554ee0a jdk7-b126 +ef19f173578c804772d586a959fa3ab8a12c0598 jdk7-b127 diff --git a/jdk/.hgtags b/jdk/.hgtags index 90b30b8f1df..684719db0b2 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -100,3 +100,6 @@ ac311eb325bfc763698219252bf3cee9e091f3af jdk7-b122 869190935eedee7750d955019ab2a1b80f0a13a8 jdk7-b123 1c72adc9d5f331cb882cf5354ba0dcb118a60b23 jdk7-b124 0a56bdd709d01c1663047e55201d19152ffd3d69 jdk7-b125 +8361ef97a0f90086c9048beaf7cea1a37216c4cd jdk7-b126 +29e09de1d0b4f84faea114cf10b3ec08b59acc4e jdk7-b127 +f08682e23279d6cccbdcafda1eb0647ba4900874 jdk7-b128 diff --git a/jdk/make/Makefile b/jdk/make/Makefile index 36bf631d5b8..74651fca20b 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -100,7 +100,6 @@ CACERTS_FILE.desc = Location of certificates file DEVTOOLS_PATH.desc = Directory containing zip and unzip CUPS_HEADERS_PATH.desc = Include directory location for CUPS header files DXSDK_PATH.desc = Root directory of DirectX SDK -MSVCRT_DLL_PATH.desc = Directory containing mscvrt.dll # Make variables to print out (description and value) VARIABLE_PRINTVAL_LIST += \ @@ -133,12 +132,10 @@ VARIABLE_CHECKFIL_LIST += \ ifeq ($(PLATFORM), windows) VARIABLE_PRINTVAL_LIST += \ - DXSDK_PATH \ - MSVCRT_DLL_PATH + DXSDK_PATH VARIABLE_CHECKDIR_LIST += \ - DXSDK_PATH \ - MSVCRT_DLL_PATH + DXSDK_PATH endif diff --git a/jdk/make/com/sun/java/pack/Makefile b/jdk/make/com/sun/java/pack/Makefile index 6b5b0bfc241..e7fe8d44b76 100644 --- a/jdk/make/com/sun/java/pack/Makefile +++ b/jdk/make/com/sun/java/pack/Makefile @@ -155,6 +155,7 @@ ifdef MT $(MT) /manifest $(OBJDIR)/unpack200$(EXE_SUFFIX).manifest /outputresource:$(TEMPDIR)/unpack200$(EXE_SUFFIX);#1 endif $(CP) $(TEMPDIR)/unpack200$(EXE_SUFFIX) $(UNPACK_EXE) + @$(call binary_file_verification,$@) $(install-module-file) ifeq ($(PLATFORM), windows) diff --git a/jdk/make/common/Defs-windows.gmk b/jdk/make/common/Defs-windows.gmk index d93a4832f70..7899b0e668d 100644 --- a/jdk/make/common/Defs-windows.gmk +++ b/jdk/make/common/Defs-windows.gmk @@ -67,28 +67,27 @@ PLATFORM_INCLUDE = $(INCLUDEDIR)/$(PLATFORM_INCLUDE_NAME) # The following DLL's are considered MS runtime libraries and should # not to be REBASEd, see deploy/make/common/Release.gmk. -# msvcrt.dll, msvcrnn.dll [msvcr71 or msvcr80 or msvcr90] : Microsoft runtimes -MS_RUNTIME_LIBRARIES = msvcrt.dll +# msvcr*.dll: Microsoft runtimes ifeq ($(ARCH_DATA_MODEL), 32) ifeq ($(COMPILER_VERSION), VS2003) MSVCRNN_DLL = msvcr71.dll MSVCPNN_DLL = msvcp71.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL) endif ifeq ($(COMPILER_VERSION), VS2005) MSVCRNN_DLL = msvcr80.dll MSVCPNN_DLL = msvcp80.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL) endif ifeq ($(COMPILER_VERSION), VS2008) MSVCRNN_DLL = msvcr90.dll MSVCPNN_DLL = msvcp90.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL) endif ifeq ($(COMPILER_VERSION), VS2010) MSVCRNN_DLL = msvcr100.dll MSVCPNN_DLL = msvcp100.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL) endif endif @@ -96,12 +95,12 @@ ifeq ($(ARCH_DATA_MODEL), 64) ifeq ($(COMPILER_VERSION), VS2008) MSVCRNN_DLL = msvcr90.dll MSVCPNN_DLL = msvcp90.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL) endif ifeq ($(COMPILER_VERSION), VS2010) MSVCRNN_DLL = msvcr100.dll MSVCPNN_DLL = msvcp100.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) + MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL) endif endif @@ -283,7 +282,7 @@ ifeq ($(MFC_DEBUG), true) MS_RUNTIME_OPTION=-MTd else # This MS debugging flag forces a dependence on the debug - # version of the runtime library (MSVCRTD.DLL), as does -MDd. + # version of the runtime library (MSVCR*D.DLL), as does -MDd. # We cannot re-distribute this debug runtime. MS_RUNTIME_OPTION=-MDd endif @@ -364,10 +363,6 @@ ifeq ($(CC_VERSION),msvc) # LFLAGS are the flags given to $(LINK) and used to build the actual DLL file BASELFLAGS = -nologo /opt:REF /incremental:no -ifdef MT - # VS2005, VS2008, and beyond: ask LINK to generate manifests for .dll & .exe - BASELFLAGS += /manifest -endif LFLAGS = $(BASELFLAGS) $(LDEBUG) $(EXTRA_LFLAGS) $(LFLAGS_$(COMPILER_VERSION)) LDDFLAGS += $(LFLAGS_$(COMPILER_VERSION)) diff --git a/jdk/make/common/Demo.gmk b/jdk/make/common/Demo.gmk index 0ba5bc19707..24ee29f0ba5 100644 --- a/jdk/make/common/Demo.gmk +++ b/jdk/make/common/Demo.gmk @@ -73,8 +73,11 @@ DEMO_BUILD_AREA = $(DEMOCLASSDIR)/$(PRODUCT)/$(DEMONAME) # Destination "src" directory DEMO_BUILD_SRCDIR = $(DEMO_BUILD_AREA)/src -DEMO_BUILD_SRCZIP = $(DEMO_BUILD_AREA)/src.zip -DEMO_SOURCE_ZIP = $(DEMO_DESTDIR)/src.zip + +ifndef DEMO_SKIP_SRCZIP + DEMO_BUILD_SRCZIP = $(DEMO_BUILD_AREA)/src.zip + DEMO_SOURCE_ZIP = $(DEMO_DESTDIR)/src.zip +endif # Place to hold the jar image we are creating DEMO_JAR_IMAGE = $(DEMO_BUILD_AREA)/jar_image @@ -258,14 +261,16 @@ $(DEMO_JAR): \ endif -# Create a src.zip file -$(DEMO_BUILD_SRCZIP): $(DEMO_FULL_SOURCES) +ifndef DEMO_SKIP_SRCZIP + # Create a src.zip file + $(DEMO_BUILD_SRCZIP): $(DEMO_FULL_SOURCES) @$(prep-target) $(CD) $(DEMO_BUILD_AREA)/src && $(ZIPEXE) -q -r ../$(@F) . -# Install the destination src.zip file and create the src tree -$(DEMO_SOURCE_ZIP): $(DEMO_BUILD_SRCZIP) + # Install the destination src.zip file and create the src tree + $(DEMO_SOURCE_ZIP): $(DEMO_BUILD_SRCZIP) $(install-file) +endif # Native library building ifdef DEMO_LIBRARY @@ -289,6 +294,7 @@ $(DEMO_LIBRARY): $(DEMO_FULL_OBJECTS) @$(prep-target) $(LINK.demo) $(SHARED_LIBRARY_FLAG) $(CC_PROGRAM_OUTPUT_FLAG)$@ \ $(DEMO_FULL_OBJECTS) $(LDLIBS.demo) + @$(call binary_file_verification,$@) # Generation of any javah include file, make sure objects are dependent on it ifdef DEMO_NATIVECLASS @@ -362,7 +368,7 @@ clean clobber: $(RM) -r $(DEMO_BUILD_AREA) $(RM) -r $(DEMO_DESTDIR) -# This should not be needed, but some versions of GNU amke have a bug that +# This should not be needed, but some versions of GNU make have a bug that # sometimes deleted these files for some strange and unknown reason # (GNU make version 3.78.1 has the problem, GNU make version 3.80 doesn't?) .PRECIOUS: $(DEMO_FULL_SOURCES) $(DEMO_BUILD_SRCZIP) $(DEMO_SOURCE_ZIP) diff --git a/jdk/make/common/Library.gmk b/jdk/make/common/Library.gmk index 71758275689..5fbed139ce5 100644 --- a/jdk/make/common/Library.gmk +++ b/jdk/make/common/Library.gmk @@ -159,9 +159,6 @@ else # LIBRARY # build it into $(OBJDIR) so that the other generated files get put # there, then copy just the DLL (and MAP file) to the requested directory. # -# In VS2005 or VS2008 the link command creates a .manifest file that we want -# to insert into the linked artifact so we do not need to track it separately. -# Use ";#2" for .dll and ";#1" for .exe in the MT command below: $(ACTUAL_LIBRARY):: $(OBJDIR)/$(LIBRARY).lcf @$(prep-target) @$(MKDIR) -p $(OBJDIR) @@ -169,10 +166,8 @@ $(ACTUAL_LIBRARY):: $(OBJDIR)/$(LIBRARY).lcf -map:$(OBJDIR)/$(LIBRARY).map \ $(LFLAGS) @$(OBJDIR)/$(LIBRARY).lcf \ $(OTHER_LCF) $(JAVALIB) $(LDLIBS) -ifdef MT - $(MT) /manifest $(OBJDIR)/$(@F).manifest /outputresource:$(OBJDIR)/$(@F);#2 -endif $(CP) $(OBJDIR)/$(@F) $@ + @$(call binary_file_verification,$@) $(install-module-file) $(CP) $(OBJDIR)/$(LIBRARY).map $(@D) $(CP) $(OBJDIR)/$(LIBRARY).pdb $(@D) @@ -239,6 +234,7 @@ ifeq ($(LIBRARY), fdlibm) $(AR) -r $@ $(FILES_o) else # LIBRARY $(LINKER) $(SHARED_LIBRARY_FLAG) -o $@ $(FILES_o) $(LDLIBS) + @$(call binary_file_verification,$@) $(install-module-file) ifeq ($(WRITE_LIBVERSION),true) $(MCS) -d -a "$(FULL_VERSION)" $@ diff --git a/jdk/make/common/Modules.gmk b/jdk/make/common/Modules.gmk index c690e905b21..9bf90db2932 100644 --- a/jdk/make/common/Modules.gmk +++ b/jdk/make/common/Modules.gmk @@ -73,47 +73,20 @@ module-image-jdk:: initial-module-image-jdk trim-module-image-jdk process-module # # Paths to these files we need -JDK_MODULE_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%) -JDK_MODULE_64_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%64) -JDK_MODULE_DOCFILES = $(OTHER_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%) - -JRE_MODULE_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%) -JRE_MODULE_64_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%64) -JRE_MODULE_DOCFILES = $(OTHER_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%) -JRE_MODULE_DOCFILES += $(JRE_NAMECHANGE_DOCLIST:%=$(JRE_MODULE_IMAGE_DIR)/%$(TEXT_SUFFIX)) +JDK_MODULE_DOCFILES = $(IMAGE_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%) +JRE_MODULE_DOCFILES = $(IMAGE_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%) ###### RULES # JDK files $(JDK_MODULE_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/% $(process-doc-file) -# Removes LICENSE_VERSION or not -ifdef LICENSE_VERSION -$(JDK_MODULE_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -$(JDK_MODULE_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -else -$(JDK_MODULE_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/% - $(process-doc-file) -endif # JRE files $(JRE_MODULE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/% $(process-doc-file) -# Add $(TEXT_SUFFIX) suffix -ifdef TEXT_SUFFIX -$(JRE_MODULE_IMAGE_DIR)/%$(TEXT_SUFFIX): $(SHARE_JRE_DOC_SRC)/% - $(process-doc-file) -endif -# Removes LICENSE_VERSION or not -ifdef LICENSE_VERSION -$(JRE_MODULE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -$(JRE_MODULE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -else -$(JRE_MODULE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/% +ifeq ($(PLATFORM), windows) +$(JRE_MODULE_IMAGE_DIR)/README.txt: $(SHARE_JRE_DOC_SRC)/README $(process-doc-file) endif @@ -157,8 +130,7 @@ initial-module-image-jre-setup: $(MKDIR) -p $(JRE_MODULE_IMAGE_DIR) # 64-bit solaris jre image contains only the 64-bit add-on files. -initial-module-image-jre-sol64:: initial-module-image-jre-setup \ - $(JRE_MODULE_LICENSES) $(JRE_MODULE_64_LICENSES) +initial-module-image-jre-sol64:: initial-module-image-jre-setup @# Use tar instead of cp to preserve the symbolic links for dir in bin lib ; do \ ( $(CD) $(OUTPUTDIR) && \ @@ -174,7 +146,7 @@ initial-module-image-jre-sol64:: initial-module-image-jre-setup \ # Construct an initial jre image (initial jdk jre) no trimming or stripping initial-module-image-jre:: initial-module-image-jre-setup \ - $(JRE_LICENSES) $(JRE_MODULE_DOCFILES) \ + $(JRE_MODULE_DOCFILES) \ $(BUILDMETAINDEX_JARFILE) @# Copy in bin directory $(CD) $(OUTPUTDIR) && $(FIND) bin -depth | $(CPIO) -pdum $(JRE_MODULE_IMAGE_DIR) @@ -310,8 +282,7 @@ initial-module-image-jdk64-bindemos: # Solaris 64 bit image is special initial-module-image-jdk-sol64:: initial-module-image-jdk-setup \ - initial-module-image-jdk64-bindemos \ - $(JDK_MODULE_LICENSES) $(JDK_MODULARLIZED_64_LICENSES) + initial-module-image-jdk64-bindemos # DB files to add ifeq ($(OPENJDK),true) @@ -335,7 +306,7 @@ endif # Standard jdk image initial-module-image-jdk:: initial-module-image-jdk-setup \ initial-module-image-jdk-db \ - $(JDK_MODULE_LICENSES) $(JDK_MODULE_DOCFILES) + $(JDK_MODULE_DOCFILES) $(MKDIR) $(JDK_MODULE_IMAGE_DIR)/lib @# @# copy jdk modules to jdk/lib diff --git a/jdk/make/common/Program.gmk b/jdk/make/common/Program.gmk index 005236149d6..5700e32c89d 100644 --- a/jdk/make/common/Program.gmk +++ b/jdk/make/common/Program.gmk @@ -142,10 +142,15 @@ else STACK_SIZE=1048576 endif -# In VS2005 or VS2008 the link command creates a .manifest file that we want -# to insert into the linked artifact so we do not need to track it separately. +IMVERSION=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER) +$(OBJDIR)/$(PROGRAM).exe.manifest: $(JDK_TOPDIR)/src/windows/resource/java.manifest + @$(prep-target) + $(SED) 's%IMVERSION%$(IMVERSION)%g;s%PROGRAM%$(PROGRAM)%g' $< > $@ + +# We used a hand-crafted manifest file for all executables. +# It is tweaked to embed the build number and executable name. # Use ";#2" for .dll and ";#1" for .exe in the MT command below: -$(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX):: $(OBJDIR)/$(PROGRAM).lcf $(FILES_o) $(JLI_LCF) +$(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX):: $(OBJDIR)/$(PROGRAM).lcf $(FILES_o) $(JLI_LCF) $(OBJDIR)/$(PROGRAM).exe.manifest @$(prep-target) @set -- $?; \ $(ECHO) Rebuilding $@ because of $$1 $$2 $$3 $$4 $$5 $$6 $${7:+...}; @@ -155,6 +160,7 @@ $(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX):: $(OBJDIR)/$(PROGRAM).lcf $(FILES_o) $(JLI_LC ifdef MT $(MT) /manifest $(OBJDIR)/$(PROGRAM).exe.manifest /outputresource:$@;#1 endif + @$(call binary_file_verification,$@) else # PLATFORM @@ -179,6 +185,7 @@ $(ACTUAL_PROGRAM):: $(FILES_o) @$(MKDIR) -p $(TEMPDIR) $(LINK_PRE_CMD) $(CC) $(CC_OBJECT_OUTPUT_FLAG)$@ $(LDFLAGS) \ $(FILES_o) $(THREADLIBS) $(LDLIBS) + @$(call binary_file_verification,$@) $(install-module-file) endif # PLATFORM diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index 71d392fe666..9af023f2c54 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -26,6 +26,9 @@ include $(JDK_TOPDIR)/make/docs/CORE_PKGS.gmk include $(JDK_TOPDIR)/make/docs/NON_CORE_PKGS.gmk +# What jdk version are we building +THIS_JDK_VERSION := $(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION) + # # Perform release engineering tasks. # @@ -72,14 +75,6 @@ endif JTG_DOCS = $(JDK_TOPDIR)/src/solaris/doc -#We use this for man page header -jdkversion := $(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION) - -# Text documents on windows use this suffix -ifeq ($(PLATFORM), windows) - TEXT_SUFFIX = .txt -endif - # The base names of all the license and document files for the jdk and jre # (These files get placed in the jdk and jre install images) ifdef OPENJDK @@ -87,48 +82,24 @@ ifdef OPENJDK SHARE_JDK_DOC_SRC = $(JDK_TOPDIR) SHARE_JRE_DOC_SRC = $(JDK_TOPDIR) # Same files for jdk and jre, no name changes - LICENSE_DOCLIST_JDK = LICENSE ASSEMBLY_EXCEPTION - LICENSE_DOCLIST_JRE = LICENSE ASSEMBLY_EXCEPTION - OTHER_DOCLIST_JDK = THIRD_PARTY_README - OTHER_DOCLIST_JRE = THIRD_PARTY_README + IMAGE_DOCLIST_JDK = LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README + IMAGE_DOCLIST_JRE = LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README else # Where to find these files SHARE_JDK_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jdk SHARE_JRE_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jre - # Select the pre-release or FCS license version based on the build milestone. - LICENSE_VERSION=.pre - ifeq ($(MILESTONE), fcs) - LICENSE_VERSION=.fcs - endif + IMAGE_DOCLIST_JDK = COPYRIGHT README.html THIRDPARTYLICENSEREADME.txt + IMAGE_DOCLIST_JRE = COPYRIGHT Welcome.html THIRDPARTYLICENSEREADME.txt ifeq ($(PLATFORM), windows) - LICENSE_DOCLIST_JDK = $(subst $(LICENSE_VERSION),,\ - $(shell $(CD) $(SHARE_JDK_DOC_SRC) && \ - $(LS) *LICENSE*$(LICENSE_VERSION))) - LICENSE_DOCLIST_JRE = $(subst $(LICENSE_VERSION),,\ - $(shell $(CD) $(SHARE_JRE_DOC_SRC) && \ - $(LS) *LICENSE*$(LICENSE_VERSION))) + IMAGE_DOCLIST_JRE += README.txt else - LICENSE_DOCLIST_JDK = $(subst $(LICENSE_VERSION),,\ - $(shell $(CD) $(SHARE_JDK_DOC_SRC) && \ - $(LS) *LICENSE*$(LICENSE_VERSION) | $(GREP) -v rtf)) - LICENSE_DOCLIST_JRE = $(subst $(LICENSE_VERSION),,\ - $(shell $(CD) $(SHARE_JRE_DOC_SRC) && \ - $(LS) *LICENSE*$(LICENSE_VERSION) | $(GREP) -v rtf)) + IMAGE_DOCLIST_JRE += README endif - OTHER_DOCLIST_JDK = COPYRIGHT README.html README_ja.html README_zh_CN.html - OTHER_DOCLIST_JRE = COPYRIGHT Welcome.html - JRE_NAMECHANGE_DOCLIST = README endif # Paths to these files we need -JDK_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_IMAGE_DIR)/%) -JDK64_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_IMAGE_DIR)/%64) -JDK_DOCFILES = $(OTHER_DOCLIST_JDK:%=$(JDK_IMAGE_DIR)/%) - -JRE_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_IMAGE_DIR)/%) -JRE64_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_IMAGE_DIR)/%64) -JRE_DOCFILES = $(OTHER_DOCLIST_JRE:%=$(JRE_IMAGE_DIR)/%) -JRE_DOCFILES += $(JRE_NAMECHANGE_DOCLIST:%=$(JRE_IMAGE_DIR)/%$(TEXT_SUFFIX)) +JDK_DOCFILES = $(IMAGE_DOCLIST_JDK:%=$(JDK_IMAGE_DIR)/%) +JRE_DOCFILES = $(IMAGE_DOCLIST_JRE:%=$(JRE_IMAGE_DIR)/%) # absolute directory names: note, these must exist prior to build # time - they are created in the main Makefile. @@ -213,7 +184,7 @@ for manbase in $(MANBASEDIRS:%=%/$(MAN1SUBDIR)) ; do \ $(MKDIR) -p $1/man/$${ja_dir}/man1; \ $(CAT) $${manbase}/ja/$${manpage} \ | $(NATIVE2ASCII) -encoding $(JA_SOURCE_ENCODING) \ - | $(SED) 's/@@VERSION@@/$(jdkversion)/g' \ + | $(SED) 's/@@VERSION@@/$(THIS_JDK_VERSION)/g' \ | $(NATIVE2ASCII) -reverse -encoding $${ja_encoding} \ > $1/man/$${ja_dir}/man1/$${manpage}; \ done; \ @@ -243,6 +214,7 @@ images images-clobber \ initial-image-jre initial-image-jdk \ initial-image-jre-sol64 initial-image-jdk-sol64 \ trim-image-jre trim-image-jdk \ +identify-image-jre identify-image-jdk \ process-image-jre process-image-jdk \ compare-image \ sec-files sec-files-win jgss-files :: @@ -252,11 +224,12 @@ sec-files sec-files-win jgss-files :: images:: sanity-images post-sanity-images \ $(INITIAL_IMAGE_JRE) $(INITIAL_IMAGE_JDK) \ trim-image-jre trim-image-jdk \ + identify-image-jre identify-image-jdk \ process-image-jre process-image-jdk sec-files sec-files-win jgss-files # Don't use these -image-jre:: initial-image-jre trim-image-jre process-image-jre -image-jdk:: initial-image-jdk trim-image-jdk process-image-jdk +image-jre:: initial-image-jre trim-image-jre identify-image-jre process-image-jre +image-jdk:: initial-image-jdk trim-image-jdk identify-image-jdk process-image-jdk # # Sources we ship in the SDK. @@ -503,33 +476,12 @@ endef # JDK files $(JDK_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/% $(process-doc-file) -# Removes LICENSE_VERSION or not -ifdef LICENSE_VERSION -$(JDK_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -$(JDK_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -else -$(JDK_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/% - $(process-doc-file) -endif # JRE files $(JRE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/% $(process-doc-file) -# Add $(TEXT_SUFFIX) suffix -ifdef TEXT_SUFFIX -$(JRE_IMAGE_DIR)/%$(TEXT_SUFFIX): $(SHARE_JRE_DOC_SRC)/% - $(process-doc-file) -endif -# Removes LICENSE_VERSION or not -ifdef LICENSE_VERSION -$(JRE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -$(JRE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) - $(process-doc-file) -else -$(JRE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/% +ifeq ($(PLATFORM), windows) +$(JRE_IMAGE_DIR)/README.txt: $(SHARE_JRE_DOC_SRC)/README $(process-doc-file) endif @@ -737,8 +689,7 @@ initial-image-jre-setup: $(MKDIR) -p $(JRE_IMAGE_DIR) # 64-bit solaris jre image contains only the 64-bit add-on files. -initial-image-jre-sol64:: initial-image-jre-setup \ - $(JRE_LICENSES) $(JRE64_LICENSES) +initial-image-jre-sol64:: initial-image-jre-setup @# Use tar instead of cp to preserve the symbolic links for dir in bin lib ; do \ ( $(CD) $(OUTPUTDIR) && \ @@ -759,7 +710,7 @@ initial-image-jre-sol64:: initial-image-jre-setup \ # See "initial-image-jdk-setup" for an explanation of the rm of # drive names like C: initial-image-jre:: initial-image-jre-setup \ - $(JRE_LICENSES) $(JRE_DOCFILES) \ + $(JRE_DOCFILES) \ $(RT_JAR) $(RESOURCES_JAR) $(JSSE_JAR) \ $(BUILDMETAINDEX_JARFILE) @# Copy in bin directory @@ -835,11 +786,14 @@ else # PLATFORM endif endif # PLATFORM -# Get list of all Elf files in the jre -JRE_ELF_LIST=$(TEMPDIR)/jre-elf-files.list -$(JRE_ELF_LIST): -ifneq ($(PLATFORM), windows) +# Get list of all binary (COFF or Elf) files in the jre +JRE_BIN_LIST=$(TEMPDIR)/jre-bin-files.list +$(JRE_BIN_LIST): $(RM) $@ +ifeq ($(PLATFORM), windows) + $(FIND) $(JRE_IMAGE_DIR)/bin -type f -name \*.exe \ + -o -name \*.dll | $(EGREP) -v -i "$(MSVCRNN_DLL)" > $@ +else $(FIND) $(JRE_IMAGE_DIR)/lib -type f -name \*.$(LIB_SUFFIX) >> $@ $(FILE) `$(FIND) $(JRE_IMAGE_DIR)/bin -type f -name \*$(EXE_SUFFIX)` \ | $(EGREP) 'ELF' | $(CUT) -d':' -f1 >> $@ @@ -847,9 +801,9 @@ endif # Post process the image (strips and mcs on Elf files we are shipping) # (Note the jdk WILL want the jre image before this processing) -process-image-jre:: $(JRE_ELF_LIST) +process-image-jre:: $(JRE_BIN_LIST) ifneq ($(POST_STRIP_PROCESS), ) - for f in `$(CAT) $(JRE_ELF_LIST)`; do \ + @for f in `$(CAT) $(JRE_BIN_LIST)`; do \ $(CHMOD) u+w $${f}; \ $(ECHO) $(POST_STRIP_PROCESS) $${f}; \ $(POST_STRIP_PROCESS) $${f}; \ @@ -857,14 +811,17 @@ ifneq ($(POST_STRIP_PROCESS), ) done endif ifneq ($(POST_MCS_PROCESS), ) - for f in `$(CAT) $(JRE_ELF_LIST)`; do \ + @for f in `$(CAT) $(JRE_BIN_LIST)`; do \ $(CHMOD) u+w $${f}; \ $(ECHO) $(POST_MCS_PROCESS) $${f}; \ $(POST_MCS_PROCESS) $${f}; \ $(CHMOD) go-w $${f}; \ done endif - $(RM) $(JRE_ELF_LIST) + @for f in `$(CAT) $(JRE_BIN_LIST)`; do \ + $(call binary_file_verification,$${f}); \ + done + $(RM) $(JRE_BIN_LIST) ###################################################### # JDK Image @@ -904,8 +861,7 @@ initial-image-jdk64-bindemos: # Solaris 64 bit image is special initial-image-jdk-sol64:: initial-image-jdk-setup \ - initial-image-jdk64-bindemos \ - $(JDK_LICENSES) $(JDK64_LICENSES) + initial-image-jdk64-bindemos # DB files to add ifdef OPENJDK @@ -929,7 +885,7 @@ endif # Standard jdk image initial-image-jdk:: initial-image-jdk-setup \ initial-image-jdk-db \ - $(JDK_LICENSES) $(JDK_DOCFILES) + $(JDK_DOCFILES) $(MKDIR) $(JDK_IMAGE_DIR)/lib @# @# Copy in the jars in lib that only belong in the JDK @@ -1091,10 +1047,15 @@ trim-image-jdk:: $(RM) $(JDK_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX); \ done -# Get list of Elf files in the jdk -JDK_ELF_LIST=$(TEMPDIR)/jdk-elf-files.list -$(JDK_ELF_LIST): -ifneq ($(PLATFORM), windows) +# Get list of binary (COFF or Elf) files in the jdk +JDK_BIN_LIST=$(TEMPDIR)/jdk-bin-files.list +$(JDK_BIN_LIST): +ifeq ($(PLATFORM), windows) + $(FIND) $(JDK_IMAGE_DIR)/jre/bin -type f -name \*.exe \ + -o -name \*.dll | $(EGREP) -v -i "$(MSVCRNN_DLL)" > $@ + $(FIND) $(JDK_IMAGE_DIR)/bin -type f -name \*.exe \ + -o -name \*.dll | $(EGREP) -v -i "$(MSVCRNN_DLL)" >> $@ +else $(RM) $@ $(FIND) $(JDK_IMAGE_DIR)/jre/lib -type f -name \*.$(LIB_SUFFIX) >> $@ $(FILE) `$(FIND) $(JDK_IMAGE_DIR)/jre/bin -type f -name \*$(EXE_SUFFIX)` \ @@ -1104,9 +1065,9 @@ ifneq ($(PLATFORM), windows) endif # Post process the image (strips and mcs on files we are shipping) -process-image-jdk:: $(JDK_ELF_LIST) +process-image-jdk:: $(JDK_BIN_LIST) ifneq ($(POST_STRIP_PROCESS), ) - for f in `$(CAT) $(JDK_ELF_LIST)`; do \ + @for f in `$(CAT) $(JDK_BIN_LIST)`; do \ $(CHMOD) u+w $${f}; \ $(ECHO) $(POST_STRIP_PROCESS) $${f}; \ $(POST_STRIP_PROCESS) $${f}; \ @@ -1114,14 +1075,56 @@ ifneq ($(POST_STRIP_PROCESS), ) done endif ifneq ($(POST_MCS_PROCESS), ) - for f in `$(CAT) $(JDK_ELF_LIST)`; do \ + @for f in `$(CAT) $(JDK_BIN_LIST)`; do \ $(CHMOD) u+w $${f}; \ $(ECHO) $(POST_MCS_PROCESS) $${f}; \ $(POST_MCS_PROCESS) $${f}; \ $(CHMOD) go-w $${f}; \ done endif - $(RM) $(JDK_ELF_LIST) + @for f in `$(CAT) $(JDK_BIN_LIST)`; do \ + $(call binary_file_verification,$${f}); \ + done + $(RM) $(JDK_BIN_LIST) + +################################################################### +# What did we build +################################################################### + +# The jdk text info file that lives at the root of the install image. + +JDK_INFO_FILE = $(JDK_IMAGE_DIR)/release +JRE_INFO_FILE = $(JRE_IMAGE_DIR)/release + +# Common way to emit a line into the release or info file +define info-file-item # name value +$(PRINTF) "%s=\"%s\"\n" $1 $2 >> $@ +endef + +# Values to emit +MINIMUM_OS_NAME := $(REQUIRED_OS_NAME) +MINIMUM_OS_VERSION := $(REQUIRED_OS_VERSION) +MINIMUM_OS_ARCH := $(ARCH) + +$(JDK_INFO_FILE): FRC + $(prep-target) + $(call info-file-item, "JAVA_VERSION", "$(THIS_JDK_VERSION)") + $(call info-file-item, "OS_NAME", "$(MINIMUM_OS_NAME)") + $(call info-file-item, "OS_VERSION", "$(MINIMUM_OS_VERSION)") + $(call info-file-item, "OS_ARCH", "$(MINIMUM_OS_ARCH)") + +# Create release file to identify this image +identify-image-jdk:: $(JDK_INFO_FILE) + +$(JRE_INFO_FILE): FRC + $(prep-target) + $(call info-file-item, "JAVA_VERSION", "$(THIS_JDK_VERSION)") + $(call info-file-item, "OS_NAME", "$(MINIMUM_OS_NAME)") + $(call info-file-item, "OS_VERSION", "$(MINIMUM_OS_VERSION)") + $(call info-file-item, "OS_ARCH", "$(MINIMUM_OS_ARCH)") + +# Create release file to identify this image +identify-image-jre:: $(JRE_INFO_FILE) ################################################################### # What do we compare against @@ -1276,6 +1279,7 @@ images images-clobber:: initial-image-jre-setup \ trim-image-jre trim-image-jdk \ process-image-jre process-image-jdk \ + identify-image-jre identify-image-jdk \ install-previous-jre install-previous-jdk \ compare-image-jre compare-image-jdk \ compare-image compare-image-clobber \ diff --git a/jdk/make/common/shared/Compiler-msvc.gmk b/jdk/make/common/shared/Compiler-msvc.gmk index 49a0d5fe63c..1b6d38d5f7f 100644 --- a/jdk/make/common/shared/Compiler-msvc.gmk +++ b/jdk/make/common/shared/Compiler-msvc.gmk @@ -35,6 +35,7 @@ ifeq ($(PLATFORM), windows) LIBEXE = $(COMPILER_PATH)lib LINK = $(COMPILER_PATH)link LINK32 = $(LINK) + DUMPBIN = $(COMPILER_PATH)dumpbin.exe # Fill in unknown values COMPILER_NAME=Unknown MSVC Compiler @@ -139,8 +140,8 @@ ifeq ($(PLATFORM), windows) _OTHER_TOOLS_BIN = $(WINDOWSSDKDIR)/Bin/x64 endif endif - RC = $(_OTHER_TOOLS_BIN)/rc.exe - REBASE = $(_OTHER_TOOLS_BIN)/rebase.exe + RC = $(_OTHER_TOOLS_BIN)/RC.Exe + REBASE = $(_OTHER_TOOLS_BIN)/ReBase.Exe MT = $(_OTHER_TOOLS_BIN)/mt.exe MTL = $(_OTHER_TOOLS_BIN)/midl.exe endif diff --git a/jdk/make/common/shared/Defs-control.gmk b/jdk/make/common/shared/Defs-control.gmk index 13eb20b1da4..288eb83e01c 100644 --- a/jdk/make/common/shared/Defs-control.gmk +++ b/jdk/make/common/shared/Defs-control.gmk @@ -76,12 +76,9 @@ SRC_BUNDLEDIR = $(OUTPUTDIR)/source-bundles ABS_SRC_BUNDLEDIR = $(ABS_OUTPUTDIR)/source-bundles BIN_BUNDLEDIR = $(OUTPUTDIR)/bundles ABS_BIN_BUNDLEDIR = $(ABS_OUTPUTDIR)/bundles -JRL_BUNDLEDIR = $(OUTPUTDIR)/java.net -ABS_JRL_BUNDLEDIR = $(ABS_OUTPUTDIR)/java.net dummy := $(shell $(MKDIR) -p $(BIN_BUNDLEDIR)) dummy := $(shell $(MKDIR) -p $(SRC_BUNDLEDIR) ) -dummy := $(shell $(MKDIR) -p $(JRL_BUNDLEDIR) ) TEMP_DIR = $(OUTPUTDIR)/tmp ABS_TEMP_DIR = $(ABS_OUTPUTDIR)/tmp diff --git a/jdk/make/common/shared/Defs-linux.gmk b/jdk/make/common/shared/Defs-linux.gmk index a6be5365021..db1307056d1 100644 --- a/jdk/make/common/shared/Defs-linux.gmk +++ b/jdk/make/common/shared/Defs-linux.gmk @@ -177,3 +177,20 @@ else endif HOTSPOT_SERVER_PATH:=$(call AltCheckValue,HOTSPOT_SERVER_PATH) +# Special define for checking the binaries + +# Macro to check it's input file for banned dependencies and verify the +# binary built properly. Relies on process exit code. +define binary_file_verification # binary_file +( \ + $(ECHO) "Checking for mapfile use in: $1" && \ + if [ "`$(NM) -D -g --defined-only $1 | $(EGREP) 'SUNWprivate'`" = "" ] ; then \ + $(ECHO) "WARNING: File was not built with a mapfile: $1"; \ + fi && \ + $(ECHO) "Library loads for: $1" && \ + $(LDD) $1 && \ + $(ECHO) "RUNPATH for: $1" && \ + ( $(READELF) -d $1 | $(EGREP) 'NEEDED|RUNPATH|RPATH' ) \ +) +endef + diff --git a/jdk/make/common/shared/Defs-solaris.gmk b/jdk/make/common/shared/Defs-solaris.gmk index 98b054ef3d4..177af974855 100644 --- a/jdk/make/common/shared/Defs-solaris.gmk +++ b/jdk/make/common/shared/Defs-solaris.gmk @@ -186,3 +186,20 @@ else endif HOTSPOT_SERVER_PATH:=$(call AltCheckValue,HOTSPOT_SERVER_PATH) +# Special define for checking the binaries + +# Macro to check it's input file for banned dependencies and verify the +# binary built properly. Relies on process exit code. +define binary_file_verification # binary_file +( \ + $(ECHO) "Checking for mapfile use in: $1" && \ + if [ "`$(NM) -g -D $1 | $(EGREP) -v 'UNDEF' | $(EGREP) 'SUNWprivate'`" = "" ] ; then \ + $(ECHO) "WARNING: File was not built with a mapfile: $1"; \ + fi && \ + $(ECHO) "Library loads for: $1" && \ + $(LDD) $1 && \ + $(ECHO) "RUNPATH for: $1" && \ + ( $(DUMP) -L -v $1 | $(EGREP) 'NEEDED|RUNPATH|RPATH' ) \ +) +endef + diff --git a/jdk/make/common/shared/Defs-utils.gmk b/jdk/make/common/shared/Defs-utils.gmk index 01bb982466f..bb6aa493cf5 100644 --- a/jdk/make/common/shared/Defs-utils.gmk +++ b/jdk/make/common/shared/Defs-utils.gmk @@ -85,6 +85,7 @@ DATE = $(UTILS_COMMAND_PATH)date DF = $(UTILS_COMMAND_PATH)df DIFF = $(UTILS_USR_BIN_PATH)diff DIRNAME = $(UTILS_USR_BIN_PATH)dirname +DUMP = $(UTILS_CCS_BIN_PATH)dump ECHO = $(UTILS_COMMAND_PATH)echo EGREP = $(UTILS_COMMAND_PATH)egrep EXPR = $(UTILS_USR_BIN_PATH)expr @@ -99,6 +100,7 @@ ID = $(UTILS_COMMAND_PATH)id ISAINFO = $(UTILS_COMMAND_PATH)isainfo KSH = $(UTILS_COMMAND_PATH)ksh LD = $(UTILS_CCS_BIN_PATH)ld +LDD = $(UTILS_USR_BIN_PATH)ldd LEX = $(UTILS_CCS_BIN_PATH)lex LN = $(UTILS_COMMAND_PATH)ln LS = $(UTILS_COMMAND_PATH)ls @@ -114,6 +116,7 @@ PKGMK = $(UTILS_COMMAND_PATH)pkgmk PRINTF = $(UTILS_USR_BIN_PATH)printf PWD = $(UTILS_COMMAND_PATH)pwd RC = $(UTILS_COMMAND_PATH)rc +READELF = $(UTILS_USR_BIN_PATH)readelf RMDIR = $(UTILS_COMMAND_PATH)rmdir RPM = $(UTILS_COMMAND_PATH)rpm RPMBUILD = $(UTILS_COMMAND_PATH)rpmbuild diff --git a/jdk/make/common/shared/Defs-versions.gmk b/jdk/make/common/shared/Defs-versions.gmk index 6784be6f04a..a51cb2b75d5 100644 --- a/jdk/make/common/shared/Defs-versions.gmk +++ b/jdk/make/common/shared/Defs-versions.gmk @@ -127,6 +127,7 @@ endif # Solaris specific ifeq ($(PLATFORM), solaris) + REQUIRED_OS_NAME = SunOS REQUIRED_OS_VERSION = 5.10 REQUIRED_OS_VARIANT_NAME = Solaris REQUIRED_OS_VARIANT_VERSION = $(REQUIRED_OS_VERSION) @@ -148,6 +149,7 @@ endif # Linux specific ifeq ($(PLATFORM), linux) + REQUIRED_OS_NAME = Linux REQUIRED_OS_VERSION = 2.6 REQUIRED_OS_VARIANT_NAME = Fedora REQUIRED_OS_VARIANT_VERSION = 9 @@ -166,6 +168,7 @@ endif # Windows specific ifeq ($(PLATFORM), windows) + REQUIRED_OS_NAME = Windows ifeq ($(ARCH_DATA_MODEL),64) REQUIRED_OS_VERSION = 5.2 REQUIRED_OS_VARIANT_NAME = Windows2003 diff --git a/jdk/make/common/shared/Defs-windows.gmk b/jdk/make/common/shared/Defs-windows.gmk index 6a6fbffd39a..e1af407680d 100644 --- a/jdk/make/common/shared/Defs-windows.gmk +++ b/jdk/make/common/shared/Defs-windows.gmk @@ -288,8 +288,8 @@ ifndef VS2010_EXISTS xVS100COMNTOOLS :="$(_program_files32)/Microsoft Visual Studio 10.0/Common7/Tools/" fVS100COMNTOOLS :=$(call FullPath,$(xVS100COMNTOOLS)) else + xVS100COMNTOOLS :="$(subst \,/,$(VS100COMNTOOLS))" ifneq ($(word 2,$(VS100COMNTOOLS)),) - xVS100COMNTOOLS :="$(subst \,/,$(VS100COMNTOOLS))" fVS100COMNTOOLS :=$(call FullPath,$(xVS100COMNTOOLS)) else fVS100COMNTOOLS :=$(xVS100COMNTOOLS) @@ -551,18 +551,6 @@ ifndef ALT_BOOTDIR _BOOTDIR3 =$(SLASH_JAVA)/re/jdk/$(PREVIOUS_JDK_VERSION)/archive/fcs/binaries/$(PLATFORM)-$(ARCH) endif -# 32 bit always needs 2 runtimes, 64 bit usually does too - -# MSVCRT_DLL_PATH: location of msvcrt.dll that will be re-distributed -ifdef ALT_MSVCRT_DLL_PATH - xALT_MSVCRT_DLL_PATH :="$(subst \,/,$(ALT_MSVCRT_DLL_PATH))" - MSVCRT_DLL_PATH :=$(call FullPath,$(xALT_MSVCRT_DLL_PATH)) -else - MSVCRT_DLL_PATH :=$(call FullPath,$(_system_root)/system32/) -endif -MSVCRT_DLL_PATH:=$(call AltCheckSpaces,MSVCRT_DLL_PATH) -MSVCRT_DLL_PATH:=$(call AltCheckValue,MSVCRT_DLL_PATH) - # 32bit always needs the MSVCRNN runtime, 64bit does when using VS2008 ifeq ($(ARCH_DATA_MODEL), 32) _NEEDS_MSVCRNN = true @@ -641,15 +629,6 @@ else endif INSTALL_MSSDK:=$(call AltCheckSpaces,INSTALL_MSSDK) -# INSTALL_MSIVAL2: Installation of MsiVal2 for this platform (for install) -ifdef ALT_INSTALL_MSIVAL2 - xALT_INSTALL_MSIVAL2 :="$(subst \,/,$(ALT_INSTALL_MSIVAL2))" - INSTALL_MSIVAL2 :=$(call FullPath,$(xALT_INSTALL_MSIVAL2)) -else - INSTALL_MSIVAL2 :=$(_program_files32)/MsiVal2 -endif -INSTALL_MSIVAL2:=$(call AltCheckSpaces,INSTALL_MSIVAL2) - # WSCRIPT: path to wscript.exe (used in creating install bundles) ifdef ALT_WSCRIPT xALT_WSCRIPT :="$(subst \,/,$(ALT_WSCRIPT))" @@ -685,43 +664,6 @@ else endif CABARC:=$(call AltCheckSpaces,CABARC) -# MSIVAL2: path to msival2.exe (used in validating install msi files) -ifdef ALT_MSIVAL2 - xALT_MSIVAL2 :="$(subst \,/,$(ALT_MSIVAL2))" - MSIVAL2 =$(xALT_MSIVAL2) -else - _MSIVAL2_1 :=$(INSTALL_MSIVAL2)/msival2.exe - _MSIVAL2_2 :=$(DEVTOOLS_PATH)msival2.exe - MSIVAL2 :=$(call FileExists,$(_MSIVAL2_1),$(_MSIVAL2_2)) -endif -MSIVAL2:=$(call AltCheckSpaces,MSIVAL2) -# suppress msival2 checks, as it hangs jprt builds -ifdef SKIP_MSIVAL2 - MSIVAL2 := $(ECHO) -endif - -# LOGOCUB: path to cub file for (used in validating install msi files) -ifdef ALT_LOGOCUB - xALT_LOGOCUB :="$(subst \,/,$(ALT_LOGOCUB))" - LOGOCUB =$(xALT_LOGOCUB) -else - _LOGOCUB1 :=$(INSTALL_MSIVAL2)/logo.cub - _LOGOCUB2 :=$(DEVTOOLS_PATH)logo.cub - LOGOCUB :=$(call FileExists,$(_LOGOCUB1),$(_LOGOCUB2)) -endif -LOGOCUB:=$(call AltCheckSpaces,LOGOCUB) - -# MSITRAN: path to msitran.exe (used in creating install bundles and sponsors) -ifdef ALT_MSITRAN - xALT_MSITRAN :="$(subst \,/,$(ALT_MSITRAN))" - MSITRAN =$(xALT_MSITRAN) -else - _MSITRAN1 :=$(INSTALL_MSSDK)/Bin/msitran.exe - _MSITRAN2 :=$(DEVTOOLS_PATH)msitran.exe - MSITRAN :=$(call FileExists,$(_MSITRAN1),$(_MSITRAN2)) -endif -MSITRAN:=$(call AltCheckSpaces,MSITRAN) - # MSICERT: path to msicert.exe (used in creating install bundles) ifdef ALT_MSICERT xALT_MSICERT :="$(subst \,/,$(ALT_MSICERT))" @@ -798,3 +740,50 @@ else endif HOTSPOT_LIB_PATH:=$(call AltCheckSpaces,HOTSPOT_LIB_PATH) HOTSPOT_LIB_PATH:=$(call AltCheckValue,HOTSPOT_LIB_PATH) + +# Special define for checking the binaries + +ifeq ($(VS2010_EXISTS),true) + +# All windows dll and exe files should have been built with /NXCOMPAT +# and be setup for dynamic base addresses. +# In addition, we should not be dependent on certain dll files that +# we do not or cannot redistribute. + +# List of filenames we should NOT be dependent on +BANNED_DLLS=msvcp100[.]dll|msvcr100d[.]dll|msvcrtd[.]dll + +# Macro to check it's input file for banned dependencies and verify the +# binary was built properly. Relies on process exit code. +define binary_file_verification # binary_file +( \ + $(ECHO) "Checking for /NXCOMPAT usage in: $1" && \ + if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'NX compatible'`" = "" ] ; then \ + $(ECHO) "ERROR: Did not find 'NX compatible' in headers: $1" ; \ + $(DUMPBIN) /headers $1 ; \ + exit 7 ; \ + fi ; \ + $(ECHO) "Checking for /DYNAMICBASE usage in: $1" && \ + if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'Dynamic base'`" = "" ] ; then \ + $(ECHO) "ERROR: Did not find 'Dynamic base' in headers: $1" ; \ + $(DUMPBIN) /headers $1 ; \ + exit 8 ; \ + fi ; \ + $(ECHO) "Checking for banned dependencies in: $1" && \ + if [ "`$(DUMPBIN) /dependents $1 | $(EGREP) -i '$(BANNED_DLLS)'`" != "" ] ; then \ + $(ECHO) "ERROR: Found us of $(BANNED_DLLS)"; \ + $(DUMPBIN) /dependents $1 ; \ + exit 9 ; \ + fi ; \ +) +endef + +else + +# Macro to check it's input file for banned dependencies and verify the +# binary was built properly. Relies on process exit code. +define binary_file_verification # binary_file +endef + +endif + diff --git a/jdk/make/common/shared/Sanity-Settings.gmk b/jdk/make/common/shared/Sanity-Settings.gmk index 7e77e11aeb0..ce89bd96092 100644 --- a/jdk/make/common/shared/Sanity-Settings.gmk +++ b/jdk/make/common/shared/Sanity-Settings.gmk @@ -96,7 +96,6 @@ ifeq ($(PLATFORM),solaris) endif endif ifeq ($(PLATFORM),windows) - ALL_SETTINGS+=$(call addAltSetting,MSVCRT_DLL_PATH) ifneq ($(MSVCRNN_DLL),) ALL_SETTINGS+=$(call addAltSetting,MSVCRNN_DLL_PATH) endif @@ -117,6 +116,9 @@ ALL_SETTINGS+=$(call addRequiredVersionSetting,ZIP_VER) ALL_SETTINGS+=$(call addRequiredVersionSetting,UNZIP_VER) ifeq ($(PLATFORM),windows) ALL_SETTINGS+=$(call addRequiredVersionSetting,LINK_VER) + ALL_SETTINGS+=$(call addRequiredSetting,CC) + ALL_SETTINGS+=$(call addRequiredSetting,LINK) + ALL_SETTINGS+=$(call addRequiredSetting,DUMPBIN) endif ALL_SETTINGS+=$(call addRequiredVersionSetting,ANT_VER) ALL_SETTINGS+=$(call addRequiredSetting,TEMPDIR) @@ -226,13 +228,13 @@ ifeq ($(PLATFORM),windows) ALL_SETTINGS+=$(call addAltSetting,DXSDK_INCLUDE_PATH) ALL_SETTINGS+=$(call addAltSetting,DXSDK_LIB_PATH) ALL_SETTINGS+=$(call addAltSetting,WINDOWSSDKDIR) + ALL_SETTINGS+=$(call addRequiredSetting,RC) + ALL_SETTINGS+=$(call addRequiredSetting,REBASE) ifndef OPENJDK ALL_SETTINGS+=$(call addAltSetting,DEPLOY_MSSDK) ALL_SETTINGS+=$(call addAltSetting,INSTALL_MSSDK) ALL_SETTINGS+=$(call addAltSetting,WSCRIPT) ALL_SETTINGS+=$(call addAltSetting,MSICERT) - ALL_SETTINGS+=$(call addAltSetting,MSITRAN) - ALL_SETTINGS+=$(call addAltSetting,MSIVAL2) endif endif ALL_SETTINGS+=$(call addAltSetting,CACERTS_FILE) diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index b17690ca4c2..0cf3433f9dc 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -879,13 +879,6 @@ sane-devtools_path: ###################################################### sane-msvcrt_path: ifeq ($(PLATFORM), windows) - @if [ ! -r "$(MSVCRT_DLL_PATH)/msvcrt.dll" ]; then \ - $(ECHO) "ERROR: You do not have access to msvcrt.dll. \n" \ - " Please check your access to \n" \ - " $(MSVCRT_DLL_PATH) \n" \ - " and/or check your value of ALT_MSVCRT_DLL_PATH. \n" \ - "" >> $(ERROR_FILE) ; \ - fi ifneq ($(MSVCRNN_DLL),) @if [ ! -r "$(MSVCRNN_DLL_PATH)/$(MSVCRNN_DLL)" ]; then \ $(ECHO) "ERROR: You do not have access to $(MSVCRNN_DLL). \n" \ @@ -1018,6 +1011,22 @@ ifeq ($(PLATFORM), windows) " and/or check your value of ALT_MSDEVTOOLS_PATH. \n" \ "" >> $(ERROR_FILE) ; \ fi + else + ifeq ($(wildcard $(REBASE)),) + @$(ECHO) "ERROR: Cannot find the REBASE utility from path: $(REBASE)\n" \ + " This is normally obtained from the WINDOWSSDKDIR." \ + "" >> $(ERROR_FILE) + endif + ifeq ($(wildcard $(RC)),) + @$(ECHO) "ERROR: Cannot find the RC utility from path: $(RC)\n" \ + " This is normally obtained from the WINDOWSSDKDIR." \ + "" >> $(ERROR_FILE) + endif + ifeq ($(wildcard $(DUMPBIN)),) + @$(ECHO) "ERROR: Cannot find the DUMPBIN utility from path: $(DUMPBIN)\n" \ + " This is normally obtained from the WINDOWSSDKDIR." \ + "" >> $(ERROR_FILE) + endif endif endif @@ -1459,25 +1468,6 @@ ifeq ($(PLATFORM), windows) fi endif -###################################################### -# Check for existence of INSTALL_MSIVAL2 on windows -###################################################### -sane-install-msival2_path: -ifeq ($(PLATFORM), windows) - @if [ -z "$(INSTALL_MSIVAL2)" ]; then \ - $(ECHO) "WARNING: Your INSTALL_MSIVAL2 setting is empty.\n" \ - " It is recommended to set ALT_INSTALL_MSIVAL2.\n" \ - "" >> $(WARNING_FILE) ; \ - fi - @if [ ! -r "$(INSTALL_MSIVAL2)" ]; then \ - $(ECHO) "ERROR: You do not have a valid INSTALL_MSIVAL2 setting. \n" \ - " Please check your access to \n" \ - " $(INSTALL_MSIVAL2) \n" \ - " and/or check your value of ALT_INSTALL_MSIVAL2. \n" \ - "" >> $(ERROR_FILE) ; \ - fi -endif - ###################################################### # Check the GNU C++ compiler for OJI plugin ###################################################### diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 9f4d420aa42..ad37a7b3401 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -93,10 +93,6 @@ ifeq ($(PLATFORM), windows) IMPORT_LIST += $(MS_RUNTIME_LIBRARIES:%=$(BINDIR)/%) -# NOTE: These might actually come from BUILDDIR, depends on the settings. -$(BINDIR)/msvcrt.dll: $(MSVCRT_DLL_PATH)/msvcrt.dll - $(install-import-file) - $(call chmod-file, a+x) $(BINDIR)/$(MSVCRNN_DLL): $(MSVCRNN_DLL_PATH)/$(MSVCRNN_DLL) $(install-import-file) $(call chmod-file, a+x) @@ -223,12 +219,15 @@ endif # PLATFORM $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVM_NAME): $(HOTSPOT_CLIENT_PATH)/$(JVM_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(KERNEL_LOCATION)/$(JVM_NAME): $(HOTSPOT_KERNEL_PATH)/$(JVM_NAME) $(install-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(LIBJSIG_NAME): $(HOTSPOT_IMPORT_PATH)/$(ARCH_VM_SUBDIR)/$(LIBJSIG_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(LIBJSIG_NAME) \ $(LIB_LOCATION)/$(SERVER_LOCATION)/$(LIBJSIG_NAME): @@ -237,30 +236,39 @@ $(LIB_LOCATION)/$(SERVER_LOCATION)/$(LIBJSIG_NAME): $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVMDB_NAME): $(HOTSPOT_CLIENT_PATH)/$(JVMDB_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(CLIENT_LOCATION)/64/$(JVMDB_NAME): $(HOTSPOT_CLIENT_PATH)/64/$(JVMDB_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDB_NAME): $(HOTSPOT_SERVER_PATH)/$(JVMDB_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDB_NAME): $(HOTSPOT_SERVER_PATH)/64/$(JVMDB_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVMDTRACE_NAME): $(HOTSPOT_CLIENT_PATH)/$(JVMDTRACE_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(CLIENT_LOCATION)/64/$(JVMDTRACE_NAME): $(HOTSPOT_CLIENT_PATH)/64/$(JVMDTRACE_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDTRACE_NAME): $(HOTSPOT_SERVER_PATH)/$(JVMDTRACE_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDTRACE_NAME): $(HOTSPOT_SERVER_PATH)/64/$(JVMDTRACE_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVM_NAME): $(HOTSPOT_SERVER_PATH)/$(JVM_NAME) $(install-import-file) + @$(call binary_file_verification,$@) $(LIB_LOCATION)/$(SERVER_LOCATION)/Xusage.txt : $(HOTSPOT_SERVER_PATH)/Xusage.txt $(install-import-file) diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index a498c46680f..9d7ead8b865 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -50,7 +50,7 @@ # # Assumes basic unix utilities are in the PATH already (uname, hostname, etc.). # -# On Windows, assumes PROCESSOR_IDENTIFIER, VS71COMNTOOLS, +# On Windows, assumes PROCESSOR_IDENTIFIER, VS100COMNTOOLS, # SYSTEMROOT (or SystemRoot), COMPUTERNAME (or hostname works), and # USERNAME is defined in the environment. # This profile does not rely on using vcvars32.bat and 64bit Setup.bat. @@ -81,8 +81,7 @@ # Windows Only: # ALT_UNIXCOMMAND_PATH # ALT_DXSDK_PATH -# ALT_MSVCRT_DLL_PATH -# ALT_MSVCR71_DLL_PATH +# ALT_MSVCRNN_DLL_PATH # ############################################################################# # @@ -213,78 +212,17 @@ else # Compiler setup (nasty part) # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. # NOTE: CYGWIN has a link.exe too, make sure the compilers are first - if [ "${windows_arch}" = i586 ] ; then - # 32bit Windows compiler settings - # VisualStudio .NET 2003 VC++ 7.1 (VS71COMNTOOLS should be defined) - vs_root=$(${cygpath} "${VS71COMNTOOLS}/../..") - # Fill in PATH, LIB, and INCLUDE (unset all others to make sure) - vc7_root="${vs_root}/Vc7" - compiler_path="${vc7_root}/bin" - platform_sdk="${vc7_root}/PlatformSDK" - - # LIB and INCLUDE must use ; as a separator - include4sdk="${vc7_root}/atlmfc/include" - include4sdk="${include4sdk};${vc7_root}/include" - include4sdk="${include4sdk};${platform_sdk}/include/prerelease" - include4sdk="${include4sdk};${platform_sdk}/include" - include4sdk="${include4sdk};${vs_root}/SDK/v1.1/include" - lib4sdk="${lib4sdk};${vc7_root}/lib" - lib4sdk="${lib4sdk};${platform_sdk}/lib/prerelease" - lib4sdk="${lib4sdk};${platform_sdk}/lib" - lib4sdk="${lib4sdk};${vs_root}/SDK/v1.1/lib" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${vs_root}/Common7/Tools/bin;${path4sdk}" - path4sdk="${vs_root}/SDK/v1.1/bin;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools/bin/prerelease;${path4sdk}" - path4sdk="${vs_root}/Common7/IDE;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - elif [ "${windows_arch}" = amd64 ] ; then - # AMD64 64bit Windows compiler settings - if [ "${ALT_DEPLOY_MSSDK}" != "" ] ; then - platform_sdk=${ALT_DEPLOY_MSSDK} - else - platform_sdk=$(${cygpath} "C:/Program Files/Microsoft Platform SDK/") - fi - if [ "${ALT_COMPILER_PATH}" != "" ] ; then - compiler_path=${ALT_COMPILER_PATH} - if [ "${ALT_DEPLOY_MSSDK}" = "" ] ; then - platform_sdk=${ALT_COMPILER_PATH}/../../../.. - fi - else - compiler_path="${platform_sdk}/Bin/win64/x86/AMD64" - fi - # LIB and INCLUDE must use ; as a separator - include4sdk="${platform_sdk}/Include" - include4sdk="${include4sdk};${platform_sdk}/Include/crt/sys" - include4sdk="${include4sdk};${platform_sdk}/Include/mfc" - include4sdk="${include4sdk};${platform_sdk}/Include/atl" - include4sdk="${include4sdk};${platform_sdk}/Include/crt" - lib4sdk="${platform_sdk}/Lib/AMD64" - lib4sdk="${lib4sdk};${platform_sdk}/Lib/AMD64/atlmfc" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${platform_sdk}/bin;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - fi - # Export LIB and INCLUDE - unset lib - unset Lib - LIB="${lib4sdk}" - export LIB - unset include - unset Include - INCLUDE="${include4sdk}" - export INCLUDE - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="$(echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g')" - path4sdk="${slash_path}" - - # Convert path4sdk to cygwin style - path4sdk="$(/usr/bin/cygpath -p ${path4sdk})" + # Use supplied vsvars.sh + repo=`hg root` + if [ -f "${repo}/make/scripts/vsvars.sh" ] ; then + eval `sh ${repo}/make/scripts/vsvars.sh -v10` + elif [ -f "${repo}/../make/scripts/vsvars.sh" ] ; then + eval `sh ${repo}/../make/scripts/vsvars.sh -v10` + else + echo "WARNING: No make/scripts/vsvars.sh file found" + fi + fi # Get the previous JDK to be used to bootstrap the build diff --git a/jdk/make/mkdemo/jfc/Makefile b/jdk/make/mkdemo/jfc/Makefile index 35ab79b70c9..decfac45061 100644 --- a/jdk/make/mkdemo/jfc/Makefile +++ b/jdk/make/mkdemo/jfc/Makefile @@ -43,7 +43,7 @@ SUBDIRS = \ # Some demos aren't currently included in OpenJDK ifndef OPENJDK - SUBDIRS += Java2D SwingSet2 Stylepad + SUBDIRS += Java2D SwingSet2 SwingSet3 Stylepad endif include $(BUILDDIR)/common/Subdirs.gmk diff --git a/jdk/make/mkdemo/jfc/SwingSet3/Makefile b/jdk/make/mkdemo/jfc/SwingSet3/Makefile new file mode 100644 index 00000000000..9b9fddacaf5 --- /dev/null +++ b/jdk/make/mkdemo/jfc/SwingSet3/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# +# Makefile to build the SwingSet3 demo. +# + +BUILDDIR = ../../.. +PRODUCT = demo/jfc +DEMONAME = SwingSet3 +include $(BUILDDIR)/common/Defs.gmk + +DEMO_ROOT = $(CLOSED_SRC)/share/demo/jfc/$(DEMONAME) +DEMO_DESTDIR = $(DEMODIR)/jfc/$(DEMONAME) +DEMO_TOPFILES = ./readme.html ./swingset3.png +DEMO_SKIP_SRCZIP = true + +# +# Demo jar building rules. +# +include $(BUILDDIR)/common/Demo.gmk diff --git a/jdk/make/sun/awt/Makefile b/jdk/make/sun/awt/Makefile index 87fd56b6dad..7d8b4b6a6f1 100644 --- a/jdk/make/sun/awt/Makefile +++ b/jdk/make/sun/awt/Makefile @@ -369,10 +369,6 @@ FONTCONFIGS_SRC = $(CLOSED_SRC)/solaris/classes/sun/awt/fontconfigs _FONTCONFIGS = \ fontconfig.properties \ fontconfig.RedHat.properties \ - fontconfig.RedHat.2.1.properties \ - fontconfig.RedHat.3.properties \ - fontconfig.RedHat.4.properties \ - fontconfig.Sun.properties \ fontconfig.Turbo.properties \ fontconfig.SuSE.10.properties \ fontconfig.SuSE.11.properties @@ -388,9 +384,7 @@ ifeq ($(PLATFORM), solaris) FONTCONFIGS_SRC = $(PLATFORM_SRC)/classes/sun/awt/fontconfigs _FONTCONFIGS = \ - fontconfig.properties \ - fontconfig.5.9.properties \ - fontconfig.5.8.properties + fontconfig.properties FONTCONFIGS_SRC_PREFIX = $(PLATFORM). diff --git a/jdk/make/sun/awt/mapfile-mawt-vers b/jdk/make/sun/awt/mapfile-mawt-vers index b80f30fed50..f1b7143e948 100644 --- a/jdk/make/sun/awt/mapfile-mawt-vers +++ b/jdk/make/sun/awt/mapfile-mawt-vers @@ -515,8 +515,7 @@ SUNWprivate_1.1 { getDefaultConfig; Java_sun_font_FontConfigManager_getFontConfig; Java_sun_font_FontConfigManager_getFontConfigAASettings; - Java_sun_awt_X11FontManager_getFontPath; - Java_sun_awt_X11FontManager_setNativeFontPath; + Java_sun_awt_X11FontManager_getFontPathNative; Java_sun_font_SunFontManager_populateFontFileNameMap; # CDE private entry point diff --git a/jdk/make/sun/awt/mapfile-vers-linux b/jdk/make/sun/awt/mapfile-vers-linux index 60fa9ccef69..d2fbf560c9b 100644 --- a/jdk/make/sun/awt/mapfile-vers-linux +++ b/jdk/make/sun/awt/mapfile-vers-linux @@ -537,8 +537,7 @@ SUNWprivate_1.1 { getDefaultConfig; Java_sun_font_FontConfigManager_getFontConfig; Java_sun_font_FontConfigManager_getFontConfigAASettings; - Java_sun_awt_X11FontManager_getFontPath; - Java_sun_awt_X11FontManager_setNativeFontPath; + Java_sun_awt_X11FontManager_getFontPathNative; Java_sun_font_SunFontManager_populateFontFileNameMap; # CDE private entry point diff --git a/jdk/make/sun/headless/mapfile-vers b/jdk/make/sun/headless/mapfile-vers index c82b6116fcc..dfb6aa361ae 100644 --- a/jdk/make/sun/headless/mapfile-vers +++ b/jdk/make/sun/headless/mapfile-vers @@ -65,7 +65,7 @@ SUNWprivate_1.1 { Java_sun_font_FontConfigManager_getFontConfig; Java_sun_font_FontConfigManager_getFontConfigAASettings; Java_sun_font_FontConfigManager_getFontConfigVersion; - Java_sun_awt_X11FontManager_getFontPath; + Java_sun_awt_X11FontManager_getFontPathNative; Java_sun_awt_FontDescriptor_initIDs; Java_sun_awt_PlatformFont_initIDs; diff --git a/jdk/make/sun/xawt/Makefile b/jdk/make/sun/xawt/Makefile index ffbe2b97112..f1297ef192f 100644 --- a/jdk/make/sun/xawt/Makefile +++ b/jdk/make/sun/xawt/Makefile @@ -136,8 +136,25 @@ ifeq ($(PLATFORM), linux) -I$(OPENWIN_HOME)/include endif +# We have some odd logic here because some Solaris 10 updates +# have a render.h file that suggests gradients are supported, but +# the Xrender.h doesn't have the corresponding type definitions. +# Earlier updates have neither. We'd like to know if there's a mismatch. +# Whilst in the C preprocessor we can tell if the render.h define's are set +# we can't tell anything about C declarations. +# A grep of Xrender.h is the only way to know this. If they are absent +# we will set a flag indicating this mismatch and the JDK source file +# will interpret it to resolve the problem. ifeq ($(PLATFORM), solaris) CPPFLAGS += -I$(OPENWIN_HOME)/include/X11/extensions + OS_VERSION := $(shell uname -r) + XRENDER_H := $(OPENWIN_HOME)/share/include/X11/extensions/Xrender.h + ifeq ($(OS_VERSION),5.10) + LINEARGRADIENT_CNT := $(shell $(EGREP) -c XLinearGradient $(XRENDER_H)) + ifeq ($(LINEARGRADIENT_CNT),0) + CFLAGS+= -DSOLARIS10_NO_XRENDER_STRUCTS + endif + endif endif ifeq ($(MILESTONE), internal) diff --git a/jdk/make/sun/xawt/mapfile-vers b/jdk/make/sun/xawt/mapfile-vers index 7eac730927d..479a55a800d 100644 --- a/jdk/make/sun/xawt/mapfile-vers +++ b/jdk/make/sun/xawt/mapfile-vers @@ -188,8 +188,7 @@ SUNWprivate_1.1 { Java_sun_font_FontConfigManager_getFontConfig; Java_sun_font_FontConfigManager_getFontConfigAASettings; Java_sun_font_FontConfigManager_getFontConfigVersion; - Java_sun_awt_X11FontManager_getFontPath; - Java_sun_font_X11FontManager_setNativeFontPath; + Java_sun_awt_X11FontManager_getFontPathNative; Java_sun_awt_X11GraphicsEnvironment_initDisplay; Java_sun_awt_X11GraphicsEnvironment_initGLX; Java_sun_awt_X11GraphicsEnvironment_initXRender; diff --git a/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java b/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java index 766e383ffb0..9f8042229d2 100644 --- a/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java +++ b/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java @@ -1387,203 +1387,13 @@ public abstract class CubicCurve2D implements Shape, Cloneable { return false; } - // Trivially accept if either endpoint is inside the rectangle - // (not on its border since it may end there and not go inside) - // Record where they lie with respect to the rectangle. - // -1 => left, 0 => inside, 1 => right - double x1 = getX1(); - double y1 = getY1(); - int x1tag = getTag(x1, x, x+w); - int y1tag = getTag(y1, y, y+h); - if (x1tag == INSIDE && y1tag == INSIDE) { - return true; - } - double x2 = getX2(); - double y2 = getY2(); - int x2tag = getTag(x2, x, x+w); - int y2tag = getTag(y2, y, y+h); - if (x2tag == INSIDE && y2tag == INSIDE) { - return true; - } - - double ctrlx1 = getCtrlX1(); - double ctrly1 = getCtrlY1(); - double ctrlx2 = getCtrlX2(); - double ctrly2 = getCtrlY2(); - int ctrlx1tag = getTag(ctrlx1, x, x+w); - int ctrly1tag = getTag(ctrly1, y, y+h); - int ctrlx2tag = getTag(ctrlx2, x, x+w); - int ctrly2tag = getTag(ctrly2, y, y+h); - - // Trivially reject if all points are entirely to one side of - // the rectangle. - if (x1tag < INSIDE && x2tag < INSIDE && - ctrlx1tag < INSIDE && ctrlx2tag < INSIDE) - { - return false; // All points left - } - if (y1tag < INSIDE && y2tag < INSIDE && - ctrly1tag < INSIDE && ctrly2tag < INSIDE) - { - return false; // All points above - } - if (x1tag > INSIDE && x2tag > INSIDE && - ctrlx1tag > INSIDE && ctrlx2tag > INSIDE) - { - return false; // All points right - } - if (y1tag > INSIDE && y2tag > INSIDE && - ctrly1tag > INSIDE && ctrly2tag > INSIDE) - { - return false; // All points below - } - - // Test for endpoints on the edge where either the segment - // or the curve is headed "inwards" from them - // Note: These tests are a superset of the fast endpoint tests - // above and thus repeat those tests, but take more time - // and cover more cases - if (inwards(x1tag, x2tag, ctrlx1tag) && - inwards(y1tag, y2tag, ctrly1tag)) - { - // First endpoint on border with either edge moving inside - return true; - } - if (inwards(x2tag, x1tag, ctrlx2tag) && - inwards(y2tag, y1tag, ctrly2tag)) - { - // Second endpoint on border with either edge moving inside - return true; - } - - // Trivially accept if endpoints span directly across the rectangle - boolean xoverlap = (x1tag * x2tag <= 0); - boolean yoverlap = (y1tag * y2tag <= 0); - if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) { - return true; - } - if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) { - return true; - } - - // We now know that both endpoints are outside the rectangle - // but the 4 points are not all on one side of the rectangle. - // Therefore the curve cannot be contained inside the rectangle, - // but the rectangle might be contained inside the curve, or - // the curve might intersect the boundary of the rectangle. - - double[] eqn = new double[4]; - double[] res = new double[4]; - if (!yoverlap) { - // Both y coordinates for the closing segment are above or - // below the rectangle which means that we can only intersect - // if the curve crosses the top (or bottom) of the rectangle - // in more than one place and if those crossing locations - // span the horizontal range of the rectangle. - fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly1, ctrly2, y2); - int num = solveCubic(eqn, res); - num = evalCubic(res, num, true, true, null, - x1, ctrlx1, ctrlx2, x2); - // odd counts imply the crossing was out of [0,1] bounds - // otherwise there is no way for that part of the curve to - // "return" to meet its endpoint - return (num == 2 && - getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0); - } - - // Y ranges overlap. Now we examine the X ranges - if (!xoverlap) { - // Both x coordinates for the closing segment are left of - // or right of the rectangle which means that we can only - // intersect if the curve crosses the left (or right) edge - // of the rectangle in more than one place and if those - // crossing locations span the vertical range of the rectangle. - fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2); - int num = solveCubic(eqn, res); - num = evalCubic(res, num, true, true, null, - y1, ctrly1, ctrly2, y2); - // odd counts imply the crossing was out of [0,1] bounds - // otherwise there is no way for that part of the curve to - // "return" to meet its endpoint - return (num == 2 && - getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0); - } - - // The X and Y ranges of the endpoints overlap the X and Y - // ranges of the rectangle, now find out how the endpoint - // line segment intersects the Y range of the rectangle - double dx = x2 - x1; - double dy = y2 - y1; - double k = y2 * x1 - x2 * y1; - int c1tag, c2tag; - if (y1tag == INSIDE) { - c1tag = x1tag; - } else { - c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w); - } - if (y2tag == INSIDE) { - c2tag = x2tag; - } else { - c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w); - } - // If the part of the line segment that intersects the Y range - // of the rectangle crosses it horizontally - trivially accept - if (c1tag * c2tag <= 0) { - return true; - } - - // Now we know that both the X and Y ranges intersect and that - // the endpoint line segment does not directly cross the rectangle. - // - // We can almost treat this case like one of the cases above - // where both endpoints are to one side, except that we may - // get one or three intersections of the curve with the vertical - // side of the rectangle. This is because the endpoint segment - // accounts for the other intersection in an even pairing. Thus, - // with the endpoint crossing we end up with 2 or 4 total crossings. - // - // (Remember there is overlap in both the X and Y ranges which - // means that the segment itself must cross at least one vertical - // edge of the rectangle - in particular, the "near vertical side" - // - leaving an odd number of intersections for the curve.) - // - // Now we calculate the y tags of all the intersections on the - // "near vertical side" of the rectangle. We will have one with - // the endpoint segment, and one or three with the curve. If - // any pair of those vertical intersections overlap the Y range - // of the rectangle, we have an intersection. Otherwise, we don't. - - // c1tag = vertical intersection class of the endpoint segment - // - // Choose the y tag of the endpoint that was not on the same - // side of the rectangle as the subsegment calculated above. - // Note that we can "steal" the existing Y tag of that endpoint - // since it will be provably the same as the vertical intersection. - c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag); - - // Now we have to calculate an array of solutions of the curve - // with the "near vertical side" of the rectangle. Then we - // need to sort the tags and do a pairwise range test to see - // if either of the pairs of crossings spans the Y range of - // the rectangle. - // - // Note that the c2tag can still tell us which vertical edge - // to test against. - fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2); - int num = solveCubic(eqn, res); - num = evalCubic(res, num, true, true, null, y1, ctrly1, ctrly2, y2); - - // Now put all of the tags into a bucket and sort them. There - // is an intersection iff one of the pairs of tags "spans" the - // Y range of the rectangle. - int tags[] = new int[num+1]; - for (int i = 0; i < num; i++) { - tags[i] = getTag(res[i], y, y+h); - } - tags[num] = c1tag; - Arrays.sort(tags); - return ((num >= 1 && tags[0] * tags[1] <= 0) || - (num >= 3 && tags[2] * tags[3] <= 0)); + int numCrossings = rectCrossings(x, y, w, h); + // the intended return value is + // numCrossings != 0 || numCrossings == Curve.RECT_INTERSECTS + // but if (numCrossings != 0) numCrossings == INTERSECTS won't matter + // and if !(numCrossings != 0) then numCrossings == 0, so + // numCrossings != RECT_INTERSECT + return numCrossings != 0; } /** @@ -1602,20 +1412,32 @@ public abstract class CubicCurve2D implements Shape, Cloneable { if (w <= 0 || h <= 0) { return false; } - // Assertion: Cubic curves closed by connecting their - // endpoints form either one or two convex halves with - // the closing line segment as an edge of both sides. - if (!(contains(x, y) && - contains(x + w, y) && - contains(x + w, y + h) && - contains(x, y + h))) { - return false; + + int numCrossings = rectCrossings(x, y, w, h); + return !(numCrossings == 0 || numCrossings == Curve.RECT_INTERSECTS); + } + + private int rectCrossings(double x, double y, double w, double h) { + int crossings = 0; + if (!(getX1() == getX2() && getY1() == getY2())) { + crossings = Curve.rectCrossingsForLine(crossings, + x, y, + x+w, y+h, + getX1(), getY1(), + getX2(), getY2()); + if (crossings == Curve.RECT_INTERSECTS) { + return crossings; + } } - // Either the rectangle is entirely inside one of the convex - // halves or it crosses from one to the other, in which case - // it must intersect the closing line segment. - Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); - return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2()); + // we call this with the curve's direction reversed, because we wanted + // to call rectCrossingsForLine first, because it's cheaper. + return Curve.rectCrossingsForCubic(crossings, + x, y, + x+w, y+h, + getX2(), getY2(), + getCtrlX2(), getCtrlY2(), + getCtrlX1(), getCtrlY1(), + getX1(), getY1(), 0); } /** diff --git a/jdk/src/share/classes/javax/swing/AbstractButton.java b/jdk/src/share/classes/javax/swing/AbstractButton.java index aac3be32aa4..7aff31b4c67 100644 --- a/jdk/src/share/classes/javax/swing/AbstractButton.java +++ b/jdk/src/share/classes/javax/swing/AbstractButton.java @@ -1335,7 +1335,6 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * * @param a the button's action * @since 1.3 - * @see Actions * @see Action * @see #setAction */ diff --git a/jdk/src/share/classes/javax/swing/JEditorPane.java b/jdk/src/share/classes/javax/swing/JEditorPane.java index acc91080086..056cc36b394 100644 --- a/jdk/src/share/classes/javax/swing/JEditorPane.java +++ b/jdk/src/share/classes/javax/swing/JEditorPane.java @@ -145,8 +145,8 @@ import javax.accessibility.*; *
  • * One way is to specify the character set as a parameter of the MIME * type. This will be established by a call to the - * setContentType method. If the content - * is loaded by the setPage method the content + * {@link #setContentType setContentType} method. If the content + * is loaded by the {@link #setPage setPage} method the content * type will have been set according to the specification of the URL. * It the file is loaded directly, the content type would be expected to * have been set prior to loading. diff --git a/jdk/src/share/classes/javax/swing/JFileChooser.java b/jdk/src/share/classes/javax/swing/JFileChooser.java index eb67589e15c..3715ca0f43b 100644 --- a/jdk/src/share/classes/javax/swing/JFileChooser.java +++ b/jdk/src/share/classes/javax/swing/JFileChooser.java @@ -256,10 +256,6 @@ public class JFileChooser extends JComponent implements Accessible { private FileView fileView = null; - // uiFileView is not serialized, as it is initialized - // by updateUI() after deserialization - private transient FileView uiFileView = null; - private boolean controlsShown = true; private boolean useFileHiding = true; @@ -1504,6 +1500,9 @@ public class JFileChooser extends JComponent implements Accessible { if(getFileView() != null) { filename = getFileView().getName(f); } + + FileView uiFileView = getUI().getFileView(this); + if(filename == null && uiFileView != null) { filename = uiFileView.getName(f); } @@ -1524,6 +1523,9 @@ public class JFileChooser extends JComponent implements Accessible { if(getFileView() != null) { description = getFileView().getDescription(f); } + + FileView uiFileView = getUI().getFileView(this); + if(description == null && uiFileView != null) { description = uiFileView.getDescription(f); } @@ -1544,6 +1546,9 @@ public class JFileChooser extends JComponent implements Accessible { if(getFileView() != null) { typeDescription = getFileView().getTypeDescription(f); } + + FileView uiFileView = getUI().getFileView(this); + if(typeDescription == null && uiFileView != null) { typeDescription = uiFileView.getTypeDescription(f); } @@ -1564,6 +1569,9 @@ public class JFileChooser extends JComponent implements Accessible { if(getFileView() != null) { icon = getFileView().getIcon(f); } + + FileView uiFileView = getUI().getFileView(this); + if(icon == null && uiFileView != null) { icon = uiFileView.getIcon(f); } @@ -1584,6 +1592,9 @@ public class JFileChooser extends JComponent implements Accessible { if (getFileView() != null) { traversable = getFileView().isTraversable(f); } + + FileView uiFileView = getUI().getFileView(this); + if (traversable == null && uiFileView != null) { traversable = uiFileView.isTraversable(f); } @@ -1791,7 +1802,6 @@ public class JFileChooser extends JComponent implements Accessible { } setUI(ui); - uiFileView = getUI().getFileView(this); if(isAcceptAllFileFilterUsed()) { addChoosableFileFilter(getAcceptAllFileFilter()); } diff --git a/jdk/src/share/classes/javax/swing/SizeSequence.java b/jdk/src/share/classes/javax/swing/SizeSequence.java index 5667a66ce08..1ec97520827 100644 --- a/jdk/src/share/classes/javax/swing/SizeSequence.java +++ b/jdk/src/share/classes/javax/swing/SizeSequence.java @@ -132,7 +132,7 @@ public class SizeSequence { * can use insertEntries or setSizes. * * @see #insertEntries - * @see #setSizes + * @see #setSizes(int[]) */ public SizeSequence() { a = emptyArray; diff --git a/jdk/src/share/classes/javax/swing/TransferHandler.java b/jdk/src/share/classes/javax/swing/TransferHandler.java index 4854fdc75bf..eb7f8d1a644 100644 --- a/jdk/src/share/classes/javax/swing/TransferHandler.java +++ b/jdk/src/share/classes/javax/swing/TransferHandler.java @@ -344,7 +344,7 @@ public class TransferHandler implements Serializable { * * @return the drop location * @throws IllegalStateException if this is not a drop - * @see #isDrop + * @see #isDrop() */ public DropLocation getDropLocation() { assureIsDrop(); @@ -380,7 +380,7 @@ public class TransferHandler implements Serializable { * * @param showDropLocation whether or not to indicate the drop location * @throws IllegalStateException if this is not a drop - * @see #isDrop + * @see #isDrop() */ public void setShowDropLocation(boolean showDropLocation) { assureIsDrop(); @@ -406,7 +406,7 @@ public class TransferHandler implements Serializable { * @see #getDropAction * @see #getUserDropAction * @see #getSourceDropActions - * @see #isDrop + * @see #isDrop() */ public void setDropAction(int dropAction) { assureIsDrop(); @@ -440,7 +440,7 @@ public class TransferHandler implements Serializable { * @throws IllegalStateException if this is not a drop * @see #setDropAction * @see #getUserDropAction - * @see #isDrop + * @see #isDrop() */ public int getDropAction() { return dropAction == -1 ? getUserDropAction() : dropAction; @@ -468,7 +468,7 @@ public class TransferHandler implements Serializable { * @throws IllegalStateException if this is not a drop * @see #setDropAction * @see #getDropAction - * @see #isDrop + * @see #isDrop() */ public int getUserDropAction() { assureIsDrop(); @@ -501,7 +501,7 @@ public class TransferHandler implements Serializable { * * @return the drag source's supported drop actions * @throws IllegalStateException if this is not a drop - * @see #isDrop + * @see #isDrop() */ public int getSourceDropActions() { assureIsDrop(); diff --git a/jdk/src/share/classes/javax/swing/event/InternalFrameAdapter.java b/jdk/src/share/classes/javax/swing/event/InternalFrameAdapter.java index 071942e8ca7..47ed2c69c95 100644 --- a/jdk/src/share/classes/javax/swing/event/InternalFrameAdapter.java +++ b/jdk/src/share/classes/javax/swing/event/InternalFrameAdapter.java @@ -32,8 +32,7 @@ package javax.swing.event; * equivalent to the WindowAdapter class in the AWT. *

    * See How to Write an Internal Frame Listener - * in The Java Tutorial and - * The Java Class Libraries (update) + * in The Java Tutorial * * @see InternalFrameEvent * @see InternalFrameListener diff --git a/jdk/src/share/classes/javax/swing/event/InternalFrameListener.java b/jdk/src/share/classes/javax/swing/event/InternalFrameListener.java index 22258be8b8b..c156767725f 100644 --- a/jdk/src/share/classes/javax/swing/event/InternalFrameListener.java +++ b/jdk/src/share/classes/javax/swing/event/InternalFrameListener.java @@ -33,9 +33,7 @@ import java.util.EventListener; * in the AWT. *

    * See How to Write an Internal Frame Listener - * in The Java Tutorial and - * The Java Class Libraries (update) - * for further documentation. + * in The Java Tutorial for further documentation. * * @see java.awt.event.WindowListener * diff --git a/jdk/src/share/classes/javax/swing/plaf/multi/doc-files/multi_tsc.html b/jdk/src/share/classes/javax/swing/plaf/multi/doc-files/multi_tsc.html index c86476b19c4..5160494f750 100644 --- a/jdk/src/share/classes/javax/swing/plaf/multi/doc-files/multi_tsc.html +++ b/jdk/src/share/classes/javax/swing/plaf/multi/doc-files/multi_tsc.html @@ -66,7 +66,7 @@ This document has the following sections: Before reading further, you should be familiar with the concept of pluggable look and feels. For basic information, see -Choosing the Look and Feel, +How to Set the Look and Feel, a section in The Java Tutorial. For architectural details, you can read diff --git a/jdk/src/share/classes/javax/swing/plaf/synth/doc-files/synthFileFormat.html b/jdk/src/share/classes/javax/swing/plaf/synth/doc-files/synthFileFormat.html index f5f66a2d2a1..dfb99f4ef50 100644 --- a/jdk/src/share/classes/javax/swing/plaf/synth/doc-files/synthFileFormat.html +++ b/jdk/src/share/classes/javax/swing/plaf/synth/doc-files/synthFileFormat.html @@ -91,7 +91,7 @@ div.example {

     <!ELEMENT style (property | defaultsProperty | state | font | graphicsUtils |
    -                 insets | painter | imagePainter | opaque | (%beansPersistance;) |
    +                 insets | painter | imagePainter | opaque | (%beansPersistance;) |
                      imageIcon)*>
     <!ATTLIST style
               id              ID          #IMPLIED
    @@ -250,8 +250,8 @@ div.example {
         

    Defines the font for the current state, or style. You must - specify either an idref or a - name and size. + specify either an idref or a + name and size.

    The following example creates a style with a Font of @@ -797,7 +797,7 @@ div.example { path CDATA #REQUIRED sourceInsets CDATA #IMPLIED destinationInsets CDATA #IMPLIED - paintCenter (true|false) "true" + paintCenter (true|false) "true" stretch (true|false) "true" center (true|false) "false" > diff --git a/jdk/src/share/classes/javax/swing/text/AsyncBoxView.java b/jdk/src/share/classes/javax/swing/text/AsyncBoxView.java index 00cd059cc23..ab3f9c34d1e 100644 --- a/jdk/src/share/classes/javax/swing/text/AsyncBoxView.java +++ b/jdk/src/share/classes/javax/swing/text/AsyncBoxView.java @@ -384,7 +384,7 @@ public class AsyncBoxView extends View { /** * Loads all of the children to initialize the view. - * This is called by the setParent + * This is called by the {@link #setParent setParent} * method. Subclasses can reimplement this to initialize * their child views in a different manner. The default * implementation creates a child view for each diff --git a/jdk/src/share/classes/javax/swing/text/DefaultCaret.java b/jdk/src/share/classes/javax/swing/text/DefaultCaret.java index 7a3a2807bbb..b51cd4012c8 100644 --- a/jdk/src/share/classes/javax/swing/text/DefaultCaret.java +++ b/jdk/src/share/classes/javax/swing/text/DefaultCaret.java @@ -70,7 +70,7 @@ import sun.swing.SwingUtilities2; * will render a solid color as specified in the associated text component * in the SelectionColor property. This can easily be changed * by reimplementing the - * getSelectionHighlighter + * {@link #getSelectionPainter getSelectionPainter} * method. *

    * A customized caret appearance can be achieved by reimplementing diff --git a/jdk/src/share/classes/javax/swing/text/TableView.java b/jdk/src/share/classes/javax/swing/text/TableView.java index 3c15ba0f41d..bab545c7af5 100644 --- a/jdk/src/share/classes/javax/swing/text/TableView.java +++ b/jdk/src/share/classes/javax/swing/text/TableView.java @@ -315,7 +315,7 @@ public abstract class TableView extends BoxView { * updated along the minor axis. *

    * This is implemented to call the - * layoutColumns method, and then + * {@link #layoutColumns layoutColumns} method, and then * forward to the superclass to actually carry out the layout * of the tables rows. * diff --git a/jdk/src/share/classes/javax/swing/text/View.java b/jdk/src/share/classes/javax/swing/text/View.java index 369907d2e63..38573feba17 100644 --- a/jdk/src/share/classes/javax/swing/text/View.java +++ b/jdk/src/share/classes/javax/swing/text/View.java @@ -117,7 +117,7 @@ A view has the following responsibilities: what it is prepared to deal with.

  • The coordinate system is the same as the hosting Component (i.e. the Component returned by the - getContainer method). + {@link #getContainer getContainer} method). This means a child view lives in the same coordinate system as the parent view unless the parent has explicitly changed the coordinate system. To schedule itself to be repainted a view can call repaint on the hosting @@ -180,9 +180,9 @@ A view has the following responsibilities: starting from the root of the view hierarchy. The methods for doing this are:

    @@ -497,6 +497,10 @@ public abstract class View implements SwingConstants { public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) throws BadLocationException { + if (pos < -1) { + // -1 is a reserved value, see the code below + throw new BadLocationException("Invalid position", pos); + } biasRet[0] = Position.Bias.Forward; switch (direction) { @@ -670,15 +674,15 @@ public abstract class View implements SwingConstants { * spread out into the following calls that subclasses can * reimplement: *

      - *
    1. updateChildren is called + *
    2. {@link #updateChildren updateChildren} is called * if there were any changes to the element this view is * responsible for. If this view has child views that are * represent the child elements, then this method should do * whatever is necessary to make sure the child views correctly * represent the model. - *
    3. forwardUpdate is called + *
    4. {@link #forwardUpdate forwardUpdate} is called * to forward the DocumentEvent to the appropriate child views. - *
    5. updateLayout is called to + *
    6. {@link #updateLayout updateLayout} is called to * give the view a chance to either repair its layout, to reschedule * layout, or do nothing. *
    @@ -711,15 +715,15 @@ public abstract class View implements SwingConstants { * spread out into the following calls that subclasses can * reimplement: *
      - *
    1. updateChildren is called + *
    2. {@link #updateChildren updateChildren} is called * if there were any changes to the element this view is * responsible for. If this view has child views that are * represent the child elements, then this method should do * whatever is necessary to make sure the child views correctly * represent the model. - *
    3. forwardUpdate is called + *
    4. {@link #forwardUpdate forwardUpdate} is called * to forward the DocumentEvent to the appropriate child views. - *
    5. updateLayout is called to + *
    6. {@link #updateLayout updateLayout} is called to * give the view a chance to either repair its layout, to reschedule * layout, or do nothing. *
    @@ -752,15 +756,15 @@ public abstract class View implements SwingConstants { * spread out into the following calls that subclasses can * reimplement: *
      - *
    1. updateChildren is called + *
    2. {@link #updateChildren updateChildren} is called * if there were any changes to the element this view is * responsible for. If this view has child views that are * represent the child elements, then this method should do * whatever is necessary to make sure the child views correctly * represent the model. - *
    3. forwardUpdate is called + *
    4. {@link #forwardUpdate forwardUpdate} is called * to forward the DocumentEvent to the appropriate child views. - *
    5. updateLayout is called to + *
    6. {@link #updateLayout updateLayout} is called to * give the view a chance to either repair its layout, to reschedule * layout, or do nothing. *
    @@ -1186,7 +1190,7 @@ public abstract class View implements SwingConstants { * simply messages the view with a call to insertUpdate, * removeUpdate, or changedUpdate depending * upon the type of the event. This is called by - * forwardUpdate to forward + * {@link #forwardUpdate forwardUpdate} to forward * the event to children that need it. * * @param v the child view to forward the event to diff --git a/jdk/src/share/classes/javax/swing/text/html/HTMLEditorKit.java b/jdk/src/share/classes/javax/swing/text/html/HTMLEditorKit.java index f9642c7bdd7..1c5275e77a3 100644 --- a/jdk/src/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/jdk/src/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -123,7 +123,7 @@ import java.lang.ref.*; * to load. By default, this kit produces documents that will be * loaded asynchronously if loaded using JEditorPane.setPage. * This is controlled by a property on the document. The method - * createDefaultDocument can + * {@link #createDefaultDocument createDefaultDocument} can * be overriden to change this. The batching of work is done * by the HTMLDocument.HTMLReader class. The actual * work is done by the DefaultStyledDocument and @@ -558,7 +558,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * automatically or only FormSubmitEvent is fired. * By default it is set to true. * - * @see #isAutoFormSubmission + * @see #isAutoFormSubmission() * @see FormSubmitEvent * @since 1.5 */ diff --git a/jdk/src/share/classes/javax/swing/text/html/ParagraphView.java b/jdk/src/share/classes/javax/swing/text/html/ParagraphView.java index f0ee60ea700..e180e0e112e 100644 --- a/jdk/src/share/classes/javax/swing/text/html/ParagraphView.java +++ b/jdk/src/share/classes/javax/swing/text/html/ParagraphView.java @@ -61,7 +61,7 @@ public class ParagraphView extends javax.swing.text.ParagraphView { *

    * This is implemented * to forward to the superclass as well as call the - * setPropertiesFromAttributes + * {@link #setPropertiesFromAttributes setPropertiesFromAttributes} * method to set the paragraph properties from the css * attributes. The call is made at this time to ensure * the ability to resolve upward through the parents diff --git a/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java b/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java index 8d5bab21515..e82a5dc8ac9 100644 --- a/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java +++ b/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java @@ -51,7 +51,7 @@ import javax.swing.text.*; *

    * The primary entry point for HTML View implementations * to get their attributes is the - * getViewAttributes + * {@link #getViewAttributes getViewAttributes} * method. This should be implemented to establish the * desired policy used to associate attributes with the view. * Each HTMLEditorKit (i.e. and therefore each associated diff --git a/jdk/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java b/jdk/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java index 06b53483dc0..f8aa19f9b03 100644 --- a/jdk/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java +++ b/jdk/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java @@ -48,7 +48,11 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl private static final Object DTD_KEY = new Object(); - protected static synchronized void setDefaultDTD() { + protected static void setDefaultDTD() { + getDefaultDTD(); + } + + private static synchronized DTD getDefaultDTD() { AppContext appContext = AppContext.getAppContext(); DTD dtd = (DTD) appContext.get(DTD_KEY); @@ -67,6 +71,8 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl appContext.put(DTD_KEY, dtd); } + + return dtd; } protected static DTD createDTD(DTD dtd, String name) { @@ -92,7 +98,7 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl } public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException { - new DocumentParser((DTD) AppContext.getAppContext().get(DTD_KEY)).parse(r, cb, ignoreCharSet); + new DocumentParser(getDefaultDTD()).parse(r, cb, ignoreCharSet); } /** diff --git a/jdk/src/share/classes/sun/applet/AppletClassLoader.java b/jdk/src/share/classes/sun/applet/AppletClassLoader.java index 730134007b1..40fd6b28903 100644 --- a/jdk/src/share/classes/sun/applet/AppletClassLoader.java +++ b/jdk/src/share/classes/sun/applet/AppletClassLoader.java @@ -663,13 +663,15 @@ public class AppletClassLoader extends URLClassLoader { // set the context class loader to the AppletClassLoader. creatorThread.setContextClassLoader(AppletClassLoader.this); - synchronized(creatorThread.syncObject) { - creatorThread.start(); - try { - creatorThread.syncObject.wait(); - } catch (InterruptedException e) { } - appContext = creatorThread.appContext; - } + creatorThread.start(); + try { + synchronized(creatorThread.syncObject) { + while (!creatorThread.created) { + creatorThread.syncObject.wait(); + } + } + } catch (InterruptedException e) { } + appContext = creatorThread.appContext; return null; } }); @@ -854,14 +856,16 @@ public void grab() { class AppContextCreator extends Thread { Object syncObject = new Object(); AppContext appContext = null; + volatile boolean created = false; AppContextCreator(ThreadGroup group) { super(group, "AppContextCreator"); } public void run() { - synchronized(syncObject) { - appContext = SunToolkit.createNewAppContext(); + appContext = SunToolkit.createNewAppContext(); + created = true; + synchronized(syncObject) { syncObject.notifyAll(); } } // run() diff --git a/jdk/src/share/classes/sun/awt/SunToolkit.java b/jdk/src/share/classes/sun/awt/SunToolkit.java index 0442aeeaba6..b3067aeba2e 100644 --- a/jdk/src/share/classes/sun/awt/SunToolkit.java +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java @@ -696,7 +696,9 @@ public abstract class SunToolkit extends Toolkit synchronized (lock) { executeOnEventHandlerThread(event); - lock.wait(); + while(!event.isDispatched()) { + lock.wait(); + } } Throwable eventThrowable = event.getThrowable(); diff --git a/jdk/src/share/classes/sun/font/FileFontStrike.java b/jdk/src/share/classes/sun/font/FileFontStrike.java index ae6045f696c..3782c9ed3ba 100644 --- a/jdk/src/share/classes/sun/font/FileFontStrike.java +++ b/jdk/src/share/classes/sun/font/FileFontStrike.java @@ -151,6 +151,23 @@ public class FileFontStrike extends PhysicalStrike { } } + /* Amble fonts are better rendered unhinted although there's the + * inevitable fuzziness that accompanies this due to no longer + * snapping stems to the pixel grid. The exception is that in B&W + * mode they are worse without hinting. The down side to that is that + * B&W metrics will differ which normally isn't the case, although + * since AA mode is part of the measuring context that should be OK. + * We don't expect Amble to be installed in the Windows fonts folder. + * If we were to, then we'd also might want to disable using the + * native rasteriser path which is used for LCD mode for platform + * fonts. since we have no way to disable hinting by GDI. + * In the case of Amble, since its 'gasp' table says to disable + * hinting, I'd expect GDI to follow that, so likely it should + * all be consistent even if GDI used. + */ + boolean disableHinting = desc.aaHint != INTVAL_TEXT_ANTIALIAS_OFF && + fileFont.familyName.startsWith("Amble"); + /* If any of the values is NaN then substitute the null scaler context. * This will return null images, zero advance, and empty outlines * as no rendering need take place in this case. @@ -165,7 +182,7 @@ public class FileFontStrike extends PhysicalStrike { pScalerContext = fileFont.getScaler().createScalerContext(matrix, fileFont instanceof TrueTypeFont, desc.aaHint, desc.fmHint, - boldness, italic); + boldness, italic, disableHinting); } mapper = fileFont.getMapper(); @@ -566,10 +583,44 @@ public class FileFontStrike extends PhysicalStrike { if (glyphCode >= INVISIBLE_GLYPHS) { return 0f; } + + /* Notes on the (getUserAdv == false) case. + * + * Setting getUserAdv == false is internal to this class. + * If there's no graphics transform we can let + * getGlyphAdvance take its course, and potentially caching in + * advances arrays, except for signalling that + * getUserAdv == false means there is no need to create an image. + * It is possible that code already calculated the user advance, + * and it is desirable to take advantage of that work. + * But, if there's a transform and we want device advance, we + * can't use any values cached in the advances arrays - unless + * first re-transform them into device space using 'desc.devTx'. + * invertDevTx is null if the graphics transform is identity, + * a translate, or non-invertible. The latter case should + * not ever occur in the getUserAdv == false path. + * In other words its either null, or the inversion of a + * simple uniform scale. If its null, we can populate and + * use the advance caches as normal. + * + * If we don't find a cached value, obtain the device advance and + * return it. This will get stashed on the image by the caller and any + * subsequent metrics calls will be able to use it as is the case + * whenever an image is what is initially requested. + * + * Don't query if there's a value cached on the image, since this + * getUserAdv==false code path is entered solely when none exists. + */ if (horizontalAdvances != null) { advance = horizontalAdvances[glyphCode]; if (advance != Float.MAX_VALUE) { - return advance; + if (!getUserAdv && invertDevTx != null) { + Point2D.Float metrics = new Point2D.Float(advance, 0f); + desc.devTx.deltaTransform(metrics, metrics); + return metrics.x; + } else { + return advance; + } } } else if (segmentedCache && segHorizontalAdvances != null) { int segIndex = glyphCode >> SEGSHIFT; @@ -577,11 +628,23 @@ public class FileFontStrike extends PhysicalStrike { if (subArray != null) { advance = subArray[glyphCode % SEGSIZE]; if (advance != Float.MAX_VALUE) { - return advance; + if (!getUserAdv && invertDevTx != null) { + Point2D.Float metrics = new Point2D.Float(advance, 0f); + desc.devTx.deltaTransform(metrics, metrics); + return metrics.x; + } else { + return advance; + } } } } + if (!getUserAdv && invertDevTx != null) { + Point2D.Float metrics = new Point2D.Float(); + fileFont.getGlyphMetrics(pScalerContext, glyphCode, metrics); + return metrics.x; + } + if (invertDevTx != null || !getUserAdv) { /* If there is a device transform need x & y advance to * transform back into user space. @@ -725,7 +788,7 @@ public class FileFontStrike extends PhysicalStrike { return getGlyphMetrics(glyphCode, true); } - private Point2D.Float getGlyphMetrics(int glyphCode, boolean getUserAdv) { + private Point2D.Float getGlyphMetrics(int glyphCode, boolean getImage) { Point2D.Float metrics = new Point2D.Float(); // !!! or do we force sgv user glyphs? @@ -733,7 +796,7 @@ public class FileFontStrike extends PhysicalStrike { return metrics; } long glyphPtr; - if (getImageWithAdvance && getUserAdv) { + if (getImageWithAdvance && getImage) { /* A heuristic optimisation says that for most cases its * worthwhile retrieving the image at the same time as the * metrics. So here we get the image data even if its not @@ -750,9 +813,9 @@ public class FileFontStrike extends PhysicalStrike { metrics.y = StrikeCache.unsafe.getFloat (glyphPtr + StrikeCache.yAdvanceOffset); /* advance is currently in device space, need to convert back - * into user space, unless getUserAdv == false. + * into user space. * This must not include the translation component. */ - if (invertDevTx != null && getUserAdv) { + if (invertDevTx != null) { invertDevTx.deltaTransform(metrics, metrics); } } else { @@ -781,9 +844,9 @@ public class FileFontStrike extends PhysicalStrike { if (value == null) { fileFont.getGlyphMetrics(pScalerContext, glyphCode, metrics); /* advance is currently in device space, need to convert back - * into user space, unless getUserAdv == false. + * into user space. */ - if (invertDevTx != null && getUserAdv) { + if (invertDevTx != null) { invertDevTx.deltaTransform(metrics, metrics); } value = new Point2D.Float(metrics.x, metrics.y); diff --git a/jdk/src/share/classes/sun/font/FontScaler.java b/jdk/src/share/classes/sun/font/FontScaler.java index eae9fb22ab5..a2c1c09ef7f 100644 --- a/jdk/src/share/classes/sun/font/FontScaler.java +++ b/jdk/src/share/classes/sun/font/FontScaler.java @@ -242,9 +242,10 @@ public abstract class FontScaler implements DisposerRecord { freed when corresponding strike is being released. */ abstract long createScalerContext(double[] matrix, - boolean fontType, - int aa, int fm, - float boldness, float italic); + boolean fontType, + int aa, int fm, + float boldness, float italic, + boolean disableHinting); /* Marks context as invalid because native scaler is invalid. Notes: diff --git a/jdk/src/share/classes/sun/font/FreetypeFontScaler.java b/jdk/src/share/classes/sun/font/FreetypeFontScaler.java index bb4143c048d..69d0c53965e 100644 --- a/jdk/src/share/classes/sun/font/FreetypeFontScaler.java +++ b/jdk/src/share/classes/sun/font/FreetypeFontScaler.java @@ -211,7 +211,8 @@ class FreetypeFontScaler extends FontScaler { } long createScalerContext(double[] matrix, boolean fontType, - int aa, int fm, float boldness, float italic) { + int aa, int fm, float boldness, float italic, + boolean disableHinting) { if (nativeScaler != 0L) { return createScalerContextNative(nativeScaler, matrix, fontType, aa, fm, boldness, italic); diff --git a/jdk/src/share/classes/sun/font/NullFontScaler.java b/jdk/src/share/classes/sun/font/NullFontScaler.java index 1258243550b..857ec5a88c8 100644 --- a/jdk/src/share/classes/sun/font/NullFontScaler.java +++ b/jdk/src/share/classes/sun/font/NullFontScaler.java @@ -67,7 +67,7 @@ class NullFontScaler extends FontScaler { long getLayoutTableCache() {return 0L;} long createScalerContext(double[] matrix, boolean fontType, int aa, - int fm, float boldness, float italic) { + int fm, float boldness, float italic, boolean disableHinting) { return getNullScalerContext(); } diff --git a/jdk/src/share/classes/sun/font/SunFontManager.java b/jdk/src/share/classes/sun/font/SunFontManager.java index 991064e38ae..e9b3bf171d0 100644 --- a/jdk/src/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/share/classes/sun/font/SunFontManager.java @@ -1576,7 +1576,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { .info("Trying to resolve file " + fullPath); } do { - ttf = new TrueTypeFont(fullPath, null, fn++, true); + ttf = new TrueTypeFont(fullPath, null, fn++, false); // prefer the font's locale name. String fontName = ttf.getFontName(l).toLowerCase(); if (unmappedFonts.contains(fontName)) { @@ -1595,6 +1595,207 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { } } + /* Hardwire the English names and expected file names of fonts + * commonly used at start up. Avoiding until later even the small + * cost of calling platform APIs to locate these can help. + * The code that registers these fonts needs to "bail" if any + * of the files do not exist, so it will verify the existence of + * all non-null file names first. + * They are added in to a map with nominally the first + * word in the name of the family as the key. In all the cases + * we are using the the family name is a single word, and as is + * more or less required the family name is the initial sequence + * in a full name. So lookup first finds the matching description, + * then registers the whole family, returning the right font. + */ + public static class FamilyDescription { + public String familyName; + public String plainFullName; + public String boldFullName; + public String italicFullName; + public String boldItalicFullName; + public String plainFileName; + public String boldFileName; + public String italicFileName; + public String boldItalicFileName; + } + + static HashMap platformFontMap; + + /** + * default implementation does nothing. + */ + public HashMap populateHardcodedFileNameMap() { + return new HashMap(0); + } + + Font2D findFontFromPlatformMap(String lcName, int style) { + if (platformFontMap == null) { + platformFontMap = populateHardcodedFileNameMap(); + } + + if (platformFontMap == null || platformFontMap.size() == 0) { + return null; + } + + int spaceIndex = lcName.indexOf(' '); + String firstWord = lcName; + if (spaceIndex > 0) { + firstWord = lcName.substring(0, spaceIndex); + } + + FamilyDescription fd = platformFontMap.get(firstWord); + if (fd == null) { + return null; + } + /* Once we've established that its at least the first word, + * we need to dig deeper to make sure its a match for either + * a full name, or the family name, to make sure its not + * a request for some other font that just happens to start + * with the same first word. + */ + int styleIndex = -1; + if (lcName.equalsIgnoreCase(fd.plainFullName)) { + styleIndex = 0; + } else if (lcName.equalsIgnoreCase(fd.boldFullName)) { + styleIndex = 1; + } else if (lcName.equalsIgnoreCase(fd.italicFullName)) { + styleIndex = 2; + } else if (lcName.equalsIgnoreCase(fd.boldItalicFullName)) { + styleIndex = 3; + } + if (styleIndex == -1 && !lcName.equalsIgnoreCase(fd.familyName)) { + return null; + } + + String plainFile = null, boldFile = null, + italicFile = null, boldItalicFile = null; + + boolean failure = false; + /* In a terminal server config, its possible that getPathName() + * will return null, if the file doesn't exist, hence the null + * checks on return. But in the normal client config we need to + * follow this up with a check to see if all the files really + * exist for the non-null paths. + */ + getPlatformFontDirs(noType1Font); + + if (fd.plainFileName != null) { + plainFile = getPathName(fd.plainFileName); + if (plainFile == null) { + failure = true; + } + } + + if (fd.boldFileName != null) { + boldFile = getPathName(fd.boldFileName); + if (boldFile == null) { + failure = true; + } + } + + if (fd.italicFileName != null) { + italicFile = getPathName(fd.italicFileName); + if (italicFile == null) { + failure = true; + } + } + + if (fd.boldItalicFileName != null) { + boldItalicFile = getPathName(fd.boldItalicFileName); + if (boldItalicFile == null) { + failure = true; + } + } + + if (failure) { + if (FontUtilities.isLogging()) { + FontUtilities.getLogger(). + info("Hardcoded file missing looking for " + lcName); + } + platformFontMap.remove(firstWord); + return null; + } + + /* Some of these may be null,as not all styles have to exist */ + final String[] files = { + plainFile, boldFile, italicFile, boldItalicFile } ; + + failure = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Boolean run() { + for (int i=0; i 0 && style != font.style) { + style |= font.style; + font = fontFamily.getFont(style); + if (font == null) { + font = fontFamily.getClosestStyle(style); + } + } + } + + return font; + } private synchronized HashMap getFullNameToFileMap() { if (fontToFileMap == null) { @@ -1998,6 +2199,17 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { } if (FontUtilities.isWindows) { + + font = findFontFromPlatformMap(lowerCaseName, style); + if (FontUtilities.isLogging()) { + FontUtilities.getLogger() + .info("findFontFromPlatformMap returned " + font); + } + if (font != null) { + fontNameCache.put(mapName, font); + return font; + } + /* Don't want Windows to return a Lucida Sans font from * C:\Windows\Fonts */ @@ -2221,7 +2433,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { return FontUtilities.getFont2D(font).supportsEncoding(encoding); } - public abstract String getFontPath(boolean noType1Fonts); + protected abstract String getFontPath(boolean noType1Fonts); private Thread fileCloser = null; Vector tmpFontFiles = null; @@ -2934,8 +3146,15 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { } } + protected String[] getPlatformFontDirs(boolean noType1Fonts) { - String path = getFontPath(true); + + /* First check if we already initialised path dirs */ + if (pathDirs != null) { + return pathDirs; + } + + String path = getPlatformFontPath(noType1Fonts); StringTokenizer parser = new StringTokenizer(path, File.pathSeparator); ArrayList pathList = new ArrayList(); @@ -2945,7 +3164,8 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { } } catch (NoSuchElementException e) { } - return pathList.toArray(new String[0]); + pathDirs = pathList.toArray(new String[0]); + return pathDirs; } /** @@ -3047,7 +3267,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { /* A call to this method should be followed by a call to * registerFontDirs(..) */ - protected String getPlatformFontPath(boolean noType1Font) { + public String getPlatformFontPath(boolean noType1Font) { if (fontPath == null) { fontPath = getFontPath(noType1Font); } diff --git a/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java b/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java index 0fe6ec9bcc0..5316005c5fe 100644 --- a/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -165,7 +165,7 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment return new SunGraphics2D(sd, Color.white, Color.black, defaultFont); } - private static FontManagerForSGE getFontManagerForSGE() { + public static FontManagerForSGE getFontManagerForSGE() { FontManager fm = FontManagerFactory.getInstance(); return (FontManagerForSGE) fm; } diff --git a/jdk/src/share/demo/jvmti/index.html b/jdk/src/share/demo/jvmti/index.html index b3efe373d45..6ef96bb64b8 100644 --- a/jdk/src/share/demo/jvmti/index.html +++ b/jdk/src/share/demo/jvmti/index.html @@ -389,10 +389,9 @@ Library: Use /opt:REF when building the dll.

  • MS DLL Runtime: Use the /MD /D _STATIC_CPPLIB option.
    -This causes your dll to become dependent on MSVCRT.DLL and/or -the newer C++ runtime MSVCR71.DLL. +This causes your dll to become dependent on just MSVCR*.DLL. The option /D _STATIC_CPPLIB prevents you from becoming dependent on the -C++ library MSVCP71.DLL. +C++ library MSVCP*.DLL. This is what we use in the JDK, but there are probably many combinations that you could safely use, unfortunately there are many combinations of runtimes that will not work. diff --git a/jdk/src/share/native/sun/awt/image/jpeg/jmorecfg.h b/jdk/src/share/native/sun/awt/image/jpeg/jmorecfg.h index 95e5f33c394..be20d886c00 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/jmorecfg.h +++ b/jdk/src/share/native/sun/awt/image/jpeg/jmorecfg.h @@ -161,11 +161,11 @@ typedef short INT16; /* INT32 must hold at least signed 32-bit values. */ -#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ -#ifndef _LP64 -typedef long INT32; -#else +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#if defined(_LP64) || defined(_WIN32) /* _WIN32 is on all windows platfroms (x86 and x64) */ typedef int INT32; +#else +typedef long INT32; #endif #endif @@ -221,11 +221,14 @@ typedef unsigned int JDIMENSION; * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. */ + +#ifndef FAR #ifdef NEED_FAR_POINTERS #define FAR far #else #define FAR #endif +#endif /* diff --git a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp index 1db169a6dc3..952523105c1 100644 --- a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp +++ b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp @@ -224,6 +224,7 @@ void FontInstanceAdapter::getWideGlyphAdvance(le_uint32 glyph, LEPoint &advance) if (pt != NULL) { advance.fX = env->GetFloatField(pt, sunFontIDs.xFID); advance.fY = env->GetFloatField(pt, sunFontIDs.yFID); + env->DeleteLocalRef(pt); } } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 7493c837cb8..bd2c03c1ac6 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -137,7 +137,7 @@ void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode, JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg); } -JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { javaVM = jvm; cmsSetLogErrorHandler(errorHandler); diff --git a/jdk/src/solaris/classes/sun/awt/X11FontManager.java b/jdk/src/solaris/classes/sun/awt/X11FontManager.java index fea46ff56c3..573d250acba 100644 --- a/jdk/src/solaris/classes/sun/awt/X11FontManager.java +++ b/jdk/src/solaris/classes/sun/awt/X11FontManager.java @@ -718,25 +718,6 @@ public class X11FontManager extends SunFontManager { fontdirs = (String[])fontConfigDirs.toArray(new String[0]); } - /* Called by MToolkit to set the X11 font path */ - public static void setNativeFontPath() { - if (fontdirs == null) { - return; - } - - // need to register these individually rather than by one call - // to ensure that one bad directory doesn't cause all to be rejected - for (int i=0; iSolaris the paths needed by the JRE should - * also be available to the server, although we have no way to check this - * for sure. - * So set the font path if we think its safe to do so: - * All Solaris X servers at least back to 2.6 and up to Solaris 10 - * define the exact same vendor string. - * The version number for Solaris 2.6 is 3600, for 2.7 is 3610 and - * for Solaris 8 6410 - * we want to set the font path only for 2.8 and onwards. Earlier releases - * are unlikely to have the right fonts and can't install "all locales" - * as needed to be sure. Also Solaris 8 is the earliest release supported - * by 1.5. - */ -#ifndef HEADLESS -static int isSunXServer() { -#ifdef __solaris__ - return ((strncmp(ServerVendor(awt_display), "Sun Microsystems, Inc.", 22) == 0) || - (strncmp(ServerVendor(awt_display), "Oracle Corporation", 18) == 0) && - VendorRelease(awt_display) >= 6410); -#else - return 0; -#endif /* __solaris__ */ -} - -/* Avoid re-doing work for every call to setNativeFontPath */ -static int doSetFontPath = -1; -static int shouldSetXFontPath(JNIEnv *env) { - if (doSetFontPath == -1) { - doSetFontPath = - awt_display != NULL && (isDisplayLocal(env) || isSunXServer()); - } - return doSetFontPath; -} -#endif /* !HEADLESS */ - -JNIEXPORT void JNICALL Java_sun_font_X11FontManager_setNativeFontPath -(JNIEnv *env, jclass obj, jstring theString) { -#ifdef HEADLESS - return; -#else - fDirRecord fDir; - const char *theChars; - - if (awt_display == NULL) { - return; - } - AWT_LOCK(); - if (shouldSetXFontPath(env)) { - theChars = (*env)->GetStringUTFChars (env, theString, 0); - fDir.num = 1; - fDir.name[0] = theChars; - /* printf ("Registering the font path here %s \n", theChars ); */ - AddFontsToX11FontPath ( &fDir ); - if (theChars) { - (*env)->ReleaseStringUTFChars (env, - theString, (const char*)theChars); - } - } - AWT_UNLOCK(); - -#endif -} - #include #ifndef __linux__ /* i.e. is solaris */ #include @@ -1178,6 +1120,7 @@ Java_sun_font_FontConfigManager_getFontConfig } pattern = (*FcNameParse)((FcChar8 *)fcName); if (pattern == NULL) { + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); closeFontConfig(libfontconfig, JNI_FALSE); return; } @@ -1194,6 +1137,8 @@ Java_sun_font_FontConfigManager_getFontConfig (*FcDefaultSubstitute)(pattern); fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result); if (fontset == NULL) { + (*FcPatternDestroy)(pattern); + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); closeFontConfig(libfontconfig, JNI_FALSE); return; } @@ -1211,6 +1156,21 @@ Java_sun_font_FontConfigManager_getFontConfig file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); if (family == NULL || styleStr == NULL || fullname == NULL || file == NULL) { + if (family != NULL) { + free(family); + } + if (styleStr != NULL) { + free(styleStr); + } + if (fullname != NULL) { + free(fullname); + } + if (file != NULL) { + free(file); + } + (*FcPatternDestroy)(pattern); + (*FcFontSetDestroy)(fontset); + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); closeFontConfig(libfontconfig, JNI_FALSE); return; } @@ -1237,6 +1197,14 @@ Java_sun_font_FontConfigManager_getFontConfig result = (*FcPatternGetCharSet)(fontPattern, FC_CHARSET, 0, &charset); if (result != FcResultMatch) { + free(family); + free(family); + free(styleStr); + free(file); + (*FcPatternDestroy)(pattern); + (*FcFontSetDestroy)(fontset); + (*env)->ReleaseStringUTFChars(env, + fcNameStr, (const char*)fcName); closeFontConfig(libfontconfig, JNI_FALSE); return; } diff --git a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c index 58dfb63d0ce..1ce26c60107 100644 --- a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c +++ b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c @@ -31,6 +31,21 @@ #include +/* On Solaris 10 updates 8, 9, the render.h file defines these + * protocol values but does not define the structs in Xrender.h. + * Thus in order to get these always defined on Solaris 10 + * we will undefine the symbols if we have determined via the + * makefiles that Xrender.h is lacking the structs. This will + * trigger providing our own definitions as on earlier updates. + * We could assume that *all* Solaris 10 update versions will lack the updated + * Xrender.h and do this based solely on O/S being any 5.10 version, but this + * could still change and we'd be broken again as we'd be re-defining them. + */ +#ifdef SOLARIS10_NO_XRENDER_STRUCTS +#undef X_RenderCreateLinearGradient +#undef X_RenderCreateRadialGradient +#endif + #ifndef X_RenderCreateLinearGradient typedef struct _XLinearGradient { XPointFixed p1; diff --git a/jdk/src/windows/classes/sun/awt/Win32FontManager.java b/jdk/src/windows/classes/sun/awt/Win32FontManager.java index a6c9e5d8861..b2dd894e490 100644 --- a/jdk/src/windows/classes/sun/awt/Win32FontManager.java +++ b/jdk/src/windows/classes/sun/awt/Win32FontManager.java @@ -63,7 +63,7 @@ public class Win32FontManager extends SunFontManager { if (eudcFile != null) { try { eudcFont = new TrueTypeFont(eudcFile, null, 0, - true); + false); } catch (FontFormatException e) { } } @@ -81,6 +81,10 @@ public class Win32FontManager extends SunFontManager { */ private static native String getEUDCFontFile(); + public TrueTypeFont getEUDCFont() { + return eudcFont; + } + public Win32FontManager() { super(); AccessController.doPrivileged(new PrivilegedAction() { @@ -137,6 +141,7 @@ public class Win32FontManager extends SunFontManager { try { while (!found && parser.hasMoreTokens()) { String newPath = parser.nextToken(); + boolean isJREFont = newPath.equals(jreFontDirName); File theFile = new File(newPath, fontFileName); if (theFile.canRead()) { found = true; @@ -144,11 +149,11 @@ public class Win32FontManager extends SunFontManager { if (defer) { registerDeferredFont(fontFileName, path, nativeNames, - fontFormat, true, + fontFormat, isJREFont, fontRank); } else { registerFontFile(path, nativeNames, - fontFormat, true, + fontFormat, isJREFont, fontRank); } break; @@ -197,7 +202,7 @@ public class Win32FontManager extends SunFontManager { familyToFontListMap, Locale locale); - public synchronized native String getFontPath(boolean noType1Fonts); + protected synchronized native String getFontPath(boolean noType1Fonts); public String[] getDefaultPlatformFont() { @@ -277,4 +282,79 @@ public class Win32FontManager extends SunFontManager { protected static native void deRegisterFontWithPlatform(String fontName); + /** + * populate the map with the most common windows fonts. + */ + @Override + public HashMap populateHardcodedFileNameMap() { + HashMap platformFontMap + = new HashMap(); + FamilyDescription fd; + + /* Segoe UI is the default UI font for Vista and later, and + * is used by the Win L&F which is used by FX too. + * Tahoma is used for the Win L&F on XP. + * Verdana is used in some FX UI controls. + */ + fd = new FamilyDescription(); + fd.familyName = "Segoe UI"; + fd.plainFullName = "Segoe UI"; + fd.plainFileName = "segoeui.ttf"; + fd.boldFullName = "Segoe UI Bold"; + fd.boldFileName = "segoeuib.ttf"; + fd.italicFullName = "Segoe UI Italic"; + fd.italicFileName = "segoeuii.ttf"; + fd.boldItalicFullName = "Segoe UI Bold Italic"; + fd.boldItalicFileName = "segoeuiz.ttf"; + platformFontMap.put("segoe", fd); + + fd = new FamilyDescription(); + fd.familyName = "Tahoma"; + fd.plainFullName = "Tahoma"; + fd.plainFileName = "tahoma.ttf"; + fd.boldFullName = "Tahoma Bold"; + fd.boldFileName = "tahomabd.ttf"; + platformFontMap.put("tahoma", fd); + + fd = new FamilyDescription(); + fd.familyName = "Verdana"; + fd.plainFullName = "Verdana"; + fd.plainFileName = "verdana.TTF"; + fd.boldFullName = "Verdana Bold"; + fd.boldFileName = "verdanab.TTF"; + fd.italicFullName = "Verdana Italic"; + fd.italicFileName = "verdanai.TTF"; + fd.boldItalicFullName = "Verdana Bold Italic"; + fd.boldItalicFileName = "verdanaz.TTF"; + platformFontMap.put("verdana", fd); + + /* The following are important because they are the core + * members of the default "Dialog" font. + */ + fd = new FamilyDescription(); + fd.familyName = "Arial"; + fd.plainFullName = "Arial"; + fd.plainFileName = "ARIAL.TTF"; + fd.boldFullName = "Arial Bold"; + fd.boldFileName = "ARIALBD.TTF"; + fd.italicFullName = "Arial Italic"; + fd.italicFileName = "ARIALI.TTF"; + fd.boldItalicFullName = "Arial Bold Italic"; + fd.boldItalicFileName = "ARIALBI.TTF"; + platformFontMap.put("arial", fd); + + fd = new FamilyDescription(); + fd.familyName = "Symbol"; + fd.plainFullName = "Symbol"; + fd.plainFileName = "Symbol.TTF"; + platformFontMap.put("symbol", fd); + + fd = new FamilyDescription(); + fd.familyName = "WingDings"; + fd.plainFullName = "WingDings"; + fd.plainFileName = "WINGDING.TTF"; + platformFontMap.put("wingdings", fd); + + return platformFontMap; + } } diff --git a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java index 967bd7b74f2..b994c23a1e5 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java +++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java @@ -228,31 +228,29 @@ public class WToolkit extends SunToolkit implements Runnable { sun.java2d.Disposer.addRecord(anchor, new ToolkitDisposer()); - synchronized (this) { - // Fix for bug #4046430 -- Race condition - // where notifyAll can be called before - // the "AWT-Windows" thread's parent thread is - // waiting, resulting in a deadlock on startup. + /* + * Fix for 4701990. + * AWTAutoShutdown state must be changed before the toolkit thread + * starts to avoid race condition. + */ + AWTAutoShutdown.notifyToolkitThreadBusy(); - /* - * Fix for 4701990. - * AWTAutoShutdown state must be changed before the toolkit thread - * starts to avoid race condition. - */ - AWTAutoShutdown.notifyToolkitThreadBusy(); - - if (!startToolkitThread(this)) { - Thread toolkitThread = new Thread(this, "AWT-Windows"); - toolkitThread.setDaemon(true); - toolkitThread.start(); - } - - try { - wait(); - } - catch (InterruptedException x) { - } + if (!startToolkitThread(this)) { + Thread toolkitThread = new Thread(this, "AWT-Windows"); + toolkitThread.setDaemon(true); + toolkitThread.start(); } + + try { + synchronized(this) { + while(!inited) { + wait(); + } + } + } catch (InterruptedException x) { + // swallow the exception + } + SunToolkit.setDataTransfererClassName(DATA_TRANSFERER_CLASS_NAME); // Enabled "live resizing" by default. It remains controlled @@ -265,33 +263,38 @@ public class WToolkit extends SunToolkit implements Runnable { setExtraMouseButtonsEnabledNative(areExtraMouseButtonsEnabled); } + private final void registerShutdownHook() { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ThreadGroup currentTG = + Thread.currentThread().getThreadGroup(); + ThreadGroup parentTG = currentTG.getParent(); + while (parentTG != null) { + currentTG = parentTG; + parentTG = currentTG.getParent(); + } + Thread shutdown = new Thread(currentTG, new Runnable() { + public void run() { + shutdown(); + } + }); + shutdown.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(shutdown); + return null; + } + }); + } + public void run() { Thread.currentThread().setPriority(Thread.NORM_PRIORITY+1); boolean startPump = init(); if (startPump) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - ThreadGroup currentTG = - Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = currentTG.getParent(); - while (parentTG != null) { - currentTG = parentTG; - parentTG = currentTG.getParent(); - } - Thread shutdown = new Thread(currentTG, new Runnable() { - public void run() { - shutdown(); - } - }); - shutdown.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(shutdown); - return null; - } - }); + registerShutdownHook(); } synchronized(this) { + inited = true; notifyAll(); } @@ -309,6 +312,8 @@ public class WToolkit extends SunToolkit implements Runnable { * eventLoop() should Dispose the toolkit and exit. */ private native boolean init(); + private boolean inited = false; + private native void eventLoop(); private native void shutdown(); diff --git a/jdk/src/windows/classes/sun/print/Win32PrintService.java b/jdk/src/windows/classes/sun/print/Win32PrintService.java index 88e8daead50..2697032f6e3 100644 --- a/jdk/src/windows/classes/sun/print/Win32PrintService.java +++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java @@ -439,7 +439,14 @@ public class Win32PrintService implements PrintService, AttributeUpdater, MediaTray[] arr = new MediaTray[nTray]; int dmBin; - for (int i = 0, j=0; i < mediaTr.length; i++) { + + /* Some drivers in Win 7 don't have the same length for DC_BINS and + * DC_BINNAMES so there is no guarantee that lengths of mediaTr and + * winMediaTrayNames are equal. To avoid getting ArrayIndexOutOfBounds, + * we need to make sure we get the minimum of the two. + */ + + for (int i = 0, j=0; i < Math.min(mediaTr.length, winMediaTrayNames.length); i++) { dmBin = mediaTr[i]; if (dmBin > 0) { // check for unsupported DMBINs and create new Win32MediaTray diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp b/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp index c84e7ea4751..efb20c5d3a3 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp @@ -396,7 +396,7 @@ Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative UINT adapter; // EnumAdapterModes treats 555 and 565 formats as equivalents static D3DFORMAT formats[] = - { D3DFMT_X8R8G8B8, D3DFMT_R5G6B5 }; + { D3DFMT_X8R8G8B8, D3DFMT_R5G6B5 }; J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enumDisplayModesNative"); @@ -404,7 +404,7 @@ Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject()); adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen); - for (formatNum = 0; formatNum < 3; formatNum++) { + for (formatNum = 0; formatNum < (sizeof formats)/(sizeof *formats); formatNum++) { modesCount = pd3d9->GetAdapterModeCount(adapter, formats[formatNum]); for (modeNum = 0; modeNum < modesCount; modeNum++) { if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, formats[formatNum], diff --git a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp index cf1503981a8..cab78049f23 100644 --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp @@ -2491,7 +2491,7 @@ Java_sun_awt_windows_WToolkit_loadSystemColors(JNIEnv *env, jobject self, jint* colorsPtr = NULL; try { colorsPtr = (jint *)env->GetPrimitiveArrayCritical(colors, 0); - for (int i = 0; i < sizeof indexMap && i < colorLen; i++) { + for (int i = 0; i < (sizeof indexMap)/(sizeof *indexMap) && i < colorLen; i++) { colorsPtr[i] = DesktopColor2RGB(indexMap[i]); } } catch (...) { diff --git a/jdk/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp b/jdk/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp index 03cb4675075..efe485230a7 100644 --- a/jdk/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp @@ -214,6 +214,7 @@ Java_sun_awt_Win32FontManager_deRegisterFontWithPlatform(JNIEnv *env, #define EUDCKEY_ZH_CN L"EUDC\\936" #define EUDCKEY_ZH_TW L"EUDC\\950" #define EUDCKEY_KO_KR L"EUDC\\949" +#define EUDCKEY_EN_US L"EUDC\\1252" #define LANGID_JA_JP 0x411 #define LANGID_ZH_CN 0x0804 #define LANGID_ZH_SG 0x1004 @@ -221,6 +222,7 @@ Java_sun_awt_Win32FontManager_deRegisterFontWithPlatform(JNIEnv *env, #define LANGID_ZH_HK 0x0c04 #define LANGID_ZH_MO 0x1404 #define LANGID_KO_KR 0x0412 +#define LANGID_EN_US 0x0409 JNIEXPORT jstring JNICALL @@ -237,6 +239,9 @@ Java_sun_awt_Win32FontManager_getEUDCFontFile(JNIEnv *env, jclass cl) { LANGID langID = GetSystemDefaultLangID(); //lookup for encoding ID, EUDC only supported in //codepage 932, 936, 949, 950 (and unicode) + // On Windows 7, at least for me, it shows up in Cp1252 if + // I create a custom font. Might as well support that as it makes + // verification easier. if (langID == LANGID_JA_JP) { eudcKey = EUDCKEY_JA_JP; } else if (langID == LANGID_ZH_CN || langID == LANGID_ZH_SG) { @@ -246,6 +251,8 @@ Java_sun_awt_Win32FontManager_getEUDCFontFile(JNIEnv *env, jclass cl) { eudcKey = EUDCKEY_ZH_TW; } else if (langID == LANGID_KO_KR) { eudcKey = EUDCKEY_KO_KR; + } else if (langID == LANGID_EN_US) { + eudcKey = EUDCKEY_EN_US; } else { return NULL; } diff --git a/jdk/src/windows/resource/java.manifest b/jdk/src/windows/resource/java.manifest index 61ec5999e19..e5b44609820 100644 --- a/jdk/src/windows/resource/java.manifest +++ b/jdk/src/windows/resource/java.manifest @@ -1,12 +1,15 @@ - + -AWT +Java(TM) SE PROGRAM process + + + + + + + + + + + + + + true + + + diff --git a/jdk/test/java/awt/FontClass/LCDScale.java b/jdk/test/java/awt/FontClass/LCDScale.java new file mode 100644 index 00000000000..5f8d1f6a16d --- /dev/null +++ b/jdk/test/java/awt/FontClass/LCDScale.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * @bug 6925760 + * @summary Scaled graphics causes overlapped LCD glyphs on Windows + */ + +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; + +public class LCDScale extends Component { + + public static void main(String args[]) { + Frame f = new Frame("TL TEST"); + LCDScale td = new LCDScale(); + f.add("Center", td); + f.pack(); f.setVisible(true); + } + + + public LCDScale() { + super(); + } + + public Dimension getPreferredSize() { + return new Dimension(500,500); + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHint( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + + Font f = new Font("Dialog", Font.PLAIN, 40); + g.setFont(f); + FontRenderContext frc = g2d.getFontRenderContext(); + GlyphVector gv = f.createGlyphVector(frc, "Help"); + g2d.drawGlyphVector(gv, 10f, 50f); + Rectangle2D bds1 = gv.getLogicalBounds(); + + f = new Font("Arial", Font.PLAIN, 25); + g.setFont(f); + double s = 2.0; + AffineTransform tx = AffineTransform.getScaleInstance(s,s); + g2d.transform(tx); + frc = g2d.getFontRenderContext(); + gv = f.createGlyphVector(frc, "Help"); + g2d.drawGlyphVector(gv, 10f, 100f); + Rectangle2D bds2 = gv.getLogicalBounds(); + + System.out.println(bds1); + System.out.println(bds2); + if (bds2.getWidth()*s < bds1.getWidth()) { + throw new RuntimeException("Bounds too small"); + } + } +} + + diff --git a/jdk/test/java/awt/FontClass/X11FontPathCrashTest.java b/jdk/test/java/awt/FontClass/X11FontPathCrashTest.java new file mode 100644 index 00000000000..cbc762a36ed --- /dev/null +++ b/jdk/test/java/awt/FontClass/X11FontPathCrashTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6958221 + * @summary Test no crashing getting fonts on X11 + * @run main X11FontPathCrashTest + */ + +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; + + +public class X11FontPathCrashTest { + public static void main(String[] args) { + new Font("nonexistentfont", Font.PLAIN, 12).getFamily(); + } +} + diff --git a/jdk/test/java/awt/font/FontNames/LocaleFamilyNames.java b/jdk/test/java/awt/font/FontNames/LocaleFamilyNames.java new file mode 100644 index 00000000000..e6d71feb814 --- /dev/null +++ b/jdk/test/java/awt/font/FontNames/LocaleFamilyNames.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4935798 6521210 6901159 + * @summary Tests that all family names that are reported in all locales + * correspond to some font returned from getAllFonts(). + * @run main LocaleFamilyNames + */ +import java.awt.*; +import java.util.*; + +public class LocaleFamilyNames { + public static void main(String[] args) throws Exception { + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + + Font[] all_fonts = ge.getAllFonts(); + + Locale[] all_locales = Locale.getAvailableLocales(); + + HashSet all_families = new HashSet(); + for (int i=0; iAn HTML-formatted ToolTip"); + + frame = new JFrame(); + + frame.add(label); + frame.pack(); + frame.setVisible(true); + + ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); + + toolTipManager.setInitialDelay(0); + toolTipManager.mouseMoved(new MouseEvent(label, 0, 0, 0, 0, 0, 0, false)); + } + }); + + Thread.sleep(500); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + toolTipWidth = getTipWindow().getWidth(); + + frame.dispose(); + } + }); + + Thread thread = new Thread(new ThreadGroup("Some ThreadGroup"), new Runnable() { + public void run() { + SunToolkit.createNewAppContext(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new JFrame(); + + frame.add(label); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + + ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); + + toolTipManager.setInitialDelay(0); + toolTipManager.mouseMoved(new MouseEvent(label, 0, 0, 0, 0, 0, 0, false)); + } + }); + + Thread.sleep(500); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + int newToolTipWidth = getTipWindow().getWidth(); + + frame.dispose(); + + if (toolTipWidth != newToolTipWidth) { + throw new RuntimeException("Tooltip width is different. Initial: " + toolTipWidth + + ", new: " + newToolTipWidth); + } + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + }); + + thread.start(); + thread.join(); + } + + private static Component getTipWindow() { + try { + Field tipWindowField = ToolTipManager.class.getDeclaredField("tipWindow"); + + tipWindowField.setAccessible(true); + + Popup value = (Popup) tipWindowField.get(ToolTipManager.sharedInstance()); + + Field componentField = Popup.class.getDeclaredField("component"); + + componentField.setAccessible(true); + + return (Component) componentField.get(value); + } catch (Exception e) { + throw new RuntimeException("getToolTipComponent failed", e); + } + } +} diff --git a/jdk/test/javax/swing/text/NavigationFilter/6735293/bug6735293.java b/jdk/test/javax/swing/text/NavigationFilter/6735293/bug6735293.java new file mode 100644 index 00000000000..4d077ceba15 --- /dev/null +++ b/jdk/test/javax/swing/text/NavigationFilter/6735293/bug6735293.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6735293 + * @summary javax.swing.text.NavigationFilter.getNextVisualPositionFrom() not always throws BadLocationException + * @author Pavel Porvatov + */ + +import javax.swing.*; +import javax.swing.text.BadLocationException; +import javax.swing.text.NavigationFilter; +import javax.swing.text.Position; + +public class bug6735293 { + private static volatile JFormattedTextField jtf; + + private static volatile NavigationFilter nf; + + private static volatile JFrame jFrame; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jtf = new JFormattedTextField(); + nf = new NavigationFilter(); + jtf.setText("A text message"); + + jFrame = new JFrame(); + jFrame.getContentPane().add(jtf); + jFrame.pack(); + jFrame.setVisible(true); + } + }); + + Thread.sleep(1000); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Position.Bias[] biasRet = {Position.Bias.Forward}; + + for (int direction : new int[]{ + SwingConstants.EAST, + SwingConstants.WEST, + // the following constants still will lead to "BadLocationException: Length must be positive" + SwingConstants.SOUTH, + SwingConstants.NORTH, + }) { + for (int position : new int[]{-100, Integer.MIN_VALUE}) { + for (Position.Bias bias : new Position.Bias[]{Position.Bias.Backward, Position.Bias.Forward}) { + try { + nf.getNextVisualPositionFrom(jtf, position, bias, direction, biasRet); + + throw new RuntimeException("BadLocationException was not thrown: position = " + + position + ", bias = " + bias + ", direction = " + direction); + } catch (BadLocationException e) { + // Ok + } + } + } + } + + jFrame.dispose(); + } + }); + } +} diff --git a/jdk/test/javax/swing/text/html/parser/Parser/6990651/bug6990651.java b/jdk/test/javax/swing/text/html/parser/Parser/6990651/bug6990651.java new file mode 100644 index 00000000000..e956140aee7 --- /dev/null +++ b/jdk/test/javax/swing/text/html/parser/Parser/6990651/bug6990651.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6990651 + @summary Regression: NPE when refreshing applet since 6u22-b01 + @author Pavel Porvatov +*/ +import sun.awt.SunToolkit; + +import javax.swing.*; + +public class bug6990651 { + private static volatile JEditorPane editor; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + editor = new JEditorPane("text/html", "Hello world!"); + } + }); + + Thread thread = new Thread(new ThreadGroup("Some ThreadGroup"), new Runnable() { + public void run() { + SunToolkit.createNewAppContext(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + editor.setText("Hello world!"); + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + }); + + thread.start(); + thread.join(); + } +} diff --git a/langtools/.hgtags b/langtools/.hgtags index 112c4c2ca39..fc81571c856 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -100,3 +100,5 @@ c491eec0acc73fa41b77e1619ed03e56d8a75b83 jdk7-b118 a3b5b531542a372f30e014b1543a619a15a90780 jdk7-b123 4868a36f6fd8972505c466013813eeb28f0482ea jdk7-b124 4b0560c72b529d4b952924b2da94d8436af79d05 jdk7-b125 +438a8ad60f7ae7aa897663148fd43fe85ef05e5b jdk7-b126 +1e6094c33187f6c3dca55ced3701ee1f9d73a77d jdk7-b127 diff --git a/langtools/make/build.xml b/langtools/make/build.xml index ec3aaf8763e..aaa4d728a4c 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -352,6 +352,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +