# HG changeset patch # User ccheung # Date 1380945643 25200 # Node ID 2720ab7a0d70eb2a1ecc90a116b710defafffde8 # Parent 4212bfb33d76f9a672ca8744857b5ff03c5ac156# Parent 798522662fcd08211bd64fdde7fe22b54c83ad98 Merge diff -r 4212bfb33d76 -r 2720ab7a0d70 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Sat Oct 05 03:14:53 2013 +0200 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Fri Oct 04 21:00:43 2013 -0700 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -80,7 +81,7 @@ (JNIEnv *env, jclass cls) { jclass listClass; - if (init_libproc(getenv("LIBSAPROC_DEBUG")) != true) { + if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) { THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc"); } diff -r 4212bfb33d76 -r 2720ab7a0d70 agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Sat Oct 05 03:14:53 2013 +0200 +++ b/agent/src/os/linux/ps_proc.c Fri Oct 04 21:00:43 2013 -0700 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include "libproc_impl.h" diff -r 4212bfb33d76 -r 2720ab7a0d70 agent/src/os/linux/salibelf.c --- a/agent/src/os/linux/salibelf.c Sat Oct 05 03:14:53 2013 +0200 +++ b/agent/src/os/linux/salibelf.c Fri Oct 04 21:00:43 2013 -0700 @@ -25,6 +25,7 @@ #include "salibelf.h" #include #include +#include extern void print_debug(const char*,...); diff -r 4212bfb33d76 -r 2720ab7a0d70 agent/src/os/linux/symtab.c --- a/agent/src/os/linux/symtab.c Sat Oct 05 03:14:53 2013 +0200 +++ b/agent/src/os/linux/symtab.c Fri Oct 04 21:00:43 2013 -0700 @@ -305,7 +305,7 @@ unsigned char *bytes = (unsigned char*)(note+1) + note->n_namesz; - unsigned char *filename + char *filename = (build_id_to_debug_filename (note->n_descsz, bytes)); fd = pathmap_open(filename); diff -r 4212bfb33d76 -r 2720ab7a0d70 agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Sat Oct 05 03:14:53 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Oct 04 21:00:43 2013 -0700 @@ -134,15 +134,13 @@ private String type; private String name; private Address addr; - private String kind; - private int origin; + private int flags; - private Flag(String type, String name, Address addr, String kind, int origin) { + private Flag(String type, String name, Address addr, int flags) { this.type = type; this.name = name; this.addr = addr; - this.kind = kind; - this.origin = origin; + this.flags = flags; } public String getType() { @@ -157,12 +155,8 @@ return addr; } - public String getKind() { - return kind; - } - public int getOrigin() { - return origin; + return flags & 0xF; // XXX can we get the mask bits from somewhere? } public boolean isBool() { @@ -173,8 +167,7 @@ if (Assert.ASSERTS_ENABLED) { Assert.that(isBool(), "not a bool flag!"); } - return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) - != 0; + return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) != 0; } public boolean isIntx() { @@ -843,11 +836,10 @@ Address flagAddr = flagType.getAddressField("flags").getValue(); - AddressField typeFld = flagType.getAddressField("type"); - AddressField nameFld = flagType.getAddressField("name"); - AddressField addrFld = flagType.getAddressField("addr"); - AddressField kindFld = flagType.getAddressField("kind"); - CIntField originFld = new CIntField(flagType.getCIntegerField("origin"), 0); + AddressField typeFld = flagType.getAddressField("_type"); + AddressField nameFld = flagType.getAddressField("_name"); + AddressField addrFld = flagType.getAddressField("_addr"); + CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0); long flagSize = flagType.getSize(); // sizeof(Flag) @@ -856,9 +848,8 @@ String type = CStringUtilities.getString(typeFld.getValue(flagAddr)); String name = CStringUtilities.getString(nameFld.getValue(flagAddr)); Address addr = addrFld.getValue(flagAddr); - String kind = CStringUtilities.getString(kindFld.getValue(flagAddr)); - int origin = (int)originFld.getValue(flagAddr); - commandLineFlags[f] = new Flag(type, name, addr, kind, origin); + int flags = (int)flagsFld.getValue(flagAddr); + commandLineFlags[f] = new Flag(type, name, addr, flags); flagAddr = flagAddr.addOffsetTo(flagSize); } diff -r 4212bfb33d76 -r 2720ab7a0d70 make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Sat Oct 05 03:14:53 2013 +0200 +++ b/make/bsd/makefiles/gcc.make Fri Oct 04 21:00:43 2013 -0700 @@ -247,7 +247,7 @@ ifeq ($(USE_CLANG), true) # However we need to clean the code up before we can unrestrictedly enable this option with Clang - WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-compare # Not yet supported by clang in Xcode 4.6.2 # WARNINGS_ARE_ERRORS += -Wno-tautological-constant-out-of-range-compare @@ -262,7 +262,7 @@ # conversions which might affect the values. Only enable it in earlier versions. WARNING_FLAGS = -Wunused-function ifeq ($(USE_CLANG),) - WARNINGS_FLAGS += -Wconversion + WARNING_FLAGS += -Wconversion endif endif diff -r 4212bfb33d76 -r 2720ab7a0d70 make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Sat Oct 05 03:14:53 2013 +0200 +++ b/make/linux/makefiles/gcc.make Fri Oct 04 21:00:43 2013 -0700 @@ -208,7 +208,7 @@ ifeq ($(USE_CLANG), true) # However we need to clean the code up before we can unrestrictedly enable this option with Clang - WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -121,6 +121,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { + Label L_no_such_method; assert(method == G5_method, "interpreter calling convention"); assert_different_registers(method, target, temp); @@ -133,6 +134,9 @@ const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); __ ld(interp_only, temp); __ cmp_and_br_short(temp, 0, Assembler::zero, Assembler::pt, run_compiled_code); + // Null method test is replicated below in compiled case, + // it might be able to address across the verify_thread() + __ br_null_short(G5_method, Assembler::pn, L_no_such_method); __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target); __ jmp(target, 0); __ delayed()->nop(); @@ -141,11 +145,19 @@ // it doesn't matter, since this is interpreter code. } + // Compiled case, either static or fall-through from runtime conditional + __ br_null_short(G5_method, Assembler::pn, L_no_such_method); + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ld_ptr(G5_method, in_bytes(entry_offset), target); __ jmp(target, 0); __ delayed()->nop(); + + __ bind(L_no_such_method); + AddressLiteral ame(StubRoutines::throw_AbstractMethodError_entry()); + __ jump_to(ame, temp); + __ delayed()->nop(); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/sparc/vm/sparc.ad Fri Oct 04 21:00:43 2013 -0700 @@ -2018,6 +2018,15 @@ return L7_REGP_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return G1_REGI_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + + %} @@ -4245,12 +4254,16 @@ greater_equal(0xB); less_equal(0x2); greater(0xA); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, unsigned operand cmpOpU() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "u" %} interface(COND_INTER) %{ @@ -4260,12 +4273,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, pointer (same as unsigned) operand cmpOpP() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "p" %} interface(COND_INTER) %{ @@ -4275,12 +4292,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, branch-register encoding operand cmpOp_reg() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4290,12 +4311,16 @@ greater_equal(0x7); less_equal (0x2); greater (0x6); + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Comparison Code, floating, unordered same as less operand cmpOpF() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "fl" %} interface(COND_INTER) %{ @@ -4305,12 +4330,17 @@ greater_equal(0xB); less_equal(0xE); greater(0x6); + + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Used by long compare operand cmpOp_commute() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4320,6 +4350,8 @@ greater_equal(0x2); less_equal(0xB); greater(0x3); + overflow(0x7); + no_overflow(0xF); %} %} diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/x86/vm/assembler_x86.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -4769,7 +4769,7 @@ } void Assembler::adcq(Register dst, Register src) { - (int) prefixq_and_encode(dst->encoding(), src->encoding()); + (void) prefixq_and_encode(dst->encoding(), src->encoding()); emit_arith(0x13, 0xC0, dst, src); } @@ -4824,7 +4824,7 @@ } void Assembler::andq(Register dst, Register src) { - (int) prefixq_and_encode(dst->encoding(), src->encoding()); + (void) prefixq_and_encode(dst->encoding(), src->encoding()); emit_arith(0x23, 0xC0, dst, src); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -114,6 +114,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, bool for_compiler_entry) { assert(method == rbx, "interpreter calling convention"); + + Label L_no_such_method; + __ testptr(rbx, rbx); + __ jcc(Assembler::zero, L_no_such_method); + __ verify_method_ptr(method); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { @@ -138,6 +143,9 @@ const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ jmp(Address(method, entry_offset)); + + __ bind(L_no_such_method); + __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/x86/vm/x86_32.ad Fri Oct 04 21:00:43 2013 -0700 @@ -1534,6 +1534,14 @@ return EBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return EAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + // Returns true if the high 32 bits of the value is known to be zero. bool is_operand_hi32_zero(Node* n) { int opc = n->Opcode(); @@ -4922,6 +4930,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4939,6 +4949,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4957,6 +4969,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4974,6 +4988,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4981,6 +4997,8 @@ operand cmpOp_fcmov() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ equal (0x0C8); @@ -4989,6 +5007,8 @@ greater_equal(0x1C0); less_equal (0x0D0); greater (0x1D0); + overflow(0x0, "o"); // not really supported by the instruction + no_overflow(0x1, "no"); // not really supported by the instruction %} %} @@ -5004,6 +5024,8 @@ greater_equal(0xE, "le"); less_equal(0xD, "ge"); greater(0xC, "l"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -7496,6 +7518,31 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- + +instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + // Integer Addition Instructions instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Sat Oct 05 03:14:53 2013 +0200 +++ b/src/cpu/x86/vm/x86_64.ad Fri Oct 04 21:00:43 2013 -0700 @@ -1649,6 +1649,14 @@ return PTR_RBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return INT_RAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + %} //----------ENCODING BLOCK----------------------------------------------------- @@ -4133,6 +4141,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4151,6 +4161,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4170,6 +4182,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4187,6 +4201,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -6922,6 +6938,30 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- +instruct addExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/adlc/adlparse.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -3395,12 +3395,16 @@ char *greater_equal; char *less_equal; char *greater; + char *overflow; + char *no_overflow; const char *equal_format = "eq"; const char *not_equal_format = "ne"; const char *less_format = "lt"; const char *greater_equal_format = "ge"; const char *less_equal_format = "le"; const char *greater_format = "gt"; + const char *overflow_format = "o"; + const char *no_overflow_format = "no"; if (_curchar != '%') { parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); @@ -3437,6 +3441,12 @@ else if ( strcmp(field,"greater") == 0 ) { greater = interface_field_parse(&greater_format); } + else if ( strcmp(field,"overflow") == 0 ) { + overflow = interface_field_parse(&overflow_format); + } + else if ( strcmp(field,"no_overflow") == 0 ) { + no_overflow = interface_field_parse(&no_overflow_format); + } else { parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; @@ -3455,7 +3465,9 @@ less, less_format, greater_equal, greater_equal_format, less_equal, less_equal_format, - greater, greater_format); + greater, greater_format, + overflow, overflow_format, + no_overflow, no_overflow_format); return inter; } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/adlc/archDesc.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1192,6 +1192,8 @@ || strcmp(idealName,"CmpF") == 0 || strcmp(idealName,"FastLock") == 0 || strcmp(idealName,"FastUnlock") == 0 + || strcmp(idealName,"AddExactI") == 0 + || strcmp(idealName,"FlagsProj") == 0 || strcmp(idealName,"Bool") == 0 || strcmp(idealName,"Binary") == 0 ) { // Removed ConI from the must_clone list. CPUs that cannot use diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/adlc/formssel.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -2757,14 +2757,18 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format) + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format) : Interface("COND_INTER"), _equal(equal), _equal_format(equal_format), _not_equal(not_equal), _not_equal_format(not_equal_format), _less(less), _less_format(less_format), _greater_equal(greater_equal), _greater_equal_format(greater_equal_format), _less_equal(less_equal), _less_equal_format(less_equal_format), - _greater(greater), _greater_format(greater_format) { + _greater(greater), _greater_format(greater_format), + _overflow(overflow), _overflow_format(overflow_format), + _no_overflow(no_overflow), _no_overflow_format(no_overflow_format) { } CondInterface::~CondInterface() { // not owner of any character arrays @@ -2777,12 +2781,14 @@ // Write info to output files void CondInterface::output(FILE *fp) { Interface::output(fp); - if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); - if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); - if ( _less != NULL ) fprintf(fp," less == %s\n", _less); - if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); - if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); - if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); + if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); + if ( _less != NULL ) fprintf(fp," less == %s\n", _less); + if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); + if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); + if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _overflow != NULL ) fprintf(fp," overflow == %s\n", _overflow); + if ( _no_overflow != NULL ) fprintf(fp," no_overflow == %s\n", _no_overflow); // fprintf(fp,"\n"); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/adlc/formssel.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -798,12 +798,16 @@ const char *_greater_equal; const char *_less_equal; const char *_greater; + const char *_overflow; + const char *_no_overflow; const char *_equal_format; const char *_not_equal_format; const char *_less_format; const char *_greater_equal_format; const char *_less_equal_format; const char *_greater_format; + const char *_overflow_format; + const char *_no_overflow_format; // Public Methods CondInterface(const char* equal, const char* equal_format, @@ -811,7 +815,9 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format); + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format); ~CondInterface(); void dump(); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/adlc/output_h.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -388,6 +388,8 @@ fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print(\"%s\");\n",i,cond->_greater_equal_format); fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print(\"%s\");\n",i,cond->_less_format); fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print(\"%s\");\n",i,cond->_greater_format); + fprintf(fp, " else if( _c%d == BoolTest::overflow ) st->print(\"%s\");\n",i,cond->_overflow_format); + fprintf(fp, " else if( _c%d == BoolTest::no_overflow ) st->print(\"%s\");\n",i,cond->_no_overflow_format); } // Output code that dumps constant values, increment "i" if type is constant @@ -1208,6 +1210,8 @@ fprintf(fp," case BoolTest::ne : return not_equal();\n"); fprintf(fp," case BoolTest::le : return less_equal();\n"); fprintf(fp," case BoolTest::ge : return greater_equal();\n"); + fprintf(fp," case BoolTest::overflow : return overflow();\n"); + fprintf(fp," case BoolTest::no_overflow: return no_overflow();\n"); fprintf(fp," default : ShouldNotReachHere(); return 0;\n"); fprintf(fp," }\n"); fprintf(fp," };\n"); @@ -1373,6 +1377,14 @@ if( greater != NULL ) { define_oper_interface(fp, *oper, _globalNames, "greater", greater); } + const char *overflow = cInterface->_overflow; + if( overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "overflow", overflow); + } + const char *no_overflow = cInterface->_no_overflow; + if( no_overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "no_overflow", no_overflow); + } } // end Conditional Interface // Check if it is a Constant Interface else if (oper->_interface->is_ConstInterface() != NULL ) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1078,14 +1078,17 @@ // replace instructions // first replace the tail, then the call #ifdef ARM - if(load_klass_or_mirror_patch_id && !VM_Version::supports_movw()) { + if((load_klass_or_mirror_patch_id || + stub_id == Runtime1::load_appendix_patching_id) && + !VM_Version::supports_movw()) { nmethod* nm = CodeCache::find_nmethod(instr_pc); address addr = NULL; assert(nm != NULL, "invalid nmethod_pc"); RelocIterator mds(nm, copy_buff, copy_buff + 1); while (mds.next()) { if (mds.type() == relocInfo::oop_type) { - assert(stub_id == Runtime1::load_mirror_patching_id, "wrong stub id"); + assert(stub_id == Runtime1::load_mirror_patching_id || + stub_id == Runtime1::load_appendix_patching_id, "wrong stub id"); oop_Relocation* r = mds.oop_reloc(); addr = (address)r->oop_addr(); break; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1787,7 +1787,7 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_LambdaForm_Hidden; - case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code return _field_Stable; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/classfile/defaultMethods.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -793,7 +793,7 @@ -#ifndef PRODUCT +#ifdef ASSERT // Return true is broad type is a covariant return of narrow type static bool covariant_return_type(BasicType narrow, BasicType broad) { if (narrow == broad) { @@ -804,7 +804,7 @@ } return false; } -#endif // ndef PRODUCT +#endif static int assemble_redirect( BytecodeConstantPool* cp, BytecodeBuffer* buffer, @@ -1095,4 +1095,3 @@ MetadataFactory::free_array(cld, original_ordering); } } - diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -270,7 +270,7 @@ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ - template(sun_invoke_Stable_signature, "Lsun/invoke/Stable;") \ + template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ template(java_lang_invoke_MagicLambdaImpl, "java/lang/invoke/MagicLambdaImpl") \ @@ -631,6 +631,10 @@ do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ \ + do_name(addExact_name,"addExact") \ + do_name(subtractExact_name,"subtractExact") \ + do_name(multiplyExact_name,"multiplyExact") \ + \ do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \ do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \ do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \ @@ -643,6 +647,7 @@ do_intrinsic(_dexp, java_lang_Math, exp_name, double_double_signature, F_S) \ do_intrinsic(_min, java_lang_Math, min_name, int2_int_signature, F_S) \ do_intrinsic(_max, java_lang_Math, max_name, int2_int_signature, F_S) \ + do_intrinsic(_addExact, java_lang_Math, addExact_name, int2_int_signature, F_S) \ \ do_intrinsic(_floatToRawIntBits, java_lang_Float, floatToRawIntBits_name, float_int_signature, F_S) \ do_name( floatToRawIntBits_name, "floatToRawIntBits") \ diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/code/codeCache.cpp --- a/src/share/vm/code/codeCache.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/code/codeCache.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -124,7 +124,6 @@ int CodeCache::_number_of_nmethods_with_dependencies = 0; bool CodeCache::_needs_cache_clean = false; nmethod* CodeCache::_scavenge_root_nmethods = NULL; -nmethod* CodeCache::_saved_nmethods = NULL; int CodeCache::_codemem_full_count = 0; @@ -464,96 +463,11 @@ } #endif //PRODUCT -/** - * Remove and return nmethod from the saved code list in order to reanimate it. - */ -nmethod* CodeCache::reanimate_saved_code(Method* m) { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - nmethod* saved = _saved_nmethods; - nmethod* prev = NULL; - while (saved != NULL) { - if (saved->is_in_use() && saved->method() == m) { - if (prev != NULL) { - prev->set_saved_nmethod_link(saved->saved_nmethod_link()); - } else { - _saved_nmethods = saved->saved_nmethod_link(); - } - assert(saved->is_speculatively_disconnected(), "shouldn't call for other nmethods"); - saved->set_speculatively_disconnected(false); - saved->set_saved_nmethod_link(NULL); - if (PrintMethodFlushing) { - saved->print_on(tty, " ### nmethod is reconnected"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_reconnected compile_id='%3d'", saved->compile_id()); - xtty->method(m); - xtty->stamp(); - xtty->end_elem(); - } - return saved; - } - prev = saved; - saved = saved->saved_nmethod_link(); - } - return NULL; -} - -/** - * Remove nmethod from the saved code list in order to discard it permanently - */ -void CodeCache::remove_saved_code(nmethod* nm) { - // For conc swpr this will be called with CodeCache_lock taken by caller - assert_locked_or_safepoint(CodeCache_lock); - assert(nm->is_speculatively_disconnected(), "shouldn't call for other nmethods"); - nmethod* saved = _saved_nmethods; - nmethod* prev = NULL; - while (saved != NULL) { - if (saved == nm) { - if (prev != NULL) { - prev->set_saved_nmethod_link(saved->saved_nmethod_link()); - } else { - _saved_nmethods = saved->saved_nmethod_link(); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_removed compile_id='%3d'", nm->compile_id()); - xtty->stamp(); - xtty->end_elem(); - } - return; - } - prev = saved; - saved = saved->saved_nmethod_link(); - } - ShouldNotReachHere(); -} - -void CodeCache::speculatively_disconnect(nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); - assert(nm->is_in_use() && !nm->is_speculatively_disconnected(), "should only disconnect live nmethods"); - nm->set_saved_nmethod_link(_saved_nmethods); - _saved_nmethods = nm; - if (PrintMethodFlushing) { - nm->print_on(tty, " ### nmethod is speculatively disconnected"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("nmethod_disconnected compile_id='%3d'", nm->compile_id()); - xtty->method(nm->method()); - xtty->stamp(); - xtty->end_elem(); - } - nm->method()->clear_code(); - nm->set_speculatively_disconnected(true); -} - void CodeCache::gc_prologue() { assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called"); } - void CodeCache::gc_epilogue() { assert_locked_or_safepoint(CodeCache_lock); FOR_ALL_ALIVE_BLOBS(cb) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/code/codeCache.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -57,7 +57,6 @@ static int _number_of_nmethods_with_dependencies; static bool _needs_cache_clean; static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() - static nmethod* _saved_nmethods; // Linked list of speculatively disconnected nmethods. static void verify_if_often() PRODUCT_RETURN; @@ -167,17 +166,12 @@ static size_t capacity() { return _heap->capacity(); } static size_t max_capacity() { return _heap->max_capacity(); } static size_t unallocated_capacity() { return _heap->unallocated_capacity(); } - static bool needs_flushing() { return unallocated_capacity() < CodeCacheFlushingMinimumFreeSpace; } static double reverse_free_ratio(); static bool needs_cache_clean() { return _needs_cache_clean; } static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } static void clear_inline_caches(); // clear all inline caches - static nmethod* reanimate_saved_code(Method* m); - static void remove_saved_code(nmethod* nm); - static void speculatively_disconnect(nmethod* nm); - // Deoptimization static int mark_for_deoptimization(DepChange& changes); #ifdef HOTSWAP diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/code/nmethod.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -462,7 +462,6 @@ _state = alive; _marked_for_reclamation = 0; _has_flushed_dependencies = 0; - _speculatively_disconnected = 0; _has_unsafe_access = 0; _has_method_handle_invokes = 0; _lazy_critical_native = 0; @@ -481,7 +480,6 @@ _osr_link = NULL; _scavenge_root_link = NULL; _scavenge_root_state = 0; - _saved_nmethod_link = NULL; _compiler = NULL; #ifdef HAVE_DTRACE_H @@ -686,6 +684,7 @@ _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); code_buffer->copy_values_to(this); if (ScavengeRootsInCode && detect_scavenge_root_oops()) { @@ -770,6 +769,7 @@ _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); code_buffer->copy_values_to(this); debug_only(verify_scavenge_root_oops()); @@ -842,6 +842,7 @@ _comp_level = comp_level; _compiler = compiler; _orig_pc_offset = orig_pc_offset; + _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); // Section offsets _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); @@ -1176,7 +1177,7 @@ // This is a private interface with the sweeper. void nmethod::mark_as_seen_on_stack() { - assert(is_not_entrant(), "must be a non-entrant method"); + assert(is_alive(), "Must be an alive method"); // Set the traversal mark to ensure that the sweeper does 2 // cleaning passes before moving to zombie. set_stack_traversal_mark(NMethodSweeper::traversal_count()); @@ -1261,7 +1262,7 @@ set_osr_link(NULL); //set_scavenge_root_link(NULL); // done by prune_scavenge_root_nmethods - NMethodSweeper::notify(this); + NMethodSweeper::notify(); } void nmethod::invalidate_osr_method() { @@ -1351,6 +1352,15 @@ nmethod_needs_unregister = true; } + // Must happen before state change. Otherwise we have a race condition in + // nmethod::can_not_entrant_be_converted(). I.e., a method can immediately + // transition its state from 'not_entrant' to 'zombie' without having to wait + // for stack scanning. + if (state == not_entrant) { + mark_as_seen_on_stack(); + OrderAccess::storestore(); + } + // Change state _state = state; @@ -1369,11 +1379,6 @@ HandleMark hm; method()->clear_code(); } - - if (state == not_entrant) { - mark_as_seen_on_stack(); - } - } // leave critical region under Patching_lock // When the nmethod becomes zombie it is no longer alive so the @@ -1416,7 +1421,7 @@ } // Make sweeper aware that there is a zombie method that needs to be removed - NMethodSweeper::notify(this); + NMethodSweeper::notify(); return true; } @@ -1451,10 +1456,6 @@ CodeCache::drop_scavenge_root_nmethod(this); } - if (is_speculatively_disconnected()) { - CodeCache::remove_saved_code(this); - } - #ifdef SHARK ((SharkCompiler *) compiler())->free_compiled_method(insts_begin()); #endif // SHARK diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/code/nmethod.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -119,7 +119,6 @@ // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods - nmethod* _saved_nmethod_link; // from CodeCache::speculatively_disconnect static nmethod* volatile _oops_do_mark_nmethods; nmethod* volatile _oops_do_mark_link; @@ -165,7 +164,6 @@ // protected by CodeCache_lock bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) - bool _speculatively_disconnected; // Marked for potential unload bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) bool _marked_for_deoptimization; // Used for stack deoptimization @@ -180,7 +178,7 @@ unsigned int _has_wide_vectors:1; // Preserve wide vectors at safepoints // Protected by Patching_lock - unsigned char _state; // {alive, not_entrant, zombie, unloaded} + volatile unsigned char _state; // {alive, not_entrant, zombie, unloaded} #ifdef ASSERT bool _oops_are_stale; // indicates that it's no longer safe to access oops section @@ -202,11 +200,18 @@ // not_entrant method removal. Each mark_sweep pass will update // this mark to current sweep invocation count if it is seen on the - // stack. An not_entrant method can be removed when there is no + // stack. An not_entrant method can be removed when there are no // more activations, i.e., when the _stack_traversal_mark is less than // current sweep traversal index. long _stack_traversal_mark; + // The _hotness_counter indicates the hotness of a method. The higher + // the value the hotter the method. The hotness counter of a nmethod is + // set to [(ReservedCodeCacheSize / (1024 * 1024)) * 2] each time the method + // is active while stack scanning (mark_active_nmethods()). The hotness + // counter is decreased (by 1) while sweeping. + int _hotness_counter; + ExceptionCache *_exception_cache; PcDescCache _pc_desc_cache; @@ -382,6 +387,10 @@ int total_size () const; + void dec_hotness_counter() { _hotness_counter--; } + void set_hotness_counter(int val) { _hotness_counter = val; } + int hotness_counter() const { return _hotness_counter; } + // Containment bool consts_contains (address addr) const { return consts_begin () <= addr && addr < consts_end (); } bool insts_contains (address addr) const { return insts_begin () <= addr && addr < insts_end (); } @@ -408,8 +417,8 @@ // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } - bool make_zombie() { return make_not_entrant_or_zombie(zombie); } + bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } + bool make_zombie() { return make_not_entrant_or_zombie(zombie); } // used by jvmti to track if the unload event has been reported bool unload_reported() { return _unload_reported; } @@ -437,9 +446,6 @@ bool has_method_handle_invokes() const { return _has_method_handle_invokes; } void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool is_speculatively_disconnected() const { return _speculatively_disconnected; } - void set_speculatively_disconnected(bool z) { _speculatively_disconnected = z; } - bool is_lazy_critical_native() const { return _lazy_critical_native; } void set_lazy_critical_native(bool z) { _lazy_critical_native = z; } @@ -499,9 +505,6 @@ nmethod* scavenge_root_link() const { return _scavenge_root_link; } void set_scavenge_root_link(nmethod *n) { _scavenge_root_link = n; } - nmethod* saved_nmethod_link() const { return _saved_nmethod_link; } - void set_saved_nmethod_link(nmethod *n) { _saved_nmethod_link = n; } - public: // Sweeper support diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -634,19 +634,36 @@ NMethodSweeper::possibly_sweep(); MutexLocker locker(lock()); - // Wait for an available CompileTask. + // If _first is NULL we have no more compile jobs. There are two reasons for + // having no compile jobs: First, we compiled everything we wanted. Second, + // we ran out of code cache so compilation has been disabled. In the latter + // case we perform code cache sweeps to free memory such that we can re-enable + // compilation. while (_first == NULL) { - // There is no work to be done right now. Wait. - if (UseCodeCacheFlushing && (!CompileBroker::should_compile_new_jobs() || CodeCache::needs_flushing())) { - // During the emergency sweeping periods, wake up and sweep occasionally - bool timedout = lock()->wait(!Mutex::_no_safepoint_check_flag, NmethodSweepCheckInterval*1000); - if (timedout) { + if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs()) { + // Wait a certain amount of time to possibly do another sweep. + // We must wait until stack scanning has happened so that we can + // transition a method's state from 'not_entrant' to 'zombie'. + long wait_time = NmethodSweepCheckInterval * 1000; + if (FLAG_IS_DEFAULT(NmethodSweepCheckInterval)) { + // Only one thread at a time can do sweeping. Scale the + // wait time according to the number of compiler threads. + // As a result, the next sweep is likely to happen every 100ms + // with an arbitrary number of threads that do sweeping. + wait_time = 100 * CICompilerCount; + } + bool timeout = lock()->wait(!Mutex::_no_safepoint_check_flag, wait_time); + if (timeout) { MutexUnlocker ul(lock()); - // When otherwise not busy, run nmethod sweeping NMethodSweeper::possibly_sweep(); } } else { - // During normal operation no need to wake up on timer + // If there are no compilation tasks and we can compile new jobs + // (i.e., there is enough free space in the code cache) there is + // no need to invoke the sweeper. As a result, the hotness of methods + // remains unchanged. This behavior is desired, since we want to keep + // the stable state, i.e., we do not want to evict methods from the + // code cache if it is unnecessary. lock()->wait(); } } @@ -1227,16 +1244,9 @@ return method_code; } } - if (method->is_not_compilable(comp_level)) return NULL; - - if (UseCodeCacheFlushing) { - nmethod* saved = CodeCache::reanimate_saved_code(method()); - if (saved != NULL) { - method->set_code(method, saved); - return saved; - } + if (method->is_not_compilable(comp_level)) { + return NULL; } - } else { // osr compilation #ifndef TIERED @@ -1585,9 +1595,6 @@ if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) { // the code cache is really full handle_full_code_cache(); - } else if (UseCodeCacheFlushing && CodeCache::needs_flushing()) { - // Attempt to start cleaning the code cache while there is still a little headroom - NMethodSweeper::handle_full_code_cache(false); } CompileTask* task = queue->get(); @@ -1943,7 +1950,11 @@ } #endif if (UseCodeCacheFlushing) { - NMethodSweeper::handle_full_code_cache(true); + // Since code cache is full, immediately stop new compiles + if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { + NMethodSweeper::log_sweep("disable_compiler"); + NMethodSweeper::possibly_sweep(); + } } else { UseCompiler = false; AlwaysCompileLoopMethods = false; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -81,7 +81,7 @@ size_t* marked_bytes_array, BitMap* task_card_bm) { G1CollectedHeap* g1h = _g1h; - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); + CardTableModRefBS* ct_bs = g1h->g1_barrier_set(); HeapWord* start = mr.start(); HeapWord* end = mr.end(); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1CardCounts.cpp --- a/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -65,9 +65,7 @@ // threshold limit is no more than this. guarantee(G1ConcRSHotCardLimit <= max_jubyte, "sanity"); - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ct_bs = (CardTableModRefBS*)bs; + _ct_bs = _g1h->g1_barrier_set(); _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start()); // Allocate/Reserve the counts table diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -125,10 +125,8 @@ int _histo[256]; public: ClearLoggedCardTableEntryClosure() : - _calls(0) + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); for (int i = 0; i < 256; i++) _histo[i] = 0; } bool do_card_ptr(jbyte* card_ptr, int worker_i) { @@ -158,11 +156,8 @@ CardTableModRefBS* _ctbs; public: RedirtyLoggedCardTableEntryClosure() : - _calls(0) - { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); - } + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) {} + bool do_card_ptr(jbyte* card_ptr, int worker_i) { if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) { _calls++; @@ -478,7 +473,7 @@ void G1CollectedHeap::check_ct_logs_at_safepoint() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + CardTableModRefBS* ct_bs = g1_barrier_set(); // Count the dirty cards at the start. CountNonCleanMemRegionClosure count1(this); @@ -1205,7 +1200,7 @@ }; void G1CollectedHeap::clear_rsets_post_compaction() { - PostMCRemSetClearClosure rs_clear(this, mr_bs()); + PostMCRemSetClearClosure rs_clear(this, g1_barrier_set()); heap_region_iterate(&rs_clear); } @@ -1777,7 +1772,6 @@ } bool G1CollectedHeap::expand(size_t expand_bytes) { - size_t old_mem_size = _g1_storage.committed_size(); size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_size_up(aligned_expand_bytes, HeapRegion::GrainBytes); @@ -1787,6 +1781,13 @@ ergo_format_byte("attempted expansion amount"), expand_bytes, aligned_expand_bytes); + if (_g1_storage.uncommitted_size() == 0) { + ergo_verbose0(ErgoHeapSizing, + "did not expand the heap", + ergo_format_reason("heap already fully expanded")); + return false; + } + // First commit the memory. HeapWord* old_end = (HeapWord*) _g1_storage.high(); bool successful = _g1_storage.expand_by(aligned_expand_bytes); @@ -1845,7 +1846,6 @@ } void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { - size_t old_mem_size = _g1_storage.committed_size(); size_t aligned_shrink_bytes = ReservedSpace::page_align_size_down(shrink_bytes); aligned_shrink_bytes = align_size_down(aligned_shrink_bytes, @@ -2045,20 +2045,13 @@ // 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()); - if (barrier_set()->is_a(BarrierSet::ModRef)) { - _mr_bs = (ModRefBarrierSet*)_barrier_set; - } else { - vm_exit_during_initialization("G1 requires a mod ref bs."); + if (!barrier_set()->is_a(BarrierSet::G1SATBCTLogging)) { + vm_exit_during_initialization("G1 requires a G1SATBLoggingCardTableModRefBS"); return JNI_ENOMEM; } // Also create a G1 rem set. - if (mr_bs()->is_a(BarrierSet::CardTableModRef)) { - _g1_rem_set = new G1RemSet(this, (CardTableModRefBS*)mr_bs()); - } else { - vm_exit_during_initialization("G1 requires a cardtable mod ref bs."); - return JNI_ENOMEM; - } + _g1_rem_set = new G1RemSet(this, g1_barrier_set()); // Carve out the G1 part of the heap. @@ -3681,6 +3674,11 @@ assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); // Fill TLAB's and such ensure_parsability(true); + + if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && + (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { + g1_rem_set()->print_periodic_summary_info("Before GC RS summary"); + } } void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { @@ -3689,7 +3687,7 @@ (G1SummarizeRSetStatsPeriod > 0) && // we are at the end of the GC. Total collections has already been increased. ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_periodic_summary_info(); + g1_rem_set()->print_periodic_summary_info("After GC RS summary"); } // FIXME: what is this about? @@ -4550,7 +4548,7 @@ : _g1h(g1h), _refs(g1h->task_queue(queue_num)), _dcq(&g1h->dirty_card_queue_set()), - _ct_bs((CardTableModRefBS*)_g1h->barrier_set()), + _ct_bs(g1h->g1_barrier_set()), _g1_rem(g1h->g1_rem_set()), _hash_seed(17), _queue_num(queue_num), _term_attempts(0), @@ -5979,11 +5977,11 @@ } class G1ParCleanupCTTask : public AbstractGangTask { - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; HeapRegion* volatile _su_head; public: - G1ParCleanupCTTask(CardTableModRefBS* ct_bs, + G1ParCleanupCTTask(G1SATBCardTableModRefBS* ct_bs, G1CollectedHeap* g1h) : AbstractGangTask("G1 Par Cleanup CT Task"), _ct_bs(ct_bs), _g1h(g1h) { } @@ -6006,9 +6004,9 @@ #ifndef PRODUCT class G1VerifyCardTableCleanup: public HeapRegionClosure { G1CollectedHeap* _g1h; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: - G1VerifyCardTableCleanup(G1CollectedHeap* g1h, CardTableModRefBS* ct_bs) + G1VerifyCardTableCleanup(G1CollectedHeap* g1h, G1SATBCardTableModRefBS* ct_bs) : _g1h(g1h), _ct_bs(ct_bs) { } virtual bool doHeapRegion(HeapRegion* r) { if (r->is_survivor()) { @@ -6022,7 +6020,7 @@ void G1CollectedHeap::verify_not_dirty_region(HeapRegion* hr) { // All of the region should be clean. - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->end()); ct_bs->verify_not_dirty_region(mr); } @@ -6035,13 +6033,13 @@ // not dirty that area (one less thing to have to do while holding // a lock). So we can only verify that [bottom(),pre_dummy_top()] // is dirty. - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->pre_dummy_top()); ct_bs->verify_dirty_region(mr); } void G1CollectedHeap::verify_dirty_young_list(HeapRegion* head) { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); for (HeapRegion* hr = head; hr != NULL; hr = hr->get_next_young_region()) { verify_dirty_region(hr); } @@ -6053,7 +6051,7 @@ #endif void G1CollectedHeap::cleanUpCardTable() { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (barrier_set()); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); double start = os::elapsedTime(); { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -31,6 +31,7 @@ #include "gc_implementation/g1/g1HRPrinter.hpp" #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" #include "gc_implementation/g1/heapRegionSets.hpp" @@ -791,8 +792,6 @@ // The g1 remembered set of the heap. G1RemSet* _g1_rem_set; - // And it's mod ref barrier set, used to track updates for the above. - ModRefBarrierSet* _mr_bs; // A set of cards that cover the objects for which the Rsets should be updated // concurrently after the collection. @@ -1127,7 +1126,6 @@ // The rem set and barrier set. G1RemSet* g1_rem_set() const { return _g1_rem_set; } - ModRefBarrierSet* mr_bs() const { return _mr_bs; } unsigned get_gc_time_stamp() { return _gc_time_stamp; @@ -1346,6 +1344,10 @@ virtual bool is_in_closed_subset(const void* p) const; + G1SATBCardTableModRefBS* g1_barrier_set() { + return (G1SATBCardTableModRefBS*) barrier_set(); + } + // This resets the card table to all zeros. It is used after // a collection pause which used the card table to claim cards. void cleanUpCardTable(); @@ -1875,7 +1877,7 @@ G1CollectedHeap* _g1h; RefToScanQueue* _refs; DirtyCardQueue _dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; G1ParGCAllocBufferContainer _surviving_alloc_buffer; @@ -1914,7 +1916,7 @@ void add_to_undo_waste(size_t waste) { _undo_waste += waste; } DirtyCardQueue& dirty_card_queue() { return _dcq; } - CardTableModRefBS* ctbs() { return _ct_bs; } + G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } template void immediate_rs_update(HeapRegion* from, T* p, int tid) { if (!from->is_survivor()) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -134,7 +134,7 @@ assert(containing_hr->is_in(end - 1), "it should also contain end - 1"); MemRegion mr(start, end); - ((CardTableModRefBS*)_g1h->barrier_set())->dirty(mr); + g1_barrier_set()->dirty(mr); } inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1EvacFailure.hpp --- a/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -41,11 +41,11 @@ private: G1CollectedHeap* _g1; DirtyCardQueue *_dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} + _g1(g1), _ct_bs(_g1->g1_barrier_set()), _dcq(dcq) {} virtual void do_oop(narrowOop* p) { do_oop_work(p); } virtual void do_oop( oop* p) { do_oop_work(p); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -220,7 +220,7 @@ public: G1PrepareCompactClosure(CompactibleSpace* cs) : _g1h(G1CollectedHeap::heap()), - _mrbs(G1CollectedHeap::heap()->mr_bs()), + _mrbs(_g1h->g1_barrier_set()), _cp(NULL, cs, cs->initialize_threshold()), _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -83,7 +83,9 @@ for (uint i = 0; i < n_workers(); i++) { _cset_rs_update_cl[i] = NULL; } - _prev_period_summary.initialize(this, n_workers()); + if (G1SummarizeRSetStats) { + _prev_period_summary.initialize(this); + } } G1RemSet::~G1RemSet() { @@ -109,7 +111,7 @@ CodeBlobToOopClosure* _code_root_cl; G1BlockOffsetSharedArray* _bot_shared; - CardTableModRefBS *_ct_bs; + G1SATBCardTableModRefBS *_ct_bs; double _strong_code_root_scan_time_sec; int _worker_i; @@ -130,7 +132,7 @@ { _g1h = G1CollectedHeap::heap(); _bot_shared = _g1h->bot_shared(); - _ct_bs = (CardTableModRefBS*) (_g1h->barrier_set()); + _ct_bs = _g1h->g1_barrier_set(); _block_size = MAX2(G1RSetScanBlockSize, 1); } @@ -505,12 +507,7 @@ ScrubRSClosure(BitMap* region_bm, BitMap* card_bm) : _g1h(G1CollectedHeap::heap()), _region_bm(region_bm), _card_bm(card_bm), - _ctbs(NULL) - { - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ctbs = (CardTableModRefBS*)bs; - } + _ctbs(_g1h->g1_barrier_set()) {} bool doHeapRegion(HeapRegion* r) { if (!r->continuesHumongous()) { @@ -731,19 +728,19 @@ return has_refs_into_cset; } -void G1RemSet::print_periodic_summary_info() { +void G1RemSet::print_periodic_summary_info(const char* header) { G1RemSetSummary current; - current.initialize(this, n_workers()); + current.initialize(this); _prev_period_summary.subtract_from(¤t); - print_summary_info(&_prev_period_summary); + print_summary_info(&_prev_period_summary, header); _prev_period_summary.set(¤t); } void G1RemSet::print_summary_info() { G1RemSetSummary current; - current.initialize(this, n_workers()); + current.initialize(this); print_summary_info(¤t, " Cumulative RS summary"); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1RemSet.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -145,7 +145,7 @@ virtual void print_summary_info(); // Print accumulated summary info from the last time called. - virtual void print_periodic_summary_info(); + virtual void print_periodic_summary_info(const char* header); // Prepare remembered set for verification. virtual void prepare_for_verify(); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -77,12 +77,12 @@ return _rs_threads_vtimes[thread]; } -void G1RemSetSummary::initialize(G1RemSet* remset, uint num_workers) { +void G1RemSetSummary::initialize(G1RemSet* remset) { assert(_rs_threads_vtimes == NULL, "just checking"); assert(remset != NULL, "just checking"); _remset = remset; - _num_vtimes = num_workers; + _num_vtimes = ConcurrentG1Refine::thread_num(); _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC); memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); @@ -125,25 +125,115 @@ _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; } +static double percent_of(size_t numerator, size_t denominator) { + if (denominator != 0) { + return (double)numerator / denominator * 100.0f; + } else { + return 0.0f; + } +} + +static size_t round_to_K(size_t value) { + return value / K; +} + +class RegionTypeCounter VALUE_OBJ_CLASS_SPEC { +private: + const char* _name; + + size_t _rs_mem_size; + size_t _cards_occupied; + size_t _amount; + + size_t _code_root_mem_size; + size_t _code_root_elems; + + double rs_mem_size_percent_of(size_t total) { + return percent_of(_rs_mem_size, total); + } + + double cards_occupied_percent_of(size_t total) { + return percent_of(_cards_occupied, total); + } + + double code_root_mem_size_percent_of(size_t total) { + return percent_of(_code_root_mem_size, total); + } + + double code_root_elems_percent_of(size_t total) { + return percent_of(_code_root_elems, total); + } + + size_t amount() const { return _amount; } + +public: + + RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0), + _amount(0), _code_root_mem_size(0), _code_root_elems(0) { } + + void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size, + size_t code_root_elems) { + _rs_mem_size += rs_mem_size; + _cards_occupied += cards_occupied; + _code_root_mem_size += code_root_mem_size; + _code_root_elems += code_root_elems; + _amount++; + } + + size_t rs_mem_size() const { return _rs_mem_size; } + size_t cards_occupied() const { return _cards_occupied; } + + size_t code_root_mem_size() const { return _code_root_mem_size; } + size_t code_root_elems() const { return _code_root_elems; } + + void print_rs_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name); + } + + void print_cards_occupied_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) entries by %zd %s regions", cards_occupied(), cards_occupied_percent_of(total), amount(), _name); + } + + void print_code_root_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name); + } + + void print_code_root_elems_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) elements by %zd %s regions", code_root_elems(), code_root_elems_percent_of(total), amount(), _name); + } +}; + + class HRRSStatsIter: public HeapRegionClosure { - size_t _occupied; +private: + RegionTypeCounter _young; + RegionTypeCounter _humonguous; + RegionTypeCounter _free; + RegionTypeCounter _old; + RegionTypeCounter _all; - size_t _total_rs_mem_sz; size_t _max_rs_mem_sz; HeapRegion* _max_rs_mem_sz_region; - size_t _total_code_root_mem_sz; + size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } + size_t total_cards_occupied() const { return _all.cards_occupied(); } + + size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } + HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } + size_t _max_code_root_mem_sz; HeapRegion* _max_code_root_mem_sz_region; + + size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } + size_t total_code_root_elems() const { return _all.code_root_elems(); } + + size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } + HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } + public: - HRRSStatsIter() : - _occupied(0), - _total_rs_mem_sz(0), - _max_rs_mem_sz(0), - _max_rs_mem_sz_region(NULL), - _total_code_root_mem_sz(0), - _max_code_root_mem_sz(0), - _max_code_root_mem_sz_region(NULL) + HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"), + _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL), + _max_rs_mem_sz(0), _max_code_root_mem_sz(0) {} bool doHeapRegion(HeapRegion* r) { @@ -156,46 +246,95 @@ _max_rs_mem_sz = rs_mem_sz; _max_rs_mem_sz_region = r; } - _total_rs_mem_sz += rs_mem_sz; - + size_t occupied_cards = hrrs->occupied(); size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); - if (code_root_mem_sz > _max_code_root_mem_sz) { - _max_code_root_mem_sz = code_root_mem_sz; + if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz_region = r; } - _total_code_root_mem_sz += code_root_mem_sz; + size_t code_root_elems = hrrs->strong_code_roots_list_length(); - size_t occ = hrrs->occupied(); - _occupied += occ; + RegionTypeCounter* current = NULL; + if (r->is_young()) { + current = &_young; + } else if (r->isHumongous()) { + current = &_humonguous; + } else if (r->is_empty()) { + current = &_free; + } else { + current = &_old; + } + current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); + _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); + return false; } - size_t total_rs_mem_sz() { return _total_rs_mem_sz; } - size_t max_rs_mem_sz() { return _max_rs_mem_sz; } - HeapRegion* max_rs_mem_sz_region() { return _max_rs_mem_sz_region; } - size_t total_code_root_mem_sz() { return _total_code_root_mem_sz; } - size_t max_code_root_mem_sz() { return _max_code_root_mem_sz; } - HeapRegion* max_code_root_mem_sz_region() { return _max_code_root_mem_sz_region; } - size_t occupied() { return _occupied; } + + void print_summary_on(outputStream* out) { + RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL }; + + out->print_cr("\n Current rem set statistics"); + out->print_cr(" Total per region rem sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_rs_mem_info_on(out, total_rs_mem_sz()); + } + + out->print_cr(" Static structures = "SIZE_FORMAT"K," + " free_lists = "SIZE_FORMAT"K.", + round_to_K(HeapRegionRemSet::static_mem_size()), + round_to_K(HeapRegionRemSet::fl_mem_size())); + + out->print_cr(" "SIZE_FORMAT" occupied cards represented.", + total_cards_occupied()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_cards_occupied_info_on(out, total_cards_occupied()); + } + + // Largest sized rem set region statistics + HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); + out->print_cr(" Region with largest rem set = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", + HR_FORMAT_PARAMS(max_rs_mem_sz_region()), + round_to_K(rem_set->mem_size()), + round_to_K(rem_set->occupied())); + + // Strong code root statistics + HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); + out->print_cr(" Total heap region code root sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_code_root_mem_sz()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); + } + + out->print_cr(" "SIZE_FORMAT" code roots represented.", + total_code_root_elems()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_elems_info_on(out, total_code_root_elems()); + } + + out->print_cr(" Region with largest amount of code roots = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", + HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()), + round_to_K(max_code_root_rem_set->strong_code_roots_list_length())); + } }; -double calc_percentage(size_t numerator, size_t denominator) { - if (denominator != 0) { - return (double)numerator / denominator * 100.0; - } else { - return 0.0f; - } -} - void G1RemSetSummary::print_on(outputStream* out) { - out->print_cr("\n Concurrent RS processed "SIZE_FORMAT" cards", + out->print_cr("\n Recent concurrent refinement statistics"); + out->print_cr(" Processed "SIZE_FORMAT" cards", num_concurrent_refined_cards()); out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", num_processed_buf_total(), - calc_percentage(num_processed_buf_rs_threads(), num_processed_buf_total())); + percent_of(num_processed_buf_rs_threads(), num_processed_buf_total())); out->print_cr(" %8d (%5.1f%%) by mutator threads.", num_processed_buf_mutator(), - calc_percentage(num_processed_buf_mutator(), num_processed_buf_total())); + percent_of(num_processed_buf_mutator(), num_processed_buf_total())); + out->print_cr(" Did %d coarsenings.", num_coarsenings()); out->print_cr(" Concurrent RS threads times (s)"); out->print(" "); for (uint i = 0; i < _num_vtimes; i++) { @@ -207,33 +346,5 @@ HRRSStatsIter blk; G1CollectedHeap::heap()->heap_region_iterate(&blk); - // RemSet stats - out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_rs_mem_sz()/K, blk.max_rs_mem_sz()/K); - out->print_cr(" Static structures = "SIZE_FORMAT"K," - " free_lists = "SIZE_FORMAT"K.", - HeapRegionRemSet::static_mem_size() / K, - HeapRegionRemSet::fl_mem_size() / K); - out->print_cr(" "SIZE_FORMAT" occupied cards represented.", - blk.occupied()); - HeapRegion* max_rs_mem_sz_region = blk.max_rs_mem_sz_region(); - HeapRegionRemSet* max_rs_rem_set = max_rs_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", - HR_FORMAT_PARAMS(max_rs_mem_sz_region), - (max_rs_rem_set->mem_size() + K - 1)/K, - (max_rs_rem_set->occupied() + K - 1)/K); - out->print_cr(" Did %d coarsenings.", num_coarsenings()); - // Strong code root stats - out->print_cr(" Total heap region code-root set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_code_root_mem_sz()/K, blk.max_code_root_mem_sz()/K); - HeapRegion* max_code_root_mem_sz_region = blk.max_code_root_mem_sz_region(); - HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", - HR_FORMAT_PARAMS(max_code_root_mem_sz_region), - (max_code_root_rem_set->strong_code_roots_mem_size() + K - 1)/K, - (max_code_root_rem_set->strong_code_roots_list_length())); + blk.print_summary_on(out); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -84,7 +84,7 @@ void subtract_from(G1RemSetSummary* other); // initialize and get the first sampling - void initialize(G1RemSet* remset, uint num_workers); + void initialize(G1RemSet* remset); void print_on(outputStream* out); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -64,6 +64,27 @@ } } +bool G1SATBCardTableModRefBS::mark_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + // It's already processed + if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { + return false; + } + // Cached bit can be installed either on a clean card or on a claimed card. + jbyte new_val = val; + if (val == clean_card_val()) { + new_val = (jbyte)deferred_card_val(); + } else { + if (val & claimed_card_val()) { + new_val = val | (jbyte)deferred_card_val(); + } + } + if (new_val != val) { + Atomic::cmpxchg(new_val, &_byte_map[card_index], val); + } + return true; +} + G1SATBCardTableLoggingModRefBS:: G1SATBCardTableLoggingModRefBS(MemRegion whole_heap, int max_covered_regions) : diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -89,6 +89,42 @@ write_ref_array_pre_work(dst, count); } } + +/* + Claimed and deferred bits are used together in G1 during the evacuation + pause. These bits can have the following state transitions: + 1. The claimed bit can be put over any other card state. Except that + the "dirty -> dirty and claimed" transition is checked for in + G1 code and is not used. + 2. Deferred bit can be set only if the previous state of the card + was either clean or claimed. mark_card_deferred() is wait-free. + We do not care if the operation is be successful because if + it does not it will only result in duplicate entry in the update + buffer because of the "cache-miss". So it's not worth spinning. + */ + + bool is_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); + } + + void set_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + if (val == clean_card_val()) { + val = (jbyte)claimed_card_val(); + } else { + val |= (jbyte)claimed_card_val(); + } + _byte_map[card_index] = val; + } + + bool mark_card_deferred(size_t card_index); + + bool is_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); + } + }; // Adds card-table logging to the post-barrier. diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -40,10 +40,8 @@ void initialize_flags() { // Do basic sizing work - this->TwoGenerationCollectorPolicy::initialize_flags(); + TwoGenerationCollectorPolicy::initialize_flags(); - // If the user hasn't explicitly set the number of worker - // threads, set the count. assert(UseSerialGC || !FLAG_IS_DEFAULT(ParallelGCThreads) || (ParallelGCThreads > 0), diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -53,7 +53,6 @@ // Forward decls class elapsedTimer; -class GenerationSizer; class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { friend class PSGCAdaptivePolicyCounters; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -26,7 +26,6 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -27,7 +27,6 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/parallelScavenge/pcTasks.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -27,7 +27,6 @@ #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" -#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -423,60 +423,6 @@ inline_write_ref_field(field, newVal); } -/* - Claimed and deferred bits are used together in G1 during the evacuation - pause. These bits can have the following state transitions: - 1. The claimed bit can be put over any other card state. Except that - the "dirty -> dirty and claimed" transition is checked for in - G1 code and is not used. - 2. Deferred bit can be set only if the previous state of the card - was either clean or claimed. mark_card_deferred() is wait-free. - We do not care if the operation is be successful because if - it does not it will only result in duplicate entry in the update - buffer because of the "cache-miss". So it's not worth spinning. - */ - - -bool CardTableModRefBS::claim_card(size_t card_index) { - jbyte val = _byte_map[card_index]; - assert(val != dirty_card_val(), "Shouldn't claim a dirty card"); - while (val == clean_card_val() || - (val & (clean_card_mask_val() | claimed_card_val())) != claimed_card_val()) { - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)claimed_card_val(); - } else { - new_val = val | (jbyte)claimed_card_val(); - } - jbyte res = Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - if (res == val) { - return true; - } - val = res; - } - return false; -} - -bool CardTableModRefBS::mark_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - // It's already processed - if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { - return false; - } - // Cached bit can be installed either on a clean card or on a claimed card. - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)deferred_card_val(); - } else { - if (val & claimed_card_val()) { - new_val = val | (jbyte)deferred_card_val(); - } - } - if (new_val != val) { - Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - } - return true; -} void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr, diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/cardTableModRefBS.hpp --- a/src/share/vm/memory/cardTableModRefBS.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/cardTableModRefBS.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -339,34 +339,10 @@ _byte_map[card_index] = dirty_card_val(); } - bool is_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); - } - - void set_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - if (val == clean_card_val()) { - val = (jbyte)claimed_card_val(); - } else { - val |= (jbyte)claimed_card_val(); - } - _byte_map[card_index] = val; - } - - bool claim_card(size_t card_index); - bool is_card_clean(size_t card_index) { return _byte_map[card_index] == clean_card_val(); } - bool is_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); - } - - bool mark_card_deferred(size_t card_index); - // Card marking array base (adjusted for heap low boundary) // This would be the 0th element of _byte_map, if the heap started at 0x0. // But since the heap starts at some higher address, this points to somewhere diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/collectorPolicy.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -64,19 +64,21 @@ vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); } - if (!is_size_aligned(MaxMetaspaceSize, max_alignment())) { - FLAG_SET_ERGO(uintx, MaxMetaspaceSize, - restricted_align_down(MaxMetaspaceSize, max_alignment())); - } + // Do not use FLAG_SET_ERGO to update MaxMetaspaceSize, since this will + // override if MaxMetaspaceSize was set on the command line or not. + // This information is needed later to conform to the specification of the + // java.lang.management.MemoryUsage API. + // + // Ideally, we would be able to set the default value of MaxMetaspaceSize in + // globals.hpp to the aligned value, but this is not possible, since the + // alignment depends on other flags being parsed. + MaxMetaspaceSize = restricted_align_down(MaxMetaspaceSize, max_alignment()); if (MetaspaceSize > MaxMetaspaceSize) { - FLAG_SET_ERGO(uintx, MetaspaceSize, MaxMetaspaceSize); + MetaspaceSize = MaxMetaspaceSize; } - if (!is_size_aligned(MetaspaceSize, min_alignment())) { - FLAG_SET_ERGO(uintx, MetaspaceSize, - restricted_align_down(MetaspaceSize, min_alignment())); - } + MetaspaceSize = restricted_align_down(MetaspaceSize, min_alignment()); assert(MetaspaceSize <= MaxMetaspaceSize, "Must be"); @@ -135,15 +137,8 @@ GenRemSet* CollectorPolicy::create_rem_set(MemRegion whole_heap, int max_covered_regions) { - switch (rem_set_name()) { - case GenRemSet::CardTable: { - CardTableRS* res = new CardTableRS(whole_heap, max_covered_regions); - return res; - } - default: - guarantee(false, "unrecognized GenRemSet::Name"); - return NULL; - } + assert(rem_set_name() == GenRemSet::CardTable, "unrecognized GenRemSet::Name"); + return new CardTableRS(whole_heap, max_covered_regions); } void CollectorPolicy::cleared_all_soft_refs() { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/genRemSet.cpp --- a/src/share/vm/memory/genRemSet.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/genRemSet.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -32,13 +32,8 @@ // enumeration.) uintx GenRemSet::max_alignment_constraint(Name nm) { - switch (nm) { - case GenRemSet::CardTable: - return CardTableRS::ct_max_alignment_constraint(); - default: - guarantee(false, "Unrecognized GenRemSet type."); - return (0); // Make Windows compiler happy - } + assert(nm == GenRemSet::CardTable, "Unrecognized GenRemSet type."); + return CardTableRS::ct_max_alignment_constraint(); } class HasAccumulatedModifiedOopsClosure : public KlassClosure { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/metaspace.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -3104,7 +3104,7 @@ MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) { // DumpSharedSpaces doesn't use class metadata area (yet) // Also, don't use class_vsm() unless UseCompressedClassPointers is true. - if (mdtype == ClassType && using_class_space()) { + if (is_class_space_allocation(mdtype)) { return class_vsm()->allocate(word_size); } else { return vsm()->allocate(word_size); @@ -3252,8 +3252,8 @@ MetaspaceAux::dump(gclog_or_tty); } // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support - const char* space_string = (mdtype == ClassType) ? "Compressed class space" : - "Metadata space"; + const char* space_string = is_class_space_allocation(mdtype) ? "Compressed class space" : + "Metadata space"; report_java_out_of_memory(space_string); if (JvmtiExport::should_post_resource_exhausted()) { @@ -3261,7 +3261,7 @@ JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR, space_string); } - if (mdtype == ClassType) { + if (is_class_space_allocation(mdtype)) { THROW_OOP_0(Universe::out_of_memory_error_class_metaspace()); } else { THROW_OOP_0(Universe::out_of_memory_error_metaspace()); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/memory/metaspace.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -235,6 +235,9 @@ return NOT_LP64(false) LP64_ONLY(UseCompressedClassPointers && !DumpSharedSpaces); } + static bool is_class_space_allocation(MetadataType mdType) { + return mdType == ClassType && using_class_space(); + } }; class MetaspaceAux : AllStatic { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/oops/method.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -901,16 +901,6 @@ // This function must not hit a safepoint! address Method::verified_code_entry() { debug_only(No_Safepoint_Verifier nsv;) - nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code); - if (code == NULL && UseCodeCacheFlushing) { - nmethod *saved_code = CodeCache::reanimate_saved_code(this); - if (saved_code != NULL) { - methodHandle method(this); - assert( ! saved_code->is_osr_method(), "should not get here for osr" ); - set_code( method, saved_code ); - } - } - assert(_from_compiled_entry != NULL, "must be set"); return _from_compiled_entry; } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/c2_globals.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -636,7 +636,9 @@ \ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ - + \ + product(bool, UseMathExactIntrinsics, true, \ + "Enables intrinsification of various java.lang.Math funcitons") C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/callGenerator.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -65,6 +65,8 @@ virtual bool is_predicted() const { return false; } // is_trap: Does not return to the caller. (E.g., uncommon trap.) virtual bool is_trap() const { return false; } + // does_virtual_dispatch: Should try inlining as normal method first. + virtual bool does_virtual_dispatch() const { return false; } // is_late_inline: supports conversion of call into an inline virtual bool is_late_inline() const { return false; } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/classes.cpp --- a/src/share/vm/opto/classes.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/classes.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -32,6 +32,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/multnode.hpp" #include "opto/node.hpp" diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/classes.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -29,6 +29,7 @@ macro(AbsF) macro(AbsI) macro(AddD) +macro(AddExactI) macro(AddF) macro(AddI) macro(AddL) @@ -133,6 +134,7 @@ macro(ExpD) macro(FastLock) macro(FastUnlock) +macro(FlagsProj) macro(Goto) macro(Halt) macro(If) @@ -167,6 +169,7 @@ macro(LoopLimit) macro(Mach) macro(MachProj) +macro(MathExact) macro(MaxI) macro(MemBarAcquire) macro(MemBarAcquireLock) diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/doCall.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -110,6 +110,7 @@ // then we return it as the inlined version of the call. // We do this before the strict f.p. check below because the // intrinsics handle strict f.p. correctly. + CallGenerator* cg_intrinsic = NULL; if (allow_inline && allow_intrinsics) { CallGenerator* cg = find_intrinsic(callee, call_does_dispatch); if (cg != NULL) { @@ -121,7 +122,16 @@ cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); } } - return cg; + + // If intrinsic does the virtual dispatch, we try to use the type profile + // first, and hopefully inline it as the regular virtual call below. + // We will retry the intrinsic if nothing had claimed it afterwards. + if (cg->does_virtual_dispatch()) { + cg_intrinsic = cg; + cg = NULL; + } else { + return cg; + } } } @@ -266,6 +276,13 @@ } } + // Nothing claimed the intrinsic, we go with straight-forward inlining + // for already discovered intrinsic. + if (allow_inline && allow_intrinsics && cg_intrinsic != NULL) { + assert(cg_intrinsic->does_virtual_dispatch(), "sanity"); + return cg_intrinsic; + } + // There was no special inlining tactic, or it bailed out. // Use a more generic tactic, like a simple call. if (call_does_dispatch) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/graphKit.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -3849,9 +3849,9 @@ const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* value_field_type = string_type->add_offset(value_offset); - int value_field_idx = C->get_alias_index(value_field_type); - store_to_memory(ctrl, basic_plus_adr(str, value_offset), - value, T_OBJECT, value_field_idx); + + store_oop_to_object(ctrl, str, basic_plus_adr(str, value_offset), value_field_type, + value, TypeAryPtr::CHARS, T_OBJECT); } void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/ifnode.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -76,6 +76,7 @@ if( !i1->is_Bool() ) return NULL; BoolNode *b = i1->as_Bool(); Node *cmp = b->in(1); + if( cmp->is_FlagsProj() ) return NULL; if( !cmp->is_Cmp() ) return NULL; i1 = cmp->in(1); if( i1 == NULL || !i1->is_Phi() ) return NULL; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/lcm.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -472,6 +472,13 @@ break; } + // For nodes that produce a FlagsProj, make the node adjacent to the + // use of the FlagsProj + if (use->is_FlagsProj() && get_block_for_node(use) == block) { + found_machif = true; + break; + } + // More than this instruction pending for successor to be ready, // don't choose this if other opportunities are ready if (ready_cnt.at(use->_idx) > 1) diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/library_call.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -32,6 +32,7 @@ #include "opto/callGenerator.hpp" #include "opto/cfgnode.hpp" #include "opto/idealKit.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" @@ -46,19 +47,22 @@ private: bool _is_virtual; bool _is_predicted; + bool _does_virtual_dispatch; vmIntrinsics::ID _intrinsic_id; public: - LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, vmIntrinsics::ID id) + LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, bool does_virtual_dispatch, vmIntrinsics::ID id) : InlineCallGenerator(m), _is_virtual(is_virtual), _is_predicted(is_predicted), + _does_virtual_dispatch(does_virtual_dispatch), _intrinsic_id(id) { } virtual bool is_intrinsic() const { return true; } virtual bool is_virtual() const { return _is_virtual; } virtual bool is_predicted() const { return _is_predicted; } + virtual bool does_virtual_dispatch() const { return _does_virtual_dispatch; } virtual JVMState* generate(JVMState* jvms); virtual Node* generate_predicate(JVMState* jvms); vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } @@ -199,6 +203,8 @@ bool inline_math_native(vmIntrinsics::ID id); bool inline_trig(vmIntrinsics::ID id); bool inline_math(vmIntrinsics::ID id); + bool inline_math_mathExact(Node* math); + bool inline_math_addExact(); bool inline_exp(); bool inline_pow(); void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); @@ -352,6 +358,7 @@ } bool is_predicted = false; + bool does_virtual_dispatch = false; switch (id) { case vmIntrinsics::_compareTo: @@ -378,8 +385,10 @@ break; case vmIntrinsics::_hashCode: if (!InlineObjectHash) return NULL; + does_virtual_dispatch = true; break; case vmIntrinsics::_clone: + does_virtual_dispatch = true; case vmIntrinsics::_copyOf: case vmIntrinsics::_copyOfRange: if (!InlineObjectCopy) return NULL; @@ -498,6 +507,15 @@ if (!UseCRC32Intrinsics) return NULL; break; + case vmIntrinsics::_addExact: + if (!Matcher::match_rule_supported(Op_AddExactI)) { + return NULL; + } + if (!UseMathExactIntrinsics) { + return NULL; + } + break; + default: assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); @@ -529,7 +547,7 @@ if (!InlineUnsafeOps) return NULL; } - return new LibraryIntrinsic(m, is_virtual, is_predicted, (vmIntrinsics::ID) id); + return new LibraryIntrinsic(m, is_virtual, is_predicted, does_virtual_dispatch, (vmIntrinsics::ID) id); } //----------------------register_library_intrinsics----------------------- @@ -668,6 +686,8 @@ case vmIntrinsics::_min: case vmIntrinsics::_max: return inline_min_max(intrinsic_id()); + case vmIntrinsics::_addExact: return inline_math_addExact(); + case vmIntrinsics::_arraycopy: return inline_arraycopy(); case vmIntrinsics::_compareTo: return inline_string_compareTo(); @@ -1911,6 +1931,45 @@ return true; } +bool LibraryCallKit::inline_math_mathExact(Node* math) { + Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node)); + Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node)); + + Node* bol = _gvn.transform( new (C) BoolNode(flags, BoolTest::overflow) ); + IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); + Node* fast_path = _gvn.transform( new (C) IfFalseNode(check)); + Node* slow_path = _gvn.transform( new (C) IfTrueNode(check) ); + + { + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + } + + set_control(fast_path); + set_result(result); + return true; +} + +bool LibraryCallKit::inline_math_addExact() { + Node* arg1 = argument(0); + Node* arg2 = argument(1); + + Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) ); + if (add->Opcode() == Op_AddExactI) { + return inline_math_mathExact(add); + } else { + set_result(add); + } + return true; +} + Node* LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) { // These are the candidate return value: diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/loopTransform.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -776,6 +776,9 @@ continue; // not RC Node *cmp = bol->in(1); + if (cmp->is_FlagsProj()) { + continue; + } Node *rc_exp = cmp->in(1); Node *limit = cmp->in(2); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/loopopts.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -2355,7 +2355,8 @@ opc == Op_Catch || opc == Op_CatchProj || opc == Op_Jump || - opc == Op_JumpProj) { + opc == Op_JumpProj || + opc == Op_FlagsProj) { #if !defined(PRODUCT) if (TracePartialPeeling) { tty->print_cr("\nExit control too complex: lp: %d", head->_idx); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/matcher.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1964,6 +1964,7 @@ case Op_Catch: case Op_CatchProj: case Op_CProj: + case Op_FlagsProj: case Op_JumpProj: case Op_JProj: case Op_NeverBranch: diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/matcher.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -337,6 +337,9 @@ // Register for MODL projection of divmodL static RegMask modL_proj_mask(); + static const RegMask mathExactI_result_proj_mask(); + static const RegMask mathExactI_flags_proj_mask(); + // Use hardware DIV instruction when it is faster than // a code which use multiply for division by constant. static bool use_asm_for_ldiv_by_con( jlong divisor ); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/mathexactnode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, 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 "memory/allocation.inline.hpp" +#include "opto/addnode.hpp" +#include "opto/machnode.hpp" +#include "opto/mathexactnode.hpp" +#include "opto/matcher.hpp" +#include "opto/subnode.hpp" + +MathExactNode::MathExactNode(Node* ctrl, Node* n1, Node* n2) : MultiNode(3) { + init_req(0, ctrl); + init_req(1, n1); + init_req(2, n2); +} + +Node* AddExactINode::match(const ProjNode* proj, const Matcher* m) { + uint ideal_reg = proj->ideal_reg(); + RegMask rm; + if (proj->_con == result_proj_node) { + rm = m->mathExactI_result_proj_mask(); + } else { + assert(proj->_con == flags_proj_node, "must be result or flags"); + assert(ideal_reg == Op_RegFlags, "sanity"); + rm = m->mathExactI_flags_proj_mask(); + } + return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg); +} + +// If the MathExactNode won't overflow we have to replace the +// FlagsProjNode and ProjNode that is generated by the MathExactNode +Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) { + PhaseIterGVN *igvn = phase->is_IterGVN(); + if (igvn) { + ProjNode* result = result_node(); + ProjNode* flags = flags_node(); + + if (result != NULL) { + igvn->replace_node(result, new_result); + } + + if (flags != NULL) { + BoolNode* bolnode = (BoolNode *) flags->unique_out(); + switch (bolnode->_test._test) { + case BoolTest::overflow: + // if the check is for overflow - never taken + igvn->replace_node(bolnode, phase->intcon(0)); + break; + case BoolTest::no_overflow: + // if the check is for no overflow - always taken + igvn->replace_node(bolnode, phase->intcon(1)); + break; + default: + fatal("Unexpected value of BoolTest"); + break; + } + flags->del_req(0); + } + } + return new_result; +} + +Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node *arg1 = in(1); + Node *arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jint val1 = arg1->get_int(); + jint val2 = arg2->get_int(); + jint result = val1 + val2; + // Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result + if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) { + Node* con_result = ConINode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeInt::ZERO) { // (Add 0 x) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2 == TypeInt::ZERO) { // (Add x 0) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2->singleton()) { + return NULL; // no change - keep constant on the right + } + + if (type1->singleton()) { + // Make it x + Constant - move constant to the right + swap_edges(1, 2); + return this; + } + + if (arg2->is_Load()) { + return NULL; // no change - keep load on the right + } + + if (arg1->is_Load()) { + // Make it x + Load - move load to the right + swap_edges(1, 2); + return this; + } + + if (arg1->_idx > arg2->_idx) { + // Sort the edges + swap_edges(1, 2); + return this; + } + + return NULL; +} + diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/mathexactnode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, 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_OPTO_MATHEXACTNODE_HPP +#define SHARE_VM_OPTO_MATHEXACTNODE_HPP + +#include "opto/multnode.hpp" +#include "opto/node.hpp" +#include "opto/type.hpp" + +class Node; + +class PhaseGVN; +class PhaseTransform; + +class MathExactNode : public MultiNode { +public: + MathExactNode(Node* ctrl, Node* in1, Node* in2); + enum { + result_proj_node = 0, + flags_proj_node = 1 + }; + virtual int Opcode() const; + virtual Node* Identity(PhaseTransform* phase) { return this; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) { return NULL; } + virtual const Type* Value(PhaseTransform* phase) const { return bottom_type(); } + virtual uint hash() const { return Node::hash(); } + virtual bool is_CFG() const { return false; } + virtual uint ideal_reg() const { return NotAMachineReg; } + + ProjNode* result_node() { return proj_out(result_proj_node); } + ProjNode* flags_node() { return proj_out(flags_proj_node); } +protected: + Node* no_overflow(PhaseGVN *phase, Node* new_result); +}; + +class AddExactINode : public MathExactNode { +public: + AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; } + virtual Node* match(const ProjNode* proj, const Matcher* m); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +class FlagsProjNode : public ProjNode { +public: + FlagsProjNode(Node* src, uint con) : ProjNode(src, con) { + init_class_id(Class_FlagsProj); + } + + virtual int Opcode() const; + virtual bool is_CFG() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::CC; } + virtual uint ideal_reg() const { return Op_RegFlags; } +}; + + +#endif + diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/multnode.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "opto/callnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/multnode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" @@ -46,15 +47,21 @@ assert(Opcode() != Op_If || outcnt() == 2, "bad if #1"); for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) { Node *p = fast_out(i); - if( !p->is_Proj() ) { + if (p->is_Proj()) { + ProjNode *proj = p->as_Proj(); + if (proj->_con == which_proj) { + assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); + return proj; + } + } else if (p->is_FlagsProj()) { + FlagsProjNode *proj = p->as_FlagsProj(); + if (proj->_con == which_proj) { + return proj; + } + } else { assert(p == this && this->is_Start(), "else must be proj"); continue; } - ProjNode *proj = p->as_Proj(); - if( proj->_con == which_proj ) { - assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); - return proj; - } } return NULL; } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/node.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -69,6 +69,7 @@ class EncodePKlassNode; class FastLockNode; class FastUnlockNode; +class FlagsProjNode; class IfNode; class IfFalseNode; class IfTrueNode; @@ -623,6 +624,7 @@ DEFINE_CLASS_ID(Cmp, Sub, 0) DEFINE_CLASS_ID(FastLock, Cmp, 0) DEFINE_CLASS_ID(FastUnlock, Cmp, 1) + DEFINE_CLASS_ID(FlagsProj, Cmp, 2) DEFINE_CLASS_ID(MergeMem, Node, 7) DEFINE_CLASS_ID(Bool, Node, 8) @@ -726,6 +728,7 @@ DEFINE_CLASS_QUERY(EncodePKlass) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) + DEFINE_CLASS_QUERY(FlagsProj) DEFINE_CLASS_QUERY(If) DEFINE_CLASS_QUERY(IfFalse) DEFINE_CLASS_QUERY(IfTrue) diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/subnode.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1064,7 +1064,7 @@ // Print special per-node info #ifndef PRODUCT void BoolTest::dump_on(outputStream *st) const { - const char *msg[] = {"eq","gt","??","lt","ne","le","??","ge"}; + const char *msg[] = {"eq","gt","of","lt","ne","le","nof","ge"}; st->print(msg[_test]); } #endif @@ -1126,7 +1126,7 @@ Node *cmp = in(1); if( !cmp->is_Sub() ) return NULL; int cop = cmp->Opcode(); - if( cop == Op_FastLock || cop == Op_FastUnlock ) return NULL; + if( cop == Op_FastLock || cop == Op_FastUnlock || cop == Op_FlagsProj) return NULL; Node *cmp1 = cmp->in(1); Node *cmp2 = cmp->in(2); if( !cmp1 ) return NULL; diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/subnode.hpp --- a/src/share/vm/opto/subnode.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/subnode.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -263,16 +263,16 @@ // We pick the values as 3 bits; the low order 2 bits we compare against the // condition codes, the high bit flips the sense of the result. struct BoolTest VALUE_OBJ_CLASS_SPEC { - enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, illegal = 8 }; + enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, overflow = 2, no_overflow = 6, illegal = 8 }; mask _test; BoolTest( mask btm ) : _test(btm) {} const Type *cc2logical( const Type *CC ) const; // Commute the test. I use a small table lookup. The table is created as // a simple char array where each element is the ASCII version of a 'mask' // enum from above. - mask commute( ) const { return mask("038147858"[_test]-'0'); } + mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } - bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le); } + bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } #ifndef PRODUCT void dump_on(outputStream *st) const; #endif diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/type.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -430,6 +430,11 @@ longpair[1] = TypeLong::LONG; TypeTuple::LONG_PAIR = TypeTuple::make(2, longpair); + const Type **intccpair = TypeTuple::fields(2); + intccpair[0] = TypeInt::INT; + intccpair[1] = TypeInt::CC; + TypeTuple::INT_CC_PAIR = TypeTuple::make(2, intccpair); + _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; _const_basic_type[T_NARROWKLASS] = Type::BOTTOM; _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; @@ -1646,6 +1651,7 @@ const TypeTuple *TypeTuple::START_I2C; const TypeTuple *TypeTuple::INT_PAIR; const TypeTuple *TypeTuple::LONG_PAIR; +const TypeTuple *TypeTuple::INT_CC_PAIR; //------------------------------make------------------------------------------- diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/opto/type.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -584,6 +584,7 @@ static const TypeTuple *START_I2C; static const TypeTuple *INT_PAIR; static const TypeTuple *LONG_PAIR; + static const TypeTuple *INT_CC_PAIR; #ifndef PRODUCT virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping #endif diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/prims/jvm.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -3984,13 +3984,13 @@ JVM_LEAF(jboolean, JVM_AccessVMBooleanFlag(const char* name, jboolean* value, jboolean is_get)) JVMWrapper("JVM_AccessBoolVMFlag"); - return is_get ? CommandLineFlags::boolAt((char*) name, (bool*) value) : CommandLineFlags::boolAtPut((char*) name, (bool*) value, INTERNAL); + return is_get ? CommandLineFlags::boolAt((char*) name, (bool*) value) : CommandLineFlags::boolAtPut((char*) name, (bool*) value, Flag::INTERNAL); JVM_END JVM_LEAF(jboolean, JVM_AccessVMIntFlag(const char* name, jint* value, jboolean is_get)) JVMWrapper("JVM_AccessVMIntFlag"); intx v; - jboolean result = is_get ? CommandLineFlags::intxAt((char*) name, &v) : CommandLineFlags::intxAtPut((char*) name, &v, INTERNAL); + jboolean result = is_get ? CommandLineFlags::intxAt((char*) name, &v) : CommandLineFlags::intxAtPut((char*) name, &v, Flag::INTERNAL); *value = (jint)v; return result; JVM_END diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -625,11 +625,11 @@ } } -static bool set_bool_flag(char* name, bool value, FlagValueOrigin origin) { +static bool set_bool_flag(char* name, bool value, Flag::Flags origin) { return CommandLineFlags::boolAtPut(name, &value, origin); } -static bool set_fp_numeric_flag(char* name, char* value, FlagValueOrigin origin) { +static bool set_fp_numeric_flag(char* name, char* value, Flag::Flags origin) { double v; if (sscanf(value, "%lf", &v) != 1) { return false; @@ -641,7 +641,7 @@ return false; } -static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { +static bool set_numeric_flag(char* name, char* value, Flag::Flags origin) { julong v; intx intx_v; bool is_neg = false; @@ -674,14 +674,14 @@ return false; } -static bool set_string_flag(char* name, const char* value, FlagValueOrigin origin) { +static bool set_string_flag(char* name, const char* value, Flag::Flags origin) { if (!CommandLineFlags::ccstrAtPut(name, &value, origin)) return false; // Contract: CommandLineFlags always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value, mtInternal); return true; } -static bool append_to_string_flag(char* name, const char* new_value, FlagValueOrigin origin) { +static bool append_to_string_flag(char* name, const char* new_value, Flag::Flags origin) { const char* old_value = ""; if (!CommandLineFlags::ccstrAt(name, &old_value)) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; @@ -709,7 +709,7 @@ return true; } -bool Arguments::parse_argument(const char* arg, FlagValueOrigin origin) { +bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -850,7 +850,7 @@ } bool Arguments::process_argument(const char* arg, - jboolean ignore_unrecognized, FlagValueOrigin origin) { + jboolean ignore_unrecognized, Flag::Flags origin) { JDK_Version since = JDK_Version(); @@ -904,7 +904,7 @@ jio_fprintf(defaultStream::error_stream(), "Did you mean '%s%s%s'?\n", (fuzzy_matched->is_bool()) ? "(+/-)" : "", - fuzzy_matched->name, + fuzzy_matched->_name, (fuzzy_matched->is_bool()) ? "" : "="); } } @@ -952,7 +952,7 @@ // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -970,7 +970,7 @@ } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1132,6 +1132,9 @@ Tier3InvokeNotifyFreqLog = 0; Tier4InvocationThreshold = 0; } + if (FLAG_IS_DEFAULT(NmethodSweepFraction)) { + FLAG_SET_DEFAULT(NmethodSweepFraction, 1 + ReservedCodeCacheSize / (16 * M)); + } } #if INCLUDE_ALL_GCS @@ -2337,6 +2340,10 @@ (2*G)/M); status = false; } + + status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction"); + status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity"); + return status; } @@ -2438,7 +2445,7 @@ } // Parse JavaVMInitArgs structure passed in - result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, COMMAND_LINE); + result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, Flag::COMMAND_LINE); if (result != JNI_OK) { return result; } @@ -2510,7 +2517,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, - FlagValueOrigin origin) { + Flag::Flags origin) { // Remaining part of option string const char* tail; @@ -3333,7 +3340,7 @@ } } - return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, ENVIRON_VAR)); + return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, Flag::ENVIRON_VAR)); } return JNI_OK; } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/arguments.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -360,15 +360,15 @@ // Argument parsing static void do_pd_flag_adjustments(); - static bool parse_argument(const char* arg, FlagValueOrigin origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, FlagValueOrigin origin); + static bool parse_argument(const char* arg, Flag::Flags origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(char* arg); static jint parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p); static jint parse_vm_init_args(const JavaVMInitArgs* args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, FlagValueOrigin origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, Flag::Flags origin); static jint finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/globals.cpp --- a/src/share/vm/runtime/globals.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/globals.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -62,26 +62,174 @@ MATERIALIZE_FLAGS_EXT +void Flag::check_writable() { + if (is_constant_in_binary()) { + fatal(err_msg("flag is constant: %s", _name)); + } +} + +bool Flag::is_bool() const { + return strcmp(_type, "bool") == 0; +} + +bool Flag::get_bool() const { + return *((bool*) _addr); +} + +void Flag::set_bool(bool value) { + check_writable(); + *((bool*) _addr) = value; +} + +bool Flag::is_intx() const { + return strcmp(_type, "intx") == 0; +} + +intx Flag::get_intx() const { + return *((intx*) _addr); +} + +void Flag::set_intx(intx value) { + check_writable(); + *((intx*) _addr) = value; +} + +bool Flag::is_uintx() const { + return strcmp(_type, "uintx") == 0; +} + +uintx Flag::get_uintx() const { + return *((uintx*) _addr); +} + +void Flag::set_uintx(uintx value) { + check_writable(); + *((uintx*) _addr) = value; +} + +bool Flag::is_uint64_t() const { + return strcmp(_type, "uint64_t") == 0; +} + +uint64_t Flag::get_uint64_t() const { + return *((uint64_t*) _addr); +} + +void Flag::set_uint64_t(uint64_t value) { + check_writable(); + *((uint64_t*) _addr) = value; +} + +bool Flag::is_double() const { + return strcmp(_type, "double") == 0; +} + +double Flag::get_double() const { + return *((double*) _addr); +} + +void Flag::set_double(double value) { + check_writable(); + *((double*) _addr) = value; +} + +bool Flag::is_ccstr() const { + return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; +} + +bool Flag::ccstr_accumulates() const { + return strcmp(_type, "ccstrlist") == 0; +} + +ccstr Flag::get_ccstr() const { + return *((ccstr*) _addr); +} + +void Flag::set_ccstr(ccstr value) { + check_writable(); + *((ccstr*) _addr) = value; +} + + +Flag::Flags Flag::get_origin() { + return Flags(_flags & VALUE_ORIGIN_MASK); +} + +void Flag::set_origin(Flags origin) { + assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | origin); +} + +bool Flag::is_default() { + return (get_origin() == DEFAULT); +} + +bool Flag::is_ergonomic() { + return (get_origin() == ERGONOMIC); +} + +bool Flag::is_command_line() { + return (get_origin() == COMMAND_LINE); +} + +bool Flag::is_product() const { + return (_flags & KIND_PRODUCT) != 0; +} + +bool Flag::is_manageable() const { + return (_flags & KIND_MANAGEABLE) != 0; +} + +bool Flag::is_diagnostic() const { + return (_flags & KIND_DIAGNOSTIC) != 0; +} + +bool Flag::is_experimental() const { + return (_flags & KIND_EXPERIMENTAL) != 0; +} + +bool Flag::is_notproduct() const { + return (_flags & KIND_NOT_PRODUCT) != 0; +} + +bool Flag::is_develop() const { + return (_flags & KIND_DEVELOP) != 0; +} + +bool Flag::is_read_write() const { + return (_flags & KIND_READ_WRITE) != 0; +} + +bool Flag::is_commercial() const { + return (_flags & KIND_COMMERCIAL) != 0; +} + +/** + * Returns if this flag is a constant in the binary. Right now this is + * true for notproduct and develop flags in product builds. + */ +bool Flag::is_constant_in_binary() const { +#ifdef PRODUCT + return is_notproduct() || is_develop(); +#else + return false; +#endif +} + bool Flag::is_unlocker() const { - return strcmp(name, "UnlockDiagnosticVMOptions") == 0 || - strcmp(name, "UnlockExperimentalVMOptions") == 0 || + return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || + strcmp(_name, "UnlockExperimentalVMOptions") == 0 || is_unlocker_ext(); } bool Flag::is_unlocked() const { - if (strcmp(kind, "{diagnostic}") == 0 || - strcmp(kind, "{C2 diagnostic}") == 0 || - strcmp(kind, "{ARCH diagnostic}") == 0 || - strcmp(kind, "{Shark diagnostic}") == 0) { + if (is_diagnostic()) { return UnlockDiagnosticVMOptions; - } else if (strcmp(kind, "{experimental}") == 0 || - strcmp(kind, "{C2 experimental}") == 0 || - strcmp(kind, "{ARCH experimental}") == 0 || - strcmp(kind, "{Shark experimental}") == 0) { + } + if (is_experimental()) { return UnlockExperimentalVMOptions; - } else { - return is_unlocked_ext(); } + return is_unlocked_ext(); } // Get custom message for this locked flag, or return NULL if @@ -91,16 +239,14 @@ } bool Flag::is_writeable() const { - return strcmp(kind, "{manageable}") == 0 || - strcmp(kind, "{product rw}") == 0 || - is_writeable_ext(); + return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); } // All flags except "manageable" are assumed to be internal flags. // Long term, we need to define a mechanism to specify which flags // are external/stable and change this function accordingly. bool Flag::is_external() const { - return strcmp(kind, "{manageable}") == 0 || is_external_ext(); + return is_manageable() || is_external_ext(); } @@ -108,53 +254,113 @@ #define FORMAT_BUFFER_LEN 16 void Flag::print_on(outputStream* st, bool withComments) { - st->print("%9s %-40s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); - if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); - if (is_intx()) st->print("%-16ld", get_intx()); - if (is_uintx()) st->print("%-16lu", get_uintx()); - if (is_uint64_t()) st->print("%-16lu", get_uint64_t()); - if (is_double()) st->print("%-16f", get_double()); + // Don't print notproduct and develop flags in a product build. + if (is_constant_in_binary()) { + return; + } + + st->print("%9s %-40s %c= ", _type, _name, (!is_default() ? ':' : ' ')); + if (is_bool()) { + st->print("%-16s", get_bool() ? "true" : "false"); + } + if (is_intx()) { + st->print("%-16ld", get_intx()); + } + if (is_uintx()) { + st->print("%-16lu", get_uintx()); + } + if (is_uint64_t()) { + st->print("%-16lu", get_uint64_t()); + } + if (is_double()) { + st->print("%-16f", get_double()); + } if (is_ccstr()) { - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - char format_buffer[FORMAT_BUFFER_LEN]; - size_t llen = pointer_delta(eol, cp, sizeof(char)); - jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, - "%%." SIZE_FORMAT "s", llen); - st->print(format_buffer, cp); - st->cr(); - cp = eol+1; - st->print("%5s %-35s += ", "", name); - } - st->print("%-16s", cp); - } - else st->print("%-16s", ""); + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + char format_buffer[FORMAT_BUFFER_LEN]; + size_t llen = pointer_delta(eol, cp, sizeof(char)); + jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, + "%%." SIZE_FORMAT "s", llen); + st->print(format_buffer, cp); + st->cr(); + cp = eol+1; + st->print("%5s %-35s += ", "", _name); + } + st->print("%-16s", cp); + } + else st->print("%-16s", ""); } - st->print("%-20s", kind); + + st->print("%-20"); + print_kind(st); + if (withComments) { #ifndef PRODUCT - st->print("%s", doc ); + st->print("%s", _doc); #endif } st->cr(); } +void Flag::print_kind(outputStream* st) { + struct Data { + int flag; + const char* name; + }; + + Data data[] = { + { KIND_C1, "C1" }, + { KIND_C2, "C2" }, + { KIND_ARCH, "ARCH" }, + { KIND_SHARK, "SHARK" }, + { KIND_PLATFORM_DEPENDENT, "pd" }, + { KIND_PRODUCT, "product" }, + { KIND_MANAGEABLE, "manageable" }, + { KIND_DIAGNOSTIC, "diagnostic" }, + { KIND_NOT_PRODUCT, "notproduct" }, + { KIND_DEVELOP, "develop" }, + { KIND_LP64_PRODUCT, "lp64_product" }, + { KIND_READ_WRITE, "rw" }, + { -1, "" } + }; + + if ((_flags & KIND_MASK) != 0) { + st->print("{"); + bool is_first = true; + + for (int i = 0; data[i].flag != -1; i++) { + Data d = data[i]; + if ((_flags & d.flag) != 0) { + if (is_first) { + is_first = false; + } else { + st->print(" "); + } + st->print(d.name); + } + } + + st->print("}"); + } +} + void Flag::print_as_flag(outputStream* st) { if (is_bool()) { - st->print("-XX:%s%s", get_bool() ? "+" : "-", name); + st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); } else if (is_intx()) { - st->print("-XX:%s=" INTX_FORMAT, name, get_intx()); + st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); } else if (is_uintx()) { - st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx()); + st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); } else if (is_uint64_t()) { - st->print("-XX:%s=" UINT64_FORMAT, name, get_uint64_t()); + st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); } else if (is_double()) { - st->print("-XX:%s=%f", name, get_double()); + st->print("-XX:%s=%f", _name, get_double()); } else if (is_ccstr()) { - st->print("-XX:%s=", name); + st->print("-XX:%s=", _name); const char* cp = get_ccstr(); if (cp != NULL) { // Need to turn embedded '\n's back into separate arguments @@ -167,7 +373,7 @@ st->print("%c", *cp); break; case '\n': - st->print(" -XX:%s=", name); + st->print(" -XX:%s=", _name); break; } } @@ -180,79 +386,51 @@ // 4991491 do not "optimize out" the was_set false values: omitting them // tickles a Microsoft compiler bug causing flagTable to be malformed -#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product}", DEFAULT }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{pd product}", DEFAULT }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{diagnostic}", DEFAULT }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{experimental}", DEFAULT }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{manageable}", DEFAULT }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product rw}", DEFAULT }, +#define NAME(name) NOT_PRODUCT(&name) PRODUCT_ONLY(&CONST_##name) -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "", DEFAULT }, - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{pd}", DEFAULT }, - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{notproduct}", DEFAULT }, -#endif +#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT) }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC) }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_EXPERIMENTAL) }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_MANAGEABLE) }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_READ_WRITE) }, +#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, +#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, #ifdef _LP64 - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{lp64_product}", DEFAULT }, +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, #else - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 product}", DEFAULT }, -#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 pd product}", DEFAULT }, -#define C1_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 diagnostic}", DEFAULT }, -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1}", DEFAULT }, - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C1 pd}", DEFAULT }, - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1 notproduct}", DEFAULT }, -#endif +#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT) }, +#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC) }, +#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP) }, +#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, -#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 product}", DEFAULT }, -#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 pd product}", DEFAULT }, -#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 diagnostic}", DEFAULT }, -#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 experimental}", DEFAULT }, -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2}", DEFAULT }, - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C2 pd}", DEFAULT }, - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2 notproduct}", DEFAULT }, -#endif +#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT) }, +#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC) }, +#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_EXPERIMENTAL) }, +#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP) }, +#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_NOT_PRODUCT) }, -#define ARCH_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH product}", DEFAULT }, -#define ARCH_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH diagnostic}", DEFAULT }, -#define ARCH_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{ARCH experimental}", DEFAULT }, -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{ARCH}", DEFAULT }, - #define ARCH_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{ARCH notproduct}", DEFAULT }, -#endif +#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_PRODUCT) }, +#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DIAGNOSTIC) }, +#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_EXPERIMENTAL) }, +#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, +#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, -#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark product}", DEFAULT }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark pd product}", DEFAULT }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark diagnostic}", DEFAULT }, -#ifdef PRODUCT - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) -#else - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark}", DEFAULT }, - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{Shark pd}", DEFAULT }, - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark notproduct}", DEFAULT }, -#endif +#define SHARK_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT) }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC) }, +#define SHARK_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP) }, +#define SHARK_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) }, static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT) @@ -285,9 +463,14 @@ // Search the flag table for a named flag Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) { - for (Flag* current = &flagTable[0]; current->name != NULL; current++) { - if (str_equal(current->name, name, length)) { - // Found a matching entry. Report locked flags only if allowed. + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + if (str_equal(current->_name, name, length)) { + // Found a matching entry. + // Don't report notproduct and develop flags in product builds. + if (current->is_constant_in_binary()) { + return NULL; + } + // Report locked flags only if allowed. if (!(current->is_unlocked() || current->is_unlocker())) { if (!allow_locked) { // disable use of locked flags, e.g. diagnostic, experimental, @@ -327,8 +510,8 @@ float score; float max_score = -1; - for (Flag* current = &flagTable[0]; current->name != NULL; current++) { - score = str_similar(current->name, name, length); + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + score = str_similar(current->_name, name, length); if (score > max_score) { max_score = score; match = current; @@ -357,25 +540,25 @@ bool CommandLineFlagsEx::is_default(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == DEFAULT); + return f->is_default(); } bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == ERGONOMIC); + return f->is_ergonomic(); } bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { assert((size_t)flag < Flag::numFlags, "bad command line flag index"); Flag* f = &Flag::flags[flag]; - return (f->origin == COMMAND_LINE); + return f->is_command_line(); } bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { Flag* result = Flag::find_flag((char*)name, strlen(name)); if (result == NULL) return false; - *value = (result->origin == COMMAND_LINE); + *value = result->is_command_line(); return true; } @@ -387,22 +570,22 @@ return true; } -bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, FlagValueOrigin origin) { +bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_bool()) return false; bool old_value = result->get_bool(); result->set_bool(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin) { +void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); faddr->set_bool(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::intxAt(char* name, size_t len, intx* value) { @@ -413,22 +596,22 @@ return true; } -bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, FlagValueOrigin origin) { +bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_intx()) return false; intx old_value = result->get_intx(); result->set_intx(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin) { +void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); faddr->set_intx(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::uintxAt(char* name, size_t len, uintx* value) { @@ -439,22 +622,22 @@ return true; } -bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin) { +bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_uintx()) return false; uintx old_value = result->get_uintx(); result->set_uintx(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin) { +void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); faddr->set_uintx(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::uint64_tAt(char* name, size_t len, uint64_t* value) { @@ -465,22 +648,22 @@ return true; } -bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin) { +bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_uint64_t()) return false; uint64_t old_value = result->get_uint64_t(); result->set_uint64_t(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin) { +void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); faddr->set_uint64_t(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::doubleAt(char* name, size_t len, double* value) { @@ -491,22 +674,22 @@ return true; } -bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin) { +bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_double()) return false; double old_value = result->get_double(); result->set_double(*value); *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } -void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin) { +void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); faddr->set_double(value); - faddr->origin = origin; + faddr->set_origin(origin); } bool CommandLineFlags::ccstrAt(char* name, size_t len, ccstr* value) { @@ -519,7 +702,7 @@ // Contract: Flag will make private copy of the incoming value. // Outgoing value is always malloc-ed, and caller MUST call free. -bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, FlagValueOrigin origin) { +bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, Flag::Flags origin) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; if (!result->is_ccstr()) return false; @@ -530,35 +713,35 @@ strcpy(new_value, *value); } result->set_ccstr(new_value); - if (result->origin == DEFAULT && old_value != NULL) { + if (result->is_default() && old_value != NULL) { // Prior value is NOT heap allocated, but was a literal constant. char* old_value_to_free = NEW_C_HEAP_ARRAY(char, strlen(old_value)+1, mtInternal); strcpy(old_value_to_free, old_value); old_value = old_value_to_free; } *value = old_value; - result->origin = origin; + result->set_origin(origin); return true; } // Contract: Flag will make private copy of the incoming value. -void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin) { +void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); ccstr old_value = faddr->get_ccstr(); char* new_value = NEW_C_HEAP_ARRAY(char, strlen(value)+1, mtInternal); strcpy(new_value, value); faddr->set_ccstr(new_value); - if (faddr->origin != DEFAULT && old_value != NULL) { + if (!faddr->is_default() && old_value != NULL) { // Prior value is heap allocated so free it. FREE_C_HEAP_ARRAY(char, old_value, mtInternal); } - faddr->origin = origin; + faddr->set_origin(origin); } extern "C" { static int compare_flags(const void* void_a, const void* void_b) { - return strcmp((*((Flag**) void_a))->name, (*((Flag**) void_b))->name); + return strcmp((*((Flag**) void_a))->_name, (*((Flag**) void_b))->_name); } } @@ -567,20 +750,19 @@ // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. - // Compute size - int length= 0; - while (flagTable[length].name != NULL) length++; + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; // Sort Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); - for (int index = 0; index < length; index++) { - array[index] = &flagTable[index]; + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; } qsort(array, length, sizeof(Flag*), compare_flags); // Print - for (int i = 0; i < length; i++) { - if (array[i]->origin /* naked field! */) { + for (size_t i = 0; i < length; i++) { + if (array[i]->get_origin() /* naked field! */) { array[i]->print_as_flag(out); out->print(" "); } @@ -603,20 +785,19 @@ // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. - // Compute size - int length= 0; - while (flagTable[length].name != NULL) length++; + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; // Sort Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); - for (int index = 0; index < length; index++) { - array[index] = &flagTable[index]; + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; } qsort(array, length, sizeof(Flag*), compare_flags); // Print out->print_cr("[Global flags]"); - for (int i = 0; i < length; i++) { + for (size_t i = 0; i < length; i++) { if (array[i]->is_unlocked()) { array[i]->print_on(out, withComments); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -194,29 +194,49 @@ typedef const char* ccstr; typedef const char* ccstrlist; // represents string arguments which accumulate -enum FlagValueOrigin { - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 99 -}; +struct Flag { + enum Flags { + // value origin + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + + LAST_VALUE_ORIGIN = INTERNAL, + VALUE_ORIGIN_BITS = 4, + VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), -struct Flag { - const char *type; - const char *name; - void* addr; + // flag kind + KIND_PRODUCT = 1 << 4, + KIND_MANAGEABLE = 1 << 5, + KIND_DIAGNOSTIC = 1 << 6, + KIND_EXPERIMENTAL = 1 << 7, + KIND_NOT_PRODUCT = 1 << 8, + KIND_DEVELOP = 1 << 9, + KIND_PLATFORM_DEPENDENT = 1 << 10, + KIND_READ_WRITE = 1 << 11, + KIND_C1 = 1 << 12, + KIND_C2 = 1 << 13, + KIND_ARCH = 1 << 14, + KIND_SHARK = 1 << 15, + KIND_LP64_PRODUCT = 1 << 16, + KIND_COMMERCIAL = 1 << 17, - NOT_PRODUCT(const char *doc;) + KIND_MASK = ~VALUE_ORIGIN_MASK + }; - const char *kind; - FlagValueOrigin origin; + const char* _type; + const char* _name; + void* _addr; + NOT_PRODUCT(const char* _doc;) + Flags _flags; // points to all Flags static array - static Flag *flags; + static Flag* flags; // number of flags static size_t numFlags; @@ -224,30 +244,50 @@ static Flag* find_flag(const char* name, size_t length, bool allow_locked = false); static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); - bool is_bool() const { return strcmp(type, "bool") == 0; } - bool get_bool() const { return *((bool*) addr); } - void set_bool(bool value) { *((bool*) addr) = value; } + void check_writable(); + + bool is_bool() const; + bool get_bool() const; + void set_bool(bool value); + + bool is_intx() const; + intx get_intx() const; + void set_intx(intx value); - bool is_intx() const { return strcmp(type, "intx") == 0; } - intx get_intx() const { return *((intx*) addr); } - void set_intx(intx value) { *((intx*) addr) = value; } + bool is_uintx() const; + uintx get_uintx() const; + void set_uintx(uintx value); - bool is_uintx() const { return strcmp(type, "uintx") == 0; } - uintx get_uintx() const { return *((uintx*) addr); } - void set_uintx(uintx value) { *((uintx*) addr) = value; } + bool is_uint64_t() const; + uint64_t get_uint64_t() const; + void set_uint64_t(uint64_t value); + + bool is_double() const; + double get_double() const; + void set_double(double value); - bool is_uint64_t() const { return strcmp(type, "uint64_t") == 0; } - uint64_t get_uint64_t() const { return *((uint64_t*) addr); } - void set_uint64_t(uint64_t value) { *((uint64_t*) addr) = value; } + bool is_ccstr() const; + bool ccstr_accumulates() const; + ccstr get_ccstr() const; + void set_ccstr(ccstr value); + + Flags get_origin(); + void set_origin(Flags origin); - bool is_double() const { return strcmp(type, "double") == 0; } - double get_double() const { return *((double*) addr); } - void set_double(double value) { *((double*) addr) = value; } + bool is_default(); + bool is_ergonomic(); + bool is_command_line(); - bool is_ccstr() const { return strcmp(type, "ccstr") == 0 || strcmp(type, "ccstrlist") == 0; } - bool ccstr_accumulates() const { return strcmp(type, "ccstrlist") == 0; } - ccstr get_ccstr() const { return *((ccstr*) addr); } - void set_ccstr(ccstr value) { *((ccstr*) addr) = value; } + bool is_product() const; + bool is_manageable() const; + bool is_diagnostic() const; + bool is_experimental() const; + bool is_notproduct() const; + bool is_develop() const; + bool is_read_write() const; + bool is_commercial() const; + + bool is_constant_in_binary() const; bool is_unlocker() const; bool is_unlocked() const; @@ -263,6 +303,7 @@ void get_locked_message_ext(char*, int) const; void print_on(outputStream* st, bool withComments = false ); + void print_kind(outputStream* st); void print_as_flag(outputStream* st); }; @@ -310,33 +351,33 @@ public: static bool boolAt(char* name, size_t len, bool* value); static bool boolAt(char* name, bool* value) { return boolAt(name, strlen(name), value); } - static bool boolAtPut(char* name, size_t len, bool* value, FlagValueOrigin origin); - static bool boolAtPut(char* name, bool* value, FlagValueOrigin origin) { return boolAtPut(name, strlen(name), value, origin); } + static bool boolAtPut(char* name, size_t len, bool* value, Flag::Flags origin); + static bool boolAtPut(char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } static bool intxAt(char* name, size_t len, intx* value); static bool intxAt(char* name, intx* value) { return intxAt(name, strlen(name), value); } - static bool intxAtPut(char* name, size_t len, intx* value, FlagValueOrigin origin); - static bool intxAtPut(char* name, intx* value, FlagValueOrigin origin) { return intxAtPut(name, strlen(name), value, origin); } + static bool intxAtPut(char* name, size_t len, intx* value, Flag::Flags origin); + static bool intxAtPut(char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } static bool uintxAt(char* name, size_t len, uintx* value); static bool uintxAt(char* name, uintx* value) { return uintxAt(name, strlen(name), value); } - static bool uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin); - static bool uintxAtPut(char* name, uintx* value, FlagValueOrigin origin) { return uintxAtPut(name, strlen(name), value, origin); } + static bool uintxAtPut(char* name, size_t len, uintx* value, Flag::Flags origin); + static bool uintxAtPut(char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } static bool uint64_tAt(char* name, size_t len, uint64_t* value); static bool uint64_tAt(char* name, uint64_t* value) { return uint64_tAt(name, strlen(name), value); } - static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin); - static bool uint64_tAtPut(char* name, uint64_t* value, FlagValueOrigin origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, Flag::Flags origin); + static bool uint64_tAtPut(char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } static bool doubleAt(char* name, size_t len, double* value); static bool doubleAt(char* name, double* value) { return doubleAt(name, strlen(name), value); } - static bool doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin); - static bool doubleAtPut(char* name, double* value, FlagValueOrigin origin) { return doubleAtPut(name, strlen(name), value, origin); } + static bool doubleAtPut(char* name, size_t len, double* value, Flag::Flags origin); + static bool doubleAtPut(char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } static bool ccstrAt(char* name, size_t len, ccstr* value); static bool ccstrAt(char* name, ccstr* value) { return ccstrAt(name, strlen(name), value); } - static bool ccstrAtPut(char* name, size_t len, ccstr* value, FlagValueOrigin origin); - static bool ccstrAtPut(char* name, ccstr* value, FlagValueOrigin origin) { return ccstrAtPut(name, strlen(name), value, origin); } + static bool ccstrAtPut(char* name, size_t len, ccstr* value, Flag::Flags origin); + static bool ccstrAtPut(char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } // Returns false if name is not a command line flag. static bool wasSetOnCmdline(const char* name, bool* value); @@ -2830,6 +2871,10 @@ product(intx, NmethodSweepCheckInterval, 5, \ "Compilers wake up every n seconds to possibly sweep nmethods") \ \ + product(intx, NmethodSweepActivity, 10, \ + "Removes cold nmethods from code cache if > 0. Higher values " \ + "result in more aggressive sweeping") \ + \ notproduct(bool, LogSweeper, false, \ "Keep a ring buffer of sweeper activity") \ \ @@ -3201,15 +3246,6 @@ product(bool, UseCodeCacheFlushing, true, \ "Attempt to clean the code cache before shutting off compiler") \ \ - product(intx, MinCodeCacheFlushingInterval, 30, \ - "Min number of seconds between code cache cleaning sessions") \ - \ - product(uintx, CodeCacheFlushingMinimumFreeSpace, 1500*K, \ - "When less than X space left, start code cache cleaning") \ - \ - product(uintx, CodeCacheFlushingFraction, 2, \ - "Fraction of the code cache that is flushed when full") \ - \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ @@ -3730,20 +3766,20 @@ */ // Interface macros -#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PD_PRODUCT_FLAG(type, name, doc) extern "C" type name; -#define DECLARE_DIAGNOSTIC_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PD_PRODUCT_FLAG(type, name, doc) extern "C" type name; +#define DECLARE_DIAGNOSTIC_FLAG(type, name, value, doc) extern "C" type name; #define DECLARE_EXPERIMENTAL_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_MANAGEABLE_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PRODUCT_RW_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_MANAGEABLE_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PRODUCT_RW_FLAG(type, name, value, doc) extern "C" type name; #ifdef PRODUCT -#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) const type name = value; -#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) const type name = pd_##name; -#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) +#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type CONST_##name; const type name = value; +#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type CONST_##name; const type name = pd_##name; +#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type CONST_##name; #else -#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name; -#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name; -#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name; +#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name; +#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type name; #endif // Special LP64 flags, product only needed for now. #ifdef _LP64 @@ -3753,23 +3789,23 @@ #endif // _LP64 // Implementation macros -#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name; -#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc) type name = pd_##name; +#define MATERIALIZE_DIAGNOSTIC_FLAG(type, name, value, doc) type name = value; #define MATERIALIZE_EXPERIMENTAL_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value; #ifdef PRODUCT -#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) /* flag name is constant */ -#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) /* flag name is constant */ -#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) +#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type CONST_##name = value; +#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type CONST_##name = pd_##name; +#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type CONST_##name = value; #else -#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value; -#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name; -#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name; +#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value; #endif #ifdef _LP64 -#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value; +#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value; #else #define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) /* flag is constant */ #endif // _LP64 diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/globals_extension.hpp --- a/src/share/vm/runtime/globals_extension.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/globals_extension.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -34,64 +34,42 @@ // Parens left off in the following for the enum decl below. #define FLAG_MEMBER(flag) Flag_##flag -#define RUNTIME_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define RUNTIME_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_MANAGEABLE_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define RUNTIME_PRODUCT_RW_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) +#define RUNTIME_MANAGEABLE_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PRODUCT_RW_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #else - #define RUNTIME_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#else -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C1_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), -#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), - #define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define C2_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define ARCH_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), - #define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), -#endif +#define ARCH_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER, RUNTIME_LP64_PRODUCT_FLAG_MEMBER) @@ -114,64 +92,42 @@ #define FLAG_MEMBER_WITH_TYPE(flag,type) Flag_##flag##_##type -#define RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) +#define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #else - #define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#else -#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ +#define RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ - #define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define ARCH_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define ARCH_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#define ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#ifdef PRODUCT - #define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ - #define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) -#else - #define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), - #define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), -#endif +#define ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE, @@ -233,19 +189,19 @@ #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) -#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), COMMAND_LINE)) -#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), ERGONOMIC)) +#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::COMMAND_LINE)) +#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name,type), (type)(value), Flag::ERGONOMIC)) // Can't put the following in CommandLineFlags because // of a circular dependency on the enum definition. class CommandLineFlagsEx : CommandLineFlags { public: - static void boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin); - static void intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin); - static void uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin); - static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin); - static void doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin); - static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin); + static void boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin); + static void intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); + static void uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); + static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); + static void doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); + static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); static bool is_default(CommandLineFlag flag); static bool is_ergo(CommandLineFlag flag); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/safepoint.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -519,8 +519,8 @@ } { - TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime); - NMethodSweeper::scan_stacks(); + TraceTime t4("mark nmethods", TraceSafepointCleanupTime); + NMethodSweeper::mark_active_nmethods(); } if (SymbolTable::needs_rehashing()) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/sweeper.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -127,64 +127,79 @@ #define SWEEP(nm) #endif +nmethod* NMethodSweeper::_current = NULL; // Current nmethod +long NMethodSweeper::_traversals = 0; // Nof. stack traversals performed +int NMethodSweeper::_seen = 0; // Nof. nmethods we have currently processed in current pass of CodeCache +int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep +int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep +int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep -long NMethodSweeper::_traversals = 0; // No. of stack traversals performed -nmethod* NMethodSweeper::_current = NULL; // Current nmethod -int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache -int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep -int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep -int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep - -volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +volatile int NMethodSweeper::_invocations = 0; // Nof. invocations left until we are completed with this pass volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. -jint NMethodSweeper::_locked_seen = 0; +jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; -bool NMethodSweeper::_resweep = false; -jint NMethodSweeper::_flush_token = 0; -jlong NMethodSweeper::_last_full_flush_time = 0; -int NMethodSweeper::_highest_marked = 0; -int NMethodSweeper::_dead_compile_ids = 0; -long NMethodSweeper::_last_flush_traversal_id = 0; +bool NMethodSweeper::_request_mark_phase = false; -int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache int NMethodSweeper::_total_nof_methods_reclaimed = 0; -jlong NMethodSweeper::_total_time_sweeping = 0; -jlong NMethodSweeper::_total_time_this_sweep = 0; -jlong NMethodSweeper::_peak_sweep_time = 0; -jlong NMethodSweeper::_peak_sweep_fraction_time = 0; -jlong NMethodSweeper::_total_disconnect_time = 0; -jlong NMethodSweeper::_peak_disconnect_time = 0; +jlong NMethodSweeper::_total_time_sweeping = 0; +jlong NMethodSweeper::_total_time_this_sweep = 0; +jlong NMethodSweeper::_peak_sweep_time = 0; +jlong NMethodSweeper::_peak_sweep_fraction_time = 0; +int NMethodSweeper::_hotness_counter_reset_val = 0; + class MarkActivationClosure: public CodeBlobClosure { public: virtual void do_code_blob(CodeBlob* cb) { - // If we see an activation belonging to a non_entrant nmethod, we mark it. - if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { - ((nmethod*)cb)->mark_as_seen_on_stack(); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*)cb; + nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val()); + // If we see an activation belonging to a non_entrant nmethod, we mark it. + if (nm->is_not_entrant()) { + nm->mark_as_seen_on_stack(); + } } } }; static MarkActivationClosure mark_activation_closure; +class SetHotnessClosure: public CodeBlobClosure { +public: + virtual void do_code_blob(CodeBlob* cb) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*)cb; + nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val()); + } + } +}; +static SetHotnessClosure set_hotness_closure; + + +int NMethodSweeper::hotness_counter_reset_val() { + if (_hotness_counter_reset_val == 0) { + _hotness_counter_reset_val = (ReservedCodeCacheSize < M) ? 1 : (ReservedCodeCacheSize / M) * 2; + } + return _hotness_counter_reset_val; +} bool NMethodSweeper::sweep_in_progress() { return (_current != NULL); } -void NMethodSweeper::scan_stacks() { +// Scans the stacks of all Java threads and marks activations of not-entrant methods. +// No need to synchronize access, since 'mark_active_nmethods' is always executed at a +// safepoint. +void NMethodSweeper::mark_active_nmethods() { assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); - if (!MethodFlushing) return; - - // No need to synchronize access, since this is always executed at a - // safepoint. - - // Make sure CompiledIC_lock in unlocked, since we might update some - // inline caches. If it is, we just bail-out and try later. - if (CompiledIC_lock->is_locked() || Patching_lock->is_locked()) return; + // If we do not want to reclaim not-entrant or zombie methods there is no need + // to scan stacks + if (!MethodFlushing) { + return; + } // Check for restart assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid"); - if (!sweep_in_progress() && _resweep) { + if (!sweep_in_progress() && need_marking_phase()) { _seen = 0; _invocations = NmethodSweepFraction; _current = CodeCache::first_nmethod(); @@ -197,30 +212,22 @@ Threads::nmethods_do(&mark_activation_closure); // reset the flags since we started a scan from the beginning. - _resweep = false; + reset_nmethod_marking(); _locked_seen = 0; _not_entrant_seen_on_stack = 0; + } else { + // Only set hotness counter + Threads::nmethods_do(&set_hotness_closure); } - if (UseCodeCacheFlushing) { - // only allow new flushes after the interval is complete. - jlong now = os::javaTimeMillis(); - jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; - jlong curr_interval = now - _last_full_flush_time; - if (curr_interval > max_interval) { - _flush_token = 0; - } - - if (!CodeCache::needs_flushing() && !CompileBroker::should_compile_new_jobs()) { - CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); - log_sweep("restart_compiler"); - } - } + OrderAccess::storestore(); } void NMethodSweeper::possibly_sweep() { assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); - if (!MethodFlushing || !sweep_in_progress()) return; + if (!MethodFlushing || !sweep_in_progress()) { + return; + } if (_invocations > 0) { // Only one thread at a time will sweep @@ -258,8 +265,7 @@ if (!CompileBroker::should_compile_new_jobs()) { // If we have turned off compilations we might as well do full sweeps // in order to reach the clean state faster. Otherwise the sleeping compiler - // threads will slow down sweeping. After a few iterations the cache - // will be clean and sweeping stops (_resweep will not be set) + // threads will slow down sweeping. _invocations = 1; } @@ -271,9 +277,11 @@ int todo = (CodeCache::nof_nmethods() - _seen) / _invocations; int swept_count = 0; + assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); assert(!CodeCache_lock->owned_by_self(), "just checking"); + int freed_memory = 0; { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -299,7 +307,7 @@ // Now ready to process nmethod and give up CodeCache_lock { MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - process_nmethod(_current); + freed_memory += process_nmethod(_current); } _seen++; _current = next; @@ -308,11 +316,11 @@ assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); - if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) { + if (!sweep_in_progress() && !need_marking_phase() && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were // nmethods we were unable to process either because they were - // locked or were still on stack. We don't have to aggresively - // clean them up so just stop scanning. We could scan once more + // locked or were still on stack. We don't have to aggressively + // clean them up so just stop scanning. We could scan once more // but that complicates the control logic and it's unlikely to // matter much. if (PrintMethodFlushing) { @@ -351,9 +359,16 @@ log_sweep("finished"); } - // Sweeper is the only case where memory is released, - // check here if it is time to restart the compiler. - if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs() && !CodeCache::needs_flushing()) { + // Sweeper is the only case where memory is released, check here if it + // is time to restart the compiler. Only checking if there is a certain + // amount of free memory in the code cache might lead to re-enabling + // compilation although no memory has been released. For example, there are + // cases when compilation was disabled although there is 4MB (or more) free + // memory in the code cache. The reason is code cache fragmentation. Therefore, + // it only makes sense to re-enable compilation if we have actually freed memory. + // Note that typically several kB are released for sweeping 16MB of the code + // cache. As a result, 'freed_memory' > 0 to restart the compiler. + if (UseCodeCacheFlushing && (!CompileBroker::should_compile_new_jobs() && (freed_memory > 0))) { CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); log_sweep("restart_compiler"); } @@ -367,8 +382,8 @@ _thread = CompilerThread::current(); if (!nm->is_zombie() && !nm->is_unloaded()) { // Only expose live nmethods for scanning - _thread->set_scanned_nmethod(nm); - } + _thread->set_scanned_nmethod(nm); + } } ~NMethodMarker() { _thread->set_scanned_nmethod(NULL); @@ -392,20 +407,20 @@ nm->flush(); } -void NMethodSweeper::process_nmethod(nmethod *nm) { +int NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); + int freed_memory = 0; // Make sure this nmethod doesn't get unloaded during the scan, - // since the locks acquired below might safepoint. + // since safepoints may happen during acquired below locks. NMethodMarker nmm(nm); - SWEEP(nm); // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods if (nm->is_alive()) { - // Clean-up all inline caches that points to zombie/non-reentrant methods + // Clean inline caches that point to zombie/non-entrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); @@ -413,18 +428,19 @@ _locked_seen++; SWEEP(nm); } - return; + return freed_memory; } if (nm->is_zombie()) { - // If it is first time, we see nmethod then we mark it. Otherwise, - // we reclame it. When we have seen a zombie method twice, we know that + // If it is the first time we see nmethod then we mark it. Otherwise, + // we reclaim it. When we have seen a zombie method twice, we know that // there are no inline caches that refer to it. if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); } + freed_memory = nm->total_size(); release_nmethod(nm); _flushed_count++; } else { @@ -432,19 +448,19 @@ tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); } nm->mark_for_reclamation(); - _resweep = true; + request_nmethod_marking(); _marked_count++; SWEEP(nm); } } else if (nm->is_not_entrant()) { - // If there is no current activations of this method on the + // If there are no current activations of this method on the // stack we can safely convert it to a zombie method if (nm->can_not_entrant_be_converted()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } nm->make_zombie(); - _resweep = true; + request_nmethod_marking(); _zombified_count++; SWEEP(nm); } else { @@ -459,159 +475,57 @@ } } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie - if (PrintMethodFlushing && Verbose) + if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); - + } if (nm->is_osr_method()) { SWEEP(nm); // No inline caches will ever point to osr methods, so we can just remove it + freed_memory = nm->total_size(); release_nmethod(nm); _flushed_count++; } else { nm->make_zombie(); - _resweep = true; + request_nmethod_marking(); _zombified_count++; SWEEP(nm); } } else { - assert(nm->is_alive(), "should be alive"); - if (UseCodeCacheFlushing) { - if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() && - (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) { - // This method has not been called since the forced cleanup happened - nm->make_not_entrant(); + if (!nm->is_locked_by_vm() && !nm->is_osr_method() && !nm->is_native_method()) { + // Do not make native methods and OSR-methods not-entrant + nm->dec_hotness_counter(); + // Get the initial value of the hotness counter. This value depends on the + // ReservedCodeCacheSize + int reset_val = hotness_counter_reset_val(); + int time_since_reset = reset_val - nm->hotness_counter(); + double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity); + // The less free space in the code cache we have - the bigger reverse_free_ratio() is. + // I.e., 'threshold' increases with lower available space in the code cache and a higher + // NmethodSweepActivity. If the current hotness counter - which decreases from its initial + // value until it is reset by stack walking - is smaller than the computed threshold, the + // corresponding nmethod is considered for removal. + if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > 10)) { + // A method is marked as not-entrant if the method is + // 1) 'old enough': nm->hotness_counter() < threshold + // 2) The method was in_use for a minimum amount of time: (time_since_reset > 10) + // The second condition is necessary if we are dealing with very small code cache + // sizes (e.g., <10m) and the code cache size is too small to hold all hot methods. + // The second condition ensures that methods are not immediately made not-entrant + // after compilation. + nm->make_not_entrant(); + request_nmethod_marking(); + } } } - - // Clean-up all inline caches that points to zombie/non-reentrant methods + // Clean-up all inline caches that point to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } -} - -// Code cache unloading: when compilers notice the code cache is getting full, -// they will call a vm op that comes here. This code attempts to speculatively -// unload the oldest half of the nmethods (based on the compile job id) by -// saving the old code in a list in the CodeCache. Then -// execution resumes. If a method so marked is not called by the second sweeper -// stack traversal after the current one, the nmethod will be marked non-entrant and -// got rid of by normal sweeping. If the method is called, the Method*'s -// _code field is restored and the Method*/nmethod -// go back to their normal state. -void NMethodSweeper::handle_full_code_cache(bool is_full) { - - if (is_full) { - // Since code cache is full, immediately stop new compiles - if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { - log_sweep("disable_compiler"); - } - } - - // Make sure only one thread can flush - // The token is reset after CodeCacheMinimumFlushInterval in scan stacks, - // no need to check the timeout here. - jint old = Atomic::cmpxchg( 1, &_flush_token, 0 ); - if (old != 0) { - return; - } - - VM_HandleFullCodeCache op(is_full); - VMThread::execute(&op); - - // resweep again as soon as possible - _resweep = true; + return freed_memory; } -void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { - // If there was a race in detecting full code cache, only run - // one vm op for it or keep the compiler shut off - - jlong disconnect_start_counter = os::elapsed_counter(); - - // Traverse the code cache trying to dump the oldest nmethods - int curr_max_comp_id = CompileBroker::get_compilation_id(); - int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; - - log_sweep("start_cleaning"); - - nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); - jint disconnected = 0; - jint made_not_entrant = 0; - jint nmethod_count = 0; - - while ((nm != NULL)){ - int curr_comp_id = nm->compile_id(); - - // OSR methods cannot be flushed like this. Also, don't flush native methods - // since they are part of the JDK in most cases - if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) { - - // only count methods that can be speculatively disconnected - nmethod_count++; - - if (nm->is_in_use() && (curr_comp_id < flush_target)) { - if ((nm->method()->code() == nm)) { - // This method has not been previously considered for - // unloading or it was restored already - CodeCache::speculatively_disconnect(nm); - disconnected++; - } else if (nm->is_speculatively_disconnected()) { - // This method was previously considered for preemptive unloading and was not called since then - CompilationPolicy::policy()->delay_compilation(nm->method()); - nm->make_not_entrant(); - made_not_entrant++; - } - - if (curr_comp_id > _highest_marked) { - _highest_marked = curr_comp_id; - } - } - } - nm = CodeCache::alive_nmethod(CodeCache::next(nm)); - } - - // remember how many compile_ids wheren't seen last flush. - _dead_compile_ids = curr_max_comp_id - nmethod_count; - - log_sweep("stop_cleaning", - "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", - disconnected, made_not_entrant); - - // Shut off compiler. Sweeper will start over with a new stack scan and - // traversal cycle and turn it back on if it clears enough space. - if (is_full) { - _last_full_flush_time = os::javaTimeMillis(); - } - - jlong disconnect_end_counter = os::elapsed_counter(); - jlong disconnect_time = disconnect_end_counter - disconnect_start_counter; - _total_disconnect_time += disconnect_time; - _peak_disconnect_time = MAX2(disconnect_time, _peak_disconnect_time); - - EventCleanCodeCache event(UNTIMED); - if (event.should_commit()) { - event.set_starttime(disconnect_start_counter); - event.set_endtime(disconnect_end_counter); - event.set_disconnectedCount(disconnected); - event.set_madeNonEntrantCount(made_not_entrant); - event.commit(); - } - _number_of_flushes++; - - // After two more traversals the sweeper will get rid of unrestored nmethods - _last_flush_traversal_id = _traversals; - _resweep = true; -#ifdef ASSERT - - if(PrintMethodFlushing && Verbose) { - tty->print_cr("### sweeper: unload time: " INT64_FORMAT, (jlong)disconnect_time); - } -#endif -} - - // Print out some state information about the current sweep and the // state of the code cache if it's requested. void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/sweeper.hpp --- a/src/share/vm/runtime/sweeper.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/sweeper.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -27,8 +27,30 @@ // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches -// - reclamation of unreferences zombie nmethods -// +// - reclamation of nmethods +// Removing nmethods from the code cache includes two operations +// 1) mark active nmethods +// Is done in 'mark_active_nmethods()'. This function is called at a +// safepoint and marks all nmethods that are active on a thread's stack. +// 2) sweep nmethods +// Is done in sweep_code_cache(). This function is the only place in the +// sweeper where memory is reclaimed. Note that sweep_code_cache() is not +// called at a safepoint. However, sweep_code_cache() stops executing if +// another thread requests a safepoint. Consequently, 'mark_active_nmethods()' +// and sweep_code_cache() cannot execute at the same time. +// To reclaim memory, nmethods are first marked as 'not-entrant'. Methods can +// be made not-entrant by (i) the sweeper, (ii) deoptimization, (iii) dependency +// invalidation, and (iv) being replaced be a different method version (tiered +// compilation). Not-entrant nmethod cannot be called by Java threads, but they +// can still be active on the stack. To ensure that active nmethod are not reclaimed, +// we have to wait until the next marking phase has completed. If a not-entrant +// nmethod was NOT marked as active, it can be converted to 'zombie' state. To safely +// remove the nmethod, all inline caches (IC) that point to the the nmethod must be +// cleared. After that, the nmethod can be evicted from the code cache. Each nmethod's +// state change happens during separate sweeps. It may take at least 3 sweeps before an +// nmethod's space is freed. Sweeping is currently done by compiler threads between +// compilations or at least each 5 sec (NmethodSweepCheckInterval) when the code cache +// is full. class NMethodSweeper : public AllStatic { static long _traversals; // Stack scan count, also sweep ID. @@ -41,46 +63,38 @@ static volatile int _invocations; // No. of invocations left until we are completed with this pass static volatile int _sweep_started; // Flag to control conc sweeper - //The following are reset in scan_stacks and synchronized by the safepoint - static bool _resweep; // Indicates that a change has happend and we want another sweep, - // always checked and reset at a safepoint so memory will be in sync. - static int _locked_seen; // Number of locked nmethods encountered during the scan + //The following are reset in mark_active_nmethods and synchronized by the safepoint + static bool _request_mark_phase; // Indicates that a change has happend and we need another mark pahse, + // always checked and reset at a safepoint so memory will be in sync. + static int _locked_seen; // Number of locked nmethods encountered during the scan static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack - static jint _flush_token; // token that guards method flushing, making sure it is executed only once. - - // These are set during a flush, a VM-operation - static long _last_flush_traversal_id; // trav number at last flush unloading - static jlong _last_full_flush_time; // timestamp of last emergency unloading - - // These are synchronized by the _sweep_started token - static int _highest_marked; // highest compile id dumped at last emergency unloading - static int _dead_compile_ids; // number of compile ids that where not in the cache last flush // Stat counters - static int _number_of_flushes; // Total of full traversals caused by full cache static int _total_nof_methods_reclaimed; // Accumulated nof methods flushed static jlong _total_time_sweeping; // Accumulated time sweeping static jlong _total_time_this_sweep; // Total time this sweep static jlong _peak_sweep_time; // Peak time for a full sweep static jlong _peak_sweep_fraction_time; // Peak time sweeping one fraction - static jlong _total_disconnect_time; // Total time cleaning code mem - static jlong _peak_disconnect_time; // Peak time cleaning code mem - static void process_nmethod(nmethod *nm); + static int process_nmethod(nmethod *nm); static void release_nmethod(nmethod* nm); - static void log_sweep(const char* msg, const char* format = NULL, ...); static bool sweep_in_progress(); + static void sweep_code_cache(); + static void request_nmethod_marking() { _request_mark_phase = true; } + static void reset_nmethod_marking() { _request_mark_phase = false; } + static bool need_marking_phase() { return _request_mark_phase; } + + static int _hotness_counter_reset_val; public: static long traversal_count() { return _traversals; } - static int number_of_flushes() { return _number_of_flushes; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } static jlong total_time_sweeping() { return _total_time_sweeping; } static jlong peak_sweep_time() { return _peak_sweep_time; } static jlong peak_sweep_fraction_time() { return _peak_sweep_fraction_time; } - static jlong total_disconnect_time() { return _total_disconnect_time; } - static jlong peak_disconnect_time() { return _peak_disconnect_time; } + static void log_sweep(const char* msg, const char* format = NULL, ...); + #ifdef ASSERT static bool is_sweeping(nmethod* which) { return _current == which; } @@ -90,19 +104,18 @@ static void report_events(); #endif - static void scan_stacks(); // Invoked at the end of each safepoint - static void sweep_code_cache(); // Concurrent part of sweep job - static void possibly_sweep(); // Compiler threads call this to sweep + static void mark_active_nmethods(); // Invoked at the end of each safepoint + static void possibly_sweep(); // Compiler threads call this to sweep - static void notify(nmethod* nm) { + static int sort_nmethods_by_hotness(nmethod** nm1, nmethod** nm2); + static int hotness_counter_reset_val(); + + static void notify() { // Request a new sweep of the code cache from the beginning. No // need to synchronize the setting of this flag since it only // changes to false at safepoint so we can never overwrite it with false. - _resweep = true; + request_nmethod_marking(); } - - static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate - static void speculative_disconnect_nmethods(bool was_full); // Called by vm op to deal with alloc failure }; #endif // SHARE_VM_RUNTIME_SWEEPER_HPP diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -176,6 +176,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/parse.hpp" @@ -841,7 +842,7 @@ nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ - nonstatic_field(nmethod, _state, unsigned char) \ + nonstatic_field(nmethod, _state, volatile unsigned char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ nonstatic_field(nmethod, _deoptimize_mh_offset, int) \ @@ -1185,11 +1186,10 @@ /* -XX flags */ \ /*********************/ \ \ - nonstatic_field(Flag, type, const char*) \ - nonstatic_field(Flag, name, const char*) \ - unchecked_nonstatic_field(Flag, addr, sizeof(void*)) /* NOTE: no type */ \ - nonstatic_field(Flag, kind, const char*) \ - nonstatic_field(Flag, origin, FlagValueOrigin) \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) /* NOTE: no type */ \ + nonstatic_field(Flag, _flags, Flag::Flags) \ static_field(Flag, flags, Flag*) \ static_field(Flag, numFlags, size_t) \ \ @@ -1360,6 +1360,7 @@ declare_integer_type(long) \ declare_integer_type(char) \ declare_unsigned_integer_type(unsigned char) \ + declare_unsigned_integer_type(volatile unsigned char) \ declare_unsigned_integer_type(u_char) \ declare_unsigned_integer_type(unsigned int) \ declare_unsigned_integer_type(uint) \ @@ -1382,6 +1383,7 @@ declare_toplevel_type(char**) \ declare_toplevel_type(u_char*) \ declare_toplevel_type(unsigned char*) \ + declare_toplevel_type(volatile unsigned char*) \ \ /*******************************************************************/ \ /* Types which it will be handy to have available over in the SA */ \ @@ -1928,6 +1930,9 @@ declare_c2_type(CmpF3Node, CmpFNode) \ declare_c2_type(CmpDNode, CmpNode) \ declare_c2_type(CmpD3Node, CmpDNode) \ + declare_c2_type(MathExactNode, MultiNode) \ + declare_c2_type(AddExactINode, MathExactNode) \ + declare_c2_type(FlagsProjNode, ProjNode) \ declare_c2_type(BoolNode, Node) \ declare_c2_type(AbsNode, Node) \ declare_c2_type(AbsINode, AbsNode) \ @@ -2074,7 +2079,7 @@ declare_integer_type(JavaThreadState) \ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ - declare_integer_type(FlagValueOrigin) \ + declare_integer_type(Flag::Flags) \ COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ @@ -2082,7 +2087,7 @@ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ - declare_type(Array, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ \ declare_integer_type(AccessFlags) /* FIXME: wrong type (not integer) */\ declare_toplevel_type(address) /* FIXME: should this be an integer type? */\ diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/vm_operations.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -173,10 +173,6 @@ SymbolTable::unlink(); } -void VM_HandleFullCodeCache::doit() { - NMethodSweeper::speculative_disconnect_nmethods(_is_full); -} - void VM_Verify::doit() { Universe::heap()->prepare_for_verify(); Universe::verify(_silent); diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/runtime/vm_operations.hpp Fri Oct 04 21:00:43 2013 -0700 @@ -51,7 +51,6 @@ template(DeoptimizeAll) \ template(ZombieAll) \ template(UnlinkSymbols) \ - template(HandleFullCodeCache) \ template(Verify) \ template(PrintJNI) \ template(HeapDumper) \ @@ -261,16 +260,6 @@ bool allow_nested_vm_operations() const { return true; } }; -class VM_HandleFullCodeCache: public VM_Operation { - private: - bool _is_full; - public: - VM_HandleFullCodeCache(bool is_full) { _is_full = is_full; } - VMOp_Type type() const { return VMOp_HandleFullCodeCache; } - void doit(); - bool allow_nested_vm_operations() const { return true; } -}; - #ifndef PRODUCT class VM_DeoptimizeAll: public VM_Operation { private: diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/services/attachListener.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -245,7 +245,7 @@ } value = (tmp != 0); } - bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::boolAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -263,7 +263,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::intxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -282,7 +282,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -301,7 +301,7 @@ return JNI_ERR; } } - bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -316,7 +316,7 @@ out->print_cr("flag value must be a string"); return JNI_ERR; } - bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (res) { FREE_C_HEAP_ARRAY(char, value, mtInternal); } else { diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/services/classLoadingService.cpp --- a/src/share/vm/services/classLoadingService.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/services/classLoadingService.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -202,7 +202,7 @@ MutexLocker m(Management_lock); // verbose will be set to the previous value - bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, Flag::MANAGEMENT); assert(succeed, "Setting TraceClassLoading flag fails"); reset_trace_class_unloading(); @@ -213,7 +213,7 @@ void ClassLoadingService::reset_trace_class_unloading() { assert(Management_lock->owned_by_self(), "Must own the Management_lock"); bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); - bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, Flag::MANAGEMENT); assert(succeed, "Setting TraceClassUnLoading flag fails"); } diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/services/dtraceAttacher.cpp --- a/src/share/vm/services/dtraceAttacher.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/services/dtraceAttacher.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -51,7 +51,7 @@ static void set_bool_flag(const char* flag, bool value) { CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value, - ATTACH_ON_DEMAND); + Flag::ATTACH_ON_DEMAND); } // Enable only the "fine grained" flags. Do *not* touch diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/services/management.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -1643,9 +1643,13 @@ int num_entries = 0; for (int i = 0; i < nFlags; i++) { Flag* flag = &Flag::flags[i]; + // Exclude notproduct and develop flags in product builds. + if (flag->is_constant_in_binary()) { + continue; + } // Exclude the locked (experimental, diagnostic) flags if (flag->is_unlocked() || flag->is_unlocker()) { - Handle s = java_lang_String::create_from_str(flag->name, CHECK_0); + Handle s = java_lang_String::create_from_str(flag->_name, CHECK_0); flags_ah->obj_at_put(num_entries, s()); num_entries++; } @@ -1669,7 +1673,7 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { - flag_name = java_lang_String::create_from_str(flag->name, CHECK_false); + flag_name = java_lang_String::create_from_str(flag->_name, CHECK_false); } else { flag_name = name; } @@ -1698,23 +1702,23 @@ global->writeable = flag->is_writeable(); global->external = flag->is_external(); - switch (flag->origin) { - case DEFAULT: + switch (flag->get_origin()) { + case Flag::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case COMMAND_LINE: + case Flag::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case ENVIRON_VAR: + case Flag::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case CONFIG_FILE: + case Flag::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case MANAGEMENT: + case Flag::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case ERGONOMIC: + case Flag::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; default: @@ -1781,6 +1785,10 @@ int num_entries = 0; for (int i = 0; i < nFlags && num_entries < count; i++) { Flag* flag = &Flag::flags[i]; + // Exclude notproduct and develop flags in product builds. + if (flag->is_constant_in_binary()) { + continue; + } // Exclude the locked (diagnostic, experimental) flags if ((flag->is_unlocked() || flag->is_unlocker()) && add_global_entry(env, null_h, &globals[num_entries], flag, THREAD)) { @@ -1813,23 +1821,23 @@ bool succeed; if (flag->is_bool()) { bool bvalue = (new_value.z == JNI_TRUE ? true : false); - succeed = CommandLineFlags::boolAtPut(name, &bvalue, MANAGEMENT); + succeed = CommandLineFlags::boolAtPut(name, &bvalue, Flag::MANAGEMENT); } else if (flag->is_intx()) { intx ivalue = (intx)new_value.j; - succeed = CommandLineFlags::intxAtPut(name, &ivalue, MANAGEMENT); + succeed = CommandLineFlags::intxAtPut(name, &ivalue, Flag::MANAGEMENT); } else if (flag->is_uintx()) { uintx uvalue = (uintx)new_value.j; - succeed = CommandLineFlags::uintxAtPut(name, &uvalue, MANAGEMENT); + succeed = CommandLineFlags::uintxAtPut(name, &uvalue, Flag::MANAGEMENT); } else if (flag->is_uint64_t()) { uint64_t uvalue = (uint64_t)new_value.j; - succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, MANAGEMENT); + succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, Flag::MANAGEMENT); } else if (flag->is_ccstr()) { oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { THROW(vmSymbols::java_lang_NullPointerException()); } ccstr svalue = java_lang_String::as_utf8_string(str); - succeed = CommandLineFlags::ccstrAtPut(name, &svalue, MANAGEMENT); + succeed = CommandLineFlags::ccstrAtPut(name, &svalue, Flag::MANAGEMENT); } assert(succeed, "Setting flag should succeed"); JVM_END diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/services/memoryService.cpp Fri Oct 04 21:00:43 2013 -0700 @@ -515,7 +515,7 @@ bool MemoryService::set_verbose(bool verbose) { MutexLocker m(Management_lock); // verbose will be set to the previous value - bool succeed = CommandLineFlags::boolAtPut((char*)"PrintGC", &verbose, MANAGEMENT); + bool succeed = CommandLineFlags::boolAtPut((char*)"PrintGC", &verbose, Flag::MANAGEMENT); assert(succeed, "Setting PrintGC flag fails"); ClassLoadingService::reset_trace_class_unloading(); @@ -618,4 +618,3 @@ MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime, _recordGCEndTime, _countCollection, _cause); } - diff -r 4212bfb33d76 -r 2720ab7a0d70 src/share/vm/trace/trace.xml --- a/src/share/vm/trace/trace.xml Sat Oct 05 03:14:53 2013 +0200 +++ b/src/share/vm/trace/trace.xml Fri Oct 04 21:00:43 2013 -0700 @@ -313,13 +313,6 @@ - - - - - 5) { + Verify.verify(values[i & 255] + i, values[i & 255] - i); + } else { + Verify.verify(values[i & 255] - i, values[i & 255] + i); + } + } + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/intrinsics/mathexact/LoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/LoopDependentTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile LoopDependentTest.java Verify.java + * @run main LoopDependentTest + * + */ + +import java.lang.ArithmeticException; + +public class LoopDependentTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + for (int i = 0; i < 50000; ++i) { + Verify.verify(rnd1 + i, rnd2 + i); + Verify.verify(rnd1 + i, rnd2 + (i & 0xff)); + Verify.verify(rnd1 - i, rnd2 - (i & 0xff)); + Verify.verify(rnd1 + i + 1, rnd2 + i + 2); + Verify.verify(rnd1 + i * 2, rnd2 + i); + } + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/intrinsics/mathexact/NonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NonConstantTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile NonConstantTest.java Verify.java + * @run main NonConstantTest + * + */ + +import java.lang.ArithmeticException; + +public class NonConstantTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + Verify.verify(rnd1, rnd2); + Verify.verify(rnd1, rnd2 + 1); + Verify.verify(rnd1 + 1, rnd2); + Verify.verify(rnd1 - 1, rnd2); + Verify.verify(rnd1, rnd2 - 1); + } + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/intrinsics/mathexact/Verify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/Verify.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, 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. + */ + +public class Verify { + public static String throwWord(boolean threw) { + return (threw ? "threw" : "didn't throw"); + } + + public static void verify(int a, int b) { + boolean exception1 = false, exception2 = false; + int result1 = 0, result2 = 0; + try { + result1 = testIntrinsic(a, b); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = testNonIntrinsic(a, b); + } catch (ArithmeticException e) { + exception2 = true; + } + + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version " + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version returned: " + a + " while NonIntrinsic version returned: " + b); + } + } + + public static int testIntrinsic(int a, int b) { + return java.lang.Math.addExact(a, b); + } + + public static int testNonIntrinsic(int a, int b) { + return safeAddExact(a, b); + } + + // Copied java.lang.Math.addExact to avoid intrinsification + public static int safeAddExact(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +/** + * A minimal classloader for loading bytecodes that could not result from + * properly compiled Java. + * + * @author dr2chase + */ +public class ByteClassLoader extends ClassLoader { + /** + * (pre)load class name using classData for the definition. + * + * @param name + * @param classData + * @return + */ + public Class loadBytes(String name, byte[] classData) { + Class clazz = defineClass(name, classData, 0, classData.length); + resolveClass(clazz); + return clazz; + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/jsr292/methodHandleExceptions/C.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/C.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, 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 class -- implements I, which provides default for m, but this class + * declares it abstract which (should) hide the interface default, and throw + * an abstract method error if it is called (calling it requires bytecode hacking + * or inconsistent compilation). + */ +public abstract class C implements I { + public abstract int m(); +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/jsr292/methodHandleExceptions/I.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/I.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +public interface I { + default public int m() { return 1; } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +import java.lang.reflect.InvocationTargetException; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * @test + * @bug 8025260 + * @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path + * + * @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java + * @run main/othervm TestAMEnotNPE + */ + +public class TestAMEnotNPE implements Opcodes { + + /** + * The bytes for D, a NOT abstract class extending abstract class C + * without supplying an implementation for abstract method m. + * There is a default method in the interface I, but it should lose to + * the abstract class. + + class D extends C { + D() { super(); } + // does not define m + } + + * @return + * @throws Exception + */ + public static byte[] bytesForD() throws Exception { + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "C", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + + /** + * The bytecodes for an invokeExact of a particular methodHandle, I.m, invoked on a D + + class T { + T() { super(); } // boring constructor + int test() { + MethodHandle mh = `I.m():int`; + D d = new D(); + return mh.invokeExact(d); // Should explode here, AbstractMethodError + } + } + + * @return + * @throws Exception + */ + public static byte[] bytesForT() throws Exception { + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null); + mv.visitCode(); + mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I")); + mv.visitTypeInsn(NEW, "D"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "D", "", "()V"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I"); + mv.visitInsn(IRETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + public static void main(String args[] ) throws Throwable { + ByteClassLoader bcl = new ByteClassLoader(); + Class d = bcl.loadBytes("D", bytesForD()); + Class t = bcl.loadBytes("T", bytesForT()); + try { + Object result = t.getMethod("test").invoke(null); + System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw no exception"); + throw new Error("Missing expected exception"); + } catch (InvocationTargetException e) { + Throwable th = e.getCause(); + if (th instanceof AbstractMethodError) { + th.printStackTrace(System.out); + System.out.println("PASS, saw expected exception (AbstractMethodError, wrapped in InvocationTargetException)."); + } else { + System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th); + throw th; + } + } + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/CompilerWhiteBoxTest.java --- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -74,6 +74,9 @@ protected static final int THRESHOLD; /** count of invocation to triger OSR compilation */ protected static final long BACKEDGE_THRESHOLD; + /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ + protected static final String MODE + = System.getProperty("java.vm.info"); static { if (TIERED_COMPILATION) { @@ -202,7 +205,7 @@ if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { throw new RuntimeException(method + " osr_comp_level must be == 0"); } - } + } /** * Checks, that {@linkplain #method} is compiled. diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/DeoptimizeAllTest.java --- a/test/compiler/whitebox/DeoptimizeAllTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -53,6 +53,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } compile(); checkCompiled(); WHITE_BOX.deoptimizeAll(); diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/DeoptimizeMethodTest.java --- a/test/compiler/whitebox/DeoptimizeMethodTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -53,6 +53,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } compile(); checkCompiled(); deoptimize(); diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/EnqueueMethodForCompilationTest.java --- a/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -70,12 +70,10 @@ int compLevel = getCompLevel(); int bci = WHITE_BOX.getMethodEntryBci(method); - System.out.println("bci = " + bci); - printInfo(); deoptimize(); - printInfo(); checkNotCompiled(); - printInfo(); + WHITE_BOX.clearMethodState(method); + WHITE_BOX.enqueueMethodForCompilation(method, compLevel, bci); checkCompiled(); deoptimize(); diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/IsMethodCompilableTest.java --- a/test/compiler/whitebox/IsMethodCompilableTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -68,6 +68,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); } diff -r 4212bfb33d76 -r 2720ab7a0d70 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Fri Oct 04 21:00:43 2013 -0700 @@ -62,6 +62,12 @@ */ @Override protected void test() throws Exception { + if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + "compiled ")) { + System.err.printf("Warning: %s is not applicable in %s%n", + testCase.name(), CompilerWhiteBoxTest.MODE); + return; + } checkNotCompiled(); if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/g1/TestSummarizeRSetStats.java --- a/test/gc/g1/TestSummarizeRSetStats.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/gc/g1/TestSummarizeRSetStats.java Fri Oct 04 21:00:43 2013 -0700 @@ -25,140 +25,61 @@ * @test TestSummarizeRSetStats.java * @bug 8013895 * @library /testlibrary - * @build TestSummarizeRSetStats + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStats * @summary Verify output of -XX:+G1SummarizeRSetStats * @run main TestSummarizeRSetStats * * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. */ -import com.oracle.java.testlibrary.*; -import java.lang.Thread; -import java.util.ArrayList; -import java.util.Arrays; - -class RunSystemGCs { - // 4M size, both are directly allocated into the old gen - static Object[] largeObject1 = new Object[1024 * 1024]; - static Object[] largeObject2 = new Object[1024 * 1024]; - - static int[] temp; - - public static void main(String[] args) { - // create some cross-references between these objects - for (int i = 0; i < largeObject1.length; i++) { - largeObject1[i] = largeObject2; - } - - for (int i = 0; i < largeObject2.length; i++) { - largeObject2[i] = largeObject1; - } - - int numGCs = Integer.parseInt(args[0]); - - if (numGCs > 0) { - // try to force a minor collection: the young gen is 4M, the - // amount of data allocated below is roughly that (4*1024*1024 + - // some header data) - for (int i = 0; i < 1024 ; i++) { - temp = new int[1024]; - } - } - - for (int i = 0; i < numGCs - 1; i++) { - System.gc(); - } - } -} - public class TestSummarizeRSetStats { - public static String runTest(String[] additionalArgs, int numGCs) throws Exception { - ArrayList finalargs = new ArrayList(); - String[] defaultArgs = new String[] { - "-XX:+UseG1GC", - "-Xmn4m", - "-Xmx20m", - "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking - "-XX:+PrintGC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:G1HeapRegionSize=1M", - }; - - finalargs.addAll(Arrays.asList(defaultArgs)); - - if (additionalArgs != null) { - finalargs.addAll(Arrays.asList(additionalArgs)); - } - - finalargs.add(RunSystemGCs.class.getName()); - finalargs.add(String.valueOf(numGCs)); - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - finalargs.toArray(new String[0])); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - output.shouldHaveExitValue(0); - - String result = output.getStdout(); - return result; - } - - private static void expectStatistics(String result, int expectedCumulative, int expectedPeriodic) throws Exception { - int actualTotal = result.split("Concurrent RS processed").length - 1; - int actualCumulative = result.split("Cumulative RS summary").length - 1; - - if (expectedCumulative != actualCumulative) { - throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); - } - - if (expectedPeriodic != (actualTotal - actualCumulative)) { - throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); - } - } - public static void main(String[] args) throws Exception { String result; - // no RSet statistics output - result = runTest(null, 0); - expectStatistics(result, 0, 0); + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } - // no RSet statistics output - result = runTest(null, 2); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // no RSet statistics output - result = runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); - expectStatistics(result, 1, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // two times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); - expectStatistics(result, 1, 1); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); - // four times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 1, 3); + // four times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 6); - // three times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); - expectStatistics(result, 1, 2); + // three times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 4); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); - expectStatistics(result, 1, 1); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); } } diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/g1/TestSummarizeRSetStatsPerRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsPerRegion.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, 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 TestSummarizeRSetStatsPerRegion.java + * @bug 8014078 + * @library /testlibrary + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStatsPerRegion + * @summary Verify output of -XX:+G1SummarizeRSetStats in regards to per-region type output + * @run main TestSummarizeRSetStatsPerRegion + */ + +import com.oracle.java.testlibrary.*; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +public class TestSummarizeRSetStatsPerRegion { + + public static void main(String[] args) throws Exception { + String result; + + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 2); + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/g1/TestSummarizeRSetStatsThreads.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsThreads.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, 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 TestSummarizeRSetStatsThreads + * @bug 8025441 + * @summary Ensure that various values of worker threads/concurrent + * refinement threads do not crash the VM. + * @key gc + * @library /testlibrary + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestSummarizeRSetStatsThreads { + + private static void runTest(int refinementThreads, int workerThreads) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+G1SummarizeRSetStats", + "-XX:G1ConcRefinementThreads=" + refinementThreads, + "-XX:ParallelGCThreads=" + workerThreads, + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // check output to contain the string "Concurrent RS threads times (s)" followed by + // the correct number of values in the next line. + + // a zero in refinement thread numbers indicates that the value in ParallelGCThreads should be used. + // Additionally use at least one thread. + int expectedNumRefinementThreads = refinementThreads == 0 ? workerThreads : refinementThreads; + expectedNumRefinementThreads = Math.max(1, expectedNumRefinementThreads); + // create the pattern made up of n copies of a floating point number pattern + String numberPattern = String.format("%0" + expectedNumRefinementThreads + "d", 0) + .replace("0", "\\s+\\d+\\.\\d+"); + String pattern = "Concurrent RS threads times \\(s\\)$" + numberPattern + "$"; + Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStdout()); + + if (!m.find()) { + throw new Exception("Could not find correct output for concurrent RS threads times in stdout," + + " should match the pattern \"" + pattern + "\", but stdout is \n" + output.getStdout()); + } + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + // different valid combinations of number of refinement and gc worker threads + runTest(0, 0); + runTest(0, 5); + runTest(5, 0); + runTest(10, 10); + runTest(1, 2); + runTest(4, 3); + } +} diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/g1/TestSummarizeRSetStatsTools.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStatsTools.java Fri Oct 04 21:00:43 2013 -0700 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * Common helpers for TestSummarizeRSetStats* tests + */ + +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +import com.oracle.java.testlibrary.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +class VerifySummaryOutput { + // 4M size, both are directly allocated into the old gen + static Object[] largeObject1 = new Object[1024 * 1024]; + static Object[] largeObject2 = new Object[1024 * 1024]; + + static int[] temp; + + public static void main(String[] args) { + // create some cross-references between these objects + for (int i = 0; i < largeObject1.length; i++) { + largeObject1[i] = largeObject2; + } + + for (int i = 0; i < largeObject2.length; i++) { + largeObject2[i] = largeObject1; + } + + int numGCs = Integer.parseInt(args[0]); + + if (numGCs > 0) { + // try to force a minor collection: the young gen is 4M, the + // amount of data allocated below is roughly that (4*1024*1024 + + // some header data) + for (int i = 0; i < 1024 ; i++) { + temp = new int[1024]; + } + } + + for (int i = 0; i < numGCs - 1; i++) { + System.gc(); + } + } +} + +public class TestSummarizeRSetStatsTools { + + // the VM is currently run using G1GC, i.e. trying to test G1 functionality. + public static boolean testingG1GC() { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + + VMOption option = diagnostic.getVMOption("UseG1GC"); + if (option.getValue().equals("false")) { + System.out.println("Skipping this test. It is only a G1 test."); + return false; + } + return true; + } + + public static String runTest(String[] additionalArgs, int numGCs) throws Exception { + ArrayList finalargs = new ArrayList(); + String[] defaultArgs = new String[] { + "-XX:+UseG1GC", + "-XX:+UseCompressedOops", + "-Xmn4m", + "-Xmx20m", + "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking + "-XX:+PrintGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:G1HeapRegionSize=1M", + }; + + finalargs.addAll(Arrays.asList(defaultArgs)); + + if (additionalArgs != null) { + finalargs.addAll(Arrays.asList(additionalArgs)); + } + + finalargs.add(VerifySummaryOutput.class.getName()); + finalargs.add(String.valueOf(numGCs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + String result = output.getStdout(); + return result; + } + + private static void checkCounts(int expected, int actual, String which) throws Exception { + if (expected != actual) { + throw new Exception("RSet summaries mention " + which + " regions an incorrect number of times. Expected " + expected + ", got " + actual); + } + } + + public static void expectPerRegionRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + expectRSetSummaries(result, expectedCumulative, expectedPeriodic); + int actualYoung = result.split("Young regions").length - 1; + int actualHumonguous = result.split("Humonguous regions").length - 1; + int actualFree = result.split("Free regions").length - 1; + int actualOther = result.split("Old regions").length - 1; + + // the strings we check for above are printed four times per summary + int expectedPerRegionTypeInfo = (expectedCumulative + expectedPeriodic) * 4; + + checkCounts(expectedPerRegionTypeInfo, actualYoung, "Young"); + checkCounts(expectedPerRegionTypeInfo, actualHumonguous, "Humonguous"); + checkCounts(expectedPerRegionTypeInfo, actualFree, "Free"); + checkCounts(expectedPerRegionTypeInfo, actualOther, "Old"); + } + + public static void expectRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + int actualTotal = result.split("concurrent refinement").length - 1; + int actualCumulative = result.split("Cumulative RS summary").length - 1; + + if (expectedCumulative != actualCumulative) { + throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); + } + + if (expectedPeriodic != (actualTotal - actualCumulative)) { + throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); + } + } +} + diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/metaspace/G1AddMetaspaceDependency.java --- a/test/gc/metaspace/G1AddMetaspaceDependency.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/gc/metaspace/G1AddMetaspaceDependency.java Fri Oct 04 21:00:43 2013 -0700 @@ -107,7 +107,6 @@ Loader f_loader = new Loader(b_name, b_bytes, a_name, a_loader); Loader g_loader = new Loader(b_name, b_bytes, a_name, a_loader); - byte[] b = new byte[20 * 2 << 20]; Class c; c = b_loader.loadClass(b_name); c = c_loader.loadClass(b_name); diff -r 4212bfb33d76 -r 2720ab7a0d70 test/gc/metaspace/TestPerfCountersAndMemoryPools.java --- a/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/gc/metaspace/TestPerfCountersAndMemoryPools.java Fri Oct 04 21:00:43 2013 -0700 @@ -29,10 +29,11 @@ /* @test TestPerfCountersAndMemoryPools * @bug 8023476 + * @library /testlibrary * @summary Tests that a MemoryPoolMXBeans and PerfCounters for metaspace * report the same data. - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint TestPerfCountersAndMemoryPools */ public class TestPerfCountersAndMemoryPools { public static void main(String[] args) throws Exception { @@ -43,11 +44,11 @@ } } - private static MemoryUsage getMemoryUsage(String memoryPoolName) { + private static MemoryPoolMXBean getMemoryPool(String memoryPoolName) { List pools = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean pool : pools) { if (pool.getName().equals(memoryPoolName)) { - return pool.getUsage(); + return pool; } } @@ -57,19 +58,18 @@ private static void checkMemoryUsage(String memoryPoolName, String perfNS) throws Exception { - // Need to do a gc before each comparison to update the perf counters + MemoryPoolMXBean pool = getMemoryPool(memoryPoolName); - System.gc(); - MemoryUsage mu = getMemoryUsage(memoryPoolName); - assertEQ(getMinCapacity(perfNS), mu.getInit()); - + // Must do a GC to update performance counters System.gc(); - mu = getMemoryUsage(memoryPoolName); - assertEQ(getUsed(perfNS), mu.getUsed()); + assertEQ(getMinCapacity(perfNS), pool.getUsage().getInit()); + // Must do a second GC to update the perfomance counters again, since + // the call pool.getUsage().getInit() could have allocated some + // metadata. System.gc(); - mu = getMemoryUsage(memoryPoolName); - assertEQ(getCapacity(perfNS), mu.getCommitted()); + assertEQ(getUsed(perfNS), pool.getUsage().getUsed()); + assertEQ(getCapacity(perfNS), pool.getUsage().getCommitted()); } private static long getMinCapacity(String ns) throws Exception { diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java Fri Oct 04 21:00:43 2013 -0700 @@ -36,8 +36,7 @@ import java.nio.file.attribute.*; /** - * * Handler for dirs containing classes to compile. - * @author igor.ignatyev@oracle.com + * Handler for dirs containing classes to compile. */ public class ClassPathDirEntry extends PathHandler { diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java Fri Oct 04 21:00:43 2013 -0700 @@ -35,7 +35,6 @@ /** * Handler for jar-files containing classes to compile. - * @author igor.ignatyev@oracle.com */ public class ClassPathJarEntry extends PathHandler { diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java Fri Oct 04 21:00:43 2013 -0700 @@ -31,8 +31,6 @@ /** * Handler for dirs containing jar-files with classes to compile. - * - * @author igor.ignatyev@oracle.com */ public class ClassPathJarInDirEntry extends PathHandler { diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java Fri Oct 04 21:00:43 2013 -0700 @@ -32,8 +32,6 @@ /** * Handler for files containing a list of classes to compile. - * - * @author igor.ignatyev@oracle.com */ public class ClassesListInFile extends PathHandler { public ClassesListInFile(Path root, Executor executor) { diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java Fri Oct 04 21:00:43 2013 -0700 @@ -32,9 +32,6 @@ import java.util.List; import java.util.concurrent.*; -/** - * @author igor.ignatyev@oracle.com - */ public class CompileTheWorld { /** * Entry point. Compiles classes in {@code args}, or all classes in diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Fri Oct 04 21:00:43 2013 -0700 @@ -36,8 +36,6 @@ /** * Provide method to compile whole class. * Also contains compiled methods and classes counters. - * - * @author igor.ignatyev@oracle.com */ public class Compiler { private Compiler() { } diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java Fri Oct 04 21:00:43 2013 -0700 @@ -35,10 +35,7 @@ /** * Abstract handler for path. - *

* Concrete subclasses should implement method {@link #process()}. - * - * @author igor.ignatyev@oracle.com */ public abstract class PathHandler { private static final Pattern JAR_IN_DIR_PATTERN diff -r 4212bfb33d76 -r 2720ab7a0d70 test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java --- a/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Sat Oct 05 03:14:53 2013 +0200 +++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Fri Oct 04 21:00:43 2013 -0700 @@ -31,8 +31,6 @@ /** * Auxiliary methods. - * - * @author igor.ignatyev@oracle.com */ public class Utils { /**