# HG changeset patch # User jiangli # Date 1366075523 14400 # Node ID 8df6ddda809007d32f0028637a3a89f619113d17 # Parent c60f69931e1a01c947b7d02a88ee73915082bbba# Parent 42a42da29fd71fc1859eac4b3f1d7ab3111a939c Merge diff -r c60f69931e1a -r 8df6ddda8090 agent/src/share/classes/sun/jvm/hotspot/oops/Method.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java Thu Apr 11 21:54:46 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -49,19 +49,13 @@ Type type = db.lookupType("Method"); constMethod = type.getAddressField("_constMethod"); methodData = type.getAddressField("_method_data"); + methodCounters = type.getAddressField("_method_counters"); methodSize = new CIntField(type.getCIntegerField("_method_size"), 0); accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); code = type.getAddressField("_code"); vtableIndex = new CIntField(type.getCIntegerField("_vtable_index"), 0); - if (!VM.getVM().isCore()) { - invocationCounter = new CIntField(type.getCIntegerField("_invocation_counter"), 0); - backedgeCounter = new CIntField(type.getCIntegerField("_backedge_counter"), 0); - } bytecodeOffset = type.getSize(); - interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0); - interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0); - /* interpreterEntry = type.getAddressField("_interpreter_entry"); fromCompiledCodeEntryPoint = type.getAddressField("_from_compiled_code_entry_point"); @@ -80,18 +74,14 @@ // Fields private static AddressField constMethod; private static AddressField methodData; + private static AddressField methodCounters; private static CIntField methodSize; private static CIntField accessFlags; private static CIntField vtableIndex; - private static CIntField invocationCounter; - private static CIntField backedgeCounter; private static long bytecodeOffset; private static AddressField code; - private static CIntField interpreterThrowoutCountField; - private static CIntField interpreterInvocationCountField; - // constant method names - , // Initialized lazily to avoid initialization ordering dependencies between Method and SymbolTable private static Symbol objectInitializerName; @@ -127,6 +117,10 @@ Address addr = methodData.getValue(getAddress()); return (MethodData) VMObjectFactory.newObject(MethodData.class, addr); } + public MethodCounters getMethodCounters() { + Address addr = methodCounters.getValue(getAddress()); + return (MethodCounters) VMObjectFactory.newObject(MethodCounters.class, addr); + } /** WARNING: this is in words, not useful in this system; use getObjectSize() instead */ public long getMethodSize() { return methodSize.getValue(this); } public long getMaxStack() { return getConstMethod().getMaxStack(); } @@ -139,16 +133,10 @@ public long getCodeSize() { return getConstMethod().getCodeSize(); } public long getVtableIndex() { return vtableIndex.getValue(this); } public long getInvocationCounter() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(!VM.getVM().isCore(), "must not be used in core build"); - } - return invocationCounter.getValue(this); + return getMethodCounters().getInvocationCounter(); } public long getBackedgeCounter() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(!VM.getVM().isCore(), "must not be used in core build"); - } - return backedgeCounter.getValue(this); + return getMethodCounters().getBackedgeCounter(); } // get associated compiled native method, if available, else return null. @@ -369,10 +357,10 @@ } public int interpreterThrowoutCount() { - return (int) interpreterThrowoutCountField.getValue(this); + return getMethodCounters().interpreterThrowoutCount(); } public int interpreterInvocationCount() { - return (int) interpreterInvocationCountField.getValue(this); + return getMethodCounters().interpreterInvocationCount(); } } diff -r c60f69931e1a -r 8df6ddda8090 agent/src/share/classes/sun/jvm/hotspot/oops/MethodCounters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/MethodCounters.java Mon Apr 15 21:25:23 2013 -0400 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +package sun.jvm.hotspot.oops; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +public class MethodCounters extends Metadata { + public MethodCounters(Address addr) { + super(addr); + } + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + Type type = db.lookupType("MethodCounters"); + + interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0); + interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0); + if (!VM.getVM().isCore()) { + invocationCounter = new CIntField(type.getCIntegerField("_invocation_counter"), 0); + backedgeCounter = new CIntField(type.getCIntegerField("_backedge_counter"), 0); + } + } + + private static CIntField interpreterInvocationCountField; + private static CIntField interpreterThrowoutCountField; + private static CIntField invocationCounter; + private static CIntField backedgeCounter; + + public int interpreterInvocationCount() { + return (int) interpreterInvocationCountField.getValue(this); + } + + public int interpreterThrowoutCount() { + return (int) interpreterThrowoutCountField.getValue(this); + } + public long getInvocationCounter() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(!VM.getVM().isCore(), "must not be used in core build"); + } + return invocationCounter.getValue(this); + } + public long getBackedgeCounter() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(!VM.getVM().isCore(), "must not be used in core build"); + } + return backedgeCounter.getValue(this); + } + + public void printValueOn(PrintStream tty) { + } +} + diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/sparc/vm/cppInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -404,14 +404,20 @@ // ??: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { + Label done; + const Register Rcounters = G3_scratch; + + __ ld_ptr(STATE(_method), G5_method); + __ get_method_counters(G5_method, Rcounters, done); + // Update standard invocation counters - __ increment_invocation_counter(O0, G3_scratch); - if (ProfileInterpreter) { // %%% Merge this into MethodData* - __ ld_ptr(STATE(_method), G3_scratch); - Address interpreter_invocation_counter(G3_scratch, 0, in_bytes(Method::interpreter_invocation_counter_offset())); - __ ld(interpreter_invocation_counter, G3_scratch); - __ inc(G3_scratch); - __ st(G3_scratch, interpreter_invocation_counter); + __ increment_invocation_counter(Rcounters, O0, G4_scratch); + if (ProfileInterpreter) { + Address interpreter_invocation_counter(Rcounters, 0, + in_bytes(MethodCounters::interpreter_invocation_counter_offset())); + __ ld(interpreter_invocation_counter, G4_scratch); + __ inc(G4_scratch); + __ st(G4_scratch, interpreter_invocation_counter); } Address invocation_limit(G3_scratch, (address)&InvocationCounter::InterpreterInvocationLimit); @@ -420,7 +426,7 @@ __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); __ delayed()->nop(); - + __ bind(done); } address InterpreterGenerator::generate_empty_entry(void) { diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -30,6 +30,7 @@ #include "oops/markOop.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" +#include "oops/methodCounters.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/jvmtiThreadState.hpp" @@ -2086,19 +2087,28 @@ #endif /* CC_INTERP */ -void InterpreterMacroAssembler::increment_invocation_counter( Register Rtmp, Register Rtmp2 ) { +void InterpreterMacroAssembler::get_method_counters(Register method, + Register Rcounters, + Label& skip) { + Label has_counters; + Address method_counters(method, in_bytes(Method::method_counters_offset())); + ld_ptr(method_counters, Rcounters); + br_notnull_short(Rcounters, Assembler::pt, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + ld_ptr(method_counters, Rcounters); + br_null_short(Rcounters, Assembler::pn, skip); // No MethodCounters, OutOfMemory + bind(has_counters); +} + +void InterpreterMacroAssembler::increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) { assert(UseCompiler, "incrementing must be useful"); -#ifdef CC_INTERP - Address inv_counter(G5_method, Method::invocation_counter_offset() + - InvocationCounter::counter_offset()); - Address be_counter (G5_method, Method::backedge_counter_offset() + + assert_different_registers(Rcounters, Rtmp, Rtmp2); + + Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); -#else - Address inv_counter(Lmethod, Method::invocation_counter_offset() + - InvocationCounter::counter_offset()); - Address be_counter (Lmethod, Method::backedge_counter_offset() + - InvocationCounter::counter_offset()); -#endif /* CC_INTERP */ + Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() + + InvocationCounter::counter_offset()); int delta = InvocationCounter::count_increment; // Load each counter in a register @@ -2122,19 +2132,15 @@ // Note that this macro must leave the backedge_count + invocation_count in Rtmp! } -void InterpreterMacroAssembler::increment_backedge_counter( Register Rtmp, Register Rtmp2 ) { +void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) { assert(UseCompiler, "incrementing must be useful"); -#ifdef CC_INTERP - Address be_counter (G5_method, Method::backedge_counter_offset() + - InvocationCounter::counter_offset()); - Address inv_counter(G5_method, Method::invocation_counter_offset() + + assert_different_registers(Rcounters, Rtmp, Rtmp2); + + Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); -#else - Address be_counter (Lmethod, Method::backedge_counter_offset() + - InvocationCounter::counter_offset()); - Address inv_counter(Lmethod, Method::invocation_counter_offset() + - InvocationCounter::counter_offset()); -#endif /* CC_INTERP */ + Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + int delta = InvocationCounter::count_increment; // Load each counter in a register ld( be_counter, Rtmp ); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -263,8 +263,9 @@ void compute_stack_base( Register Rdest ); #endif /* CC_INTERP */ - void increment_invocation_counter( Register Rtmp, Register Rtmp2 ); - void increment_backedge_counter( Register Rtmp, Register Rtmp2 ); + void get_method_counters(Register method, Register Rcounters, Label& skip); + void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); + void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); #ifndef CC_INTERP void test_backedge_count_for_osr( Register backedge_count, Register branch_bcp, Register Rtmp ); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -292,11 +292,15 @@ // ??: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. + // Note: In tiered we increment either counters in MethodCounters* or in + // MDO depending if we're profiling or not. + const Register Rcounters = G3_scratch; + Label done; + if (TieredCompilation) { const int increment = InvocationCounter::count_increment; const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; - Label no_mdo, done; + Label no_mdo; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); @@ -311,23 +315,26 @@ __ ba_short(done); } - // Increment counter in Method* + // Increment counter in MethodCounters* __ bind(no_mdo); - Address invocation_counter(Lmethod, - in_bytes(Method::invocation_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); + Address invocation_counter(Rcounters, + in_bytes(MethodCounters::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ get_method_counters(Lmethod, Rcounters, done); __ increment_mask_and_jump(invocation_counter, increment, mask, - G3_scratch, Lscratch, + G4_scratch, Lscratch, Assembler::zero, overflow); __ bind(done); } else { // Update standard invocation counters - __ increment_invocation_counter(O0, G3_scratch); - if (ProfileInterpreter) { // %%% Merge this into MethodData* - Address interpreter_invocation_counter(Lmethod,in_bytes(Method::interpreter_invocation_counter_offset())); - __ ld(interpreter_invocation_counter, G3_scratch); - __ inc(G3_scratch); - __ st(G3_scratch, interpreter_invocation_counter); + __ get_method_counters(Lmethod, Rcounters, done); + __ increment_invocation_counter(Rcounters, O0, G4_scratch); + if (ProfileInterpreter) { + Address interpreter_invocation_counter(Rcounters, + in_bytes(MethodCounters::interpreter_invocation_counter_offset())); + __ ld(interpreter_invocation_counter, G4_scratch); + __ inc(G4_scratch); + __ st(G4_scratch, interpreter_invocation_counter); } if (ProfileInterpreter && profile_method != NULL) { @@ -345,6 +352,7 @@ __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance __ delayed()->nop(); + __ bind(done); } } diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1604,9 +1604,8 @@ // Normal (non-jsr) branch handling // Save the current Lbcp - const Register O0_cur_bcp = O0; - __ mov( Lbcp, O0_cur_bcp ); - + const Register l_cur_bcp = Lscratch; + __ mov( Lbcp, l_cur_bcp ); bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; if ( increment_invocation_counter_for_backward_branches ) { @@ -1616,6 +1615,9 @@ // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr + const Register Rcounters = G3_scratch; + __ get_method_counters(Lmethod, Rcounters, Lforward); + if (TieredCompilation) { Label Lno_mdo, Loverflow; int increment = InvocationCounter::count_increment; @@ -1628,21 +1630,22 @@ // Increment backedge counter in the MDO Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); - __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, Lscratch, + __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, Assembler::notZero, &Lforward); __ ba_short(Loverflow); } - // If there's no MDO, increment counter in Method* + // If there's no MDO, increment counter in MethodCounters* __ bind(Lno_mdo); - Address backedge_counter(Lmethod, in_bytes(Method::backedge_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - __ increment_mask_and_jump(backedge_counter, increment, mask, G3_scratch, Lscratch, + Address backedge_counter(Rcounters, + in_bytes(MethodCounters::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, Assembler::notZero, &Lforward); __ bind(Loverflow); // notify point for loop, pass branch bytecode - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), O0_cur_bcp); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), l_cur_bcp); // Was an OSR adapter generated? // O0 = osr nmethod @@ -1679,15 +1682,15 @@ } else { // Update Backedge branch separately from invocations const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(G4_invoke_ctr, G1_scratch); + __ increment_backedge_counter(Rcounters, G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(O2_bumped_count, l_cur_bcp, G3_scratch); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, O0_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(G4_invoke_ctr, l_cur_bcp, G3_scratch); } } } diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/cppInterpreter_x86.cpp --- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -570,20 +570,28 @@ // rcx: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - - const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset()); - const Address backedge_counter (rbx, Method::backedge_counter_offset() + InvocationCounter::counter_offset()); - - if (ProfileInterpreter) { // %%% Merge this into MethodData* - __ incrementl(Address(rbx,Method::interpreter_invocation_counter_offset())); + Label done; + const Address invocation_counter(rax, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + const Address backedge_counter (rax, + MethodCounter::backedge_counter_offset() + + InvocationCounter::counter_offset()); + + __ get_method_counters(rbx, rax, done); + + if (ProfileInterpreter) { + __ incrementl(Address(rax, + MethodCounters::interpreter_invocation_counter_offset())); } // Update standard invocation counters - __ movl(rax, backedge_counter); // load backedge counter - + __ movl(rcx, invocation_counter); __ increment(rcx, InvocationCounter::count_increment); + __ movl(invocation_counter, rcx); // save invocation count + + __ movl(rax, backedge_counter); // load backedge counter __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits - __ movl(invocation_counter, rcx); // save invocation count __ addl(rcx, rax); // add both counters // profile_method is non-null only for interpreted method so @@ -593,7 +601,7 @@ __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); __ jcc(Assembler::aboveEqual, *overflow); - + __ bind(done); } void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { @@ -977,7 +985,6 @@ address entry_point = __ pc(); const Address constMethod (rbx, Method::const_offset()); - const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset()); const Address access_flags (rbx, Method::access_flags_offset()); const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset()); @@ -1029,8 +1036,6 @@ } #endif - if (inc_counter) __ movl(rcx, invocation_counter); // (pre-)fetch invocation count - const Register unlock_thread = LP64_ONLY(r15_thread) NOT_LP64(rax); NOT_LP64(__ movptr(unlock_thread, STATE(_thread));) // get thread // Since at this point in the method invocation the exception handler diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -266,6 +266,20 @@ addptr(cache, tmp); // construct pointer to cache entry } +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + movptr(mcs, Address(method, Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::notZero, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + movptr(mcs, Address(method,Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + // Load object from cpool->resolved_references(index) void InterpreterMacroAssembler::load_resolved_reference_at_index( Register result, Register index) { diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/interp_masm_x86_32.hpp --- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -89,6 +89,7 @@ void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); + void get_method_counters(Register method, Register mcs, Label& skip); // load cpool->resolved_references(index); void load_resolved_reference_at_index(Register result, Register index); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -271,6 +271,20 @@ addptr(cache, tmp); // construct pointer to cache entry } +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + movptr(mcs, Address(method, Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::notZero, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + movptr(mcs, Address(method,Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + // Load object from cpool->resolved_references(index) void InterpreterMacroAssembler::load_resolved_reference_at_index( Register result, Register index) { diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -111,6 +111,7 @@ void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); + void get_method_counters(Register method, Register mcs, Label& skip); // load cpool->resolved_references(index); void load_resolved_reference_at_index(Register result, Register index); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -344,13 +344,13 @@ // rcx: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - const Address invocation_counter(rbx, in_bytes(Method::invocation_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. + Label done; + // Note: In tiered we increment either counters in MethodCounters* or in MDO + // depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; - Label no_mdo, done; + Label no_mdo; if (ProfileInterpreter) { // Are we profiling? __ movptr(rax, Address(rbx, Method::method_data_offset())); @@ -363,23 +363,38 @@ __ jmpb(done); } __ bind(no_mdo); - // Increment counter in Method* (we don't need to load it, it's in rcx). - __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, true, Assembler::zero, overflow); + // Increment counter in MethodCounters + const Address invocation_counter(rax, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + + __ get_method_counters(rbx, rax, done); + __ increment_mask_and_jump(invocation_counter, increment, mask, + rcx, false, Assembler::zero, overflow); __ bind(done); } else { - const Address backedge_counter (rbx, Method::backedge_counter_offset() + - InvocationCounter::counter_offset()); + const Address backedge_counter (rax, + MethodCounters::backedge_counter_offset() + + InvocationCounter::counter_offset()); + const Address invocation_counter(rax, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + + __ get_method_counters(rbx, rax, done); - if (ProfileInterpreter) { // %%% Merge this into MethodData* - __ incrementl(Address(rbx,Method::interpreter_invocation_counter_offset())); + if (ProfileInterpreter) { + __ incrementl(Address(rax, + MethodCounters::interpreter_invocation_counter_offset())); } + // Update standard invocation counters - __ movl(rax, backedge_counter); // load backedge counter + __ movl(rcx, invocation_counter); + __ incrementl(rcx, InvocationCounter::count_increment); + __ movl(invocation_counter, rcx); // save invocation count - __ incrementl(rcx, InvocationCounter::count_increment); + __ movl(rax, backedge_counter); // load backedge counter __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits - __ movl(invocation_counter, rcx); // save invocation count __ addl(rcx, rax); // add both counters // profile_method is non-null only for interpreted method so @@ -399,6 +414,7 @@ __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); __ jcc(Assembler::aboveEqual, *overflow); + __ bind(done); } } @@ -868,7 +884,6 @@ address entry_point = __ pc(); const Address constMethod (rbx, Method::const_offset()); - const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset()); const Address access_flags (rbx, Method::access_flags_offset()); const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset()); @@ -897,9 +912,7 @@ // NULL oop temp (mirror or jni oop result) __ push((int32_t)NULL_WORD); - if (inc_counter) __ movl(rcx, invocation_counter); // (pre-)fetch invocation count // initialize fixed part of activation frame - generate_fixed_frame(true); // make sure method is native & not abstract @@ -1286,7 +1299,6 @@ address entry_point = __ pc(); const Address constMethod (rbx, Method::const_offset()); - const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset()); const Address access_flags (rbx, Method::access_flags_offset()); const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset()); const Address size_of_locals (rdx, ConstMethod::size_of_locals_offset()); @@ -1326,7 +1338,6 @@ __ bind(exit); } - if (inc_counter) __ movl(rcx, invocation_counter); // (pre-)fetch invocation count // initialize fixed part of activation frame generate_fixed_frame(false); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -300,13 +300,12 @@ Label* overflow, Label* profile_method, Label* profile_method_continue) { - const Address invocation_counter(rbx, in_bytes(Method::invocation_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); + Label done; // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; - Label no_mdo, done; + Label no_mdo; if (ProfileInterpreter) { // Are we profiling? __ movptr(rax, Address(rbx, Method::method_data_offset())); @@ -319,25 +318,36 @@ __ jmpb(done); } __ bind(no_mdo); - // Increment counter in Method* (we don't need to load it, it's in ecx). - __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, true, Assembler::zero, overflow); + // Increment counter in MethodCounters + const Address invocation_counter(rax, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + __ get_method_counters(rbx, rax, done); + __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, + false, Assembler::zero, overflow); __ bind(done); } else { - const Address backedge_counter(rbx, - Method::backedge_counter_offset() + - InvocationCounter::counter_offset()); + const Address backedge_counter(rax, + MethodCounters::backedge_counter_offset() + + InvocationCounter::counter_offset()); + const Address invocation_counter(rax, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); - if (ProfileInterpreter) { // %%% Merge this into MethodData* - __ incrementl(Address(rbx, - Method::interpreter_invocation_counter_offset())); + __ get_method_counters(rbx, rax, done); + + if (ProfileInterpreter) { + __ incrementl(Address(rax, + MethodCounters::interpreter_invocation_counter_offset())); } // Update standard invocation counters - __ movl(rax, backedge_counter); // load backedge counter + __ movl(rcx, invocation_counter); + __ incrementl(rcx, InvocationCounter::count_increment); + __ movl(invocation_counter, rcx); // save invocation count - __ incrementl(rcx, InvocationCounter::count_increment); + __ movl(rax, backedge_counter); // load backedge counter __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits - __ movl(invocation_counter, rcx); // save invocation count __ addl(rcx, rax); // add both counters // profile_method is non-null only for interpreted method so @@ -354,6 +364,7 @@ __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); __ jcc(Assembler::aboveEqual, *overflow); + __ bind(done); } } @@ -843,9 +854,6 @@ address entry_point = __ pc(); const Address constMethod (rbx, Method::const_offset()); - const Address invocation_counter(rbx, Method:: - invocation_counter_offset() + - InvocationCounter::counter_offset()); const Address access_flags (rbx, Method::access_flags_offset()); const Address size_of_parameters(rcx, ConstMethod:: size_of_parameters_offset()); @@ -876,10 +884,6 @@ // (static native method holder mirror/jni oop result) __ push((int) NULL_WORD); - if (inc_counter) { - __ movl(rcx, invocation_counter); // (pre-)fetch invocation count - } - // initialize fixed part of activation frame generate_fixed_frame(true); @@ -1296,9 +1300,6 @@ address entry_point = __ pc(); const Address constMethod(rbx, Method::const_offset()); - const Address invocation_counter(rbx, - Method::invocation_counter_offset() + - InvocationCounter::counter_offset()); const Address access_flags(rbx, Method::access_flags_offset()); const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset()); @@ -1343,10 +1344,6 @@ __ bind(exit); } - // (pre-)fetch invocation count - if (inc_counter) { - __ movl(rcx, invocation_counter); - } // initialize fixed part of activation frame generate_fixed_frame(false); diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -1546,9 +1546,10 @@ __ get_method(rcx); // ECX holds method __ profile_taken_branch(rax,rbx); // EAX holds updated MDP, EBX holds bumped taken count - const ByteSize be_offset = Method::backedge_counter_offset() + InvocationCounter::counter_offset(); - const ByteSize inv_offset = Method::invocation_counter_offset() + InvocationCounter::counter_offset(); - const int method_offset = frame::interpreter_frame_method_offset * wordSize; + const ByteSize be_offset = MethodCounters::backedge_counter_offset() + + InvocationCounter::counter_offset(); + const ByteSize inv_offset = MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset(); // Load up EDX with the branch displacement __ movl(rdx, at_bcp(1)); @@ -1596,6 +1597,22 @@ __ testl(rdx, rdx); // check if forward or backward branch __ jcc(Assembler::positive, dispatch); // count only if backward branch + // check if MethodCounters exists + Label has_counters; + __ movptr(rax, Address(rcx, Method::method_counters_offset())); + __ testptr(rax, rax); + __ jcc(Assembler::notZero, has_counters); + __ push(rdx); + __ push(rcx); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), + rcx); + __ pop(rcx); + __ pop(rdx); + __ movptr(rax, Address(rcx, Method::method_counters_offset())); + __ testptr(rax, rax); + __ jcc(Assembler::zero, dispatch); + __ bind(has_counters); + if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; @@ -1613,16 +1630,19 @@ __ jmp(dispatch); } __ bind(no_mdo); - // Increment backedge counter in Method* + // Increment backedge counter in MethodCounters* + __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); } else { // increment counter + __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter __ incrementl(rax, InvocationCounter::count_increment); // increment counter __ movl(Address(rcx, be_offset), rax); // store counter __ movl(rax, Address(rcx, inv_offset)); // load invocation counter + __ andl(rax, InvocationCounter::count_mask_value); // and the status bits __ addl(rax, Address(rcx, be_offset)); // add both counters diff -r c60f69931e1a -r 8df6ddda8090 src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1564,11 +1564,10 @@ __ profile_taken_branch(rax, rbx); // rax holds updated MDP, rbx // holds bumped taken count - const ByteSize be_offset = Method::backedge_counter_offset() + + const ByteSize be_offset = MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset(); - const ByteSize inv_offset = Method::invocation_counter_offset() + + const ByteSize inv_offset = MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset(); - const int method_offset = frame::interpreter_frame_method_offset * wordSize; // Load up edx with the branch displacement __ movl(rdx, at_bcp(1)); @@ -1618,6 +1617,22 @@ // r14: locals pointer __ testl(rdx, rdx); // check if forward or backward branch __ jcc(Assembler::positive, dispatch); // count only if backward branch + + // check if MethodCounters exists + Label has_counters; + __ movptr(rax, Address(rcx, Method::method_counters_offset())); + __ testptr(rax, rax); + __ jcc(Assembler::notZero, has_counters); + __ push(rdx); + __ push(rcx); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), + rcx); + __ pop(rcx); + __ pop(rdx); + __ movptr(rax, Address(rcx, Method::method_counters_offset())); + __ jcc(Assembler::zero, dispatch); + __ bind(has_counters); + if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; @@ -1635,16 +1650,19 @@ __ jmp(dispatch); } __ bind(no_mdo); - // Increment backedge counter in Method* + // Increment backedge counter in MethodCounters* + __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); } else { // increment counter + __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter __ incrementl(rax, InvocationCounter::count_increment); // increment counter __ movl(Address(rcx, be_offset), rax); // store counter __ movl(rax, Address(rcx, inv_offset)); // load invocation counter + __ andl(rax, InvocationCounter::count_mask_value); // and the status bits __ addl(rax, Address(rcx, be_offset)); // add both counters diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -3044,21 +3044,20 @@ assert(level > CompLevel_simple, "Shouldn't be here"); int offset = -1; - LIR_Opr counter_holder = new_register(T_METADATA); - LIR_Opr meth; + LIR_Opr counter_holder; if (level == CompLevel_limited_profile) { - offset = in_bytes(backedge ? Method::backedge_counter_offset() : - Method::invocation_counter_offset()); - __ metadata2reg(method->constant_encoding(), counter_holder); - meth = counter_holder; + address counters_adr = method->ensure_method_counters(); + counter_holder = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(counters_adr), counter_holder); + offset = in_bytes(backedge ? MethodCounters::backedge_counter_offset() : + MethodCounters::invocation_counter_offset()); } else if (level == CompLevel_full_profile) { + counter_holder = new_register(T_METADATA); offset = in_bytes(backedge ? MethodData::backedge_counter_offset() : MethodData::invocation_counter_offset()); ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); __ metadata2reg(md->constant_encoding(), counter_holder); - meth = new_register(T_METADATA); - __ metadata2reg(method->constant_encoding(), meth); } else { ShouldNotReachHere(); } @@ -3069,6 +3068,8 @@ __ store(result, counter); if (notify) { LIR_Opr mask = load_immediate(frequency << InvocationCounter::count_shift, T_INT); + LIR_Opr meth = new_register(T_METADATA); + __ metadata2reg(method->constant_encoding(), meth); __ logical_and(result, mask, result); __ cmp(lir_cond_equal, result, LIR_OprFact::intConst(0)); // The bci for info can point to cmp for if's we want the if bci diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/ci/ciMethod.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -905,6 +905,20 @@ } // ------------------------------------------------------------------ +// ciMethod::ensure_method_counters +// +address ciMethod::ensure_method_counters() { + check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, get_Method()); + MethodCounters *counter = mh->method_counters(); + if (counter == NULL) { + counter = Method::build_method_counters(mh(), CHECK_AND_CLEAR_NULL); + } + return (address)counter; +} + +// ------------------------------------------------------------------ // ciMethod::should_exclude // // Should this method be excluded from compilation? @@ -1191,13 +1205,14 @@ ASSERT_IN_VM; 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(), - method->invocation_counter()->raw_counter(), - method->backedge_counter()->raw_counter(), + mcs == NULL ? 0 : mcs->invocation_counter()->raw_counter(), + mcs == NULL ? 0 : mcs->backedge_counter()->raw_counter(), interpreter_invocation_count(), interpreter_throwout_count(), _instructions_size); diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/ci/ciMethod.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -262,6 +262,7 @@ bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const; bool check_call(int refinfo_index, bool is_static) const; bool ensure_method_data(); // make sure it exists in the VM also + address ensure_method_counters(); int instructions_size(); int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/ci/ciReplay.cpp --- a/src/share/vm/ci/ciReplay.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/ci/ciReplay.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -920,12 +920,17 @@ method->print_name(tty); tty->cr(); } else { + EXCEPTION_CONTEXT; + MethodCounters* mcs = method->method_counters(); // 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; - method->invocation_counter()->_counter = rec->invocation_counter; - method->backedge_counter()->_counter = rec->backedge_counter; + if (mcs == NULL) { + mcs = Method::build_method_counters(method, CHECK_AND_CLEAR); + } + mcs->invocation_counter()->_counter = rec->invocation_counter; + mcs->backedge_counter()->_counter = rec->backedge_counter; } } diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -454,7 +454,7 @@ continuation = Interpreter::remove_activation_entry(); #endif // Count this for compilation purposes - h_method->interpreter_throwout_increment(); + h_method->interpreter_throwout_increment(THREAD); } else { // handler in this method => change bci/bcp to handler bci/bcp and continue there handler_pc = h_method->code_base() + handler_bci; @@ -903,6 +903,15 @@ fr.interpreter_frame_set_mdp(new_mdp); IRT_END +IRT_ENTRY(MethodCounters*, InterpreterRuntime::build_method_counters(JavaThread* thread, Method* m)) + MethodCounters* mcs = Method::build_method_counters(m, thread); + if (HAS_PENDING_EXCEPTION) { + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + CLEAR_PENDING_EXCEPTION; + } + return mcs; +IRT_END + IRT_ENTRY(void, InterpreterRuntime::at_safepoint(JavaThread* thread)) // We used to need an explict preserve_arguments here for invoke bytecodes. However, diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/interpreter/interpreterRuntime.hpp --- a/src/share/vm/interpreter/interpreterRuntime.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -169,6 +169,7 @@ #ifdef ASSERT static void verify_mdp(Method* method, address bcp, address mdp); #endif // ASSERT + static MethodCounters* build_method_counters(JavaThread* thread, Method* m); }; diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/interpreter/invocationCounter.cpp --- a/src/share/vm/interpreter/invocationCounter.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/interpreter/invocationCounter.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -104,15 +104,19 @@ static address do_nothing(methodHandle method, TRAPS) { // dummy action for inactive invocation counters - method->invocation_counter()->set_carry(); - method->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); + MethodCounters* mcs = method->method_counters(); + assert(mcs != NULL, ""); + mcs->invocation_counter()->set_carry(); + mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); return NULL; } static address do_decay(methodHandle method, TRAPS) { // decay invocation counters so compilation gets delayed - method->invocation_counter()->decay(); + MethodCounters* mcs = method->method_counters(); + assert(mcs != NULL, ""); + mcs->invocation_counter()->decay(); return NULL; } diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/oops/method.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -91,7 +91,7 @@ set_hidden(false); set_dont_inline(false); set_method_data(NULL); - set_interpreter_throwout_count(0); + set_method_counters(NULL); set_vtable_index(Method::garbage_vtable_index); // Fix and bury in Method* @@ -105,16 +105,6 @@ } NOT_PRODUCT(set_compiled_invocation_count(0);) - set_interpreter_invocation_count(0); - invocation_counter()->init(); - backedge_counter()->init(); - clear_number_of_breakpoints(); - -#ifdef TIERED - set_rate(0); - set_prev_event_count(0); - set_prev_time(0); -#endif } // Release Method*. The nmethod will be gone when we get here because @@ -124,6 +114,8 @@ set_constMethod(NULL); MetadataFactory::free_metadata(loader_data, method_data()); set_method_data(NULL); + MetadataFactory::free_metadata(loader_data, method_counters()); + set_method_counters(NULL); // The nmethod will be gone when we get here. if (code() != NULL) _code = NULL; } @@ -323,7 +315,10 @@ // compiler does not bump invocation counter of compiled methods return true; } - else if (_invocation_counter.carry() || (method_data() != NULL && method_data()->invocation_counter()->carry())) { + else if ((method_counters() != NULL && + method_counters()->invocation_counter()->carry()) || + (method_data() != NULL && + method_data()->invocation_counter()->carry())) { // The carry bit is set when the counter overflows and causes // a compilation to occur. We don't know how many times // the counter has been reset, so we simply assume it has @@ -387,6 +382,18 @@ } } +MethodCounters* Method::build_method_counters(Method* m, TRAPS) { + methodHandle mh(m); + ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); + MethodCounters* counters = MethodCounters::allocate(loader_data, CHECK_NULL); + if (mh->method_counters() == NULL) { + mh->set_method_counters(counters); + } else { + MetadataFactory::free_metadata(loader_data, counters); + } + return mh->method_counters(); +} + void Method::cleanup_inline_caches() { // The current system doesn't use inline caches in the interpreter // => nothing to do (keep this method around for future use) @@ -794,8 +801,6 @@ set_signature_handler(NULL); } NOT_PRODUCT(set_compiled_invocation_count(0);) - invocation_counter()->reset(); - backedge_counter()->reset(); _adapter = NULL; _from_compiled_entry = NULL; @@ -808,8 +813,7 @@ assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); set_method_data(NULL); - set_interpreter_throwout_count(0); - set_interpreter_invocation_count(0); + set_method_counters(NULL); } // Called when the method_holder is getting linked. Setup entrypoints so the method @@ -1545,28 +1549,34 @@ int Method::invocation_count() { + MethodCounters *mcs = method_counters(); if (TieredCompilation) { MethodData* const mdo = method_data(); - if (invocation_counter()->carry() || ((mdo != NULL) ? mdo->invocation_counter()->carry() : false)) { + if (((mcs != NULL) ? mcs->invocation_counter()->carry() : false) || + ((mdo != NULL) ? mdo->invocation_counter()->carry() : false)) { return InvocationCounter::count_limit; } else { - return invocation_counter()->count() + ((mdo != NULL) ? mdo->invocation_counter()->count() : 0); + return ((mcs != NULL) ? mcs->invocation_counter()->count() : 0) + + ((mdo != NULL) ? mdo->invocation_counter()->count() : 0); } } else { - return invocation_counter()->count(); + return (mcs == NULL) ? 0 : mcs->invocation_counter()->count(); } } int Method::backedge_count() { + MethodCounters *mcs = method_counters(); if (TieredCompilation) { MethodData* const mdo = method_data(); - if (backedge_counter()->carry() || ((mdo != NULL) ? mdo->backedge_counter()->carry() : false)) { + if (((mcs != NULL) ? mcs->backedge_counter()->carry() : false) || + ((mdo != NULL) ? mdo->backedge_counter()->carry() : false)) { return InvocationCounter::count_limit; } else { - return backedge_counter()->count() + ((mdo != NULL) ? mdo->backedge_counter()->count() : 0); + return ((mcs != NULL) ? mcs->backedge_counter()->count() : 0) + + ((mdo != NULL) ? mdo->backedge_counter()->count() : 0); } } else { - return backedge_counter()->count(); + return (mcs == NULL) ? 0 : mcs->backedge_counter()->count(); } } @@ -1621,12 +1631,12 @@ assert(orig_bytecode() == code, "original bytecode must be the same"); } #endif + Thread *thread = Thread::current(); *method->bcp_from(_bci) = Bytecodes::_breakpoint; - method->incr_number_of_breakpoints(); + method->incr_number_of_breakpoints(thread); SystemDictionary::notice_modification(); { // Deoptimize all dependents on this method - Thread *thread = Thread::current(); HandleMark hm(thread); methodHandle mh(thread, method); Universe::flush_dependents_on_method(mh); @@ -1636,7 +1646,7 @@ void BreakpointInfo::clear(Method* method) { *method->bcp_from(_bci) = orig_bytecode(); assert(method->number_of_breakpoints() > 0, "must not go negative"); - method->decr_number_of_breakpoints(); + method->decr_number_of_breakpoints(Thread::current()); } // jmethodID handling diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/oops/method.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -31,6 +31,7 @@ #include "interpreter/invocationCounter.hpp" #include "oops/annotations.hpp" #include "oops/constantPool.hpp" +#include "oops/methodCounters.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.hpp" #include "oops/typeArrayOop.hpp" @@ -100,6 +101,7 @@ class LocalVariableTableElement; class AdapterHandlerEntry; class MethodData; +class MethodCounters; class ConstMethod; class InlineTableSizes; class KlassSizeStats; @@ -109,7 +111,7 @@ private: ConstMethod* _constMethod; // Method read-only data. MethodData* _method_data; - int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) + MethodCounters* _method_counters; AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) // note: can have vtables with >2**16 elements (because of inheritance) @@ -124,15 +126,6 @@ _hidden : 1, _dont_inline : 1, : 3; - u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting - u2 _number_of_breakpoints; // fullspeed debugging support - InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations - InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequencey-based optimizations - -#ifdef TIERED - float _rate; // Events (invocation and backedge counter increments) per millisecond - jlong _prev_time; // Previous time the rate was acquired -#endif #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) @@ -247,11 +240,31 @@ void clear_all_breakpoints(); // Tracking number of breakpoints, for fullspeed debugging. // Only mutated by VM thread. - u2 number_of_breakpoints() const { return _number_of_breakpoints; } - void incr_number_of_breakpoints() { ++_number_of_breakpoints; } - void decr_number_of_breakpoints() { --_number_of_breakpoints; } + u2 number_of_breakpoints() const { + if (method_counters() == NULL) { + return 0; + } else { + return method_counters()->number_of_breakpoints(); + } + } + void incr_number_of_breakpoints(TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->incr_number_of_breakpoints(); + } + } + void decr_number_of_breakpoints(TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->decr_number_of_breakpoints(); + } + } // Initialization only - void clear_number_of_breakpoints() { _number_of_breakpoints = 0; } + void clear_number_of_breakpoints() { + if (method_counters() != NULL) { + method_counters()->clear_number_of_breakpoints(); + } + } // index into InstanceKlass methods() array // note: also used by jfr @@ -288,14 +301,20 @@ void set_highest_osr_comp_level(int level); // Count of times method was exited via exception while interpreting - void interpreter_throwout_increment() { - if (_interpreter_throwout_count < 65534) { - _interpreter_throwout_count++; + void interpreter_throwout_increment(TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->interpreter_throwout_increment(); } } - int interpreter_throwout_count() const { return _interpreter_throwout_count; } - void set_interpreter_throwout_count(int count) { _interpreter_throwout_count = count; } + int interpreter_throwout_count() const { + if (method_counters() == NULL) { + return 0; + } else { + return method_counters()->interpreter_throwout_count(); + } + } // size of parameters int size_of_parameters() const { return constMethod()->size_of_parameters(); } @@ -339,23 +358,54 @@ MethodData* method_data() const { return _method_data; } + void set_method_data(MethodData* data) { _method_data = data; } - // invocation counter - InvocationCounter* invocation_counter() { return &_invocation_counter; } - InvocationCounter* backedge_counter() { return &_backedge_counter; } + MethodCounters* method_counters() const { + return _method_counters; + } + + + void set_method_counters(MethodCounters* counters) { + _method_counters = counters; + } #ifdef TIERED // We are reusing interpreter_invocation_count as a holder for the previous event count! // We can do that since interpreter_invocation_count is not used in tiered. - int prev_event_count() const { return _interpreter_invocation_count; } - void set_prev_event_count(int count) { _interpreter_invocation_count = count; } - jlong prev_time() const { return _prev_time; } - void set_prev_time(jlong time) { _prev_time = time; } - float rate() const { return _rate; } - void set_rate(float rate) { _rate = rate; } + int prev_event_count() const { + if (method_counters() == NULL) { + return 0; + } else { + return method_counters()->interpreter_invocation_count(); + } + } + void set_prev_event_count(int count, TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->set_interpreter_invocation_count(count); + } + } + jlong prev_time() const { + return method_counters() == NULL ? 0 : method_counters()->prev_time(); + } + void set_prev_time(jlong time, TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->set_prev_time(time); + } + } + float rate() const { + return method_counters() == NULL ? 0 : method_counters()->rate(); + } + void set_rate(float rate, TRAPS) { + MethodCounters* mcs = get_method_counters(CHECK); + if (mcs != NULL) { + mcs->set_rate(rate); + } + } #endif int invocation_count(); @@ -366,14 +416,17 @@ static void build_interpreter_method_data(methodHandle method, TRAPS); + static MethodCounters* build_method_counters(Method* m, TRAPS); + int interpreter_invocation_count() { if (TieredCompilation) return invocation_count(); - else return _interpreter_invocation_count; + else return (method_counters() == NULL) ? 0 : + method_counters()->interpreter_invocation_count(); } - void set_interpreter_invocation_count(int count) { _interpreter_invocation_count = count; } - int increment_interpreter_invocation_count() { + int increment_interpreter_invocation_count(TRAPS) { if (TieredCompilation) ShouldNotReachHere(); - return ++_interpreter_invocation_count; + MethodCounters* mcs = get_method_counters(CHECK_0); + return (mcs == NULL) ? 0 : mcs->increment_interpreter_invocation_count(); } #ifndef PRODUCT @@ -582,12 +635,12 @@ #endif /* CC_INTERP */ static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } - static ByteSize invocation_counter_offset() { return byte_offset_of(Method, _invocation_counter); } - static ByteSize backedge_counter_offset() { return byte_offset_of(Method, _backedge_counter); } static ByteSize method_data_offset() { return byte_offset_of(Method, _method_data); } - static ByteSize interpreter_invocation_counter_offset() { return byte_offset_of(Method, _interpreter_invocation_count); } + static ByteSize method_counters_offset() { + return byte_offset_of(Method, _method_counters); + } #ifndef PRODUCT static ByteSize compiled_invocation_counter_offset() { return byte_offset_of(Method, _compiled_invocation_count); } #endif // not PRODUCT @@ -598,8 +651,6 @@ // for code generation static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } - static int interpreter_invocation_counter_offset_in_bytes() - { return offset_of(Method, _interpreter_invocation_count); } static int intrinsic_id_offset_in_bytes() { return offset_of(Method, _intrinsic_id); } static int intrinsic_id_size_in_bytes() { return sizeof(u1); } @@ -757,6 +808,13 @@ private: void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); + MethodCounters* get_method_counters(TRAPS) { + if (_method_counters == NULL) { + build_method_counters(this, CHECK_AND_CLEAR_NULL); + } + return _method_counters; + } + public: bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/oops/methodCounters.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/methodCounters.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "oops/methodCounters.hpp" +#include "runtime/thread.inline.hpp" + +MethodCounters* MethodCounters::allocate(ClassLoaderData* loader_data, TRAPS) { + return new(loader_data, size(), false, THREAD) MethodCounters(); +} + +void MethodCounters::clear_counters() { + invocation_counter()->reset(); + backedge_counter()->reset(); + set_interpreter_throwout_count(0); + set_interpreter_invocation_count(0); +} diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/oops/methodCounters.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/methodCounters.hpp Mon Apr 15 21:25:23 2013 -0400 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_METHODCOUNTERS_HPP +#define SHARE_VM_OOPS_METHODCOUNTERS_HPP + +#include "oops/metadata.hpp" +#include "interpreter/invocationCounter.hpp" + +class MethodCounters: public MetaspaceObj { + friend class VMStructs; + private: + int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) + u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting + u2 _number_of_breakpoints; // fullspeed debugging support + InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations + InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequencey-based optimizations + +#ifdef TIERED + float _rate; // Events (invocation and backedge counter increments) per millisecond + jlong _prev_time; // Previous time the rate was acquired +#endif + + MethodCounters() : _interpreter_invocation_count(0), + _interpreter_throwout_count(0), + _number_of_breakpoints(0) +#ifdef TIERED + , _rate(0), + _prev_time(0) +#endif + { + invocation_counter()->init(); + backedge_counter()->init(); + } + + public: + static MethodCounters* allocate(ClassLoaderData* loader_data, TRAPS); + + void deallocate_contents(ClassLoaderData* loader_data) {} + DEBUG_ONLY(bool on_stack() { return false; }) // for template + + static int size() { return sizeof(MethodCounters) / wordSize; } + + bool is_klass() const { return false; } + + void clear_counters(); + + int interpreter_invocation_count() { + return _interpreter_invocation_count; + } + void set_interpreter_invocation_count(int count) { + _interpreter_invocation_count = count; + } + int increment_interpreter_invocation_count() { + return ++_interpreter_invocation_count; + } + + void interpreter_throwout_increment() { + if (_interpreter_throwout_count < 65534) { + _interpreter_throwout_count++; + } + } + int interpreter_throwout_count() const { + return _interpreter_throwout_count; + } + void set_interpreter_throwout_count(int count) { + _interpreter_throwout_count = count; + } + + u2 number_of_breakpoints() const { return _number_of_breakpoints; } + void incr_number_of_breakpoints() { ++_number_of_breakpoints; } + void decr_number_of_breakpoints() { --_number_of_breakpoints; } + void clear_number_of_breakpoints() { _number_of_breakpoints = 0; } + +#ifdef TIERED + jlong prev_time() const { return _prev_time; } + void set_prev_time(jlong time) { _prev_time = time; } + float rate() const { return _rate; } + void set_rate(float rate) { _rate = rate; } +#endif + + // invocation counter + InvocationCounter* invocation_counter() { return &_invocation_counter; } + InvocationCounter* backedge_counter() { return &_backedge_counter; } + + static ByteSize interpreter_invocation_counter_offset() { + return byte_offset_of(MethodCounters, _interpreter_invocation_count); + } + + static ByteSize invocation_counter_offset() { + return byte_offset_of(MethodCounters, _invocation_counter); + } + + static ByteSize backedge_counter_offset() { + return byte_offset_of(MethodCounters, _backedge_counter); + } + + static int interpreter_invocation_counter_offset_in_bytes() { + return offset_of(MethodCounters, _interpreter_invocation_count); + } + +}; +#endif //SHARE_VM_OOPS_METHODCOUNTERS_HPP diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/oops/methodData.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -732,14 +732,17 @@ } else { int iic = method->interpreter_invocation_count(); if (mileage < iic) mileage = iic; - InvocationCounter* ic = method->invocation_counter(); - InvocationCounter* bc = method->backedge_counter(); - int icval = ic->count(); - if (ic->carry()) icval += CompileThreshold; - if (mileage < icval) mileage = icval; - int bcval = bc->count(); - if (bc->carry()) bcval += CompileThreshold; - if (mileage < bcval) mileage = bcval; + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + InvocationCounter* ic = mcs->invocation_counter(); + InvocationCounter* bc = mcs->backedge_counter(); + int icval = ic->count(); + if (ic->carry()) icval += CompileThreshold; + if (mileage < icval) mileage = icval; + int bcval = bc->count(); + if (bc->carry()) bcval += CompileThreshold; + if (mileage < bcval) mileage = bcval; + } } return mileage; } diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/opto/parseHelper.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -337,19 +337,21 @@ if (!count_invocations()) return; // Get the Method* node. - const TypePtr* adr_type = TypeMetadataPtr::make(method()); - Node *method_node = makecon(adr_type); + ciMethod* m = method(); + address counters_adr = m->ensure_method_counters(); - // Load the interpreter_invocation_counter from the Method*. - int offset = Method::interpreter_invocation_counter_offset_in_bytes(); - Node* adr_node = basic_plus_adr(method_node, method_node, offset); - Node* cnt = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type); + Node* ctrl = control(); + const TypePtr* adr_type = TypeRawPtr::make(counters_adr); + Node *counters_node = makecon(adr_type); + Node* adr_iic_node = basic_plus_adr(counters_node, counters_node, + MethodCounters::interpreter_invocation_counter_offset_in_bytes()); + Node* cnt = make_load(ctrl, adr_iic_node, TypeInt::INT, T_INT, adr_type); test_counter_against_threshold(cnt, limit); // Add one to the counter and store Node* incr = _gvn.transform(new (C) AddINode(cnt, _gvn.intcon(1))); - store_to_memory( NULL, adr_node, incr, T_INT, adr_type ); + store_to_memory( ctrl, adr_iic_node, incr, T_INT, adr_type ); } //----------------------------method_data_addressing--------------------------- diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/prims/whitebox.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -278,6 +278,7 @@ methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); MutexLockerEx mu(Compile_lock); MethodData* mdo = mh->method_data(); + MethodCounters* mcs = mh->method_counters(); if (mdo != NULL) { mdo->init(); @@ -288,20 +289,22 @@ } } - mh->backedge_counter()->init(); - mh->invocation_counter()->init(); - mh->set_interpreter_invocation_count(0); - mh->set_interpreter_throwout_count(0); mh->clear_not_c1_compilable(); mh->clear_not_c2_compilable(); mh->clear_not_c2_osr_compilable(); NOT_PRODUCT(mh->set_compiled_invocation_count(0)); + if (mcs != NULL) { + mcs->backedge_counter()->init(); + mcs->invocation_counter()->init(); + mcs->set_interpreter_invocation_count(0); + mcs->set_interpreter_throwout_count(0); #ifdef TIERED - mh->set_rate(0.0F); - mh->set_prev_event_count(0); - mh->set_prev_time(0); + mcs->set_rate(0.0F); + mh->set_prev_event_count(0, THREAD); + mh->set_prev_time(0, THREAD); #endif + } WB_END WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -74,10 +74,11 @@ // update_rate() is called from select_task() while holding a compile queue lock. void AdvancedThresholdPolicy::update_rate(jlong t, Method* m) { + JavaThread* THREAD = JavaThread::current(); if (is_old(m)) { // We don't remove old methods from the queue, // so we can just zero the rate. - m->set_rate(0); + m->set_rate(0, THREAD); return; } @@ -93,13 +94,13 @@ if (delta_s >= TieredRateUpdateMinTime) { // And we must've taken the previous point at least 1ms before. if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) { - m->set_prev_time(t); - m->set_prev_event_count(event_count); - m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond + m->set_prev_time(t, THREAD); + m->set_prev_event_count(event_count, THREAD); + m->set_rate((float)delta_e / (float)delta_t, THREAD); // Rate is events per millisecond } else if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) { // If nothing happened for 25ms, zero the rate. Don't modify prev values. - m->set_rate(0); + m->set_rate(0, THREAD); } } } diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/runtime/compilationPolicy.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -198,8 +198,10 @@ // BUT also make sure the method doesn't look like it was never executed. // Set carry bit and reduce counter's value to min(count, CompileThreshold/2). - m->invocation_counter()->set_carry(); - m->backedge_counter()->set_carry(); + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + mcs->invocation_counter()->set_carry(); + mcs->backedge_counter()->set_carry(); assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed"); } @@ -207,8 +209,10 @@ void NonTieredCompPolicy::reset_counter_for_back_branch_event(methodHandle m) { // Delay next back-branch event but pump up invocation counter to triger // whole method compilation. - InvocationCounter* i = m->invocation_counter(); - InvocationCounter* b = m->backedge_counter(); + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + InvocationCounter* i = mcs->invocation_counter(); + InvocationCounter* b = mcs->backedge_counter(); // Don't set invocation_counter's value too low otherwise the method will // look like immature (ic < ~5300) which prevents the inlining based on @@ -227,7 +231,10 @@ class CounterDecay : public AllStatic { static jlong _last_timestamp; static void do_method(Method* m) { - m->invocation_counter()->decay(); + MethodCounters* mcs = m->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->decay(); + } } public: static void decay(); @@ -265,30 +272,44 @@ void NonTieredCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { ScopeDesc* sd = trap_scope; + MethodCounters* mcs; + InvocationCounter* c; for (; !sd->is_top(); sd = sd->sender()) { - // Reset ICs of inlined methods, since they can trigger compilations also. - sd->method()->invocation_counter()->reset(); + mcs = sd->method()->method_counters(); + if (mcs != NULL) { + // Reset ICs of inlined methods, since they can trigger compilations also. + mcs->invocation_counter()->reset(); + } } - InvocationCounter* c = sd->method()->invocation_counter(); - if (is_osr) { - // It was an OSR method, so bump the count higher. - c->set(c->state(), CompileThreshold); - } else { - c->reset(); + mcs = sd->method()->method_counters(); + if (mcs != NULL) { + c = mcs->invocation_counter(); + if (is_osr) { + // It was an OSR method, so bump the count higher. + c->set(c->state(), CompileThreshold); + } else { + c->reset(); + } + mcs->backedge_counter()->reset(); } - sd->method()->backedge_counter()->reset(); } // This method can be called by any component of the runtime to notify the policy // that it's recommended to delay the complation of this method. void NonTieredCompPolicy::delay_compilation(Method* method) { - method->invocation_counter()->decay(); - method->backedge_counter()->decay(); + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->decay(); + mcs->backedge_counter()->decay(); + } } void NonTieredCompPolicy::disable_compilation(Method* method) { - method->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); - method->backedge_counter()->set_state(InvocationCounter::wait_for_nothing); + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); + mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing); + } } CompileTask* NonTieredCompPolicy::select_task(CompileQueue* compile_queue) { @@ -371,8 +392,10 @@ #ifndef PRODUCT void NonTieredCompPolicy::trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci) { if (TraceInvocationCounterOverflow) { - InvocationCounter* ic = m->invocation_counter(); - InvocationCounter* bc = m->backedge_counter(); + MethodCounters* mcs = m->method_counters(); + assert(mcs != NULL, "MethodCounters cannot be NULL for profiling"); + InvocationCounter* ic = mcs->invocation_counter(); + InvocationCounter* bc = mcs->backedge_counter(); ResourceMark rm; const char* msg = bci == InvocationEntryBci diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/runtime/fprofiler.cpp --- a/src/share/vm/runtime/fprofiler.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/runtime/fprofiler.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -421,7 +421,8 @@ void print_method_on(outputStream* st) { ProfilerNode::print_method_on(st); - if (Verbose) method()->invocation_counter()->print_short(); + MethodCounters* mcs = method()->method_counters(); + if (Verbose && mcs != NULL) mcs->invocation_counter()->print_short(); } }; diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/runtime/simpleThresholdPolicy.cpp --- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -153,8 +153,10 @@ // Set carry flags on the counters if necessary void SimpleThresholdPolicy::handle_counter_overflow(Method* method) { - set_carry_if_necessary(method->invocation_counter()); - set_carry_if_necessary(method->backedge_counter()); + MethodCounters *mcs = method->method_counters(); + assert(mcs != NULL, ""); + set_carry_if_necessary(mcs->invocation_counter()); + set_carry_if_necessary(mcs->backedge_counter()); MethodData* mdo = method->method_data(); if (mdo != NULL) { set_carry_if_necessary(mdo->invocation_counter()); diff -r c60f69931e1a -r 8df6ddda8090 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Apr 11 21:54:46 2013 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Apr 15 21:25:23 2013 -0400 @@ -77,6 +77,7 @@ #include "oops/klass.hpp" #include "oops/markOop.hpp" #include "oops/methodData.hpp" +#include "oops/methodCounters.hpp" #include "oops/method.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" @@ -348,16 +349,17 @@ nonstatic_field(MethodData, _arg_local, intx) \ nonstatic_field(MethodData, _arg_stack, intx) \ nonstatic_field(MethodData, _arg_returned, intx) \ - nonstatic_field(Method, _constMethod, ConstMethod*) \ - nonstatic_field(Method, _method_data, MethodData*) \ - nonstatic_field(Method, _interpreter_invocation_count, int) \ + nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \ + nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \ + nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \ + nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ + nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ + nonstatic_field(Method, _constMethod, ConstMethod*) \ + nonstatic_field(Method, _method_data, MethodData*) \ + nonstatic_field(Method, _method_counters, MethodCounters*) \ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _method_size, u2) \ - nonstatic_field(Method, _interpreter_throwout_count, u2) \ - nonstatic_field(Method, _number_of_breakpoints, u2) \ - nonstatic_field(Method, _invocation_counter, InvocationCounter) \ - nonstatic_field(Method, _backedge_counter, InvocationCounter) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -1382,6 +1384,7 @@ declare_type(ConstantPoolCache, MetaspaceObj) \ declare_type(MethodData, Metadata) \ declare_type(Method, Metadata) \ + declare_type(MethodCounters, MetaspaceObj) \ declare_type(ConstMethod, MetaspaceObj) \ \ declare_toplevel_type(Symbol) \