# HG changeset patch # User coffeys # Date 1392400637 0 # Node ID dd13ef903817c6ff7bbdd7cea2c6abf6c5ec5357 # Parent 757fe22ae90681e2b6cff50699c5abbe2563dd2c# Parent 1dbaf664a611e5d9cab6d1be42537b67d0d05f94 Merge diff -r 1dbaf664a611 -r dd13ef903817 .hgtags --- a/.hgtags Thu Feb 06 17:34:47 2014 -0800 +++ b/.hgtags Fri Feb 14 17:57:17 2014 +0000 @@ -408,6 +408,8 @@ 55fb97c4c58d6ed4db8ec02a382ba518d9265815 hs25-b65 d3521d8e562a782f66fc0dfdebeffba2c7e3471d jdk8-b122 591135a7d6f96c0ef281d078cee9a8d8c342d45c jdk8-b123 +c89630a122b43d0eabd78b74f6498a1c3cf04ca3 jdk8u20-b00 +c89630a122b43d0eabd78b74f6498a1c3cf04ca3 hs25.20-b00 9b9816164447214f21b06ccf646893c281c76a42 hs25-b66 df333ee12bba67e2e928f8ce1da37afd9bf95b48 jdk8-b124 3585183c191aa6b4d0375ea659515335e1804417 hs25-b67 @@ -418,3 +420,6 @@ 35038da7bb9ddd367a0a6bf926dfb281aee1d554 jdk8-b127 874c0b4a946c362bbf20d37c2a564b39093152e6 jdk8-b128 cb39165c4a65bbff8db356df411e762f9e5423b8 jdk8-b129 +412d3b5fe90e54c0ff9d9ac7374b98607c561d5a hs25.20-b01 +4638c4d7ff106db0f29ef7f18b128dd7e69bc470 hs25.20-b02 +e56d11f8cc2158d4280f80e56d196193349c150a hs25.20-b03 diff -r 1dbaf664a611 -r dd13ef903817 .jcheck/conf --- a/.jcheck/conf Thu Feb 06 17:34:47 2014 -0800 +++ b/.jcheck/conf Fri Feb 14 17:57:17 2014 +0000 @@ -1,1 +1,2 @@ project=jdk8 +bugids=dup diff -r 1dbaf664a611 -r dd13ef903817 agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java --- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Thu Feb 06 17:34:47 2014 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Fri Feb 14 17:57:17 2014 +0000 @@ -95,9 +95,15 @@ int entryBci = task.osrBci(); int compLevel = task.compLevel(); Klass holder = method.getMethodHolder(); - out.println("compile " + holder.getName().asString() + " " + - OopUtilities.escapeString(method.getName().asString()) + " " + - method.getSignature().asString() + " " + - entryBci + " " + compLevel); + out.print("compile " + holder.getName().asString() + " " + + OopUtilities.escapeString(method.getName().asString()) + " " + + method.getSignature().asString() + " " + + entryBci + " " + compLevel); + Compile compiler = compilerData(); + if (compiler != null) { + // Dump inlining data. + compiler.dumpInlineData(out); + } + out.println(); } } diff -r 1dbaf664a611 -r dd13ef903817 agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java --- a/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java Thu Feb 06 17:34:47 2014 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java Fri Feb 14 17:57:17 2014 +0000 @@ -25,6 +25,7 @@ package sun.jvm.hotspot.opto; import java.util.*; +import java.io.PrintStream; import sun.jvm.hotspot.ci.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.runtime.*; @@ -92,4 +93,13 @@ } return null; } + + public void dumpInlineData(PrintStream out) { + InlineTree inlTree = ilt(); + if (inlTree != null) { + out.print(" inline " + inlTree.count()); + inlTree.dumpReplayData(out); + } + } + } diff -r 1dbaf664a611 -r dd13ef903817 agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java --- a/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java Thu Feb 06 17:34:47 2014 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java Fri Feb 14 17:57:17 2014 +0000 @@ -87,6 +87,11 @@ return GrowableArray.create(addr, inlineTreeConstructor); } + public int inlineLevel() { + JVMState jvms = callerJvms(); + return (jvms != null) ? jvms.depth() : 0; + } + public void printImpl(PrintStream st, int indent) { for (int i = 0; i < indent; i++) st.print(" "); st.printf(" @ %d ", callerBci()); @@ -101,4 +106,28 @@ public void print(PrintStream st) { printImpl(st, 2); } + + // Count number of nodes in this subtree + public int count() { + int result = 1; + GrowableArray subt = subtrees(); + for (int i = 0 ; i < subt.length(); i++) { + result += subt.at(i).count(); + } + return result; + } + + public void dumpReplayData(PrintStream out) { + out.printf(" %d %d ", inlineLevel(), callerBci()); + Method method = (Method)method().getMetadata(); + Klass holder = method.getMethodHolder(); + out.print(holder.getName().asString() + " " + + OopUtilities.escapeString(method.getName().asString()) + " " + + method.getSignature().asString()); + + GrowableArray subt = subtrees(); + for (int i = 0 ; i < subt.length(); i++) { + subt.at(i).dumpReplayData(out); + } + } } diff -r 1dbaf664a611 -r dd13ef903817 agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java --- a/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java Thu Feb 06 17:34:47 2014 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java Fri Feb 14 17:57:17 2014 +0000 @@ -88,6 +88,10 @@ return (int)bciField.getValue(getAddress()); } + public int depth() { + return (int)depthField.getValue(getAddress()); + } + public JVMState caller() { return create(callerField.getValue(getAddress())); } diff -r 1dbaf664a611 -r dd13ef903817 make/hotspot_version --- a/make/hotspot_version Thu Feb 06 17:34:47 2014 -0800 +++ b/make/hotspot_version Fri Feb 14 17:57:17 2014 +0000 @@ -34,8 +34,8 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2014 HS_MAJOR_VER=25 -HS_MINOR_VER=0 -HS_BUILD_NUMBER=69 +HS_MINOR_VER=20 +HS_BUILD_NUMBER=03 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1315,7 +1315,7 @@ } Address LIR_Assembler::as_Address(LIR_Address* addr) { - Register reg = addr->base()->as_register(); + Register reg = addr->base()->as_pointer_register(); LIR_Opr index = addr->index(); if (index->is_illegal()) { return Address(reg, addr->disp()); @@ -3101,7 +3101,145 @@ } void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { - fatal("Type profiling not implemented on this platform"); + Register obj = op->obj()->as_register(); + Register tmp1 = op->tmp()->as_pointer_register(); + Register tmp2 = G1; + Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label update, next, none; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + + __ verify_oop(obj); + + if (tmp1 != obj) { + __ mov(obj, tmp1); + } + if (do_null) { + __ br_notnull_short(tmp1, Assembler::pt, update); + if (!TypeEntries::was_null_seen(current_klass)) { + __ ld_ptr(mdo_addr, tmp1); + __ or3(tmp1, TypeEntries::null_seen, tmp1); + __ st_ptr(tmp1, mdo_addr); + } + if (do_update) { + __ ba(next); + __ delayed()->nop(); + } +#ifdef ASSERT + } else { + __ br_notnull_short(tmp1, Assembler::pt, update); + __ stop("unexpect null obj"); +#endif + } + + __ bind(update); + + if (do_update) { +#ifdef ASSERT + if (exact_klass != NULL) { + Label ok; + __ load_klass(tmp1, tmp1); + metadata2reg(exact_klass->constant_encoding(), tmp2); + __ cmp_and_br_short(tmp1, tmp2, Assembler::equal, Assembler::pt, ok); + __ stop("exact klass and actual klass differ"); + __ bind(ok); + } +#endif + + Label do_update; + __ ld_ptr(mdo_addr, tmp2); + + if (!no_conflict) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + if (exact_klass != NULL) { + metadata2reg(exact_klass->constant_encoding(), tmp1); + } else { + __ load_klass(tmp1, tmp1); + } + + __ xor3(tmp1, tmp2, tmp1); + __ btst(TypeEntries::type_klass_mask, tmp1); + // klass seen before, nothing to do. The unknown bit may have been + // set already but no need to check. + __ brx(Assembler::zero, false, Assembler::pt, next); + __ delayed()-> + + btst(TypeEntries::type_unknown, tmp1); + // already unknown. Nothing to do anymore. + __ brx(Assembler::notZero, false, Assembler::pt, next); + + if (TypeEntries::is_type_none(current_klass)) { + __ delayed()->btst(TypeEntries::type_mask, tmp2); + __ brx(Assembler::zero, true, Assembler::pt, do_update); + // first time here. Set profile type. + __ delayed()->or3(tmp2, tmp1, tmp2); + } else { + __ delayed()->nop(); + } + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ btst(TypeEntries::type_unknown, tmp2); + // already unknown. Nothing to do anymore. + __ brx(Assembler::notZero, false, Assembler::pt, next); + __ delayed()->nop(); + } + + // different than before. Cannot keep accurate profile. + __ or3(tmp2, TypeEntries::type_unknown, tmp2); + } else { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + if (TypeEntries::is_type_none(current_klass)) { + metadata2reg(exact_klass->constant_encoding(), tmp1); + __ xor3(tmp1, tmp2, tmp1); + __ btst(TypeEntries::type_klass_mask, tmp1); + __ brx(Assembler::zero, false, Assembler::pt, next); +#ifdef ASSERT + + { + Label ok; + __ delayed()->btst(TypeEntries::type_mask, tmp2); + __ brx(Assembler::zero, true, Assembler::pt, ok); + __ delayed()->nop(); + + __ stop("unexpected profiling mismatch"); + __ bind(ok); + } + // first time here. Set profile type. + __ or3(tmp2, tmp1, tmp2); +#else + // first time here. Set profile type. + __ delayed()->or3(tmp2, tmp1, tmp2); +#endif + + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + // already unknown. Nothing to do anymore. + __ btst(TypeEntries::type_unknown, tmp2); + __ brx(Assembler::notZero, false, Assembler::pt, next); + __ delayed()->or3(tmp2, TypeEntries::type_unknown, tmp2); + } + } + + __ bind(do_update); + __ st_ptr(tmp2, mdo_addr); + + __ bind(next); + } } void LIR_Assembler::align_backward_branch_target() { @@ -3321,9 +3459,14 @@ void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) { LIR_Address* addr = addr_opr->as_address_ptr(); - assert(addr->index()->is_illegal() && addr->scale() == LIR_Address::times_1 && Assembler::is_simm13(addr->disp()), "can't handle complex addresses yet"); - - __ add(addr->base()->as_pointer_register(), addr->disp(), dest->as_pointer_register()); + assert(addr->index()->is_illegal() && addr->scale() == LIR_Address::times_1, "can't handle complex addresses yet"); + + if (Assembler::is_simm13(addr->disp())) { + __ add(addr->base()->as_pointer_register(), addr->disp(), dest->as_pointer_register()); + } else { + __ set(addr->disp(), G3_scratch); + __ add(addr->base()->as_pointer_register(), G3_scratch, dest->as_pointer_register()); + } } diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1892,6 +1892,220 @@ } } +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr, Register tmp) { + Label not_null, do_nothing, do_update; + + assert_different_registers(obj, mdo_addr.base(), tmp); + + verify_oop(obj); + + ld_ptr(mdo_addr, tmp); + + br_notnull_short(obj, pt, not_null); + or3(tmp, TypeEntries::null_seen, tmp); + ba_short(do_update); + + bind(not_null); + load_klass(obj, obj); + + xor3(obj, tmp, obj); + btst(TypeEntries::type_klass_mask, obj); + // klass seen before, nothing to do. The unknown bit may have been + // set already but no need to check. + brx(zero, false, pt, do_nothing); + delayed()-> + + btst(TypeEntries::type_unknown, obj); + // already unknown. Nothing to do anymore. + brx(notZero, false, pt, do_nothing); + delayed()-> + + btst(TypeEntries::type_mask, tmp); + brx(zero, true, pt, do_update); + // first time here. Set profile type. + delayed()->or3(tmp, obj, tmp); + + // different than before. Cannot keep accurate profile. + or3(tmp, TypeEntries::type_unknown, tmp); + + bind(do_update); + // update profile + st_ptr(tmp, mdo_addr); + + bind(do_nothing); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + assert_different_registers(callee, tmp1, tmp2, ImethodDataPtr); + + if (MethodData::profile_arguments() || MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + ldub(ImethodDataPtr, in_bytes(DataLayout::tag_offset()) - off_to_start, tmp1); + cmp_and_br_short(tmp1, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag, notEqual, pn, profile_continue); + + if (MethodData::profile_arguments()) { + Label done; + int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); + add(ImethodDataPtr, off_to_args, ImethodDataPtr); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0 || MethodData::profile_return()) { + // If return value type is profiled we may have no argument to profile + ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1); + sub(tmp1, i*TypeStackSlotEntries::per_arg_count(), tmp1); + cmp_and_br_short(tmp1, TypeStackSlotEntries::per_arg_count(), less, pn, done); + } + ld_ptr(Address(callee, Method::const_offset()), tmp1); + lduh(Address(tmp1, ConstMethod::size_of_parameters_offset()), tmp1); + // stack offset o (zero based) from the start of the argument + // list, for n arguments translates into offset n - o - 1 from + // the end of the argument list. But there's an extra slot at + // the stop of the stack. So the offset is n - o from Lesp. + ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args, tmp2); + sub(tmp1, tmp2, tmp1); + + // Can't use MacroAssembler::argument_address() which needs Gargs to be set up + sll(tmp1, Interpreter::logStackElementSize, tmp1); + ld_ptr(Lesp, tmp1, tmp1); + + Address mdo_arg_addr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); + profile_obj_type(tmp1, mdo_arg_addr, tmp2); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + add(ImethodDataPtr, to_add, ImethodDataPtr); + off_to_args += to_add; + } + + if (MethodData::profile_return()) { + ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1); + sub(tmp1, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count(), tmp1); + } + + bind(done); + + if (MethodData::profile_return()) { + // We're right after the type profile for the last + // argument. tmp1 is the number of cells left in the + // CallTypeData/VirtualCallTypeData to reach its end. Non null + // if there's a return to profile. + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + sll(tmp1, exact_log2(DataLayout::cell_size), tmp1); + add(ImethodDataPtr, tmp1, ImethodDataPtr); + } + } else { + assert(MethodData::profile_return(), "either profile call args or call ret"); + update_mdp_by_constant(in_bytes(ReturnTypeEntry::size())); + } + + // mdp points right after the end of the + // CallTypeData/VirtualCallTypeData, right after the cells for the + // return value type if there's one. + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, Register tmp2) { + assert_different_registers(ret, tmp1, tmp2); + if (ProfileInterpreter && MethodData::profile_return()) { + Label profile_continue, done; + + test_method_data_pointer(profile_continue); + + if (MethodData::profile_return_jsr292_only()) { + // If we don't profile all invoke bytecodes we must make sure + // it's a bytecode we indeed profile. We can't go back to the + // begining of the ProfileData we intend to update to check its + // type because we're right after it and we don't known its + // length. + Label do_profile; + ldub(Lbcp, 0, tmp1); + cmp_and_br_short(tmp1, Bytecodes::_invokedynamic, equal, pn, do_profile); + cmp(tmp1, Bytecodes::_invokehandle); + br(equal, false, pn, do_profile); + delayed()->ldub(Lmethod, Method::intrinsic_id_offset_in_bytes(), tmp1); + cmp_and_br_short(tmp1, vmIntrinsics::_compiledLambdaForm, notEqual, pt, profile_continue); + + bind(do_profile); + } + + Address mdo_ret_addr(ImethodDataPtr, -in_bytes(ReturnTypeEntry::size())); + mov(ret, tmp1); + profile_obj_type(tmp1, mdo_ret_addr, tmp2); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters. + lduw(ImethodDataPtr, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()), tmp1); + cmp_and_br_short(tmp1, 0, less, pn, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + + // Pointer to the parameter area in the MDO + Register mdp = tmp1; + add(ImethodDataPtr, tmp1, mdp); + + // offset of the current profile entry to update + Register entry_offset = tmp2; + // entry_offset = array len in number of cells + ld_ptr(mdp, ArrayData::array_len_offset(), entry_offset); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + assert(off_base % DataLayout::cell_size == 0, "should be a number of cells"); + + // entry_offset (number of cells) = array len - size of 1 entry + offset of the stack slot field + sub(entry_offset, TypeStackSlotEntries::per_arg_count() - (off_base / DataLayout::cell_size), entry_offset); + // entry_offset in bytes + sll(entry_offset, exact_log2(DataLayout::cell_size), entry_offset); + + Label loop; + bind(loop); + + // load offset on the stack from the slot for this parameter + ld_ptr(mdp, entry_offset, tmp3); + sll(tmp3,Interpreter::logStackElementSize, tmp3); + neg(tmp3); + // read the parameter from the local area + ld_ptr(Llocals, tmp3, tmp3); + + // make entry_offset now point to the type field for this parameter + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + assert(type_base > off_base, "unexpected"); + add(entry_offset, type_base - off_base, entry_offset); + + // profile the parameter + Address arg_type(mdp, entry_offset); + profile_obj_type(tmp3, arg_type, tmp4); + + // go to next parameter + sub(entry_offset, TypeStackSlotEntries::per_arg_count() * DataLayout::cell_size + (type_base - off_base), entry_offset); + cmp_and_br_short(entry_offset, off_base, greaterEqual, pt, loop); + + bind(profile_continue); + } +} + // add a InterpMonitorElem to stack (see frame_sparc.hpp) void InterpreterMacroAssembler::add_monitor_to_stack( bool stack_is_empty, diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -323,6 +323,11 @@ Register scratch2, Register scratch3); + void profile_obj_type(Register obj, const Address& mdo_addr, Register tmp); + void profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual); + void profile_return_type(Register ret, Register tmp1, Register tmp2); + void profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4); + // Debugging void interp_verify_oop(Register reg, TosState state, const char * file, int line); // only if +VerifyOops && state == atos void verify_oop_or_return_address(Register reg, Register rtmp); // for astore diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -156,6 +156,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) { address entry = __ pc(); + if (state == atos) { + __ profile_return_type(O0, G3_scratch, G1_scratch); + } + #if !defined(_LP64) && defined(COMPILER2) // All return values are where we want them, except for Longs. C2 returns // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1. @@ -1333,6 +1337,7 @@ __ movbool(true, G3_scratch); __ stbool(G3_scratch, do_not_unlock_if_synchronized); + __ profile_parameters_type(G1_scratch, G3_scratch, G4_scratch, Lscratch); // increment invocation counter and check for overflow // // Note: checking for negative value instead of overflow diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -2942,12 +2942,12 @@ void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { - Register Rtemp = G4_scratch; Register Rcall = Rindex; assert_different_registers(Rcall, G5_method, Gargs, Rret); // get target Method* & entry point __ lookup_virtual_method(Rrecv, Rindex, G5_method); + __ profile_arguments_type(G5_method, Rcall, Gargs, true); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3022,6 +3022,7 @@ __ null_check(O0); __ profile_final_call(O4); + __ profile_arguments_type(G5_method, Rscratch, Gargs, true); // get return address AddressLiteral table(Interpreter::invoke_return_entry_table()); @@ -3051,6 +3052,7 @@ // do the call __ profile_call(O4); + __ profile_arguments_type(G5_method, Rscratch, Gargs, false); __ call_from_interpreter(Rscratch, Gargs, Rret); } @@ -3066,6 +3068,7 @@ // do the call __ profile_call(O4); + __ profile_arguments_type(G5_method, Rscratch, Gargs, false); __ call_from_interpreter(Rscratch, Gargs, Rret); } @@ -3091,6 +3094,7 @@ // do the call - the index (f2) contains the Method* assert_different_registers(G5_method, Gargs, Rcall); __ mov(Rindex, G5_method); + __ profile_arguments_type(G5_method, Rcall, Gargs, true); __ call_from_interpreter(Rcall, Gargs, Rret); __ bind(notFinal); @@ -3197,6 +3201,7 @@ Register Rcall = Rinterface; assert_different_registers(Rcall, G5_method, Gargs, Rret); + __ profile_arguments_type(G5_method, Rcall, Gargs, true); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3226,6 +3231,7 @@ // do the call __ verify_oop(G4_mtype); __ profile_final_call(O4); // FIXME: profile the LambdaForm also + __ profile_arguments_type(G5_method, Rscratch, Gargs, true); __ call_from_interpreter(Rscratch, Gargs, Rret); } @@ -3262,6 +3268,7 @@ // do the call __ verify_oop(G4_callsite); + __ profile_arguments_type(G5_method, Rscratch, Gargs, false); __ call_from_interpreter(Rscratch, Gargs, Rret); } diff -r 1dbaf664a611 -r dd13ef903817 src/cpu/x86/vm/interp_masm_x86.cpp --- a/src/cpu/x86/vm/interp_masm_x86.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/cpu/x86/vm/interp_masm_x86.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -127,7 +127,7 @@ if (MethodData::profile_return()) { // We're right after the type profile for the last - // argument. tmp is the number of cell left in the + // argument. tmp is the number of cells left in the // CallTypeData/VirtualCallTypeData to reach its end. Non null // if there's a return to profile. assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); @@ -198,7 +198,7 @@ // parameters. Collect profiling from last parameter down. // mdo start + parameters offset + array length - 1 addptr(mdp, tmp1); - movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset()))); + movptr(tmp1, Address(mdp, ArrayData::array_len_offset())); decrement(tmp1, TypeStackSlotEntries::per_arg_count()); Label loop; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/c1/c1_Compilation.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -259,6 +259,9 @@ } ciKlass* cha_exact_type(ciType* type); + + // Dump inlining replay data to the stream. + void dump_inline_data(outputStream* out) { /* do nothing now */ } }; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -4338,11 +4338,15 @@ #endif // PRODUCT void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) { - // A default method's holder is an interface - if (known_holder != NULL && known_holder->is_interface()) { - assert(known_holder->is_instance_klass() && ((ciInstanceKlass*)known_holder)->has_default_methods(), "should be default method"); - known_holder = NULL; + assert(known_holder == NULL || (known_holder->is_instance_klass() && + (!known_holder->is_interface() || + ((ciInstanceKlass*)known_holder)->has_default_methods())), "should be default method"); + if (known_holder != NULL) { + if (known_holder->exact_klass() == NULL) { + known_holder = compilation()->cha_exact_type(known_holder); + } } + append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined)); } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -858,9 +858,7 @@ void LIR_Assembler::verify_oop_map(CodeEmitInfo* info) { #ifndef PRODUCT - if (VerifyOopMaps || VerifyOops) { - bool v = VerifyOops; - VerifyOops = true; + if (VerifyOops) { OopMapStream s(info->oop_map()); while (!s.is_done()) { OopMapValue v = s.current(); @@ -883,7 +881,6 @@ s.next(); } - VerifyOops = v; } #endif } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -3288,7 +3288,10 @@ ciSignature* signature_at_call = NULL; x->method()->get_method_at_bci(bci, ignored_will_link, &signature_at_call); - ciKlass* exact = profile_type(md, 0, md->byte_offset_of_slot(data, ret->type_offset()), + // The offset within the MDO of the entry to update may be too large + // to be used in load/store instructions on some platforms. So have + // profile_type() compute the address of the profile in a register. + ciKlass* exact = profile_type(md, md->byte_offset_of_slot(data, ret->type_offset()), 0, ret->type(), x->ret(), mdp, !x->needs_null_check(), signature_at_call->return_type()->as_klass(), diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/c1/c1_globals.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -269,9 +269,6 @@ develop(bool, PrintNotLoaded, false, \ "Prints where classes are not loaded during code generation") \ \ - notproduct(bool, VerifyOopMaps, false, \ - "Adds oopmap verification code to the generated code") \ - \ develop(bool, PrintLIR, false, \ "print low-level IR") \ \ diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1147,6 +1147,33 @@ // Don't change thread state and acquire any locks. // Safe to call from VM error reporter. + +void ciEnv::dump_compile_data(outputStream* out) { + CompileTask* task = this->task(); + Method* method = task->method(); + int entry_bci = task->osr_bci(); + int comp_level = task->comp_level(); + out->print("compile %s %s %s %d %d", + method->klass_name()->as_quoted_ascii(), + method->name()->as_quoted_ascii(), + method->signature()->as_quoted_ascii(), + entry_bci, comp_level); + if (compiler_data() != NULL) { + if (is_c2_compile(comp_level)) { // C2 or Shark +#ifdef COMPILER2 + // Dump C2 inlining data. + ((Compile*)compiler_data())->dump_inline_data(out); +#endif + } else if (is_c1_compile(comp_level)) { // C1 +#ifdef COMPILER1 + // Dump C1 inlining data. + ((Compilation*)compiler_data())->dump_inline_data(out); +#endif + } + } + out->cr(); +} + void ciEnv::dump_replay_data_unsafe(outputStream* out) { ResourceMark rm; #if INCLUDE_JVMTI @@ -1160,16 +1187,7 @@ for (int i = 0; i < objects->length(); i++) { objects->at(i)->dump_replay_data(out); } - CompileTask* task = this->task(); - Method* method = task->method(); - int entry_bci = task->osr_bci(); - int comp_level = task->comp_level(); - // Klass holder = method->method_holder(); - out->print_cr("compile %s %s %s %d %d", - method->klass_name()->as_quoted_ascii(), - method->name()->as_quoted_ascii(), - method->signature()->as_quoted_ascii(), - entry_bci, comp_level); + dump_compile_data(out); out->flush(); } @@ -1179,3 +1197,45 @@ dump_replay_data_unsafe(out); ) } + +void ciEnv::dump_replay_data(int compile_id) { + static char buffer[O_BUFLEN]; + int ret = jio_snprintf(buffer, O_BUFLEN, "replay_pid%p_compid%d.log", os::current_process_id(), compile_id); + if (ret > 0) { + int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd != -1) { + FILE* replay_data_file = os::open(fd, "w"); + if (replay_data_file != NULL) { + fileStream replay_data_stream(replay_data_file, /*need_close=*/true); + dump_replay_data(&replay_data_stream); + tty->print("# Compiler replay data is saved as: "); + tty->print_cr(buffer); + } else { + tty->print_cr("# Can't open file to dump replay data."); + } + } + } +} + +void ciEnv::dump_inline_data(int compile_id) { + static char buffer[O_BUFLEN]; + int ret = jio_snprintf(buffer, O_BUFLEN, "inline_pid%p_compid%d.log", os::current_process_id(), compile_id); + if (ret > 0) { + int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd != -1) { + FILE* inline_data_file = os::open(fd, "w"); + if (inline_data_file != NULL) { + fileStream replay_data_stream(inline_data_file, /*need_close=*/true); + GUARDED_VM_ENTRY( + MutexLocker ml(Compile_lock); + dump_compile_data(&replay_data_stream); + ) + replay_data_stream.flush(); + tty->print("# Compiler inline data is saved as: "); + tty->print_cr(buffer); + } else { + tty->print_cr("# Can't open file to dump inline data."); + } + } + } +} diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciEnv.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -451,8 +451,11 @@ void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); } // Dump the compilation replay data for the ciEnv to the stream. + void dump_replay_data(int compile_id); + void dump_inline_data(int compile_id); void dump_replay_data(outputStream* out); void dump_replay_data_unsafe(outputStream* out); + void dump_compile_data(outputStream* out); }; #endif // SHARE_VM_CI_CIENV_HPP diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciMethod.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1357,15 +1357,21 @@ #undef FETCH_FLAG_FROM_VM +void ciMethod::dump_name_as_ascii(outputStream* st) { + Method* method = get_Method(); + st->print("%s %s %s", + method->klass_name()->as_quoted_ascii(), + method->name()->as_quoted_ascii(), + method->signature()->as_quoted_ascii()); +} + void ciMethod::dump_replay_data(outputStream* st) { ResourceMark rm; Method* method = get_Method(); MethodCounters* mcs = method->method_counters(); - Klass* holder = method->method_holder(); - st->print_cr("ciMethod %s %s %s %d %d %d %d %d", - holder->name()->as_quoted_ascii(), - method->name()->as_quoted_ascii(), - method->signature()->as_quoted_ascii(), + st->print("ciMethod "); + dump_name_as_ascii(st); + st->print_cr(" %d %d %d %d %d", mcs == NULL ? 0 : mcs->invocation_counter()->raw_counter(), mcs == NULL ? 0 : mcs->backedge_counter()->raw_counter(), interpreter_invocation_count(), diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciMethod.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -310,10 +310,13 @@ bool is_accessor () const; bool is_initializer () const; bool can_be_statically_bound() const { return _can_be_statically_bound; } - void dump_replay_data(outputStream* st); bool is_boxing_method() const; bool is_unboxing_method() const; + // Replay data methods + void dump_name_as_ascii(outputStream* st); + void dump_replay_data(outputStream* st); + // Print the bytecodes of this method. void print_codes_on(outputStream* st); void print_codes() { diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciReplay.cpp --- a/src/share/vm/ci/ciReplay.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciReplay.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciReplay.hpp" +#include "ci/ciSymbol.hpp" +#include "ci/ciKlass.hpp" #include "ci/ciUtilities.hpp" #include "compiler/compileBroker.hpp" #include "memory/allocation.inline.hpp" @@ -37,74 +39,107 @@ // ciReplay typedef struct _ciMethodDataRecord { - const char* klass; - const char* method; - const char* signature; - int state; - int current_mileage; - intptr_t* data; - int data_length; - char* orig_data; - int orig_data_length; - int oops_length; - jobject* oops_handles; - int* oops_offsets; + const char* _klass_name; + const char* _method_name; + const char* _signature; + + int _state; + int _current_mileage; + + intptr_t* _data; + char* _orig_data; + jobject* _oops_handles; + int* _oops_offsets; + int _data_length; + int _orig_data_length; + int _oops_length; } ciMethodDataRecord; typedef struct _ciMethodRecord { - const char* klass; - const char* method; - const char* signature; - int instructions_size; - int interpreter_invocation_count; - int interpreter_throwout_count; - int invocation_counter; - int backedge_counter; + const char* _klass_name; + const char* _method_name; + const char* _signature; + + int _instructions_size; + int _interpreter_invocation_count; + int _interpreter_throwout_count; + int _invocation_counter; + int _backedge_counter; } ciMethodRecord; -class CompileReplay; +typedef struct _ciInlineRecord { + const char* _klass_name; + const char* _method_name; + const char* _signature; + + int _inline_depth; + int _inline_bci; +} ciInlineRecord; + +class CompileReplay; static CompileReplay* replay_state; class CompileReplay : public StackObj { private: - FILE* stream; - Thread* thread; - Handle protection_domain; - Handle loader; + FILE* _stream; + Thread* _thread; + Handle _protection_domain; + Handle _loader; - GrowableArray ci_method_records; - GrowableArray ci_method_data_records; + GrowableArray _ci_method_records; + GrowableArray _ci_method_data_records; + + // Use pointer because we may need to return inline records + // without destroying them. + GrowableArray* _ci_inline_records; const char* _error_message; - char* bufptr; - char* buffer; - int buffer_length; - int buffer_end; - int line_no; + char* _bufptr; + char* _buffer; + int _buffer_length; + int _buffer_pos; + + // "compile" data + ciKlass* _iklass; + Method* _imethod; + int _entry_bci; + int _comp_level; public: CompileReplay(const char* filename, TRAPS) { - thread = THREAD; - loader = Handle(thread, SystemDictionary::java_system_loader()); - stream = fopen(filename, "rt"); - if (stream == NULL) { + _thread = THREAD; + _loader = Handle(_thread, SystemDictionary::java_system_loader()); + _protection_domain = Handle(); + + _stream = fopen(filename, "rt"); + if (_stream == NULL) { fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); } - buffer_length = 32; - buffer = NEW_RESOURCE_ARRAY(char, buffer_length); + + _ci_inline_records = NULL; _error_message = NULL; + _buffer_length = 32; + _buffer = NEW_RESOURCE_ARRAY(char, _buffer_length); + _bufptr = _buffer; + _buffer_pos = 0; + + _imethod = NULL; + _iklass = NULL; + _entry_bci = 0; + _comp_level = 0; + test(); } ~CompileReplay() { - if (stream != NULL) fclose(stream); + if (_stream != NULL) fclose(_stream); } void test() { - strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\""); - bufptr = buffer; + strcpy(_buffer, "1 2 foo 4 bar 0x9 \"this is it\""); + _bufptr = _buffer; assert(parse_int("test") == 1, "what"); assert(parse_int("test") == 2, "what"); assert(strcmp(parse_string(), "foo") == 0, "what"); @@ -115,18 +150,18 @@ } bool had_error() { - return _error_message != NULL || thread->has_pending_exception(); + return _error_message != NULL || _thread->has_pending_exception(); } bool can_replay() { - return !(stream == NULL || had_error()); + return !(_stream == NULL || had_error()); } void report_error(const char* msg) { _error_message = msg; - // Restore the buffer contents for error reporting - for (int i = 0; i < buffer_end; i++) { - if (buffer[i] == '\0') buffer[i] = ' '; + // Restore the _buffer contents for error reporting + for (int i = 0; i < _buffer_pos; i++) { + if (_buffer[i] == '\0') _buffer[i] = ' '; } } @@ -137,10 +172,10 @@ int v = 0; int read; - if (sscanf(bufptr, "%i%n", &v, &read) != 1) { + if (sscanf(_bufptr, "%i%n", &v, &read) != 1) { report_error(label); } else { - bufptr += read; + _bufptr += read; } return v; } @@ -152,31 +187,31 @@ intptr_t v = 0; int read; - if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) { + if (sscanf(_bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) { report_error(label); } else { - bufptr += read; + _bufptr += read; } return v; } void skip_ws() { // Skip any leading whitespace - while (*bufptr == ' ' || *bufptr == '\t') { - bufptr++; + while (*_bufptr == ' ' || *_bufptr == '\t') { + _bufptr++; } } char* scan_and_terminate(char delim) { - char* str = bufptr; - while (*bufptr != delim && *bufptr != '\0') { - bufptr++; + char* str = _bufptr; + while (*_bufptr != delim && *_bufptr != '\0') { + _bufptr++; } - if (*bufptr != '\0') { - *bufptr++ = '\0'; + if (*_bufptr != '\0') { + *_bufptr++ = '\0'; } - if (bufptr == str) { + if (_bufptr == str) { // nothing here return NULL; } @@ -195,8 +230,8 @@ skip_ws(); - if (*bufptr == '"') { - bufptr++; + if (*_bufptr == '"') { + _bufptr++; return scan_and_terminate('"'); } else { return scan_and_terminate(' '); @@ -273,7 +308,12 @@ const char* str = parse_escaped_string(); Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); if (klass_name != NULL) { - Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD); + Klass* k = NULL; + if (_iklass != NULL) { + k = (Klass*)_iklass->find_klass(ciSymbol::make(klass_name->as_C_string()))->constant_encoding(); + } else { + k = SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD); + } if (HAS_PENDING_EXCEPTION) { oop throwable = PENDING_EXCEPTION; java_lang_Throwable::print(throwable, tty); @@ -289,7 +329,7 @@ // Lookup a klass Klass* resolve_klass(const char* klass, TRAPS) { Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL); - return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL); + return SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, CHECK_NULL); } // Parse the standard tuple of @@ -304,40 +344,45 @@ return m; } + int get_line(int c) { + while(c != EOF) { + if (_buffer_pos + 1 >= _buffer_length) { + int new_length = _buffer_length * 2; + // Next call will throw error in case of OOM. + _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); + _buffer_length = new_length; + } + if (c == '\n') { + c = getc(_stream); // get next char + break; + } else if (c == '\r') { + // skip LF + } else { + _buffer[_buffer_pos++] = c; + } + c = getc(_stream); + } + // null terminate it, reset the pointer + _buffer[_buffer_pos] = '\0'; // NL or EOF + _buffer_pos = 0; + _bufptr = _buffer; + return c; + } + // Process each line of the replay file executing each command until // the file ends. void process(TRAPS) { - line_no = 1; - int pos = 0; - int c = getc(stream); + int line_no = 1; + int c = getc(_stream); while(c != EOF) { - if (pos + 1 >= buffer_length) { - int newl = buffer_length * 2; - char* newb = NEW_RESOURCE_ARRAY(char, newl); - memcpy(newb, buffer, pos); - buffer = newb; - buffer_length = newl; + c = get_line(c); + process_command(CHECK); + if (had_error()) { + tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); + tty->print_cr("%s", _buffer); + return; } - if (c == '\n') { - // null terminate it, reset the pointer and process the line - buffer[pos] = '\0'; - buffer_end = pos++; - bufptr = buffer; - process_command(CHECK); - if (had_error()) { - tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); - tty->print_cr("%s", buffer); - return; - } - pos = 0; - buffer_end = 0; - line_no++; - } else if (c == '\r') { - // skip LF - } else { - buffer[pos++] = c; - } - c = getc(stream); + line_no++; } } @@ -396,7 +441,37 @@ return true; } - // compile + // compile inline ... + void* process_inline(ciMethod* imethod, Method* m, int entry_bci, int comp_level, TRAPS) { + _imethod = m; + _iklass = imethod->holder(); + _entry_bci = entry_bci; + _comp_level = comp_level; + int line_no = 1; + int c = getc(_stream); + while(c != EOF) { + c = get_line(c); + // Expecting only lines with "compile" command in inline replay file. + char* cmd = parse_string(); + if (cmd == NULL || strcmp("compile", cmd) != 0) { + return NULL; + } + process_compile(CHECK_NULL); + if (had_error()) { + tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); + tty->print_cr("%s", _buffer); + return NULL; + } + if (_ci_inline_records != NULL && _ci_inline_records->length() > 0) { + // Found inlining record for the requested method. + return _ci_inline_records; + } + line_no++; + } + return NULL; + } + + // compile inline ... void process_compile(TRAPS) { Method* method = parse_method(CHECK); if (had_error()) return; @@ -410,6 +485,43 @@ if (!is_valid_comp_level(comp_level)) { return; } + if (_imethod != NULL) { + // Replay Inlining + if (entry_bci != _entry_bci || comp_level != _comp_level) { + return; + } + const char* iklass_name = _imethod->method_holder()->name()->as_utf8(); + const char* imethod_name = _imethod->name()->as_utf8(); + const char* isignature = _imethod->signature()->as_utf8(); + const char* klass_name = method->method_holder()->name()->as_utf8(); + const char* method_name = method->name()->as_utf8(); + const char* signature = method->signature()->as_utf8(); + if (strcmp(iklass_name, klass_name) != 0 || + strcmp(imethod_name, method_name) != 0 || + strcmp(isignature, signature) != 0) { + return; + } + } + int inline_count = 0; + if (parse_tag_and_count("inline", inline_count)) { + // Record inlining data + _ci_inline_records = new GrowableArray(); + for (int i = 0; i < inline_count; i++) { + int depth = parse_int("inline_depth"); + int bci = parse_int("inline_bci"); + if (had_error()) { + break; + } + Method* inl_method = parse_method(CHECK); + if (had_error()) { + break; + } + new_ciInlineRecord(inl_method, bci, depth); + } + } + if (_imethod != NULL) { + return; // Replay Inlining + } Klass* k = method->method_holder(); ((InstanceKlass*)k)->initialize(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -442,11 +554,11 @@ Method* method = parse_method(CHECK); if (had_error()) return; ciMethodRecord* rec = new_ciMethod(method); - rec->invocation_counter = parse_int("invocation_counter"); - rec->backedge_counter = parse_int("backedge_counter"); - rec->interpreter_invocation_count = parse_int("interpreter_invocation_count"); - rec->interpreter_throwout_count = parse_int("interpreter_throwout_count"); - rec->instructions_size = parse_int("instructions_size"); + rec->_invocation_counter = parse_int("invocation_counter"); + rec->_backedge_counter = parse_int("backedge_counter"); + rec->_interpreter_invocation_count = parse_int("interpreter_invocation_count"); + rec->_interpreter_throwout_count = parse_int("interpreter_throwout_count"); + rec->_instructions_size = parse_int("instructions_size"); } // ciMethodData orig # # ... data # # ... oops @@ -471,32 +583,32 @@ // collect and record all the needed information for later ciMethodDataRecord* rec = new_ciMethodData(method); - rec->state = parse_int("state"); - rec->current_mileage = parse_int("current_mileage"); + rec->_state = parse_int("state"); + rec->_current_mileage = parse_int("current_mileage"); - rec->orig_data = parse_data("orig", rec->orig_data_length); - if (rec->orig_data == NULL) { + rec->_orig_data = parse_data("orig", rec->_orig_data_length); + if (rec->_orig_data == NULL) { return; } - rec->data = parse_intptr_data("data", rec->data_length); - if (rec->data == NULL) { + rec->_data = parse_intptr_data("data", rec->_data_length); + if (rec->_data == NULL) { return; } - if (!parse_tag_and_count("oops", rec->oops_length)) { + if (!parse_tag_and_count("oops", rec->_oops_length)) { return; } - rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length); - rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length); - for (int i = 0; i < rec->oops_length; i++) { + rec->_oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->_oops_length); + rec->_oops_offsets = NEW_RESOURCE_ARRAY(int, rec->_oops_length); + for (int i = 0; i < rec->_oops_length; i++) { int offset = parse_int("offset"); if (had_error()) { return; } Klass* k = parse_klass(CHECK); - rec->oops_offsets[i] = offset; + rec->_oops_offsets[i] = offset; KlassHandle *kh = NEW_C_HEAP_OBJ(KlassHandle, mtCompiler); ::new ((void*)kh) KlassHandle(THREAD, k); - rec->oops_handles[i] = (jobject)kh; + rec->_oops_handles[i] = (jobject)kh; } } @@ -570,6 +682,9 @@ case JVM_CONSTANT_Utf8: case JVM_CONSTANT_Integer: case JVM_CONSTANT_Float: + case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_InvokeDynamic: if (tag != cp->tag_at(i).value()) { report_error("tag mismatch: wrong class files?"); return; @@ -729,10 +844,10 @@ // Create and initialize a record for a ciMethod ciMethodRecord* new_ciMethod(Method* method) { ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord); - rec->klass = method->method_holder()->name()->as_utf8(); - rec->method = method->name()->as_utf8(); - rec->signature = method->signature()->as_utf8(); - ci_method_records.append(rec); + rec->_klass_name = method->method_holder()->name()->as_utf8(); + rec->_method_name = method->name()->as_utf8(); + rec->_signature = method->signature()->as_utf8(); + _ci_method_records.append(rec); return rec; } @@ -741,11 +856,11 @@ const char* klass_name = method->method_holder()->name()->as_utf8(); const char* method_name = method->name()->as_utf8(); const char* signature = method->signature()->as_utf8(); - for (int i = 0; i < ci_method_records.length(); i++) { - ciMethodRecord* rec = ci_method_records.at(i); - if (strcmp(rec->klass, klass_name) == 0 && - strcmp(rec->method, method_name) == 0 && - strcmp(rec->signature, signature) == 0) { + for (int i = 0; i < _ci_method_records.length(); i++) { + ciMethodRecord* rec = _ci_method_records.at(i); + if (strcmp(rec->_klass_name, klass_name) == 0 && + strcmp(rec->_method_name, method_name) == 0 && + strcmp(rec->_signature, signature) == 0) { return rec; } } @@ -755,10 +870,10 @@ // Create and initialize a record for a ciMethodData ciMethodDataRecord* new_ciMethodData(Method* method) { ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord); - rec->klass = method->method_holder()->name()->as_utf8(); - rec->method = method->name()->as_utf8(); - rec->signature = method->signature()->as_utf8(); - ci_method_data_records.append(rec); + rec->_klass_name = method->method_holder()->name()->as_utf8(); + rec->_method_name = method->name()->as_utf8(); + rec->_signature = method->signature()->as_utf8(); + _ci_method_data_records.append(rec); return rec; } @@ -767,25 +882,65 @@ const char* klass_name = method->method_holder()->name()->as_utf8(); const char* method_name = method->name()->as_utf8(); const char* signature = method->signature()->as_utf8(); - for (int i = 0; i < ci_method_data_records.length(); i++) { - ciMethodDataRecord* rec = ci_method_data_records.at(i); - if (strcmp(rec->klass, klass_name) == 0 && - strcmp(rec->method, method_name) == 0 && - strcmp(rec->signature, signature) == 0) { + for (int i = 0; i < _ci_method_data_records.length(); i++) { + ciMethodDataRecord* rec = _ci_method_data_records.at(i); + if (strcmp(rec->_klass_name, klass_name) == 0 && + strcmp(rec->_method_name, method_name) == 0 && + strcmp(rec->_signature, signature) == 0) { return rec; } } return NULL; } + // Create and initialize a record for a ciInlineRecord + ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) { + ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord); + rec->_klass_name = method->method_holder()->name()->as_utf8(); + rec->_method_name = method->name()->as_utf8(); + rec->_signature = method->signature()->as_utf8(); + rec->_inline_bci = bci; + rec->_inline_depth = depth; + _ci_inline_records->append(rec); + return rec; + } + + // Lookup inlining data for a ciMethod + ciInlineRecord* find_ciInlineRecord(Method* method, int bci, int depth) { + if (_ci_inline_records != NULL) { + return find_ciInlineRecord(_ci_inline_records, method, bci, depth); + } + return NULL; + } + + static ciInlineRecord* find_ciInlineRecord(GrowableArray* records, + Method* method, int bci, int depth) { + if (records != NULL) { + const char* klass_name = method->method_holder()->name()->as_utf8(); + const char* method_name = method->name()->as_utf8(); + const char* signature = method->signature()->as_utf8(); + for (int i = 0; i < records->length(); i++) { + ciInlineRecord* rec = records->at(i); + if ((rec->_inline_bci == bci) && + (rec->_inline_depth == depth) && + (strcmp(rec->_klass_name, klass_name) == 0) && + (strcmp(rec->_method_name, method_name) == 0) && + (strcmp(rec->_signature, signature) == 0)) { + return rec; + } + } + } + return NULL; + } + const char* error_message() { return _error_message; } void reset() { _error_message = NULL; - ci_method_records.clear(); - ci_method_data_records.clear(); + _ci_method_records.clear(); + _ci_method_data_records.clear(); } // Take an ascii string contain \u#### escapes and convert it to utf8 @@ -845,6 +1000,37 @@ vm_exit(exit_code); } +void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) { + if (FLAG_IS_DEFAULT(InlineDataFile)) { + tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt)."); + return NULL; + } + + VM_ENTRY_MARK; + // Load and parse the replay data + CompileReplay rp(InlineDataFile, THREAD); + if (!rp.can_replay()) { + tty->print_cr("ciReplay: !rp.can_replay()"); + return NULL; + } + void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop throwable = PENDING_EXCEPTION; + CLEAR_PENDING_EXCEPTION; + java_lang_Throwable::print(throwable, tty); + tty->cr(); + java_lang_Throwable::print_stack_trace(throwable, tty); + tty->cr(); + return NULL; + } + + if (rp.had_error()) { + tty->print_cr("ciReplay: Failed on %s", rp.error_message()); + return NULL; + } + return data; +} + int ciReplay::replay_impl(TRAPS) { HandleMark hm; ResourceMark rm; @@ -890,7 +1076,6 @@ return exit_code; } - void ciReplay::initialize(ciMethodData* m) { if (replay_state == NULL) { return; @@ -909,28 +1094,28 @@ method->print_name(tty); tty->cr(); } else { - m->_state = rec->state; - m->_current_mileage = rec->current_mileage; - if (rec->data_length != 0) { - assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree"); + m->_state = rec->_state; + m->_current_mileage = rec->_current_mileage; + if (rec->_data_length != 0) { + assert(m->_data_size == rec->_data_length * (int)sizeof(rec->_data[0]), "must agree"); // Write the correct ciObjects back into the profile data ciEnv* env = ciEnv::current(); - for (int i = 0; i < rec->oops_length; i++) { - KlassHandle *h = (KlassHandle *)rec->oops_handles[i]; - *(ciMetadata**)(rec->data + rec->oops_offsets[i]) = + for (int i = 0; i < rec->_oops_length; i++) { + KlassHandle *h = (KlassHandle *)rec->_oops_handles[i]; + *(ciMetadata**)(rec->_data + rec->_oops_offsets[i]) = env->get_metadata((*h)()); } // Copy the updated profile data into place as intptr_ts #ifdef _LP64 - Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length); + Copy::conjoint_jlongs_atomic((jlong *)rec->_data, (jlong *)m->_data, rec->_data_length); #else - Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length); + Copy::conjoint_jints_atomic((jint *)rec->_data, (jint *)m->_data, rec->_data_length); #endif } // copy in the original header - Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length); + Copy::conjoint_jbytes(rec->_orig_data, (char*)&m->_orig, rec->_orig_data_length); } } @@ -939,12 +1124,38 @@ if (replay_state == NULL) { return false; } - VM_ENTRY_MARK; // ciMethod without a record shouldn't be inlined. return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; } +bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) { + if (data != NULL) { + GrowableArray* records = (GrowableArray*)data; + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL; + } else if (replay_state != NULL) { + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL; + } + return false; +} + +bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) { + if (data != NULL) { + GrowableArray* records = (GrowableArray*)data; + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL; + } else if (replay_state != NULL) { + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) == NULL; + } + return false; +} void ciReplay::initialize(ciMethod* m) { if (replay_state == NULL) { @@ -965,14 +1176,14 @@ tty->cr(); } else { EXCEPTION_CONTEXT; - // m->_instructions_size = rec->instructions_size; + // m->_instructions_size = rec->_instructions_size; m->_instructions_size = -1; - m->_interpreter_invocation_count = rec->interpreter_invocation_count; - m->_interpreter_throwout_count = rec->interpreter_throwout_count; + m->_interpreter_invocation_count = rec->_interpreter_invocation_count; + m->_interpreter_throwout_count = rec->_interpreter_throwout_count; MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR); guarantee(mcs != NULL, "method counters allocation failed"); - mcs->invocation_counter()->_counter = rec->invocation_counter; - mcs->backedge_counter()->_counter = rec->backedge_counter; + mcs->invocation_counter()->_counter = rec->_invocation_counter; + mcs->backedge_counter()->_counter = rec->_backedge_counter; } } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/ci/ciReplay.hpp --- a/src/share/vm/ci/ciReplay.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/ci/ciReplay.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -29,6 +29,73 @@ // ciReplay +// +// Replay compilation of a java method by using an information in replay file. +// Replay inlining decisions during compilation by using an information in inline file. +// +// NOTE: these replay functions only exist in debug version of VM. +// +// Replay compilation. +// ------------------- +// +// Replay data file replay.txt can be created by Serviceability Agent +// from a core file, see agent/doc/cireplay.html +// +// $ java -cp /lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB +// hsdb> attach /bin/java ./core +// hsdb> threads +// t@10 Service Thread +// t@9 C2 CompilerThread0 +// t@8 Signal Dispatcher +// t@7 Finalizer +// t@6 Reference Handler +// t@2 main +// hsdb> dumpreplaydata t@9 > replay.txt +// hsdb> quit +// +// (Note: SA could be also used to extract app.jar and boot.jar files +// from core file to replay compilation if only core file is available) +// +// Replay data file replay_pid%p.log is also created when VM crashes +// in Compiler thread during compilation. It is controlled by +// DumpReplayDataOnError flag which is ON by default. +// +// Replay file replay_pid%p_compid%d.log can be created +// for the specified java method during normal execution using +// CompileCommand option DumpReplay: +// +// -XX:CompileCommand=option,Benchmark::test,DumpReplay +// +// In this case the file name has additional compilation id "_compid%d" +// because the method could be compiled several times. +// +// To replay compilation the replay file should be specified: +// +// -XX:+ReplayCompiles -XX:ReplayDataFile=replay_pid2133.log +// +// VM thread reads data from the file immediately after VM initialization +// and puts the compilation task on compile queue. After that it goes into +// wait state (BackgroundCompilation flag is set to false) since there is no +// a program to execute. VM exits when the compilation is finished. +// +// +// Replay inlining. +// ---------------- +// +// Replay inlining file inline_pid%p_compid%d.log is created for +// a specific java method during normal execution of a java program +// using CompileCommand option DumpInline: +// +// -XX:CompileCommand=option,Benchmark::test,DumpInline +// +// To replay inlining the replay file and the method should be specified: +// +// -XX:CompileCommand=option,Benchmark::test,ReplayInline -XX:InlineDataFile=inline_pid3244_compid6.log +// +// The difference from replay compilation is that replay inlining +// is performed during normal java program execution. +// + class ciReplay { CI_PACKAGE_ACCESS @@ -37,7 +104,11 @@ static int replay_impl(TRAPS); public: + // Replay specified compilation and exit VM. static void replay(TRAPS); + // Load inlining decisions from file and use them + // during compilation of specified method. + static void* load_inline_data(ciMethod* method, int entry_bci, int comp_level); // These are used by the CI to fill in the cached data from the // replay file when replaying compiles. @@ -48,6 +119,8 @@ static bool is_loaded(Klass* klass); static bool should_not_inline(ciMethod* method); + static bool should_inline(void* data, ciMethod* method, int bci, int inline_depth); + static bool should_not_inline(void* data, ciMethod* method, int bci, int inline_depth); #endif }; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -4500,8 +4500,8 @@ break; // didn't find any match; get out } - if (super_m->is_final() && - // matching method in super is final + if (super_m->is_final() && !super_m->is_static() && + // matching method in super is final, and not static (Reflection::verify_field_access(this_klass(), super_m->method_holder(), super_m->method_holder(), diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -38,6 +38,9 @@ // -------------------------------------------------------------------------- +// the number of buckets a thread claims +const int ClaimChunkSize = 32; + SymbolTable* SymbolTable::_the_table = NULL; // Static arena for symbols that are not deallocated Arena* SymbolTable::_arena = NULL; @@ -83,16 +86,12 @@ } } -int SymbolTable::symbols_removed = 0; -int SymbolTable::symbols_counted = 0; +int SymbolTable::_symbols_removed = 0; +int SymbolTable::_symbols_counted = 0; +volatile int SymbolTable::_parallel_claimed_idx = 0; -// Remove unreferenced symbols from the symbol table -// This is done late during GC. -void SymbolTable::unlink() { - int removed = 0; - int total = 0; - size_t memory_total = 0; - for (int i = 0; i < the_table()->table_size(); ++i) { +void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { + for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* entry = the_table()->bucket(i); while (entry != NULL) { @@ -104,14 +103,14 @@ break; } Symbol* s = entry->literal(); - memory_total += s->size(); - total++; + (*memory_total) += s->size(); + (*processed)++; assert(s != NULL, "just checking"); // If reference count is zero, remove. if (s->refcount() == 0) { assert(!entry->is_shared(), "shared entries should be kept live"); delete s; - removed++; + (*removed)++; *p = entry->next(); the_table()->free_entry(entry); } else { @@ -121,12 +120,45 @@ entry = (HashtableEntry*)HashtableEntry::make_ptr(*p); } } - symbols_removed += removed; - symbols_counted += total; +} + +// Remove unreferenced symbols from the symbol table +// This is done late during GC. +void SymbolTable::unlink(int* processed, int* removed) { + size_t memory_total = 0; + buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); + _symbols_removed += *removed; + _symbols_counted += *processed; // Exclude printing for normal PrintGCDetails because people parse // this output. if (PrintGCDetails && Verbose && WizardMode) { - gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, + gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, + (memory_total*HeapWordSize)/1024); + } +} + +void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { + const int limit = the_table()->table_size(); + + size_t memory_total = 0; + + for (;;) { + // Grab next set of buckets to scan + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; + if (start_idx >= limit) { + // End of table + break; + } + + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); + buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); + } + Atomic::add(*processed, &_symbols_counted); + Atomic::add(*removed, &_symbols_removed); + // Exclude printing for normal PrintGCDetails because people parse + // this output. + if (PrintGCDetails && Verbose && WizardMode) { + gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, (memory_total*HeapWordSize)/1024); } } @@ -494,11 +526,11 @@ tty->print_cr("Total number of symbols %5d", count); tty->print_cr("Total size in memory %5dK", (memory_total*HeapWordSize)/1024); - tty->print_cr("Total counted %5d", symbols_counted); - tty->print_cr("Total removed %5d", symbols_removed); - if (symbols_counted > 0) { + tty->print_cr("Total counted %5d", _symbols_counted); + tty->print_cr("Total removed %5d", _symbols_removed); + if (_symbols_counted > 0) { tty->print_cr("Percent removed %3.2f", - ((float)symbols_removed/(float)symbols_counted)* 100); + ((float)_symbols_removed/(float)_symbols_counted)* 100); } tty->print_cr("Reference counts %5d", Symbol::_total_count); tty->print_cr("Symbol arena size %5d used %5d", @@ -739,39 +771,38 @@ return result; } -void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { +void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { + buckets_unlink_or_oops_do(is_alive, f, 0, the_table()->table_size(), processed, removed); +} + +void StringTable::possibly_parallel_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { // Readers of the table are unlocked, so we should only be removing // entries at a safepoint. assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry** p = the_table()->bucket_addr(i); - HashtableEntry* entry = the_table()->bucket(i); - while (entry != NULL) { - assert(!entry->is_shared(), "CDS not used for the StringTable"); + const int limit = the_table()->table_size(); - if (is_alive->do_object_b(entry->literal())) { - if (f != NULL) { - f->do_oop((oop*)entry->literal_addr()); - } - p = entry->next_addr(); - } else { - *p = entry->next(); - the_table()->free_entry(entry); - } - entry = *p; + for (;;) { + // Grab next set of buckets to scan + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; + if (start_idx >= limit) { + // End of table + break; } + + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); + buckets_unlink_or_oops_do(is_alive, f, start_idx, end_idx, processed, removed); } } -void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { +void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) { const int limit = the_table()->table_size(); assert(0 <= start_idx && start_idx <= limit, - err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); + err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); assert(0 <= end_idx && end_idx <= limit, - err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); + err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); assert(start_idx <= end_idx, - err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, + err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, start_idx, end_idx)); for (int i = start_idx; i < end_idx; i += 1) { @@ -786,12 +817,44 @@ } } +void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed) { + const int limit = the_table()->table_size(); + + assert(0 <= start_idx && start_idx <= limit, + err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); + assert(0 <= end_idx && end_idx <= limit, + err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); + assert(start_idx <= end_idx, + err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, + start_idx, end_idx)); + + for (int i = start_idx; i < end_idx; ++i) { + HashtableEntry** p = the_table()->bucket_addr(i); + HashtableEntry* entry = the_table()->bucket(i); + while (entry != NULL) { + assert(!entry->is_shared(), "CDS not used for the StringTable"); + + if (is_alive->do_object_b(entry->literal())) { + if (f != NULL) { + f->do_oop((oop*)entry->literal_addr()); + } + p = entry->next_addr(); + } else { + *p = entry->next(); + the_table()->free_entry(entry); + (*removed)++; + } + (*processed)++; + entry = *p; + } + } +} + void StringTable::oops_do(OopClosure* f) { - buckets_do(f, 0, the_table()->table_size()); + buckets_oops_do(f, 0, the_table()->table_size()); } void StringTable::possibly_parallel_oops_do(OopClosure* f) { - const int ClaimChunkSize = 32; const int limit = the_table()->table_size(); for (;;) { @@ -803,7 +866,7 @@ } int end_idx = MIN2(limit, start_idx + ClaimChunkSize); - buckets_do(f, start_idx, end_idx); + buckets_oops_do(f, start_idx, end_idx); } } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -86,8 +86,8 @@ static bool _needs_rehashing; // For statistics - static int symbols_removed; - static int symbols_counted; + static int _symbols_removed; + static int _symbols_counted; Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F @@ -121,6 +121,11 @@ static Arena* arena() { return _arena; } // called for statistics static void initialize_symbols(int arena_alloc_size = 0); + + static volatile int _parallel_claimed_idx; + + // Release any dead symbols + static void buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total); public: enum { symbol_alloc_batch_size = 8, @@ -177,7 +182,14 @@ unsigned int* hashValues, TRAPS); // Release any dead symbols - static void unlink(); + static void unlink() { + int processed = 0; + int removed = 0; + unlink(&processed, &removed); + } + static void unlink(int* processed, int* removed); + // Release any dead symbols, possibly parallel version + static void possibly_parallel_unlink(int* processed, int* removed); // iterate over symbols static void symbols_do(SymbolClosure *cl); @@ -235,6 +247,9 @@ // Rehash the symbol table if it gets out of balance static void rehash_table(); static bool needs_rehashing() { return _needs_rehashing; } + // Parallel chunked scanning + static void clear_parallel_claimed_index() { _parallel_claimed_idx = 0; } + static int parallel_claimed_index() { return _parallel_claimed_idx; } }; class StringTable : public Hashtable { @@ -258,7 +273,10 @@ // Apply the give oop closure to the entries to the buckets // in the range [start_idx, end_idx). - static void buckets_do(OopClosure* f, int start_idx, int end_idx); + static void buckets_oops_do(OopClosure* f, int start_idx, int end_idx); + // Unlink or apply the give oop closure to the entries to the buckets + // in the range [start_idx, end_idx). + static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); StringTable() : Hashtable((int)StringTableSize, sizeof (HashtableEntry)) {} @@ -280,15 +298,28 @@ // GC support // Delete pointers to otherwise-unreachable objects. - static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f); + static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f) { + int processed = 0; + int removed = 0; + unlink_or_oops_do(cl, f, &processed, &removed); + } static void unlink(BoolObjectClosure* cl) { - unlink_or_oops_do(cl, NULL); + int processed = 0; + int removed = 0; + unlink_or_oops_do(cl, NULL, &processed, &removed); } - + static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f, int* processed, int* removed); + static void unlink(BoolObjectClosure* cl, int* processed, int* removed) { + unlink_or_oops_do(cl, NULL, processed, removed); + } // Serially invoke "f->do_oop" on the locations of all oops in the table. static void oops_do(OopClosure* f); - // Possibly parallel version of the above + // Possibly parallel versions of the above + static void possibly_parallel_unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f, int* processed, int* removed); + static void possibly_parallel_unlink(BoolObjectClosure* cl, int* processed, int* removed) { + possibly_parallel_unlink_or_oops_do(cl, NULL, processed, removed); + } static void possibly_parallel_oops_do(OopClosure* f); // Hashing algorithm, used as the hash value used by the @@ -349,5 +380,6 @@ // Parallel chunked scanning static void clear_parallel_claimed_index() { _parallel_claimed_idx = 0; } + static int parallel_claimed_index() { return _parallel_claimed_idx; } }; #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -654,9 +654,9 @@ do_intrinsic(_addExactI, java_lang_Math, addExact_name, int2_int_signature, F_S) \ do_intrinsic(_addExactL, java_lang_Math, addExact_name, long2_long_signature, F_S) \ do_intrinsic(_decrementExactI, java_lang_Math, decrementExact_name, int_int_signature, F_S) \ - do_intrinsic(_decrementExactL, java_lang_Math, decrementExact_name, long2_long_signature, F_S) \ + do_intrinsic(_decrementExactL, java_lang_Math, decrementExact_name, long_long_signature, F_S) \ do_intrinsic(_incrementExactI, java_lang_Math, incrementExact_name, int_int_signature, F_S) \ - do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long2_long_signature, F_S) \ + do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long_long_signature, F_S) \ do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \ do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \ do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \ diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -132,9 +132,9 @@ // The installed compiler(s) AbstractCompiler* CompileBroker::_compilers[2]; -// These counters are used for assigning id's to each compilation -uint CompileBroker::_compilation_id = 0; -uint CompileBroker::_osr_compilation_id = 0; +// These counters are used to assign an unique ID to each compilation. +volatile jint CompileBroker::_compilation_id = 0; +volatile jint CompileBroker::_osr_compilation_id = 0; // Debugging information int CompileBroker::_last_compile_type = no_compile; @@ -1158,7 +1158,7 @@ // We now know that this compilation is not pending, complete, // or prohibited. Assign a compile_id to this compilation // and check to see if it is in our [Start..Stop) range. - uint compile_id = assign_compile_id(method, osr_bci); + int compile_id = assign_compile_id(method, osr_bci); if (compile_id == 0) { // The compilation falls outside the allowed range. return; @@ -1305,18 +1305,12 @@ // do the compilation if (method->is_native()) { if (!PreferInterpreterNativeStubs || method->is_method_handle_intrinsic()) { - // Acquire our lock. - int compile_id; - { - MutexLocker locker(MethodCompileQueue_lock, THREAD); - compile_id = assign_compile_id(method, standard_entry_bci); - } // To properly handle the appendix argument for out-of-line calls we are using a small trampoline that // pops off the appendix argument and jumps to the target (see gen_special_dispatch in SharedRuntime). // // Since normal compiled-to-compiled calls are not able to handle such a thing we MUST generate an adapter // in this case. If we can't generate one and use it we can not execute the out-of-line method handle calls. - (void) AdapterHandlerLibrary::create_native_wrapper(method, compile_id); + AdapterHandlerLibrary::create_native_wrapper(method); } else { return NULL; } @@ -1419,27 +1413,28 @@ return false; } - -// ------------------------------------------------------------------ -// CompileBroker::assign_compile_id -// -// Assign a serialized id number to this compilation request. If the -// number falls out of the allowed range, return a 0. OSR -// compilations may be numbered separately from regular compilations -// if certain debugging flags are used. -uint CompileBroker::assign_compile_id(methodHandle method, int osr_bci) { - assert(MethodCompileQueue_lock->owner() == Thread::current(), - "must hold the compilation queue lock"); +/** + * Generate serialized IDs for compilation requests. If certain debugging flags are used + * and the ID is not within the specified range, the method is not compiled and 0 is returned. + * The function also allows to generate separate compilation IDs for OSR compilations. + */ +int CompileBroker::assign_compile_id(methodHandle method, int osr_bci) { +#ifdef ASSERT bool is_osr = (osr_bci != standard_entry_bci); - uint id; - if (CICountOSR && is_osr) { - id = ++_osr_compilation_id; - if ((uint)CIStartOSR <= id && id < (uint)CIStopOSR) { + int id; + if (method->is_native()) { + assert(!is_osr, "can't be osr"); + // Adapters, native wrappers and method handle intrinsics + // should be generated always. + return Atomic::add(1, &_compilation_id); + } else if (CICountOSR && is_osr) { + id = Atomic::add(1, &_osr_compilation_id); + if (CIStartOSR <= id && id < CIStopOSR) { return id; } } else { - id = ++_compilation_id; - if ((uint)CIStart <= id && id < (uint)CIStop) { + id = Atomic::add(1, &_compilation_id); + if (CIStart <= id && id < CIStop) { return id; } } @@ -1447,6 +1442,11 @@ // Method was not in the appropriate compilation range. method->set_not_compilable_quietly(); return 0; +#else + // CICountOSR is a develop flag and set to 'false' by default. In a product built, + // only _compilation_id is incremented. + return Atomic::add(1, &_compilation_id); +#endif } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/compiler/compileBroker.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -246,6 +246,8 @@ // Compile type Information for print_last_compile() and CompilerCounters enum { no_compile, normal_compile, osr_compile, native_compile }; + static int assign_compile_id (methodHandle method, int osr_bci); + private: static bool _initialized; @@ -258,9 +260,8 @@ static AbstractCompiler* _compilers[2]; // These counters are used for assigning id's to each compilation - static uint _compilation_id; - static uint _osr_compilation_id; - static uint _native_compilation_id; + static volatile jint _compilation_id; + static volatile jint _osr_compilation_id; static int _last_compile_type; static int _last_compile_level; @@ -321,7 +322,6 @@ static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); - static uint assign_compile_id (methodHandle method, int osr_bci); static bool is_compile_blocking (methodHandle method, int osr_bci); static void preload_classes (methodHandle method, TRAPS); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp --- a/src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -98,116 +98,4 @@ _closure_app_seconds(0.0) { } }; -class BufferingOopsInGenClosure: public OopsInGenClosure { - BufferingOopClosure _boc; - OopsInGenClosure* _oc; - protected: - template inline void do_oop_work(T* p) { - assert(generation()->is_in_reserved((void*)p), "Must be in!"); - _boc.do_oop(p); - } - public: - BufferingOopsInGenClosure(OopsInGenClosure *oc) : - _boc(oc), _oc(oc) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } - - void done() { - _boc.done(); - } - - double closure_app_seconds () { - return _boc.closure_app_seconds(); - } - - void set_generation(Generation* gen) { - OopsInGenClosure::set_generation(gen); - _oc->set_generation(gen); - } - - void reset_generation() { - // Make sure we finish the current work with the current generation. - _boc.done(); - OopsInGenClosure::reset_generation(); - _oc->reset_generation(); - } - -}; - - -class BufferingOopsInHeapRegionClosure: public OopsInHeapRegionClosure { -private: - enum PrivateConstants { - BufferLength = 1024 - }; - - StarTask _buffer[BufferLength]; - StarTask* _buffer_top; - StarTask* _buffer_curr; - - HeapRegion* _hr_buffer[BufferLength]; - HeapRegion** _hr_curr; - - OopsInHeapRegionClosure* _oc; - double _closure_app_seconds; - - void process_buffer () { - - assert((_hr_curr - _hr_buffer) == (_buffer_curr - _buffer), - "the two lengths should be the same"); - - double start = os::elapsedTime(); - HeapRegion** hr_curr = _hr_buffer; - HeapRegion* hr_prev = NULL; - for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) { - HeapRegion* region = *hr_curr; - if (region != hr_prev) { - _oc->set_region(region); - hr_prev = region; - } - if (curr->is_narrow()) { - assert(UseCompressedOops, "Error"); - _oc->do_oop((narrowOop*)(*curr)); - } else { - _oc->do_oop((oop*)(*curr)); - } - ++hr_curr; - } - _buffer_curr = _buffer; - _hr_curr = _hr_buffer; - _closure_app_seconds += (os::elapsedTime() - start); - } - -public: - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - - template void do_oop_work(T* p) { - if (_buffer_curr == _buffer_top) { - assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr"); - process_buffer(); - } - StarTask new_ref(p); - *_buffer_curr = new_ref; - ++_buffer_curr; - *_hr_curr = _from; - ++_hr_curr; - } - void done () { - if (_buffer_curr > _buffer) { - assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr"); - process_buffer(); - } - } - double closure_app_seconds () { - return _closure_app_seconds; - } - BufferingOopsInHeapRegionClosure (OopsInHeapRegionClosure *oc) : - _oc(oc), - _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength), - _hr_curr(_hr_buffer), - _closure_app_seconds(0.0) { } -}; - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1619,7 +1619,6 @@ } }; - class G1ParVerifyFinalCountTask: public AbstractGangTask { protected: G1CollectedHeap* _g1h; @@ -2529,10 +2528,9 @@ assert(!rp->discovery_enabled(), "Post condition"); } - // Now clean up stale oops in StringTable - StringTable::unlink(&g1_is_alive); - // Clean up unreferenced symbols in symbol table. - SymbolTable::unlink(); + g1h->unlink_string_and_symbol_table(&g1_is_alive, + /* process_strings */ false, // currently strings are always roots + /* process_symbols */ true); } void ConcurrentMark::swapMarkBitMaps() { diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,8 @@ #include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" #include "memory/gcLocker.inline.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/generationSpec.hpp" +#include "memory/iterator.hpp" #include "memory/referenceProcessor.hpp" #include "oops/oop.inline.hpp" #include "oops/oop.pcgc.inline.hpp" @@ -1575,8 +1575,6 @@ void G1CollectedHeap:: resize_if_necessary_after_full_collection(size_t word_size) { - assert(MinHeapFreeRatio <= MaxHeapFreeRatio, "sanity check"); - // Include the current allocation, if any, and bytes that will be // pre-allocated to support collections, as "used". const size_t used_after_gc = used(); @@ -3096,11 +3094,7 @@ return NULL; // keep some compilers happy } -// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can -// pass it as the perm_blk to SharedHeap::process_strong_roots. -// When process_strong_roots stop calling perm_blk->younger_refs_iterate -// we can change this closure to extend the simpler OopClosure. -class VerifyRootsClosure: public OopsInGenClosure { +class VerifyRootsClosure: public OopClosure { private: G1CollectedHeap* _g1h; VerifyOption _vo; @@ -3136,7 +3130,7 @@ void do_oop(narrowOop* p) { do_oop_nv(p); } }; -class G1VerifyCodeRootOopClosure: public OopsInGenClosure { +class G1VerifyCodeRootOopClosure: public OopClosure { G1CollectedHeap* _g1h; OopClosure* _root_cl; nmethod* _nm; @@ -4670,8 +4664,8 @@ _during_initial_mark(_g1->g1_policy()->during_initial_mark_pause()), _mark_in_progress(_g1->mark_in_progress()) { } -template -void G1ParCopyClosure::mark_object(oop obj) { +template +void G1ParCopyClosure::mark_object(oop obj) { #ifdef ASSERT HeapRegion* hr = _g1->heap_region_containing(obj); assert(hr != NULL, "sanity"); @@ -4682,8 +4676,8 @@ _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); } -template -void G1ParCopyClosure +template +void G1ParCopyClosure ::mark_forwarded_object(oop from_obj, oop to_obj) { #ifdef ASSERT assert(from_obj->is_forwarded(), "from obj should be forwarded"); @@ -4706,8 +4700,8 @@ _cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id); } -template -oop G1ParCopyClosure +template +oop G1ParCopyClosure ::copy_to_survivor_space(oop old) { size_t word_sz = old->size(); HeapRegion* from_region = _g1->heap_region_containing_raw(old); @@ -4803,13 +4797,11 @@ } } -template +template template -void G1ParCopyClosure +void G1ParCopyClosure ::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - assert(barrier != G1BarrierRS || obj != NULL, - "Precondition: G1BarrierRS implies obj is non-NULL"); assert(_worker_id == _par_scan_state->queue_num(), "sanity"); @@ -4829,10 +4821,7 @@ mark_forwarded_object(obj, forwardee); } - // When scanning the RS, we only care about objs in CS. - if (barrier == G1BarrierRS) { - _par_scan_state->update_rs(_from, p, _worker_id); - } else if (barrier == G1BarrierKlass) { + if (barrier == G1BarrierKlass) { do_klass_barrier(p, forwardee); } } else { @@ -4847,14 +4836,10 @@ if (barrier == G1BarrierEvac && obj != NULL) { _par_scan_state->update_rs(_from, p, _worker_id); } - - if (do_gen_barrier && obj != NULL) { - par_do_barrier(p); - } -} - -template void G1ParCopyClosure::do_oop_work(oop* p); -template void G1ParCopyClosure::do_oop_work(narrowOop* p); +} + +template void G1ParCopyClosure::do_oop_work(oop* p); +template void G1ParCopyClosure::do_oop_work(narrowOop* p); template void G1ParScanPartialArrayClosure::do_oop_nv(T* p) { assert(has_partial_array_mask(p), "invariant"); @@ -5212,6 +5197,102 @@ SharedHeap::process_weak_roots(root_closure, &roots_in_blobs); } +class G1StringSymbolTableUnlinkTask : public AbstractGangTask { +private: + BoolObjectClosure* _is_alive; + int _initial_string_table_size; + int _initial_symbol_table_size; + + bool _process_strings; + int _strings_processed; + int _strings_removed; + + bool _process_symbols; + int _symbols_processed; + int _symbols_removed; + + bool _do_in_parallel; +public: + G1StringSymbolTableUnlinkTask(BoolObjectClosure* is_alive, bool process_strings, bool process_symbols) : + AbstractGangTask("Par String/Symbol table unlink"), _is_alive(is_alive), + _do_in_parallel(G1CollectedHeap::use_parallel_gc_threads()), + _process_strings(process_strings), _strings_processed(0), _strings_removed(0), + _process_symbols(process_symbols), _symbols_processed(0), _symbols_removed(0) { + + _initial_string_table_size = StringTable::the_table()->table_size(); + _initial_symbol_table_size = SymbolTable::the_table()->table_size(); + if (process_strings) { + StringTable::clear_parallel_claimed_index(); + } + if (process_symbols) { + SymbolTable::clear_parallel_claimed_index(); + } + } + + ~G1StringSymbolTableUnlinkTask() { + guarantee(!_process_strings || !_do_in_parallel || StringTable::parallel_claimed_index() >= _initial_string_table_size, + err_msg("claim value "INT32_FORMAT" after unlink less than initial string table size "INT32_FORMAT, + StringTable::parallel_claimed_index(), _initial_string_table_size)); + guarantee(!_process_symbols || !_do_in_parallel || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size, + err_msg("claim value "INT32_FORMAT" after unlink less than initial symbol table size "INT32_FORMAT, + SymbolTable::parallel_claimed_index(), _initial_symbol_table_size)); + } + + void work(uint worker_id) { + if (_do_in_parallel) { + int strings_processed = 0; + int strings_removed = 0; + int symbols_processed = 0; + int symbols_removed = 0; + if (_process_strings) { + StringTable::possibly_parallel_unlink(_is_alive, &strings_processed, &strings_removed); + Atomic::add(strings_processed, &_strings_processed); + Atomic::add(strings_removed, &_strings_removed); + } + if (_process_symbols) { + SymbolTable::possibly_parallel_unlink(&symbols_processed, &symbols_removed); + Atomic::add(symbols_processed, &_symbols_processed); + Atomic::add(symbols_removed, &_symbols_removed); + } + } else { + if (_process_strings) { + StringTable::unlink(_is_alive, &_strings_processed, &_strings_removed); + } + if (_process_symbols) { + SymbolTable::unlink(&_symbols_processed, &_symbols_removed); + } + } + } + + size_t strings_processed() const { return (size_t)_strings_processed; } + size_t strings_removed() const { return (size_t)_strings_removed; } + + size_t symbols_processed() const { return (size_t)_symbols_processed; } + size_t symbols_removed() const { return (size_t)_symbols_removed; } +}; + +void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive, + bool process_strings, bool process_symbols) { + uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + _g1h->workers()->active_workers() : 1); + + G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols); + if (G1CollectedHeap::use_parallel_gc_threads()) { + set_par_threads(n_workers); + workers()->run_task(&g1_unlink_task); + set_par_threads(0); + } else { + g1_unlink_task.work(0); + } + if (G1TraceStringSymbolTableScrubbing) { + gclog_or_tty->print_cr("Cleaned string and symbol table, " + "strings: "SIZE_FORMAT" processed, "SIZE_FORMAT" removed, " + "symbols: "SIZE_FORMAT" processed, "SIZE_FORMAT" removed", + g1_unlink_task.strings_processed(), g1_unlink_task.strings_removed(), + g1_unlink_task.symbols_processed(), g1_unlink_task.symbols_removed()); + } +} + // Weak Reference Processing support // An always "is_alive" closure that is used to preserve referents. diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -209,7 +209,7 @@ friend class OldGCAllocRegion; // Closures used in implementation. - template + template friend class G1ParCopyClosure; friend class G1IsAliveClosure; friend class G1EvacuateFollowersClosure; @@ -1677,6 +1677,10 @@ // after a full GC void rebuild_strong_code_roots(); + // Delete entries for dead interned string and clean up unreferenced symbols + // in symbol table, possibly in parallel. + void unlink_string_and_symbol_table(BoolObjectClosure* is_alive, bool unlink_strings = true, bool unlink_symbols = true); + // Verification // The following is just to alert the verification code diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -163,11 +163,8 @@ // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); - // Delete entries for dead interned strings. - StringTable::unlink(&GenMarkSweep::is_alive); - - // Clean up unreferenced symbols in symbol table. - SymbolTable::unlink(); + // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. + G1CollectedHeap::heap()->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); if (VerifyDuringGC) { HandleMark hm; // handle scope diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1OopClosures.hpp --- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ // A class that scans oops in a given heap region (much as OopsInGenClosure // scans oops in a generation.) -class OopsInHeapRegionClosure: public OopsInGenClosure { +class OopsInHeapRegionClosure: public ExtendedOopClosure { protected: HeapRegion* _from; public: @@ -86,13 +86,26 @@ #define G1_PARTIAL_ARRAY_MASK 0x2 -template inline bool has_partial_array_mask(T* ref) { +inline bool has_partial_array_mask(oop* ref) { return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; } -template inline T* set_partial_array_mask(T obj) { +// We never encode partial array oops as narrowOop*, so return false immediately. +// This allows the compiler to create optimized code when popping references from +// the work queue. +inline bool has_partial_array_mask(narrowOop* ref) { + assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); + return false; +} + +// Only implement set_partial_array_mask() for regular oops, not for narrowOops. +// We always encode partial arrays as regular oop, to allow the +// specialization for has_partial_array_mask() for narrowOops above. +// This means that unintentional use of this method with narrowOops are caught +// by the compiler. +inline oop* set_partial_array_mask(oop obj) { assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); - return (T*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); + return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); } template inline oop clear_partial_array_mask(T* ref) { @@ -131,7 +144,7 @@ template void do_klass_barrier(T* p, oop new_obj); }; -template +template class G1ParCopyClosure : public G1ParCopyHelper { G1ParScanClosure _scanner; template void do_oop_work(T* p); @@ -166,22 +179,16 @@ virtual void do_oop(narrowOop* p) { do_oop_nv(p); } }; -typedef G1ParCopyClosure G1ParScanExtRootClosure; -typedef G1ParCopyClosure G1ParScanMetadataClosure; +typedef G1ParCopyClosure G1ParScanExtRootClosure; +typedef G1ParCopyClosure G1ParScanMetadataClosure; -typedef G1ParCopyClosure G1ParScanAndMarkExtRootClosure; -typedef G1ParCopyClosure G1ParScanAndMarkClosure; -typedef G1ParCopyClosure G1ParScanAndMarkMetadataClosure; - -// The following closure types are no longer used but are retained -// for historical reasons: -// typedef G1ParCopyClosure G1ParScanHeapRSClosure; -// typedef G1ParCopyClosure G1ParScanAndMarkHeapRSClosure; +typedef G1ParCopyClosure G1ParScanAndMarkExtRootClosure; +typedef G1ParCopyClosure G1ParScanAndMarkMetadataClosure; // The following closure type is defined in g1_specialized_oop_closures.hpp: // -// typedef G1ParCopyClosure G1ParScanHeapEvacClosure; +// typedef G1ParCopyClosure G1ParScanHeapEvacClosure; // We use a separate closure to handle references during evacuation // failure processing. @@ -189,7 +196,7 @@ // (since that closure no longer assumes that the references it // handles point into the collection set). -typedef G1ParCopyClosure G1ParScanHeapEvacFailureClosure; +typedef G1ParCopyClosure G1ParScanHeapEvacFailureClosure; class FilterIntoCSClosure: public ExtendedOopClosure { G1CollectedHeap* _g1; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -71,6 +71,9 @@ diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ \ + experimental(bool, G1TraceStringSymbolTableScrubbing, false, \ + "Trace information string and symbol table scrubbing.") \ + \ product(double, G1ConcMarkStepDurationMillis, 10.0, \ "Target duration of individual concurrent marking steps " \ "in milliseconds.") \ diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp --- a/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -33,18 +33,17 @@ // Forward declarations. enum G1Barrier { G1BarrierNone, - G1BarrierRS, G1BarrierEvac, G1BarrierKlass }; -template +template class G1ParCopyClosure; class G1ParScanClosure; class G1ParPushHeapRSClosure; -typedef G1ParCopyClosure G1ParScanHeapEvacClosure; +typedef G1ParCopyClosure G1ParScanHeapEvacClosure; class FilterIntoCSClosure; class FilterOutOfRegionClosure; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" @@ -76,6 +77,38 @@ _old_gen_policy_is_ready = false; } +size_t PSAdaptiveSizePolicy::calculate_free_based_on_live(size_t live, uintx ratio_as_percentage) { + // We want to calculate how much free memory there can be based on the + // amount of live data currently in the old gen. Using the formula: + // ratio * (free + live) = free + // Some equation solving later we get: + // free = (live * ratio) / (1 - ratio) + + const double ratio = ratio_as_percentage / 100.0; + const double ratio_inverse = 1.0 - ratio; + const double tmp = live * ratio; + size_t free = (size_t)(tmp / ratio_inverse); + + return free; +} + +size_t PSAdaptiveSizePolicy::calculated_old_free_size_in_bytes() const { + size_t free_size = (size_t)(_promo_size + avg_promoted()->padded_average()); + size_t live = ParallelScavengeHeap::heap()->old_gen()->used_in_bytes(); + + if (MinHeapFreeRatio != 0) { + size_t min_free = calculate_free_based_on_live(live, MinHeapFreeRatio); + free_size = MAX2(free_size, min_free); + } + + if (MaxHeapFreeRatio != 100) { + size_t max_free = calculate_free_based_on_live(live, MaxHeapFreeRatio); + free_size = MIN2(max_free, free_size); + } + + return free_size; +} + void PSAdaptiveSizePolicy::major_collection_begin() { // Update the interval time _major_timer.stop(); @@ -1292,3 +1325,18 @@ st, PSScavenge::tenuring_threshold()); } + +#ifndef PRODUCT + +void TestOldFreeSpaceCalculation_test() { + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 20) == 25, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 50) == 100, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 60) == 150, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 75) == 300, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 20) == 100, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 50) == 400, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 60) == 600, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 75) == 1200, "Calculation of free memory failed"); +} + +#endif /* !PRODUCT */ diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -240,7 +240,6 @@ void major_collection_begin(); void major_collection_end(size_t amount_live, GCCause::Cause gc_cause); - // void tenured_allocation(size_t size) { _avg_pretenured->sample(size); } @@ -248,9 +247,9 @@ // Accessors // NEEDS_CLEANUP should use sizes.hpp - size_t calculated_old_free_size_in_bytes() const { - return (size_t)(_promo_size + avg_promoted()->padded_average()); - } + static size_t calculate_free_based_on_live(size_t live, uintx ratio_as_percentage); + + size_t calculated_old_free_size_in_bytes() const; size_t average_old_live_in_bytes() const { return (size_t) avg_old_live()->average(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, 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 @@ -466,10 +466,12 @@ } } - GCTraceTime tm("StringTable", false, false, &_gc_timer); - // Unlink any dead interned Strings and process the remaining live ones. - PSScavengeRootsClosure root_closure(promotion_manager); - StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); + { + GCTraceTime tm("StringTable", false, false, &_gc_timer); + // Unlink any dead interned Strings and process the remaining live ones. + PSScavengeRootsClosure root_closure(promotion_manager); + StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); + } // Finally, flush the promotion_manager's labs, and deallocate its stacks. promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer); @@ -527,8 +529,19 @@ counters->update_survivor_overflowed(_survivor_overflow); } + size_t max_young_size = young_gen->max_size(); + + // Deciding a free ratio in the young generation is tricky, so if + // MinHeapFreeRatio or MaxHeapFreeRatio are in use (implicating + // that the old generation size may have been limited because of them) we + // should then limit our young generation size using NewRatio to have it + // follow the old generation size. + if (MinHeapFreeRatio != 0 || MaxHeapFreeRatio != 100) { + max_young_size = MIN2(old_gen->capacity_in_bytes() / NewRatio, young_gen->max_size()); + } + size_t survivor_limit = - size_policy->max_survivor_size(young_gen->max_size()); + size_policy->max_survivor_size(max_young_size); _tenuring_threshold = size_policy->compute_survivor_space_size_and_threshold( _survivor_overflow, @@ -551,8 +564,7 @@ // Do call at minor collections? // Don't check if the size_policy is ready at this // level. Let the size_policy check that internally. - if (UseAdaptiveSizePolicy && - UseAdaptiveGenerationSizePolicyAtMinorCollection && + if (UseAdaptiveGenerationSizePolicyAtMinorCollection && ((gc_cause != GCCause::_java_lang_system_gc) || UseAdaptiveSizePolicyWithSystemGC)) { @@ -566,7 +578,7 @@ size_t eden_live = young_gen->eden_space()->used_in_bytes(); size_t cur_eden = young_gen->eden_space()->capacity_in_bytes(); size_t max_old_gen_size = old_gen->max_gen_size(); - size_t max_eden_size = young_gen->max_size() - + size_t max_eden_size = max_young_size - young_gen->from_space()->capacity_in_bytes() - young_gen->to_space()->capacity_in_bytes(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -127,7 +127,7 @@ void adjust_pointers(); void compact(); - // Called during/after gc + // Called during/after GC void swap_spaces(); // Resize generation using suggested free space size and survivor size @@ -146,14 +146,14 @@ size_t free_in_words() const; // The max this generation can grow to - size_t max_size() const { return _reserved.byte_size(); } + size_t max_size() const { return _reserved.byte_size(); } // The max this generation can grow to if the boundary between // the generations are allowed to move. size_t gen_size_limit() const { return _max_gen_size; } bool is_maximal_no_gc() const { - return true; // never expands except at a GC + return true; // Never expands except at a GC } // Allocation diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -649,16 +649,6 @@ } } - if (nostatics && resolved_method->is_static()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - - if (check_access) { // JDK8 adds non-public interface methods, and accessability check requirement assert(current_klass.not_null() , "current_klass should not be null"); @@ -702,6 +692,15 @@ } } + if (nostatics && resolved_method->is_static()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", + Method::name_and_sig_as_C_string(resolved_klass(), + resolved_method->name(), resolved_method->signature())); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + if (TraceItables && Verbose) { ResourceMark rm(THREAD); tty->print("invokeinterface resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/memory/allocation.cpp --- a/src/share/vm/memory/allocation.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/memory/allocation.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -140,7 +140,7 @@ void ResourceObj::set_allocation_type(address res, allocation_type type) { // Set allocation type in the resource object uintptr_t allocation = (uintptr_t)res; - assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least"); + assert((allocation & allocation_mask) == 0, err_msg("address should be aligned to 4 bytes at least: " PTR_FORMAT, res)); assert(type <= allocation_mask, "incorrect allocation type"); ResourceObj* resobj = (ResourceObj *)res; resobj->_allocation_t[0] = ~(allocation + type); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/bytecodeInfo.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -50,7 +50,10 @@ _subtrees(c->comp_arena(), 2, 0, NULL), _msg(NULL) { - NOT_PRODUCT(_count_inlines = 0;) +#ifndef PRODUCT + _count_inlines = 0; + _forced_inline = false; +#endif if (_caller_jvms != NULL) { // Keep a private copy of the caller_jvms: _caller_jvms = new (C) JVMState(caller_jvms->method(), caller_tree->caller_jvms()); @@ -81,7 +84,10 @@ _count_inline_bcs(method()->code_size()), _msg(NULL) { - NOT_PRODUCT(_count_inlines = 0;) +#ifndef PRODUCT + _count_inlines = 0; + _forced_inline = false; +#endif assert(!UseOldInlining, "do not use for old stuff"); } @@ -128,9 +134,19 @@ tty->print_cr("Inlined method is hot: "); } set_msg("force inline by CompilerOracle"); + _forced_inline = true; return true; } +#ifndef PRODUCT + int inline_depth = inline_level()+1; + if (ciReplay::should_inline(C->replay_inline_data(), callee_method, caller_bci, inline_depth)) { + set_msg("force inline by ciReplay"); + _forced_inline = true; + return true; + } +#endif + int size = callee_method->code_size_for_inlining(); // Check for too many throws (and not too huge) @@ -264,6 +280,18 @@ } #ifndef PRODUCT + int caller_bci = jvms->bci(); + int inline_depth = inline_level()+1; + if (ciReplay::should_inline(C->replay_inline_data(), callee_method, caller_bci, inline_depth)) { + set_msg("force inline by ciReplay"); + return false; + } + + if (ciReplay::should_not_inline(C->replay_inline_data(), callee_method, caller_bci, inline_depth)) { + set_msg("disallowed by ciReplay"); + return true; + } + if (ciReplay::should_not_inline(callee_method)) { set_msg("disallowed by ciReplay"); return true; @@ -343,6 +371,7 @@ } } + _forced_inline = false; // Reset if (!should_inline(callee_method, caller_method, caller_bci, profile, wci_result)) { return false; @@ -373,10 +402,10 @@ if ((!UseInterpreter || CompileTheWorld) && is_init_with_ea(callee_method, caller_method, C)) { - // Escape Analysis stress testing when running Xcomp or CTW: // inline constructors even if they are not reached. - + } else if (forced_inline()) { + // Inlining was forced by CompilerOracle or ciReplay } else if (profile.count() == 0) { // don't inline unreached call sites set_msg("call site not reached"); @@ -700,12 +729,28 @@ return iltp; } +// Count number of nodes in this subtree +int InlineTree::count() const { + int result = 1; + for (int i = 0 ; i < _subtrees.length(); i++) { + result += _subtrees.at(i)->count(); + } + return result; +} + +void InlineTree::dump_replay_data(outputStream* out) { + out->print(" %d %d ", inline_level(), caller_bci()); + method()->dump_name_as_ascii(out); + for (int i = 0 ; i < _subtrees.length(); i++) { + _subtrees.at(i)->dump_replay_data(out); + } +} #ifndef PRODUCT void InlineTree::print_impl(outputStream* st, int indent) const { for (int i = 0; i < indent; i++) st->print(" "); - st->print(" @ %d ", caller_bci()); + st->print(" @ %d", caller_bci()); method()->print_short_name(st); st->cr(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/cfgnode.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1018,7 +1018,7 @@ !jtkp->klass_is_exact() && // Keep exact interface klass (6894807) ttkp->is_loaded() && !ttkp->klass()->is_interface() ) { assert(ft == ttkp->cast_to_ptr_type(jtkp->ptr()) || - ft->isa_narrowoop() && ft->make_ptr() == ttkp->cast_to_ptr_type(jtkp->ptr()), ""); + ft->isa_narrowklass() && ft->make_ptr() == ttkp->cast_to_ptr_type(jtkp->ptr()), ""); jt = ft; } } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/chaitin.cpp --- a/src/share/vm/opto/chaitin.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/chaitin.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1682,9 +1682,21 @@ // (where top() node is placed). base->init_req(0, _cfg.get_root_node()); Block *startb = _cfg.get_block_for_node(C->top()); - startb->insert_node(base, startb->find_node(C->top())); + uint node_pos = startb->find_node(C->top()); + startb->insert_node(base, node_pos); _cfg.map_node_to_block(base, startb); assert(_lrg_map.live_range_id(base) == 0, "should not have LRG yet"); + + // The loadConP0 might have projection nodes depending on architecture + // Add the projection nodes to the CFG + for (DUIterator_Fast imax, i = base->fast_outs(imax); i < imax; i++) { + Node* use = base->fast_out(i); + if (use->is_MachProj()) { + startb->insert_node(use, ++node_pos); + _cfg.map_node_to_block(use, startb); + new_lrg(use, maxlrg++); + } + } } if (_lrg_map.live_range_id(base) == 0) { new_lrg(base, maxlrg++); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/compile.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "ci/ciReplay.hpp" #include "classfile/systemDictionary.hpp" #include "code/exceptionHandlerTable.hpp" #include "code/nmethod.hpp" @@ -647,6 +648,7 @@ _printer(IdealGraphPrinter::printer()), #endif _congraph(NULL), + _replay_inline_data(NULL), _late_inlines(comp_arena(), 2, 0, NULL), _string_late_inlines(comp_arena(), 2, 0, NULL), _boxing_late_inlines(comp_arena(), 2, 0, NULL), @@ -680,6 +682,10 @@ } set_print_assembly(print_opto_assembly); set_parsed_irreducible_loop(false); + + if (method()->has_option("ReplayInline")) { + _replay_inline_data = ciReplay::load_inline_data(method(), entry_bci(), ci_env->comp_level()); + } #endif set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining)); set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics")); @@ -849,6 +855,15 @@ #endif NOT_PRODUCT( verify_barriers(); ) + + // Dump compilation data to replay it. + if (method()->has_option("DumpReplay")) { + env()->dump_replay_data(_compile_id); + } + if (method()->has_option("DumpInline") && (ilt() != NULL)) { + env()->dump_inline_data(_compile_id); + } + // Now that we know the size of all the monitors we can add a fixed slot // for the original deopt pc. @@ -938,6 +953,7 @@ _dead_node_list(comp_arena()), _dead_node_count(0), _congraph(NULL), + _replay_inline_data(NULL), _number_of_mh_late_inlines(0), _inlining_progress(false), _inlining_incrementally(false), @@ -3757,6 +3773,16 @@ } } +// Dump inlining replay data to the stream. +// Don't change thread state and acquire any locks. +void Compile::dump_inline_data(outputStream* out) { + InlineTree* inl_tree = ilt(); + if (inl_tree != NULL) { + out->print(" inline %d", inl_tree->count()); + inl_tree->dump_replay_data(out); + } +} + int Compile::cmp_expensive_nodes(Node* n1, Node* n2) { if (n1->Opcode() < n2->Opcode()) return -1; else if (n1->Opcode() > n2->Opcode()) return 1; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/compile.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -431,6 +431,8 @@ // Are we within a PreserveJVMState block? int _preserve_jvm_state; + void* _replay_inline_data; // Pointer to data loaded from file + public: outputStream* print_inlining_stream() const { @@ -465,6 +467,11 @@ print_inlining_stream()->print(ss.as_string()); } + void* replay_inline_data() const { return _replay_inline_data; } + + // Dump inlining replay data to the stream. + void dump_inline_data(outputStream* out); + private: // Matching, CFG layout, allocation, code generation PhaseCFG* _cfg; // Results of CFG finding diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/escape.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1579,9 +1579,20 @@ jobj->set_scalar_replaceable(false); return; } + // 2. An object is not scalar replaceable if the field into which it is + // stored has multiple bases one of which is null. + if (field->base_count() > 1) { + for (BaseIterator i(field); i.has_next(); i.next()) { + PointsToNode* base = i.get(); + if (base == null_obj) { + jobj->set_scalar_replaceable(false); + return; + } + } + } } assert(use->is_Field() || use->is_LocalVar(), "sanity"); - // 2. An object is not scalar replaceable if it is merged with other objects. + // 3. An object is not scalar replaceable if it is merged with other objects. for (EdgeIterator j(use); j.has_next(); j.next()) { PointsToNode* ptn = j.get(); if (ptn->is_JavaObject() && ptn != jobj) { @@ -1600,13 +1611,13 @@ FieldNode* field = j.get()->as_Field(); int offset = field->as_Field()->offset(); - // 3. An object is not scalar replaceable if it has a field with unknown + // 4. An object is not scalar replaceable if it has a field with unknown // offset (array's element is accessed in loop). if (offset == Type::OffsetBot) { jobj->set_scalar_replaceable(false); return; } - // 4. Currently an object is not scalar replaceable if a LoadStore node + // 5. Currently an object is not scalar replaceable if a LoadStore node // access its field since the field value is unknown after it. // Node* n = field->ideal_node(); @@ -1617,7 +1628,7 @@ } } - // 5. Or the address may point to more then one object. This may produce + // 6. Or the address may point to more then one object. This may produce // the false positive result (set not scalar replaceable) // since the flow-insensitive escape analysis can't separate // the case when stores overwrite the field's value from the case diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/parse.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -141,6 +141,13 @@ GrowableArray subtrees() { return _subtrees; } void print_value_on(outputStream* st) const PRODUCT_RETURN; + + bool _forced_inline; // Inlining was forced by CompilerOracle or ciReplay + bool forced_inline() const { return _forced_inline; } + // Count number of nodes in this subtree + int count() const; + // Dump inlining replay data to the stream. + void dump_replay_data(outputStream* out); }; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/opto/type.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -3812,17 +3812,17 @@ tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); } } else // Non integral arrays. - // Must fall to bottom if exact klasses in upper lattice - // are not equal or super klass is exact. - if ( above_centerline(ptr) && klass() != tap->klass() && - // meet with top[] and bottom[] are processed further down: - tap ->_klass != NULL && this->_klass != NULL && - // both are exact and not equal: - ((tap ->_klass_is_exact && this->_klass_is_exact) || - // 'tap' is exact and super or unrelated: - (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || - // 'this' is exact and super or unrelated: - (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { + // Must fall to bottom if exact klasses in upper lattice + // are not equal or super klass is exact. + if ((above_centerline(ptr) || ptr == Constant) && klass() != tap->klass() && + // meet with top[] and bottom[] are processed further down: + tap->_klass != NULL && this->_klass != NULL && + // both are exact and not equal: + ((tap->_klass_is_exact && this->_klass_is_exact) || + // 'tap' is exact and super or unrelated: + (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || + // 'this' is exact and super or unrelated: + (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/prims/jni.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -5061,6 +5061,7 @@ void TestMetaspaceAux_test(); void TestMetachunk_test(); void TestVirtualSpaceNode_test(); +void TestOldFreeSpaceCalculation_test(); #if INCLUDE_ALL_GCS void TestG1BiasedArray_test(); #endif @@ -5081,6 +5082,7 @@ run_unit_test(QuickSort::test_quick_sort()); run_unit_test(AltHashing::test_alt_hash()); run_unit_test(test_loggc_filename()); + run_unit_test(TestOldFreeSpaceCalculation_test()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/prims/jvmtiEnvThreadState.cpp --- a/src/share/vm/prims/jvmtiEnvThreadState.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/prims/jvmtiEnvThreadState.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -272,7 +272,7 @@ // There can be a race condition between a VM_Operation reaching a safepoint // and the target thread exiting from Java execution. // We must recheck the last Java frame still exists. - if (_thread->has_last_Java_frame()) { + if (!_thread->is_exiting() && _thread->has_last_Java_frame()) { javaVFrame* vf = _thread->last_java_vframe(&rm); assert(vf != NULL, "must have last java frame"); Method* method = vf->method(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -147,6 +147,9 @@ _scratch_classes[i] = NULL; } + // Disable any dependent concurrent compilations + SystemDictionary::notice_modification(); + // Set flag indicating that some invariants are no longer true. // See jvmtiExport.hpp for detailed explanation. JvmtiExport::set_has_redefined_a_class(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1569,6 +1569,16 @@ vm_exit(1); } + if (UseAdaptiveSizePolicy) { + // We don't want to limit adaptive heap sizing's freedom to adjust the heap + // unless the user actually sets these flags. + if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) { + FLAG_SET_DEFAULT(MinHeapFreeRatio, 0); + } + if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) { + FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100); + } + } // If InitialSurvivorRatio or MinSurvivorRatio were not specified, but the // SurvivorRatio has been set, reset their default values to SurvivorRatio + @@ -1844,7 +1854,7 @@ } bool Arguments::verify_percentage(uintx value, const char* name) { - if (value <= 100) { + if (is_percentage(value)) { return true; } jio_fprintf(defaultStream::error_stream(), @@ -1932,6 +1942,34 @@ return count_p < 2 && count_t < 2; } +bool Arguments::verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio) { + if (!is_percentage(min_heap_free_ratio)) { + err_msg.print("MinHeapFreeRatio must have a value between 0 and 100"); + return false; + } + if (min_heap_free_ratio > MaxHeapFreeRatio) { + err_msg.print("MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " + "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")", min_heap_free_ratio, + MaxHeapFreeRatio); + return false; + } + return true; +} + +bool Arguments::verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio) { + if (!is_percentage(max_heap_free_ratio)) { + err_msg.print("MaxHeapFreeRatio must have a value between 0 and 100"); + return false; + } + if (max_heap_free_ratio < MinHeapFreeRatio) { + err_msg.print("MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or " + "equal to MinHeapFreeRatio (" UINTX_FORMAT ")", max_heap_free_ratio, + MinHeapFreeRatio); + return false; + } + return true; +} + // Check consistency of GC selection bool Arguments::check_gc_consistency() { check_gclog_consistency(); @@ -2037,8 +2075,6 @@ status = status && verify_interval(AdaptiveSizePolicyWeight, 0, 100, "AdaptiveSizePolicyWeight"); status = status && verify_percentage(ThresholdTolerance, "ThresholdTolerance"); - status = status && verify_percentage(MinHeapFreeRatio, "MinHeapFreeRatio"); - status = status && verify_percentage(MaxHeapFreeRatio, "MaxHeapFreeRatio"); // Divide by bucket size to prevent a large size from causing rollover when // calculating amount of memory needed to be allocated for the String table. @@ -2048,15 +2084,19 @@ status = status && verify_interval(SymbolTableSize, minimumSymbolTableSize, (max_uintx / SymbolTable::bucket_size()), "SymbolTable size"); - if (MinHeapFreeRatio > MaxHeapFreeRatio) { - jio_fprintf(defaultStream::error_stream(), - "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " - "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", - MinHeapFreeRatio, MaxHeapFreeRatio); - status = false; + { + // Using "else if" below to avoid printing two error messages if min > max. + // This will also prevent us from reporting both min>100 and max>100 at the + // same time, but that is less annoying than printing two identical errors IMHO. + FormatBuffer<80> err_msg(""); + if (!verify_MinHeapFreeRatio(err_msg, MinHeapFreeRatio)) { + jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer()); + status = false; + } else if (!verify_MaxHeapFreeRatio(err_msg, MaxHeapFreeRatio)) { + jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer()); + status = false; + } } - // Keeping the heap 100% free is hard ;-) so limit it to 99%. - MinHeapFreeRatio = MIN2(MinHeapFreeRatio, (uintx) 99); // Min/MaxMetaspaceFreeRatio status = status && verify_percentage(MinMetaspaceFreeRatio, "MinMetaspaceFreeRatio"); @@ -2689,7 +2729,7 @@ } else if (match_option(option, "-Xmaxf", &tail)) { char* err; int maxf = (int)(strtod(tail, &err) * 100); - if (*err != '\0' || maxf < 0 || maxf > 100) { + if (*err != '\0' || *tail == '\0' || maxf < 0 || maxf > 100) { jio_fprintf(defaultStream::error_stream(), "Bad max heap free percentage size: %s\n", option->optionString); @@ -2701,7 +2741,7 @@ } else if (match_option(option, "-Xminf", &tail)) { char* err; int minf = (int)(strtod(tail, &err) * 100); - if (*err != '\0' || minf < 0 || minf > 100) { + if (*err != '\0' || *tail == '\0' || minf < 0 || minf > 100) { jio_fprintf(defaultStream::error_stream(), "Bad min heap free percentage size: %s\n", option->optionString); @@ -3646,9 +3686,9 @@ // Set per-collector flags if (UseParallelGC || UseParallelOldGC) { set_parallel_gc_flags(); - } else if (UseConcMarkSweepGC) { // should be done before ParNew check below + } else if (UseConcMarkSweepGC) { // Should be done before ParNew check below set_cms_and_parnew_gc_flags(); - } else if (UseParNewGC) { // skipped if CMS is set above + } else if (UseParNewGC) { // Skipped if CMS is set above set_parnew_gc_flags(); } else if (UseG1GC) { set_g1_gc_flags(); @@ -3662,6 +3702,10 @@ " using -XX:ParallelGCThreads=N"); } } + if (MinHeapFreeRatio == 100) { + // Keeping the heap 100% free is hard ;-) so limit it to 99%. + FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99); + } #else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS @@ -3727,10 +3771,6 @@ // Doing the replace in parent maps helps speculation FLAG_SET_DEFAULT(ReplaceInParentMaps, true); } -#ifndef X86 - // Only on x86 for now - FLAG_SET_DEFAULT(TypeProfileLevel, 0); -#endif #endif if (PrintAssembly && FLAG_IS_DEFAULT(DebugNonSafepoints)) { diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/arguments.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -27,6 +27,7 @@ #include "runtime/java.hpp" #include "runtime/perfData.hpp" +#include "utilities/debug.hpp" #include "utilities/top.hpp" // Arguments parses the command line and recognizes options @@ -370,11 +371,16 @@ 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, 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); + static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); + static bool is_bad_option(const JavaVMOption* option, jboolean ignore) { return is_bad_option(option, ignore, NULL); } + + static bool is_percentage(uintx val) { + return val <= 100; + } + static bool verify_interval(uintx val, uintx min, uintx max, const char* name); static bool verify_min_value(intx val, intx min, const char* name); @@ -440,6 +446,15 @@ static jint apply_ergo(); // Adjusts the arguments after the OS have adjusted the arguments static jint adjust_after_os(); + + // Verifies that the given value will fit as a MinHeapFreeRatio. If not, an error + // message is returned in the provided buffer. + static bool verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio); + + // Verifies that the given value will fit as a MaxHeapFreeRatio. If not, an error + // message is returned in the provided buffer. + static bool verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio); + // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); static void check_deprecated_gcs(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/deoptimization.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1224,9 +1224,19 @@ load_class_by_index(constant_pool, index, THREAD); if (HAS_PENDING_EXCEPTION) { // Exception happened during classloading. We ignore the exception here, since it - // is going to be rethrown since the current activation is going to be deoptimzied and + // is going to be rethrown since the current activation is going to be deoptimized and // the interpreter will re-execute the bytecode. CLEAR_PENDING_EXCEPTION; + // Class loading called java code which may have caused a stack + // overflow. If the exception was thrown right before the return + // to the runtime the stack is no longer guarded. Reguard the + // stack otherwise if we return to the uncommon trap blob and the + // stack bang causes a stack overflow we crash. + assert(THREAD->is_Java_thread(), "only a java thread can be here"); + JavaThread* thread = (JavaThread*)THREAD; + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + assert(guard_pages_enabled, "stack banging in uncommon trap blob may cause crash"); } } diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/globals.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -2531,6 +2531,9 @@ develop(bool, PrintMethodFlushing, false, \ "Print the nmethods being flushed") \ \ + diagnostic(bool, PrintMethodFlushingStatistics, false, \ + "print statistics about method flushing") \ + \ develop(bool, UseRelocIndex, false, \ "Use an index to speed random access to relocations") \ \ @@ -3130,15 +3133,15 @@ "Maximum size of class area in Metaspace when compressed " \ "class pointers are used") \ \ - product(uintx, MinHeapFreeRatio, 40, \ + manageable(uintx, MinHeapFreeRatio, 40, \ "The minimum percentage of heap free after GC to avoid expansion."\ - " For most GCs this applies to the old generation. In G1 it" \ - " applies to the whole heap. Not supported by ParallelGC.") \ - \ - product(uintx, MaxHeapFreeRatio, 70, \ + " For most GCs this applies to the old generation. In G1 and" \ + " ParallelGC it applies to the whole heap.") \ + \ + manageable(uintx, MaxHeapFreeRatio, 70, \ "The maximum percentage of heap free after GC to avoid shrinking."\ - " For most GCs this applies to the old generation. In G1 it" \ - " applies to the whole heap. Not supported by ParallelGC.") \ + " For most GCs this applies to the old generation. In G1 and" \ + " ParallelGC it applies to the whole heap.") \ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ @@ -3306,21 +3309,21 @@ develop(intx, CIStart, 0, \ "The id of the first compilation to permit") \ \ - develop(intx, CIStop, -1, \ + develop(intx, CIStop, max_jint, \ "The id of the last compilation to permit") \ \ - develop(intx, CIStartOSR, 0, \ + develop(intx, CIStartOSR, 0, \ "The id of the first osr compilation to permit " \ "(CICountOSR must be on)") \ \ - develop(intx, CIStopOSR, -1, \ + develop(intx, CIStopOSR, max_jint, \ "The id of the last osr compilation to permit " \ "(CICountOSR must be on)") \ \ - develop(intx, CIBreakAtOSR, -1, \ + develop(intx, CIBreakAtOSR, -1, \ "The id of osr compilation to break at") \ \ - develop(intx, CIBreakAt, -1, \ + develop(intx, CIBreakAt, -1, \ "The id of compilation to break at") \ \ product(ccstrlist, CompileOnly, "", \ @@ -3339,6 +3342,10 @@ "File containing compilation replay information" \ "[default: ./replay_pid%p.log] (%p replaced with pid)") \ \ + product(ccstr, InlineDataFile, NULL, \ + "File containing inlining replay information" \ + "[default: ./inline_pid%p.log] (%p replaced with pid)") \ + \ develop(intx, ReplaySuppressInitializers, 2, \ "Control handling of class initialization during replay: " \ "0 - don't do anything special; " \ diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/java.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -52,6 +52,7 @@ #include "runtime/memprofiler.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/statSampler.hpp" +#include "runtime/sweeper.hpp" #include "runtime/task.hpp" #include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" @@ -217,9 +218,7 @@ // General statistics printing (profiling ...) - void print_statistics() { - #ifdef ASSERT if (CountRuntimeCalls) { @@ -315,6 +314,10 @@ CodeCache::print(); } + if (PrintMethodFlushingStatistics) { + NMethodSweeper::print(); + } + if (PrintCodeCache2) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::print_internals(); @@ -382,6 +385,10 @@ CodeCache::print(); } + if (PrintMethodFlushingStatistics) { + NMethodSweeper::print(); + } + #ifdef COMPILER2 if (PrintPreciseBiasedLockingStatistics) { OptoRuntime::print_named_counters(); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/perfMemory.cpp --- a/src/share/vm/runtime/perfMemory.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/perfMemory.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -155,7 +155,7 @@ void PerfMemory::destroy() { - assert(_prologue != NULL, "prologue pointer must be initialized"); + if (_prologue == NULL) return; if (_start != NULL && _prologue->overflow != 0) { diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -494,6 +494,13 @@ assert(!nm->is_native_method(), "no exception handler"); assert(nm->header_begin() != nm->exception_begin(), "no exception handler"); if (nm->is_deopt_pc(return_address)) { + // If we come here because of a stack overflow, the stack may be + // unguarded. Reguard the stack otherwise if we return to the + // deopt blob and the stack bang causes a stack overflow we + // crash. + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + assert(guard_pages_enabled, "stack banging in deopt blob may cause crash"); return SharedRuntime::deopt_blob()->unpack_with_exception(); } else { return nm->exception_begin(); @@ -2400,7 +2407,7 @@ ResourceMark rm; NOT_PRODUCT(int insts_size); - AdapterBlob* B = NULL; + AdapterBlob* new_adapter = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; { @@ -2432,7 +2439,8 @@ #ifdef ASSERT AdapterHandlerEntry* shared_entry = NULL; - if (VerifyAdapterSharing && entry != NULL) { + // Start adapter sharing verification only after the VM is booted. + if (VerifyAdapterSharing && (entry != NULL)) { shared_entry = entry; entry = NULL; } @@ -2448,41 +2456,44 @@ // Make a C heap allocated version of the fingerprint to store in the adapter fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt); + // StubRoutines::code2() is initialized after this function can be called. As a result, + // VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated + // prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C + // stub that ensure that an I2C stub is called from an interpreter frame. + bool contains_all_checks = StubRoutines::code2() != NULL; + // Create I2C & C2I handlers - BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { CodeBuffer buffer(buf); short buffer_locs[20]; buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); + MacroAssembler _masm(&buffer); - entry = SharedRuntime::generate_i2c2i_adapters(&_masm, total_args_passed, comp_args_on_stack, sig_bt, regs, fingerprint); - #ifdef ASSERT if (VerifyAdapterSharing) { if (shared_entry != NULL) { - assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size(), total_args_passed, sig_bt), - "code must match"); + assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match"); // Release the one just created and return the original _adapters->free_entry(entry); return shared_entry; } else { - entry->save_code(buf->code_begin(), buffer.insts_size(), total_args_passed, sig_bt); + entry->save_code(buf->code_begin(), buffer.insts_size()); } } #endif - B = AdapterBlob::create(&buffer); + new_adapter = AdapterBlob::create(&buffer); NOT_PRODUCT(insts_size = buffer.insts_size()); } - if (B == NULL) { + if (new_adapter == NULL) { // CodeCache is full, disable compilation // Ought to log this but compile log is only per compile thread // and we're some non descript Java thread. @@ -2490,7 +2501,7 @@ CompileBroker::handle_full_code_cache(); return NULL; // Out of CodeCache space } - entry->relocate(B->content_begin()); + entry->relocate(new_adapter->content_begin()); #ifndef PRODUCT // debugging suppport if (PrintAdapterHandlers || PrintStubCode) { @@ -2509,22 +2520,25 @@ } } #endif - - _adapters->add(entry); + // Add the entry only if the entry contains all required checks (see sharedRuntime_xxx.cpp) + // The checks are inserted only if -XX:+VerifyAdapterCalls is specified. + if (contains_all_checks || !VerifyAdapterCalls) { + _adapters->add(entry); + } } // Outside of the lock - if (B != NULL) { + if (new_adapter != NULL) { char blob_id[256]; jio_snprintf(blob_id, sizeof(blob_id), "%s(%s)@" PTR_FORMAT, - B->name(), + new_adapter->name(), fingerprint->as_string(), - B->content_begin()); - Forte::register_stub(blob_id, B->content_begin(), B->content_end()); + new_adapter->content_begin()); + Forte::register_stub(blob_id, new_adapter->content_begin(),new_adapter->content_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated(blob_id, B->content_begin(), B->content_end()); + JvmtiExport::post_dynamic_code_generated(blob_id, new_adapter->content_begin(), new_adapter->content_end()); } } return entry; @@ -2556,7 +2570,6 @@ delete _fingerprint; #ifdef ASSERT if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code, mtCode); - if (_saved_sig) FREE_C_HEAP_ARRAY(Basictype, _saved_sig, mtCode); #endif } @@ -2565,35 +2578,30 @@ // Capture the code before relocation so that it can be compared // against other versions. If the code is captured after relocation // then relative instructions won't be equivalent. -void AdapterHandlerEntry::save_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) { +void AdapterHandlerEntry::save_code(unsigned char* buffer, int length) { _saved_code = NEW_C_HEAP_ARRAY(unsigned char, length, mtCode); - _code_length = length; + _saved_code_length = length; memcpy(_saved_code, buffer, length); - _total_args_passed = total_args_passed; - _saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed, mtCode); - memcpy(_saved_sig, sig_bt, _total_args_passed * sizeof(BasicType)); } -bool AdapterHandlerEntry::compare_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) { - if (length != _code_length) { +bool AdapterHandlerEntry::compare_code(unsigned char* buffer, int length) { + if (length != _saved_code_length) { return false; } - for (int i = 0; i < length; i++) { - if (buffer[i] != _saved_code[i]) { - return false; - } - } - return true; + + return (memcmp(buffer, _saved_code, length) == 0) ? true : false; } #endif -// Create a native wrapper for this native method. The wrapper converts the -// java compiled calling convention to the native convention, handlizes -// arguments, and transitions to native. On return from the native we transition -// back to java blocking if a safepoint is in progress. -nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method, int compile_id) { +/** + * Create a native wrapper for this native method. The wrapper converts the + * Java-compiled calling convention to the native convention, handles + * arguments, and transitions to native. On return from the native we transition + * back to java blocking if a safepoint is in progress. + */ +void AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { ResourceMark rm; nmethod* nm = NULL; @@ -2602,16 +2610,19 @@ method->has_native_function(), "must have something valid to call!"); { - // perform the work while holding the lock, but perform any printing outside the lock + // Perform the work while holding the lock, but perform any printing outside the lock MutexLocker mu(AdapterHandlerLibrary_lock); // See if somebody beat us to it nm = method->code(); - if (nm) { - return nm; + if (nm != NULL) { + return; } + const int compile_id = CompileBroker::assign_compile_id(method, CompileBroker::standard_entry_bci); + assert(compile_id > 0, "Must generate native wrapper"); + + ResourceMark rm; - BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { CodeBuffer buffer(buf); @@ -2643,16 +2654,14 @@ int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, is_outgoing); // Generate the compiled-to-native wrapper code - nm = SharedRuntime::generate_native_wrapper(&_masm, - method, - compile_id, - sig_bt, - regs, - ret_type); + nm = SharedRuntime::generate_native_wrapper(&_masm, method, compile_id, sig_bt, regs, ret_type); + + if (nm != NULL) { + method->set_code(method, nm); + } } - } - - // Must unlock before calling set_code + } // Unlock AdapterHandlerLibrary_lock + // Install the generated code. if (nm != NULL) { @@ -2660,13 +2669,11 @@ ttyLocker ttyl; CompileTask::print_compilation(tty, nm, method->is_static() ? "(static)" : ""); } - method->set_code(method, nm); nm->post_compiled_method_load_event(); } else { // CodeCache is full, disable compilation CompileBroker::handle_full_code_cache(); } - return nm; } JRT_ENTRY_NO_ASYNC(void, SharedRuntime::block_for_jni_critical(JavaThread* thread)) diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/sharedRuntime.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -612,9 +612,7 @@ // Captures code and signature used to generate this adapter when // verifing adapter equivalence. unsigned char* _saved_code; - int _code_length; - BasicType* _saved_sig; - int _total_args_passed; + int _saved_code_length; #endif void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) { @@ -624,9 +622,7 @@ _c2i_unverified_entry = c2i_unverified_entry; #ifdef ASSERT _saved_code = NULL; - _code_length = 0; - _saved_sig = NULL; - _total_args_passed = 0; + _saved_code_length = 0; #endif } @@ -639,7 +635,6 @@ address get_i2c_entry() const { return _i2c_entry; } address get_c2i_entry() const { return _c2i_entry; } address get_c2i_unverified_entry() const { return _c2i_unverified_entry; } - address base_address(); void relocate(address new_base); @@ -651,8 +646,8 @@ #ifdef ASSERT // Used to verify that code generated for shared adapters is equivalent - void save_code(unsigned char* code, int length, int total_args_passed, BasicType* sig_bt); - bool compare_code(unsigned char* code, int length, int total_args_passed, BasicType* sig_bt); + void save_code (unsigned char* code, int length); + bool compare_code(unsigned char* code, int length); #endif //virtual void print_on(outputStream* st) const; DO NOT USE @@ -671,7 +666,7 @@ static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry); - static nmethod* create_native_wrapper(methodHandle method, int compile_id); + static void create_native_wrapper(methodHandle method); static AdapterHandlerEntry* get_adapter(methodHandle method); #ifdef HAVE_DTRACE_H diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/sweeper.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -129,6 +129,7 @@ nmethod* NMethodSweeper::_current = NULL; // Current nmethod long NMethodSweeper::_traversals = 0; // Stack scan count, also sweep ID. +long NMethodSweeper::_total_nof_code_cache_sweeps = 0; // Total number of full sweeps of the code cache long NMethodSweeper::_time_counter = 0; // Virtual time used to periodically invoke sweeper long NMethodSweeper::_last_sweep = 0; // Value of _time_counter when the last sweep happened int NMethodSweeper::_seen = 0; // Nof. nmethod we have currently processed in current pass of CodeCache @@ -143,13 +144,16 @@ // 1) alive -> not_entrant // 2) not_entrant -> zombie // 3) zombie -> marked_for_reclamation +int NMethodSweeper::_hotness_counter_reset_val = 0; -int NMethodSweeper::_total_nof_methods_reclaimed = 0; // Accumulated nof methods flushed -Tickspan NMethodSweeper::_total_time_sweeping; // Accumulated time sweeping -Tickspan NMethodSweeper::_total_time_this_sweep; // Total time this sweep -Tickspan NMethodSweeper::_peak_sweep_time; // Peak time for a full sweep -Tickspan NMethodSweeper::_peak_sweep_fraction_time; // Peak time sweeping one fraction -int NMethodSweeper::_hotness_counter_reset_val = 0; +long NMethodSweeper::_total_nof_methods_reclaimed = 0; // Accumulated nof methods flushed +long NMethodSweeper::_total_nof_c2_methods_reclaimed = 0; // Accumulated nof methods flushed +size_t NMethodSweeper::_total_flushed_size = 0; // Total number of bytes flushed from the code cache +Tickspan NMethodSweeper::_total_time_sweeping; // Accumulated time sweeping +Tickspan NMethodSweeper::_total_time_this_sweep; // Total time this sweep +Tickspan NMethodSweeper::_peak_sweep_time; // Peak time for a full sweep +Tickspan NMethodSweeper::_peak_sweep_fraction_time; // Peak time sweeping one fraction + class MarkActivationClosure: public CodeBlobClosure { @@ -257,9 +261,14 @@ // Large ReservedCodeCacheSize: (e.g., 256M + code Cache is 90% full). The formula // computes: (256 / 16) - 10 = 6. if (!_should_sweep) { - int time_since_last_sweep = _time_counter - _last_sweep; - double wait_until_next_sweep = (ReservedCodeCacheSize / (16 * M)) - time_since_last_sweep - - CodeCache::reverse_free_ratio(); + const int time_since_last_sweep = _time_counter - _last_sweep; + // ReservedCodeCacheSize has an 'unsigned' type. We need a 'signed' type for max_wait_time, + // since 'time_since_last_sweep' can be larger than 'max_wait_time'. If that happens using + // an unsigned type would cause an underflow (wait_until_next_sweep becomes a large positive + // value) that disables the intended periodic sweeps. + const int max_wait_time = ReservedCodeCacheSize / (16 * M); + double wait_until_next_sweep = max_wait_time - time_since_last_sweep - CodeCache::reverse_free_ratio(); + assert(wait_until_next_sweep <= (double)max_wait_time, "Calculation of code cache sweeper interval is incorrect"); if ((wait_until_next_sweep <= 0.0) || !CompileBroker::should_compile_new_jobs()) { _should_sweep = true; @@ -287,6 +296,7 @@ // We are done with sweeping the code cache once. if (_sweep_fractions_left == 0) { + _total_nof_code_cache_sweeps++; _last_sweep = _time_counter; // Reset flag; temporarily disables sweeper _should_sweep = false; @@ -373,6 +383,7 @@ _total_time_sweeping += sweep_time; _total_time_this_sweep += sweep_time; _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time); + _total_flushed_size += freed_memory; _total_nof_methods_reclaimed += _flushed_count; EventSweepCodeCache event(UNTIMED); @@ -504,6 +515,9 @@ tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); } freed_memory = nm->total_size(); + if (nm->is_compiled_by_c2()) { + _total_nof_c2_methods_reclaimed++; + } release_nmethod(nm); _flushed_count++; } else { @@ -542,6 +556,9 @@ SWEEP(nm); // No inline caches will ever point to osr methods, so we can just remove it freed_memory = nm->total_size(); + if (nm->is_compiled_by_c2()) { + _total_nof_c2_methods_reclaimed++; + } release_nmethod(nm); _flushed_count++; } else { @@ -629,3 +646,13 @@ xtty->end_elem(); } } + +void NMethodSweeper::print() { + ttyLocker ttyl; + tty->print_cr("Code cache sweeper statistics:"); + tty->print_cr(" Total sweep time: %1.0lfms", (double)_total_time_sweeping.value()/1000000); + tty->print_cr(" Total number of full sweeps: %ld", _total_nof_code_cache_sweeps); + tty->print_cr(" Total number of flushed methods: %ld(%ld C2 methods)", _total_nof_methods_reclaimed, + _total_nof_c2_methods_reclaimed); + tty->print_cr(" Total size of flushed methods: " SIZE_FORMAT "kB", _total_flushed_size/K); +} diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/runtime/sweeper.hpp --- a/src/share/vm/runtime/sweeper.hpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/runtime/sweeper.hpp Fri Feb 14 17:57:17 2014 +0000 @@ -54,28 +54,33 @@ // is full. class NMethodSweeper : public AllStatic { - static long _traversals; // Stack scan count, also sweep ID. - static long _time_counter; // Virtual time used to periodically invoke sweeper - static long _last_sweep; // Value of _time_counter when the last sweep happened - static nmethod* _current; // Current nmethod - static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache - static int _flushed_count; // Nof. nmethods flushed in current sweep - static int _zombified_count; // Nof. nmethods made zombie in current sweep - static int _marked_for_reclamation_count; // Nof. nmethods marked for reclaim in current sweep + static long _traversals; // Stack scan count, also sweep ID. + static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache + static long _time_counter; // Virtual time used to periodically invoke sweeper + static long _last_sweep; // Value of _time_counter when the last sweep happened + static nmethod* _current; // Current nmethod + static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache + static int _flushed_count; // Nof. nmethods flushed in current sweep + static int _zombified_count; // Nof. nmethods made zombie in current sweep + static int _marked_for_reclamation_count; // Nof. nmethods marked for reclaim in current sweep - static volatile int _sweep_fractions_left; // Nof. invocations left until we are completed with this pass - static volatile int _sweep_started; // Flag to control conc sweeper - static volatile bool _should_sweep; // Indicates if we should invoke the sweeper - static volatile int _bytes_changed; // Counts the total nmethod size if the nmethod changed from: - // 1) alive -> not_entrant - // 2) not_entrant -> zombie - // 3) zombie -> marked_for_reclamation + static volatile int _sweep_fractions_left; // Nof. invocations left until we are completed with this pass + static volatile int _sweep_started; // Flag to control conc sweeper + static volatile bool _should_sweep; // Indicates if we should invoke the sweeper + static volatile int _bytes_changed; // Counts the total nmethod size if the nmethod changed from: + // 1) alive -> not_entrant + // 2) not_entrant -> zombie + // 3) zombie -> marked_for_reclamation // Stat counters - static int _total_nof_methods_reclaimed; // Accumulated nof methods flushed - static Tickspan _total_time_sweeping; // Accumulated time sweeping - static Tickspan _total_time_this_sweep; // Total time this sweep - static Tickspan _peak_sweep_time; // Peak time for a full sweep - static Tickspan _peak_sweep_fraction_time; // Peak time sweeping one fraction + static long _total_nof_methods_reclaimed; // Accumulated nof methods flushed + static long _total_nof_c2_methods_reclaimed; // Accumulated nof C2-compiled methods flushed + static size_t _total_flushed_size; // Total size of flushed methods + static int _hotness_counter_reset_val; + + static Tickspan _total_time_sweeping; // Accumulated time sweeping + static Tickspan _total_time_this_sweep; // Total time this sweep + static Tickspan _peak_sweep_time; // Peak time for a full sweep + static Tickspan _peak_sweep_fraction_time; // Peak time sweeping one fraction static int process_nmethod(nmethod *nm); static void release_nmethod(nmethod* nm); @@ -83,8 +88,6 @@ static bool sweep_in_progress(); static void sweep_code_cache(); - static int _hotness_counter_reset_val; - public: static long traversal_count() { return _traversals; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } @@ -105,10 +108,10 @@ static void mark_active_nmethods(); // Invoked at the end of each safepoint static void possibly_sweep(); // Compiler threads call this to sweep - static int sort_nmethods_by_hotness(nmethod** nm1, nmethod** nm2); static int hotness_counter_reset_val(); static void report_state_change(nmethod* nm); static void possibly_enable_sweeper(); + static void print(); // Printing/debugging }; #endif // SHARE_VM_RUNTIME_SWEEPER_HPP diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/services/attachListener.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -282,6 +282,20 @@ return JNI_ERR; } } + + if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) { + out->print_cr(err_msg.buffer()); + return JNI_ERR; + } + } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) { + out->print_cr(err_msg.buffer()); + return JNI_ERR; + } + } bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/services/management.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1830,6 +1830,18 @@ succeed = CommandLineFlags::intxAtPut(name, &ivalue, Flag::MANAGEMENT); } else if (flag->is_uintx()) { uintx uvalue = (uintx)new_value.j; + + if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MaxHeapFreeRatio(err_msg, uvalue)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg.buffer()); + } + } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MinHeapFreeRatio(err_msg, uvalue)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg.buffer()); + } + } succeed = CommandLineFlags::uintxAtPut(name, &uvalue, Flag::MANAGEMENT); } else if (flag->is_uint64_t()) { uint64_t uvalue = (uint64_t)new_value.j; diff -r 1dbaf664a611 -r dd13ef903817 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Thu Feb 06 17:34:47 2014 -0800 +++ b/src/share/vm/utilities/vmError.cpp Fri Feb 14 17:57:17 2014 +0000 @@ -1040,7 +1040,7 @@ OnError = NULL; } - static bool skip_replay = false; + static bool skip_replay = ReplayCompiles; // Do not overwrite file during replay if (DumpReplayDataOnError && _thread && _thread->is_Compiler_thread() && !skip_replay) { skip_replay = true; ciEnv* env = ciEnv::current(); diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/debug/VerifyAdapterSharing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/debug/VerifyAdapterSharing.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,43 @@ +/* + * 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 8030783 + * @summary Regression test for 8026478 + * @library /testlibrary + * + */ +import com.oracle.java.testlibrary.*; + +public class VerifyAdapterSharing { + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + OutputAnalyzer out; + + pb = ProcessTools.createJavaProcessBuilder("-Xcomp", "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+VerifyAdapterSharing", "-version"); + out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build AddExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics AddExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactIntTest + * @run main Verifier hs_neg.log hs.log + */ + +public class AddExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Add).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build AddExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics AddExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class AddExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Add).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build DecrementExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics DecrementExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactIntTest + * @run main Verifier hs_neg.log hs.log + */ + +public class DecrementExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Decrement).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build DecrementExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics DecrementExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class DecrementExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Decrement).test(); + } +} \ No newline at end of file diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build IncrementExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics IncrementExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactIntTest + * @run main Verifier hs_neg.log hs.log + */ + +public class IncrementExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Increment).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build IncrementExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics IncrementExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class IncrementExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Increment).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,155 @@ +/* + * 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 com.oracle.java.testlibrary.Platform; + +import java.io.FileOutputStream; +import java.lang.reflect.Executable; +import java.util.Properties; + +public abstract class IntrinsicBase extends CompilerWhiteBoxTest { + protected String javaVmName; + protected String useMathExactIntrinsics; + + protected IntrinsicBase(TestCase testCase) { + super(testCase); + javaVmName = System.getProperty("java.vm.name"); + useMathExactIntrinsics = getVMOption("UseMathExactIntrinsics"); + } + + @Override + protected void test() throws Exception { + //java.lang.Math should be loaded to allow a compilation of the methods that use Math's method + System.out.println("class java.lang.Math should be loaded. Proof: " + Math.class); + printEnvironmentInfo(); + + int expectedIntrinsicCount = 0; + + switch (MODE) { + case "compiled mode": + case "mixed mode": + if (isServerVM()) { + if (TIERED_COMPILATION) { + int max_level = TIERED_STOP_AT_LEVEL; + expectedIntrinsicCount = (max_level == COMP_LEVEL_MAX) ? 1 : 0; + for (int i = CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE; i <= max_level; ++i) { + deoptimize(); + compileAtLevel(i); + } + } else { + expectedIntrinsicCount = 1; + deoptimize(); + compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_MAX); + } + } else { + deoptimize(); + compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); + } + + if (!isIntrinsicSupported()) { + expectedIntrinsicCount = 0; + } + break; + case "interpreted mode": //test is not applicable in this mode; + System.err.println("Warning: This test is not applicable in mode: " + MODE); + break; + default: + throw new RuntimeException("Test bug, unknown VM mode: " + MODE); + } + + System.out.println("Expected intrinsic count is " + expectedIntrinsicCount + " name " + getIntrinsicId()); + + final FileOutputStream out = new FileOutputStream(getVMOption("LogFile") + ".verify.properties"); + Properties expectedProps = new Properties(); + expectedProps.setProperty("intrinsic.name", getIntrinsicId()); + expectedProps.setProperty("intrinsic.expectedCount", String.valueOf(expectedIntrinsicCount)); + expectedProps.store(out, null); + + out.close(); + } + + protected void printEnvironmentInfo() { + System.out.println("java.vm.name=" + javaVmName); + System.out.println("os.arch=" + Platform.getOsArch()); + System.out.println("java.vm.info=" + MODE); + System.out.println("useMathExactIntrinsics=" + useMathExactIntrinsics); + } + + protected void compileAtLevel(int level) { + WHITE_BOX.enqueueMethodForCompilation(method, level); + waitBackgroundCompilation(); + checkCompilation(method, level); + } + + protected void checkCompilation(Executable executable, int level) { + if (!WHITE_BOX.isMethodCompiled(executable)) { + throw new RuntimeException("Test bug, expected compilation (level): " + level + ", but not compiled"); + } + final int compilationLevel = WHITE_BOX.getMethodCompilationLevel(executable); + if (compilationLevel != level) { + if (!(TIERED_COMPILATION && level == COMP_LEVEL_FULL_PROFILE && compilationLevel == COMP_LEVEL_LIMITED_PROFILE)) { //possible case + throw new RuntimeException("Test bug, expected compilation (level): " + level + ", but level: " + compilationLevel); + } + } + } + + protected abstract boolean isIntrinsicSupported(); + + protected abstract String getIntrinsicId(); + + protected boolean isServerVM() { + return javaVmName.toLowerCase().contains("server"); + } + + static class IntTest extends IntrinsicBase { + protected IntTest(MathIntrinsic.IntIntrinsic testCase) { + super(testCase); + } + + @Override + protected boolean isIntrinsicSupported() { + return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) && (Platform.isX86() || Platform.isX64()); + } + + @Override + protected String getIntrinsicId() { + return "_" + testCase.name().toLowerCase() + "ExactI"; + } + } + + static class LongTest extends IntrinsicBase { + protected LongTest(MathIntrinsic.LongIntrinsic testCase) { + super(testCase); + } + + @Override + protected boolean isIntrinsicSupported() { + return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) && Platform.isX64(); + } + + @Override + protected String getIntrinsicId() { + return "_" + testCase.name().toLowerCase() + "ExactL"; + } + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,155 @@ +/* + * 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.Executable; +import java.util.concurrent.Callable; + +public class MathIntrinsic { + + enum IntIntrinsic implements CompilerWhiteBoxTest.TestCase { + Add { + @Override + Object execMathMethod() { + return intR = Math.addExact(int1, int2); + } + }, + Subtract { + @Override + Object execMathMethod() { + return intR = Math.subtractExact(int1, int2); + } + }, + Multiply { + @Override + Object execMathMethod() { + return intR = Math.multiplyExact(int1, int2); + } + }, + Increment { + @Override + Object execMathMethod() { + return intR = Math.incrementExact(int1); + } + }, + Decrement { + @Override + Object execMathMethod() { + return intR = Math.decrementExact(int1); + } + }, + Negate { + @Override + Object execMathMethod() { + return intR = Math.negateExact(int1); + } + }; + protected int int1; + protected int int2; + protected int intR; + + abstract Object execMathMethod(); + + @Override + public Executable getExecutable() { + try { + return getClass().getDeclaredMethod("execMathMethod"); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Test bug, no such method: " + e); + } + } + + @Override + public Callable getCallable() { + return null; + } + + @Override + public boolean isOsr() { + return false; + } + + } + + enum LongIntrinsic implements CompilerWhiteBoxTest.TestCase { + Add { + @Override + Object execMathMethod() { + return longR = Math.addExact(long1, long2); + } + }, + Subtract { + @Override + Object execMathMethod() { + return longR = Math.subtractExact(long1, long2); + } + }, + Multiply { + @Override + Object execMathMethod() { + return longR = Math.multiplyExact(long1, long2); + } + }, + Increment { + @Override + Object execMathMethod() { + return longR = Math.incrementExact(long1); + } + }, + Decrement { + @Override + Object execMathMethod() { + return longR = Math.decrementExact(long1); + } + }, + Negate { + @Override + Object execMathMethod() { + return longR = Math.negateExact(long1); + } + }; + protected long long1; + protected long long2; + protected long longR; + + abstract Object execMathMethod(); + + @Override + public Executable getExecutable() { + try { + return getClass().getDeclaredMethod("execMathMethod"); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Test bug, no such method: " + e); + } + } + + @Override + public Callable getCallable() { + return null; + } + + @Override + public boolean isOsr() { + return false; + } + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build MultiplyExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics MultiplyExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactIntTest + * @run main Verifier hs_neg.log hs.log + */ + +public class MultiplyExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Multiply).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build MultiplyExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics MultiplyExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class MultiplyExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Multiply).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build NegateExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics NegateExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactIntTest + * @run main Verifier hs_neg.log hs.log + */ + +public class NegateExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Negate).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build NegateExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics NegateExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class NegateExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Negate).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,46 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build SubtractExactIntTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics SubtractExactIntTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactIntTest + * @run main Verifier hs_neg.log hs.log + + */ + +public class SubtractExactIntTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.IntTest(MathIntrinsic.IntIntrinsic.Subtract).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,45 @@ +/* + * 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 + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build SubtractExactLongTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs_neg.log -XX:-UseMathExactIntrinsics SubtractExactLongTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation + * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod + * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactLongTest + * @run main Verifier hs_neg.log hs.log + */ + +public class SubtractExactLongTest { + + public static void main(String[] args) throws Exception { + new IntrinsicBase.LongTest(MathIntrinsic.LongIntrinsic.Subtract).test(); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/intrinsics/mathexact/sanity/Verifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/sanity/Verifier.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,71 @@ +/* + * 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.io.BufferedReader; +import java.io.FileReader; +import java.util.Properties; + +public class Verifier { + + public static void main(String[] args) throws Exception { + if (args.length == 0) + throw new RuntimeException("Test bug, nothing to verify"); + for (String hsLogFile : args) { + verify(hsLogFile); + } + } + + private static void verify(String hsLogFile) throws Exception { + System.out.println("Verifying " + hsLogFile); + + final Properties expectedProperties = new Properties(); + final FileReader reader = new FileReader(hsLogFile + ".verify.properties"); + expectedProperties.load(reader); + reader.close(); + + int fullMatchCnt = 0; + int suspectCnt = 0; + final String intrinsicId = expectedProperties.getProperty("intrinsic.name"); + final String prefix = " constructor, + String[] args) { + if (args.length == 0) { + for (TestCase test : SimpleTestCase.values()) { + constructor.apply(test).runTest(); + } + } else { + for (String name : args) { + constructor.apply(SimpleTestCase.valueOf(name)).runTest(); + } + } + } + /** tested method */ protected final Executable method; protected final TestCase testCase; @@ -145,7 +159,7 @@ protected CompilerWhiteBoxTest(TestCase testCase) { Objects.requireNonNull(testCase); System.out.println("TEST CASE:" + testCase.name()); - method = testCase.executable; + method = testCase.getExecutable(); this.testCase = testCase; } @@ -204,7 +218,7 @@ if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { throw new RuntimeException(method + " osr_comp_level must be == 0"); } - } + } /** * Checks, that {@linkplain #method} is compiled. @@ -221,44 +235,46 @@ method, System.currentTimeMillis() - start); return; } - if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr)) { + if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { throw new RuntimeException(method + " must be " - + (testCase.isOsr ? "osr_" : "") + "compiled"); + + (testCase.isOsr() ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr) == 0) { + if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) + == 0) { throw new RuntimeException(method - + (testCase.isOsr ? " osr_" : " ") + + (testCase.isOsr() ? " osr_" : " ") + "comp_level must be != 0"); } } protected final void deoptimize() { - WHITE_BOX.deoptimizeMethod(method, testCase.isOsr); - if (testCase.isOsr) { + WHITE_BOX.deoptimizeMethod(method, testCase.isOsr()); + if (testCase.isOsr()) { WHITE_BOX.deoptimizeMethod(method, false); } } protected final int getCompLevel() { - return WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr); + return WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()); } protected final boolean isCompilable() { return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, - testCase.isOsr); + testCase.isOsr()); } protected final boolean isCompilable(int compLevel) { - return WHITE_BOX.isMethodCompilable(method, compLevel, testCase.isOsr); + return WHITE_BOX + .isMethodCompilable(method, compLevel, testCase.isOsr()); } protected final void makeNotCompilable() { WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, - testCase.isOsr); + testCase.isOsr()); } protected final void makeNotCompilable(int compLevel) { - WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr); + WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr()); } /** @@ -298,7 +314,7 @@ WHITE_BOX.isMethodCompiled(method, true)); System.out.printf("\tosr_comp_level:\t%d%n", WHITE_BOX.getMethodCompilationLevel(method, true)); - System.out.printf("\tin_queue:\t%b%n", + System.out.printf("\tin_queue:\t%b%n", WHITE_BOX.isMethodQueuedForCompilation(method)); System.out.printf("compile_queues_size:\t%d%n%n", WHITE_BOX.getCompileQueuesSize()); @@ -311,13 +327,13 @@ /** * Tries to trigger compilation of {@linkplain #method} by call - * {@linkplain #testCase.callable} enough times. + * {@linkplain TestCase#getCallable()} enough times. * * @return accumulated result * @see #compile(int) */ protected final int compile() { - if (testCase.isOsr) { + if (testCase.isOsr()) { return compile(1); } else { return compile(THRESHOLD); @@ -326,7 +342,7 @@ /** * Tries to trigger compilation of {@linkplain #method} by call - * {@linkplain #testCase.callable} specified times. + * {@linkplain TestCase#getCallable()} specified times. * * @param count invocation count * @return accumulated result @@ -336,7 +352,7 @@ Integer tmp; for (int i = 0; i < count; ++i) { try { - tmp = testCase.callable.call(); + tmp = testCase.getCallable().call(); } catch (Exception e) { tmp = null; } @@ -347,19 +363,32 @@ } return result; } + + /** + * Utility interface provides tested method and object to invoke it. + */ + public interface TestCase { + /** the name of test case */ + String name(); + + /** tested method */ + Executable getExecutable(); + + /** object to invoke {@linkplain #getExecutable()} */ + Callable getCallable(); + + /** flag for OSR test case */ + boolean isOsr(); + } } -/** - * Utility structure containing tested method and object to invoke it. - */ -enum TestCase { +enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { /** constructor test case */ CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), /** method test case */ METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), /** static method test case */ STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), - /** OSR constructor test case */ OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, Helper.OSR_CONSTRUCTOR_CALLABLE, true), @@ -368,20 +397,32 @@ /** OSR static method test case */ OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); - /** tested method */ - final Executable executable; - /** object to invoke {@linkplain #executable} */ - final Callable callable; - /** flag for OSR test case */ - final boolean isOsr; + private final Executable executable; + private final Callable callable; + private final boolean isOsr; - private TestCase(Executable executable, Callable callable, + private SimpleTestCase(Executable executable, Callable callable, boolean isOsr) { this.executable = executable; this.callable = callable; this.isOsr = isOsr; } + @Override + public Executable getExecutable() { + return executable; + } + + @Override + public Callable getCallable() { + return callable; + } + + @Override + public boolean isOsr() { + return isOsr; + } + private static class Helper { private static final Callable CONSTRUCTOR_CALLABLE @@ -436,7 +477,6 @@ } }; - private static final Constructor CONSTRUCTOR; private static final Constructor OSR_CONSTRUCTOR; private static final Method METHOD; diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/DeoptimizeAllTest.java --- a/test/compiler/whitebox/DeoptimizeAllTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,19 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build DeoptimizeAllTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* DeoptimizeAllTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeAllTest * @summary testing of WB::deoptimizeAll() * @author igor.ignatyev@oracle.com */ public class DeoptimizeAllTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new DeoptimizeAllTest(test).runTest(); - } + CompilerWhiteBoxTest.main(DeoptimizeAllTest::new, args); } - public DeoptimizeAllTest(TestCase testCase) { + private DeoptimizeAllTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -53,7 +51,7 @@ */ @Override protected void test() throws Exception { - if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( "compiled ")) { System.err.printf("Warning: %s is not applicable in %s%n", testCase.name(), CompilerWhiteBoxTest.MODE); diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/DeoptimizeMethodTest.java --- a/test/compiler/whitebox/DeoptimizeMethodTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,19 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build DeoptimizeMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* DeoptimizeMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeMethodTest * @summary testing of WB::deoptimizeMethod() * @author igor.ignatyev@oracle.com */ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new DeoptimizeMethodTest(test).runTest(); - } + CompilerWhiteBoxTest.main(DeoptimizeMethodTest::new, args); } - public DeoptimizeMethodTest(TestCase testCase) { + private DeoptimizeMethodTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -53,7 +51,7 @@ */ @Override protected void test() throws Exception { - if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( "compiled ")) { System.err.printf("Warning: %s is not applicable in %s%n", testCase.name(), CompilerWhiteBoxTest.MODE); diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/EnqueueMethodForCompilationTest.java --- a/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,19 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build EnqueueMethodForCompilationTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* EnqueueMethodForCompilationTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* EnqueueMethodForCompilationTest * @summary testing of WB::enqueueMethodForCompilation() * @author igor.ignatyev@oracle.com */ public class EnqueueMethodForCompilationTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new EnqueueMethodForCompilationTest(test).runTest(); - } + CompilerWhiteBoxTest.main(EnqueueMethodForCompilationTest::new, args); } - public EnqueueMethodForCompilationTest(TestCase testCase) { + private EnqueueMethodForCompilationTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/IsMethodCompilableTest.java --- a/test/compiler/whitebox/IsMethodCompilableTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,7 +27,7 @@ * @library /testlibrary /testlibrary/whitebox * @build IsMethodCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* IsMethodCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */ @@ -48,12 +48,10 @@ } public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new IsMethodCompilableTest(test).runTest(); - } + CompilerWhiteBoxTest.main(IsMethodCompilableTest::new, args); } - public IsMethodCompilableTest(TestCase testCase) { + private IsMethodCompilableTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -68,7 +66,7 @@ */ @Override protected void test() throws Exception { - if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( "compiled ")) { System.err.printf("Warning: %s is not applicable in %s%n", testCase.name(), CompilerWhiteBoxTest.MODE); @@ -89,7 +87,7 @@ for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) { compileAndDeoptimize(); } - if (!testCase.isOsr && !isCompilable()) { + if (!testCase.isOsr() && !isCompilable()) { // in osr test case count of deopt maybe more than iterations throw new RuntimeException(method + " is not compilable after " + (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations"); @@ -102,7 +100,7 @@ && isCompilable(); ++i) { compileAndDeoptimize(); } - if (!testCase.isOsr && i != PER_METHOD_RECOMPILATION_CUTOFF) { + if (!testCase.isOsr() && i != PER_METHOD_RECOMPILATION_CUTOFF) { // in osr test case count of deopt maybe more than iterations throw new RuntimeException(method + " is not compilable after " + i + " iterations, but must only after " diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,26 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build MakeMethodNotCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* MakeMethodNotCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* MakeMethodNotCompilableTest * @summary testing of WB::makeMethodNotCompilable() * @author igor.ignatyev@oracle.com */ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { private int bci; public static void main(String[] args) throws Exception { - if (args.length == 0) { - for (TestCase test : TestCase.values()) { - new MakeMethodNotCompilableTest(test).runTest(); - } - } else { - for (String name : args) { - new MakeMethodNotCompilableTest( - TestCase.valueOf(name)).runTest(); - } - } + CompilerWhiteBoxTest.main(MakeMethodNotCompilableTest::new, args); } - public MakeMethodNotCompilableTest(TestCase testCase) { + private MakeMethodNotCompilableTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -62,7 +53,7 @@ */ @Override protected void test() throws Exception { - if (testCase.isOsr && CompilerWhiteBoxTest.MODE.startsWith( + if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith( "compiled ")) { System.err.printf("Warning: %s is not applicable in %s%n", testCase.name(), CompilerWhiteBoxTest.MODE); diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/SetDontInlineMethodTest.java --- a/test/compiler/whitebox/SetDontInlineMethodTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/SetDontInlineMethodTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,19 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build SetDontInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* SetDontInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetDontInlineMethodTest * @summary testing of WB::testSetDontInlineMethod() * @author igor.ignatyev@oracle.com */ public class SetDontInlineMethodTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new SetDontInlineMethodTest(test).runTest(); - } + CompilerWhiteBoxTest.main(SetDontInlineMethodTest::new, args); } - public SetDontInlineMethodTest(TestCase testCase) { + private SetDontInlineMethodTest(TestCase testCase) { super(testCase); } diff -r 1dbaf664a611 -r dd13ef903817 test/compiler/whitebox/SetForceInlineMethodTest.java --- a/test/compiler/whitebox/SetForceInlineMethodTest.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/compiler/whitebox/SetForceInlineMethodTest.java Fri Feb 14 17:57:17 2014 +0000 @@ -27,19 +27,17 @@ * @library /testlibrary /testlibrary/whitebox * @build SetForceInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* SetForceInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetForceInlineMethodTest * @summary testing of WB::testSetForceInlineMethod() * @author igor.ignatyev@oracle.com */ public class SetForceInlineMethodTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - for (TestCase test : TestCase.values()) { - new SetForceInlineMethodTest(test).runTest(); - } + CompilerWhiteBoxTest.main(SetForceInlineMethodTest::new, args); } - public SetForceInlineMethodTest(TestCase testCase) { + private SetForceInlineMethodTest(TestCase testCase) { super(testCase); } diff -r 1dbaf664a611 -r dd13ef903817 test/gc/TestVerifySilently.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestVerifySilently.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014, 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 TestVerifySilently.java + * @key gc + * @bug 8032771 + * @summary Test silent verification. + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import java.util.ArrayList; +import java.util.Collections; + +class RunSystemGC { + public static void main(String args[]) throws Exception { + System.gc(); + } +} + + +public class TestVerifySilently { + private static String[] getTestJavaOpts() { + String testVmOptsStr = System.getProperty("test.java.opts"); + if (!testVmOptsStr.isEmpty()) { + return testVmOptsStr.split(" "); + } else { + return new String[] {}; + } + } + + private static OutputAnalyzer runTest(boolean verifySilently) throws Exception { + ArrayList vmOpts = new ArrayList(); + + Collections.addAll(vmOpts, getTestJavaOpts()); + Collections.addAll(vmOpts, new String[] {"-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyDuringStartup", + "-XX:+VerifyBeforeGC", + "-XX:+VerifyAfterGC", + "-XX:" + (verifySilently ? "+":"-") + "VerifySilently", + RunSystemGC.class.getName()}); + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + System.out.println("Output:\n" + output.getOutput()); + return output; + } + + + public static void main(String args[]) throws Exception { + + OutputAnalyzer output; + + output = runTest(false); + output.shouldContain("[Verifying"); + output.shouldHaveExitValue(0); + + output = runTest(true); + output.shouldNotContain("[Verifying"); + output.shouldHaveExitValue(0); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/gc/g1/TestStringSymbolTableStats.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestStringSymbolTableStats.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,57 @@ +/* + * 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 TestStringSymbolTableStats.java + * @bug 8027476 8027455 + * @summary Ensure that the G1TraceStringSymbolTableScrubbing prints the expected message. + * @key gc + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestStringSymbolTableStats { + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+G1TraceStringSymbolTableScrubbing", + SystemGCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + System.out.println("Output:\n" + output.getOutput()); + + output.shouldContain("Cleaned string and symbol table"); + output.shouldHaveExitValue(0); + } + + static class SystemGCTest { + public static void main(String [] args) { + System.out.println("Calling System.gc()"); + System.gc(); + } + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/NMT/CommandLineDetail.java --- a/test/runtime/NMT/CommandLineDetail.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/runtime/NMT/CommandLineDetail.java Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -24,7 +24,7 @@ /* * @test * @key nmt - * @summary Running with NMT detail should not result in an error or warning + * @summary Running with NMT detail should not result in an error * @library /testlibrary */ @@ -39,7 +39,6 @@ "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("error"); - output.shouldNotContain("warning"); output.shouldHaveExitValue(0); } } diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/NMT/CommandLineSummary.java --- a/test/runtime/NMT/CommandLineSummary.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/runtime/NMT/CommandLineSummary.java Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -24,7 +24,7 @@ /* * @test * @key nmt - * @summary Running with NMT summary should not result in an error or warning + * @summary Running with NMT summary should not result in an error * @library /testlibrary */ @@ -39,7 +39,6 @@ "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("error"); - output.shouldNotContain("warning"); output.shouldHaveExitValue(0); } } diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/NMT/CommandLineTurnOffNMT.java --- a/test/runtime/NMT/CommandLineTurnOffNMT.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/runtime/NMT/CommandLineTurnOffNMT.java Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -24,7 +24,7 @@ /* * @test * @key nmt - * @summary Turning off NMT should not result in an error or warning + * @summary Turning off NMT should not result in an error * @library /testlibrary */ @@ -38,7 +38,6 @@ "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("error"); - output.shouldNotContain("warning"); output.shouldHaveExitValue(0); } } diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/NMT/PrintNMTStatistics.java --- a/test/runtime/NMT/PrintNMTStatistics.java Thu Feb 06 17:34:47 2014 -0800 +++ b/test/runtime/NMT/PrintNMTStatistics.java Fri Feb 14 17:57:17 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 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 @@ -64,7 +64,6 @@ OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Java Heap (reserved="); output.shouldNotContain("error"); - output.shouldNotContain("warning"); output.shouldHaveExitValue(0); } } diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/PerfMemDestroy/PerfMemDestroy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/PerfMemDestroy/PerfMemDestroy.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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 8030955 + * @summary Allow multiple calls to PerfMemory::destroy() without asserting. + * @library /testlibrary + * @run main PerfMemDestroy + */ + +import com.oracle.java.testlibrary.*; + +public class PerfMemDestroy { + public static void main(String args[]) throws Throwable { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PerfAllowAtExitRegistration", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} diff -r 1dbaf664a611 -r dd13ef903817 test/runtime/finalStatic/FinalStatic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/finalStatic/FinalStatic.java Fri Feb 14 17:57:17 2014 +0000 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, 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 8028553 + * @summary Test that VerifyError is not thrown when 'overriding' a static method. + * @run main FinalStatic + */ + +import java.lang.reflect.*; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/* + * class A { static final int m() {return FAIL; } } + * class B extends A { int m() { return PASS; } } + * class FinalStatic { + * public static void main () { + * Object b = new B(); + * b.m(); + * } + * } + */ +public class FinalStatic { + + static final String CLASS_NAME_A = "A"; + static final String CLASS_NAME_B = "B"; + static final int FAILED = 0; + static final int EXPECTED = 1234; + + static class TestClassLoader extends ClassLoader implements Opcodes { + + @Override + public Class findClass(String name) throws ClassNotFoundException { + byte[] b; + try { + b = loadClassData(name); + } catch (Throwable th) { + // th.printStackTrace(); + throw new ClassNotFoundException("Loading error", th); + } + return defineClass(name, b, 0, b.length); + } + + private byte[] loadClassData(String name) throws Exception { + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + switch (name) { + case CLASS_NAME_A: + cw.visit(52, ACC_SUPER | ACC_PUBLIC, CLASS_NAME_A, 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(1, 1); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_FINAL | ACC_STATIC, "m", "()I", null, null); + mv.visitCode(); + mv.visitLdcInsn(FAILED); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + break; + case CLASS_NAME_B: + cw.visit(52, ACC_SUPER | ACC_PUBLIC, CLASS_NAME_B, null, CLASS_NAME_A, null); + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, CLASS_NAME_A, "", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); + mv.visitCode(); + mv.visitLdcInsn(EXPECTED); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + } + break; + default: + break; + } + cw.visitEnd(); + + return cw.toByteArray(); + } + } + + public static void main(String[] args) throws Exception { + TestClassLoader tcl = new TestClassLoader(); + Class a = tcl.loadClass(CLASS_NAME_A); + Class b = tcl.loadClass(CLASS_NAME_B); + Object inst = b.newInstance(); + Method[] meths = b.getDeclaredMethods(); + + Method m = meths[0]; + int mod = m.getModifiers(); + if ((mod & Modifier.FINAL) != 0) { + throw new Exception("FAILED: " + m + " is FINAL"); + } + if ((mod & Modifier.STATIC) != 0) { + throw new Exception("FAILED: " + m + " is STATIC"); + } + + m.setAccessible(true); + if (!m.invoke(inst).equals(EXPECTED)) { + throw new Exception("FAILED: " + EXPECTED + " from " + m); + } + + System.out.println("Passed."); + } +}