mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 11:34:38 +02:00
Merge
This commit is contained in:
commit
f9b921bd25
63 changed files with 2247 additions and 831 deletions
|
@ -32,12 +32,10 @@ import sun.jvm.hotspot.types.*;
|
||||||
import sun.jvm.hotspot.utilities.*;
|
import sun.jvm.hotspot.utilities.*;
|
||||||
|
|
||||||
public class CodeCache {
|
public class CodeCache {
|
||||||
private static AddressField heapField;
|
private static GrowableArray<CodeHeap> heapArray;
|
||||||
private static AddressField scavengeRootNMethodsField;
|
private static AddressField scavengeRootNMethodsField;
|
||||||
private static VirtualConstructor virtualConstructor;
|
private static VirtualConstructor virtualConstructor;
|
||||||
|
|
||||||
private CodeHeap heap;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
VM.registerVMInitializedObserver(new Observer() {
|
VM.registerVMInitializedObserver(new Observer() {
|
||||||
public void update(Observable o, Object data) {
|
public void update(Observable o, Object data) {
|
||||||
|
@ -49,7 +47,10 @@ public class CodeCache {
|
||||||
private static synchronized void initialize(TypeDataBase db) {
|
private static synchronized void initialize(TypeDataBase db) {
|
||||||
Type type = db.lookupType("CodeCache");
|
Type type = db.lookupType("CodeCache");
|
||||||
|
|
||||||
heapField = type.getAddressField("_heap");
|
// Get array of CodeHeaps
|
||||||
|
AddressField heapsField = type.getAddressField("_heaps");
|
||||||
|
heapArray = GrowableArray.create(heapsField.getValue(), new StaticBaseConstructor<CodeHeap>(CodeHeap.class));
|
||||||
|
|
||||||
scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
|
scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
|
||||||
|
|
||||||
virtualConstructor = new VirtualConstructor(db);
|
virtualConstructor = new VirtualConstructor(db);
|
||||||
|
@ -67,16 +68,17 @@ public class CodeCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeCache() {
|
|
||||||
heap = (CodeHeap) VMObjectFactory.newObject(CodeHeap.class, heapField.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public NMethod scavengeRootMethods() {
|
public NMethod scavengeRootMethods() {
|
||||||
return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
|
return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(Address p) {
|
public boolean contains(Address p) {
|
||||||
return getHeap().contains(p);
|
for (int i = 0; i < heapArray.length(); ++i) {
|
||||||
|
if (heapArray.at(i).contains(p)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** When VM.getVM().isDebugging() returns true, this behaves like
|
/** When VM.getVM().isDebugging() returns true, this behaves like
|
||||||
|
@ -97,14 +99,24 @@ public class CodeCache {
|
||||||
|
|
||||||
public CodeBlob findBlobUnsafe(Address start) {
|
public CodeBlob findBlobUnsafe(Address start) {
|
||||||
CodeBlob result = null;
|
CodeBlob result = null;
|
||||||
|
CodeHeap containing_heap = null;
|
||||||
|
for (int i = 0; i < heapArray.length(); ++i) {
|
||||||
|
if (heapArray.at(i).contains(start)) {
|
||||||
|
containing_heap = heapArray.at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (containing_heap == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = (CodeBlob) virtualConstructor.instantiateWrapperFor(getHeap().findStart(start));
|
result = (CodeBlob) virtualConstructor.instantiateWrapperFor(containing_heap.findStart(start));
|
||||||
}
|
}
|
||||||
catch (WrongTypeException wte) {
|
catch (WrongTypeException wte) {
|
||||||
Address cbAddr = null;
|
Address cbAddr = null;
|
||||||
try {
|
try {
|
||||||
cbAddr = getHeap().findStart(start);
|
cbAddr = containing_heap.findStart(start);
|
||||||
}
|
}
|
||||||
catch (Exception findEx) {
|
catch (Exception findEx) {
|
||||||
findEx.printStackTrace();
|
findEx.printStackTrace();
|
||||||
|
@ -167,16 +179,16 @@ public class CodeCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void iterate(CodeCacheVisitor visitor) {
|
public void iterate(CodeCacheVisitor visitor) {
|
||||||
CodeHeap heap = getHeap();
|
visitor.prologue(lowBound(), highBound());
|
||||||
Address ptr = heap.begin();
|
|
||||||
Address end = heap.end();
|
|
||||||
|
|
||||||
visitor.prologue(ptr, end);
|
|
||||||
CodeBlob lastBlob = null;
|
CodeBlob lastBlob = null;
|
||||||
while (ptr != null && ptr.lessThan(end)) {
|
|
||||||
|
for (int i = 0; i < heapArray.length(); ++i) {
|
||||||
|
CodeHeap current_heap = heapArray.at(i);
|
||||||
|
Address ptr = current_heap.begin();
|
||||||
|
while (ptr != null && ptr.lessThan(current_heap.end())) {
|
||||||
try {
|
try {
|
||||||
// Use findStart to get a pointer inside blob other findBlob asserts
|
// Use findStart to get a pointer inside blob other findBlob asserts
|
||||||
CodeBlob blob = findBlobUnsafe(heap.findStart(ptr));
|
CodeBlob blob = findBlobUnsafe(current_heap.findStart(ptr));
|
||||||
if (blob != null) {
|
if (blob != null) {
|
||||||
visitor.visit(blob);
|
visitor.visit(blob);
|
||||||
if (blob == lastBlob) {
|
if (blob == lastBlob) {
|
||||||
|
@ -187,12 +199,13 @@ public class CodeCache {
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
Address next = heap.nextBlock(ptr);
|
Address next = current_heap.nextBlock(ptr);
|
||||||
if (next != null && next.lessThan(ptr)) {
|
if (next != null && next.lessThan(ptr)) {
|
||||||
throw new InternalError("pointer moved backwards");
|
throw new InternalError("pointer moved backwards");
|
||||||
}
|
}
|
||||||
ptr = next;
|
ptr = next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
visitor.epilogue();
|
visitor.epilogue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +213,23 @@ public class CodeCache {
|
||||||
// Internals only below this point
|
// Internals only below this point
|
||||||
//
|
//
|
||||||
|
|
||||||
private CodeHeap getHeap() {
|
private Address lowBound() {
|
||||||
return heap;
|
Address low = heapArray.at(0).begin();
|
||||||
|
for (int i = 1; i < heapArray.length(); ++i) {
|
||||||
|
if (heapArray.at(i).begin().lessThan(low)) {
|
||||||
|
low = heapArray.at(i).begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Address highBound() {
|
||||||
|
Address high = heapArray.at(0).end();
|
||||||
|
for (int i = 1; i < heapArray.length(); ++i) {
|
||||||
|
if (heapArray.at(i).end().greaterThan(high)) {
|
||||||
|
high = heapArray.at(i).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return high;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
SUNWprivate_1.1 {
|
SUNWprivate_1.1 {
|
||||||
global:
|
global:
|
||||||
# Dtrace support
|
# Dtrace support
|
||||||
__1cJCodeCacheF_heap_;
|
__1cJCodeCacheG_heaps_;
|
||||||
__1cIUniverseO_collectedHeap_;
|
__1cIUniverseO_collectedHeap_;
|
||||||
__1cGMethodG__vtbl_;
|
__1cGMethodG__vtbl_;
|
||||||
__1cHnmethodG__vtbl_;
|
__1cHnmethodG__vtbl_;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
SUNWprivate_1.1 {
|
SUNWprivate_1.1 {
|
||||||
global:
|
global:
|
||||||
# Dtrace support
|
# Dtrace support
|
||||||
__1cJCodeCacheF_heap_;
|
__1cJCodeCacheG_heaps_;
|
||||||
__1cIUniverseO_collectedHeap_;
|
__1cIUniverseO_collectedHeap_;
|
||||||
__1cGMethodG__vtbl_;
|
__1cGMethodG__vtbl_;
|
||||||
__1cHnmethodG__vtbl_;
|
__1cHnmethodG__vtbl_;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
SUNWprivate_1.1 {
|
SUNWprivate_1.1 {
|
||||||
global:
|
global:
|
||||||
# Dtrace support
|
# Dtrace support
|
||||||
__1cJCodeCacheF_heap_;
|
__1cJCodeCacheG_heaps_;
|
||||||
__1cIUniverseO_collectedHeap_;
|
__1cIUniverseO_collectedHeap_;
|
||||||
__1cGMethodG__vtbl_;
|
__1cGMethodG__vtbl_;
|
||||||
__1cHnmethodG__vtbl_;
|
__1cHnmethodG__vtbl_;
|
||||||
|
|
|
@ -79,6 +79,9 @@ define_pd_global(bool, OptoScheduling, false);
|
||||||
|
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
|
define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 256*M);
|
define_pd_global(intx, ReservedCodeCacheSize, 256*M);
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 125*M);
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 126*M);
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
|
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
|
||||||
|
|
||||||
// Ergonomics related flags
|
// Ergonomics related flags
|
||||||
|
|
|
@ -47,6 +47,9 @@ define_pd_global(bool, ProfileInterpreter, false);
|
||||||
define_pd_global(intx, FreqInlineSize, 325 );
|
define_pd_global(intx, FreqInlineSize, 325 );
|
||||||
define_pd_global(bool, ResizeTLAB, true );
|
define_pd_global(bool, ResizeTLAB, true );
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 13*M );
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 14*M );
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
||||||
define_pd_global(uintx, CodeCacheMinBlockLength, 1);
|
define_pd_global(uintx, CodeCacheMinBlockLength, 1);
|
||||||
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
||||||
|
|
|
@ -74,6 +74,9 @@ define_pd_global(bool, OptoScheduling, true);
|
||||||
// InitialCodeCacheSize derived from specjbb2000 run.
|
// InitialCodeCacheSize derived from specjbb2000 run.
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
|
define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 48*M);
|
define_pd_global(intx, ReservedCodeCacheSize, 48*M);
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 21*M);
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 22*M);
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
|
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
|
||||||
|
|
||||||
// Ergonomics related flags
|
// Ergonomics related flags
|
||||||
|
@ -82,6 +85,9 @@ define_pd_global(uint64_t,MaxRAM, 128ULL*G);
|
||||||
// InitialCodeCacheSize derived from specjbb2000 run.
|
// InitialCodeCacheSize derived from specjbb2000 run.
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize
|
define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M);
|
define_pd_global(intx, ReservedCodeCacheSize, 32*M);
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 13*M);
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 14*M);
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K);
|
define_pd_global(intx, CodeCacheExpansionSize, 32*K);
|
||||||
// Ergonomics related flags
|
// Ergonomics related flags
|
||||||
define_pd_global(uint64_t,MaxRAM, 4ULL*G);
|
define_pd_global(uint64_t,MaxRAM, 4ULL*G);
|
||||||
|
|
|
@ -1128,14 +1128,17 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||||
// Hoist any int/ptr/long's in the first 6 to int regs.
|
// Hoist any int/ptr/long's in the first 6 to int regs.
|
||||||
// Hoist any flt/dbl's in the first 16 dbl regs.
|
// Hoist any flt/dbl's in the first 16 dbl regs.
|
||||||
int j = 0; // Count of actual args, not HALVES
|
int j = 0; // Count of actual args, not HALVES
|
||||||
|
VMRegPair param_array_reg; // location of the argument in the parameter array
|
||||||
for (int i = 0; i < total_args_passed; i++, j++) {
|
for (int i = 0; i < total_args_passed; i++, j++) {
|
||||||
|
param_array_reg.set_bad();
|
||||||
switch (sig_bt[i]) {
|
switch (sig_bt[i]) {
|
||||||
case T_BOOLEAN:
|
case T_BOOLEAN:
|
||||||
case T_BYTE:
|
case T_BYTE:
|
||||||
case T_CHAR:
|
case T_CHAR:
|
||||||
case T_INT:
|
case T_INT:
|
||||||
case T_SHORT:
|
case T_SHORT:
|
||||||
regs[i].set1( int_stk_helper( j ) ); break;
|
regs[i].set1(int_stk_helper(j));
|
||||||
|
break;
|
||||||
case T_LONG:
|
case T_LONG:
|
||||||
assert(sig_bt[i+1] == T_VOID, "expecting half");
|
assert(sig_bt[i+1] == T_VOID, "expecting half");
|
||||||
case T_ADDRESS: // raw pointers, like current thread, for VM calls
|
case T_ADDRESS: // raw pointers, like current thread, for VM calls
|
||||||
|
@ -1145,34 +1148,62 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||||
regs[i].set2(int_stk_helper(j));
|
regs[i].set2(int_stk_helper(j));
|
||||||
break;
|
break;
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
|
// Per SPARC Compliance Definition 2.4.1, page 3P-12 available here
|
||||||
|
// http://www.sparc.org/wp-content/uploads/2014/01/SCD.2.4.1.pdf.gz
|
||||||
|
//
|
||||||
|
// "When a callee prototype exists, and does not indicate variable arguments,
|
||||||
|
// floating-point values assigned to locations %sp+BIAS+128 through %sp+BIAS+248
|
||||||
|
// will be promoted to floating-point registers"
|
||||||
|
//
|
||||||
|
// By "promoted" it means that the argument is located in two places, an unused
|
||||||
|
// spill slot in the "parameter array" (starts at %sp+BIAS+128), and a live
|
||||||
|
// float register. In most cases, there are 6 or fewer arguments of any type,
|
||||||
|
// and the standard parameter array slots (%sp+BIAS+128 to %sp+BIAS+176 exclusive)
|
||||||
|
// serve as shadow slots. Per the spec floating point registers %d6 to %d16
|
||||||
|
// require slots beyond that (up to %sp+BIAS+248).
|
||||||
|
//
|
||||||
|
{
|
||||||
|
// V9ism: floats go in ODD registers and stack slots
|
||||||
|
int float_index = 1 + (j << 1);
|
||||||
|
param_array_reg.set1(VMRegImpl::stack2reg(float_index));
|
||||||
if (j < 16) {
|
if (j < 16) {
|
||||||
// V9ism: floats go in ODD registers
|
regs[i].set1(as_FloatRegister(float_index)->as_VMReg());
|
||||||
regs[i].set1(as_FloatRegister(1 + (j<<1))->as_VMReg());
|
|
||||||
} else {
|
} else {
|
||||||
// V9ism: floats go in ODD stack slot
|
regs[i] = param_array_reg;
|
||||||
regs[i].set1(VMRegImpl::stack2reg(1 + (j<<1)));
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case T_DOUBLE:
|
case T_DOUBLE:
|
||||||
|
{
|
||||||
assert(sig_bt[i + 1] == T_VOID, "expecting half");
|
assert(sig_bt[i + 1] == T_VOID, "expecting half");
|
||||||
|
// V9ism: doubles go in EVEN/ODD regs and stack slots
|
||||||
|
int double_index = (j << 1);
|
||||||
|
param_array_reg.set2(VMRegImpl::stack2reg(double_index));
|
||||||
if (j < 16) {
|
if (j < 16) {
|
||||||
// V9ism: doubles go in EVEN/ODD regs
|
regs[i].set2(as_FloatRegister(double_index)->as_VMReg());
|
||||||
regs[i].set2(as_FloatRegister(j<<1)->as_VMReg());
|
|
||||||
} else {
|
} else {
|
||||||
// V9ism: doubles go in EVEN/ODD stack slots
|
// V9ism: doubles go in EVEN/ODD stack slots
|
||||||
regs[i].set2(VMRegImpl::stack2reg(j<<1));
|
regs[i] = param_array_reg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case T_VOID: regs[i].set_bad(); j--; break; // Do not count HALVES
|
case T_VOID:
|
||||||
|
regs[i].set_bad();
|
||||||
|
j--;
|
||||||
|
break; // Do not count HALVES
|
||||||
default:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
if (regs[i].first()->is_stack()) {
|
// Keep track of the deepest parameter array slot.
|
||||||
int off = regs[i].first()->reg2stack();
|
if (!param_array_reg.first()->is_valid()) {
|
||||||
|
param_array_reg = regs[i];
|
||||||
|
}
|
||||||
|
if (param_array_reg.first()->is_stack()) {
|
||||||
|
int off = param_array_reg.first()->reg2stack();
|
||||||
if (off > max_stack_slots) max_stack_slots = off;
|
if (off > max_stack_slots) max_stack_slots = off;
|
||||||
}
|
}
|
||||||
if (regs[i].second()->is_stack()) {
|
if (param_array_reg.second()->is_stack()) {
|
||||||
int off = regs[i].second()->reg2stack();
|
int off = param_array_reg.second()->reg2stack();
|
||||||
if (off > max_stack_slots) max_stack_slots = off;
|
if (off > max_stack_slots) max_stack_slots = off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1358,10 +1389,9 @@ static void object_move(MacroAssembler* masm,
|
||||||
const Register rHandle = L5;
|
const Register rHandle = L5;
|
||||||
int oop_slot = rOop->input_number() * VMRegImpl::slots_per_word + oop_handle_offset;
|
int oop_slot = rOop->input_number() * VMRegImpl::slots_per_word + oop_handle_offset;
|
||||||
int offset = oop_slot * VMRegImpl::stack_slot_size;
|
int offset = oop_slot * VMRegImpl::stack_slot_size;
|
||||||
Label skip;
|
|
||||||
__ st_ptr(rOop, SP, offset + STACK_BIAS);
|
__ st_ptr(rOop, SP, offset + STACK_BIAS);
|
||||||
if (is_receiver) {
|
if (is_receiver) {
|
||||||
*receiver_offset = oop_slot * VMRegImpl::stack_slot_size;
|
*receiver_offset = offset;
|
||||||
}
|
}
|
||||||
map->set_oop(VMRegImpl::stack2reg(oop_slot));
|
map->set_oop(VMRegImpl::stack2reg(oop_slot));
|
||||||
__ add(SP, offset + STACK_BIAS, rHandle);
|
__ add(SP, offset + STACK_BIAS, rHandle);
|
||||||
|
|
|
@ -1989,7 +1989,7 @@ void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
|
||||||
// to implement the UseStrictFP mode.
|
// to implement the UseStrictFP mode.
|
||||||
const bool Matcher::strict_fp_requires_explicit_rounding = false;
|
const bool Matcher::strict_fp_requires_explicit_rounding = false;
|
||||||
|
|
||||||
// Are floats conerted to double when stored to stack during deoptimization?
|
// Are floats converted to double when stored to stack during deoptimization?
|
||||||
// Sparc does not handle callee-save floats.
|
// Sparc does not handle callee-save floats.
|
||||||
bool Matcher::float_in_double() { return false; }
|
bool Matcher::float_in_double() { return false; }
|
||||||
|
|
||||||
|
@ -3218,7 +3218,7 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI r
|
||||||
// are owned by the CALLEE. Holes should not be nessecary in the
|
// are owned by the CALLEE. Holes should not be nessecary in the
|
||||||
// incoming area, as the Java calling convention is completely under
|
// incoming area, as the Java calling convention is completely under
|
||||||
// the control of the AD file. Doubles can be sorted and packed to
|
// the control of the AD file. Doubles can be sorted and packed to
|
||||||
// avoid holes. Holes in the outgoing arguments may be nessecary for
|
// avoid holes. Holes in the outgoing arguments may be necessary for
|
||||||
// varargs C calling conventions.
|
// varargs C calling conventions.
|
||||||
// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is
|
// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is
|
||||||
// even aligned with pad0 as needed.
|
// even aligned with pad0 as needed.
|
||||||
|
@ -3284,7 +3284,7 @@ frame %{
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Body of function which returns an OptoRegs array locating
|
// Body of function which returns an OptoRegs array locating
|
||||||
// arguments either in registers or in stack slots for callin
|
// arguments either in registers or in stack slots for calling
|
||||||
// C.
|
// C.
|
||||||
c_calling_convention %{
|
c_calling_convention %{
|
||||||
// This is obviously always outgoing
|
// This is obviously always outgoing
|
||||||
|
|
|
@ -47,6 +47,9 @@ define_pd_global(intx, FreqInlineSize, 325 );
|
||||||
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
|
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 13*M );
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 14*M );
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(bool, ProfileInterpreter, false);
|
define_pd_global(bool, ProfileInterpreter, false);
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
||||||
define_pd_global(uintx, CodeCacheMinBlockLength, 1);
|
define_pd_global(uintx, CodeCacheMinBlockLength, 1);
|
||||||
|
|
|
@ -84,6 +84,9 @@ define_pd_global(bool, OptoScheduling, false);
|
||||||
define_pd_global(bool, OptoBundling, false);
|
define_pd_global(bool, OptoBundling, false);
|
||||||
|
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 48*M);
|
define_pd_global(intx, ReservedCodeCacheSize, 48*M);
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 21*M);
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 22*M);
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(uintx, CodeCacheMinBlockLength, 4);
|
define_pd_global(uintx, CodeCacheMinBlockLength, 4);
|
||||||
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ define_pd_global(uintx, NewRatio, 12 );
|
||||||
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
|
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 13*M );
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 14*M );
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 5*M );
|
||||||
define_pd_global(bool, ProfileInterpreter, false);
|
define_pd_global(bool, ProfileInterpreter, false);
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
||||||
define_pd_global(uintx, CodeCacheMinBlockLength, 1 );
|
define_pd_global(uintx, CodeCacheMinBlockLength, 1 );
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
* we link this program with -z nodefs .
|
* we link this program with -z nodefs .
|
||||||
*
|
*
|
||||||
* But for 'debug1' and 'fastdebug1' we still have to provide
|
* But for 'debug1' and 'fastdebug1' we still have to provide
|
||||||
* a particular workaround for the following symbols bellow.
|
* a particular workaround for the following symbols below.
|
||||||
* It will be good to find out a generic way in the future.
|
* It will be good to find out a generic way in the future.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -87,21 +87,24 @@ StubQueue* AbstractInterpreter::_code = NULL;
|
||||||
#endif /* ASSERT */
|
#endif /* ASSERT */
|
||||||
#endif /* COMPILER1 */
|
#endif /* COMPILER1 */
|
||||||
|
|
||||||
#define GEN_OFFS(Type,Name) \
|
#define GEN_OFFS_NAME(Type,Name,OutputType) \
|
||||||
switch(gen_variant) { \
|
switch(gen_variant) { \
|
||||||
case GEN_OFFSET: \
|
case GEN_OFFSET: \
|
||||||
printf("#define OFFSET_%-33s %ld\n", \
|
printf("#define OFFSET_%-33s %ld\n", \
|
||||||
#Type #Name, offset_of(Type, Name)); \
|
#OutputType #Name, offset_of(Type, Name)); \
|
||||||
break; \
|
break; \
|
||||||
case GEN_INDEX: \
|
case GEN_INDEX: \
|
||||||
printf("#define IDX_OFFSET_%-33s %d\n", \
|
printf("#define IDX_OFFSET_%-33s %d\n", \
|
||||||
#Type #Name, index++); \
|
#OutputType #Name, index++); \
|
||||||
break; \
|
break; \
|
||||||
case GEN_TABLE: \
|
case GEN_TABLE: \
|
||||||
printf("\tOFFSET_%s,\n", #Type #Name); \
|
printf("\tOFFSET_%s,\n", #OutputType #Name); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GEN_OFFS(Type,Name) \
|
||||||
|
GEN_OFFS_NAME(Type,Name,Type)
|
||||||
|
|
||||||
#define GEN_SIZE(Type) \
|
#define GEN_SIZE(Type) \
|
||||||
switch(gen_variant) { \
|
switch(gen_variant) { \
|
||||||
case GEN_OFFSET: \
|
case GEN_OFFSET: \
|
||||||
|
@ -246,6 +249,11 @@ int generateJvmOffsets(GEN_variant gen_variant) {
|
||||||
GEN_OFFS(VirtualSpace, _high);
|
GEN_OFFS(VirtualSpace, _high);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
/* We need to use different names here because of the template parameter */
|
||||||
|
GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _data, GrowableArray_CodeHeap);
|
||||||
|
GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _len, GrowableArray_CodeHeap);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
GEN_OFFS(CodeBlob, _name);
|
GEN_OFFS(CodeBlob, _name);
|
||||||
GEN_OFFS(CodeBlob, _header_size);
|
GEN_OFFS(CodeBlob, _header_size);
|
||||||
GEN_OFFS(CodeBlob, _content_offset);
|
GEN_OFFS(CodeBlob, _content_offset);
|
||||||
|
|
|
@ -43,7 +43,9 @@
|
||||||
|
|
||||||
extern pointer __JvmOffsets;
|
extern pointer __JvmOffsets;
|
||||||
|
|
||||||
extern pointer __1cJCodeCacheF_heap_;
|
/* GrowableArray<CodeHeaps*>* */
|
||||||
|
extern pointer __1cJCodeCacheG_heaps_;
|
||||||
|
|
||||||
extern pointer __1cIUniverseO_collectedHeap_;
|
extern pointer __1cIUniverseO_collectedHeap_;
|
||||||
|
|
||||||
extern pointer __1cHnmethodG__vtbl_;
|
extern pointer __1cHnmethodG__vtbl_;
|
||||||
|
@ -95,8 +97,8 @@ dtrace:helper:ustack:
|
||||||
/!init_done && !this->done/
|
/!init_done && !this->done/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
init_done = 1;
|
|
||||||
|
|
||||||
|
copyin_offset(POINTER_SIZE);
|
||||||
copyin_offset(COMPILER);
|
copyin_offset(COMPILER);
|
||||||
copyin_offset(OFFSET_CollectedHeap_reserved);
|
copyin_offset(OFFSET_CollectedHeap_reserved);
|
||||||
copyin_offset(OFFSET_MemRegion_start);
|
copyin_offset(OFFSET_MemRegion_start);
|
||||||
|
@ -122,6 +124,9 @@ dtrace:helper:ustack:
|
||||||
copyin_offset(OFFSET_CodeHeap_segmap);
|
copyin_offset(OFFSET_CodeHeap_segmap);
|
||||||
copyin_offset(OFFSET_CodeHeap_log2_segment_size);
|
copyin_offset(OFFSET_CodeHeap_log2_segment_size);
|
||||||
|
|
||||||
|
copyin_offset(OFFSET_GrowableArray_CodeHeap_data);
|
||||||
|
copyin_offset(OFFSET_GrowableArray_CodeHeap_len);
|
||||||
|
|
||||||
copyin_offset(OFFSET_VirtualSpace_low);
|
copyin_offset(OFFSET_VirtualSpace_low);
|
||||||
copyin_offset(OFFSET_VirtualSpace_high);
|
copyin_offset(OFFSET_VirtualSpace_high);
|
||||||
|
|
||||||
|
@ -152,25 +157,13 @@ dtrace:helper:ustack:
|
||||||
#error "Don't know architecture"
|
#error "Don't know architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_);
|
/* Read address of GrowableArray<CodeHeaps*> */
|
||||||
|
this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_);
|
||||||
|
/* Read address of _data array field in GrowableArray */
|
||||||
|
this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data);
|
||||||
|
this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len);
|
||||||
|
|
||||||
/* Reading volatile values */
|
this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
|
||||||
this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
|
||||||
|
|
||||||
this->CodeCache_high = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
|
||||||
|
|
||||||
this->CodeCache_segmap_low = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
|
|
||||||
|
|
||||||
this->CodeCache_segmap_high = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_high);
|
|
||||||
|
|
||||||
this->CodeHeap_log2_segment_size = copyin_uint32(
|
|
||||||
this->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size);
|
|
||||||
|
|
||||||
this->Method_vtbl = (pointer) &``__1cNMethodG__vtbl_;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get Java heap bounds
|
* Get Java heap bounds
|
||||||
|
@ -187,21 +180,152 @@ dtrace:helper:ustack:
|
||||||
this->heap_end = this->heap_start + this->heap_size;
|
this->heap_end = this->heap_start + this->heap_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in
|
||||||
|
* the code cache. If more code heaps are added the following probes have to
|
||||||
|
* be extended. This is done by simply adding a probe to get the heap bounds
|
||||||
|
* and another probe to set the code heap address of the newly created heap.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----- BEGIN: Get bounds of code heaps -----
|
||||||
|
*/
|
||||||
dtrace:helper:ustack:
|
dtrace:helper:ustack:
|
||||||
/!this->done &&
|
/init_done < 1 && this->number_of_heaps >= 1 && !this->done/
|
||||||
this->CodeCache_low <= this->pc && this->pc < this->CodeCache_high/
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/* CodeHeap 1 */
|
||||||
|
init_done = 1;
|
||||||
|
this->code_heap1_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap1_low = copyin_ptr(this->code_heap1_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap1_high = copyin_ptr(this->code_heap1_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 2 && this->number_of_heaps >= 2 && !this->done/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/* CodeHeap 2 */
|
||||||
|
init_done = 2;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap2_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap2_low = copyin_ptr(this->code_heap2_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap2_high = copyin_ptr(this->code_heap2_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 3 && this->number_of_heaps >= 3 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 3 */
|
||||||
|
init_done = 3;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap3_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap3_low = copyin_ptr(this->code_heap3_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap3_high = copyin_ptr(this->code_heap3_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 4 && this->number_of_heaps >= 4 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 4 */
|
||||||
|
init_done = 4;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap4_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap4_low = copyin_ptr(this->code_heap4_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap4_high = copyin_ptr(this->code_heap4_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 5 && this->number_of_heaps >= 5 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 5 */
|
||||||
|
init_done = 5;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap5_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap5_low = copyin_ptr(this->code_heap5_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap5_high = copyin_ptr(this->code_heap5_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ----- END: Get bounds of code heaps -----
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----- BEGIN: Get address of the code heap pc points to -----
|
||||||
|
*/
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
this->codecache = 1;
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap1_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap2_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap3_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap4_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap5_address;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ----- END: Get address of the code heap pc points to -----
|
||||||
|
*/
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->codecache/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/*
|
||||||
|
* Get code heap configuration
|
||||||
|
*/
|
||||||
|
this->code_heap_low = copyin_ptr(this->code_heap_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap_segmap_low = copyin_ptr(this->code_heap_address +
|
||||||
|
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap_log2_segment_size = copyin_uint32(
|
||||||
|
this->code_heap_address + OFFSET_CodeHeap_log2_segment_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find start.
|
* Find start
|
||||||
*/
|
*/
|
||||||
this->segment = (this->pc - this->CodeCache_low) >>
|
this->segment = (this->pc - this->code_heap_low) >>
|
||||||
this->CodeHeap_log2_segment_size;
|
this->code_heap_log2_segment_size;
|
||||||
this->block = this->CodeCache_segmap_low;
|
this->block = this->code_heap_segmap_low;
|
||||||
this->tag = copyin_uchar(this->block + this->segment);
|
this->tag = copyin_uchar(this->block + this->segment);
|
||||||
"second";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dtrace:helper:ustack:
|
dtrace:helper:ustack:
|
||||||
|
@ -256,8 +380,8 @@ dtrace:helper:ustack:
|
||||||
/!this->done && this->codecache/
|
/!this->done && this->codecache/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
this->block = this->CodeCache_low +
|
this->block = this->code_heap_low +
|
||||||
(this->segment << this->CodeHeap_log2_segment_size);
|
(this->segment << this->code_heap_log2_segment_size);
|
||||||
this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
|
this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,16 +150,18 @@ struct jvm_agent {
|
||||||
uint64_t Use_Compressed_Oops_address;
|
uint64_t Use_Compressed_Oops_address;
|
||||||
uint64_t Universe_narrow_oop_base_address;
|
uint64_t Universe_narrow_oop_base_address;
|
||||||
uint64_t Universe_narrow_oop_shift_address;
|
uint64_t Universe_narrow_oop_shift_address;
|
||||||
uint64_t CodeCache_heap_address;
|
uint64_t CodeCache_heaps_address;
|
||||||
|
|
||||||
/* Volatiles */
|
/* Volatiles */
|
||||||
uint8_t Use_Compressed_Oops;
|
uint8_t Use_Compressed_Oops;
|
||||||
uint64_t Universe_narrow_oop_base;
|
uint64_t Universe_narrow_oop_base;
|
||||||
uint32_t Universe_narrow_oop_shift;
|
uint32_t Universe_narrow_oop_shift;
|
||||||
uint64_t CodeCache_low;
|
// Code cache heaps
|
||||||
uint64_t CodeCache_high;
|
int32_t Number_of_heaps;
|
||||||
uint64_t CodeCache_segmap_low;
|
uint64_t* Heap_low;
|
||||||
uint64_t CodeCache_segmap_high;
|
uint64_t* Heap_high;
|
||||||
|
uint64_t* Heap_segmap_low;
|
||||||
|
uint64_t* Heap_segmap_high;
|
||||||
|
|
||||||
int32_t SIZE_CodeCache_log2_segment;
|
int32_t SIZE_CodeCache_log2_segment;
|
||||||
|
|
||||||
|
@ -278,8 +280,9 @@ static int parse_vmstructs(jvm_agent_t* J) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
|
if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
|
||||||
if (strcmp("_heap", vmp->fieldName) == 0) {
|
/* Read _heaps field of type GrowableArray<CodeHeaps*>* */
|
||||||
err = read_pointer(J, vmp->address, &J->CodeCache_heap_address);
|
if (strcmp("_heaps", vmp->fieldName) == 0) {
|
||||||
|
err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address);
|
||||||
}
|
}
|
||||||
} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
|
} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
|
||||||
if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
|
if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
|
||||||
|
@ -318,7 +321,9 @@ static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_volatiles(jvm_agent_t* J) {
|
static int read_volatiles(jvm_agent_t* J) {
|
||||||
uint64_t ptr;
|
int i;
|
||||||
|
uint64_t array_data;
|
||||||
|
uint64_t code_heap_address;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
|
err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
|
||||||
|
@ -334,20 +339,43 @@ static int read_volatiles(jvm_agent_t* J) {
|
||||||
err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
|
err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
|
/* CodeCache_heaps_address points to GrowableArray<CodeHeaps*>, read _data field
|
||||||
OFFSET_VirtualSpace_low, &J->CodeCache_low);
|
pointing to the first entry of type CodeCache* in the array */
|
||||||
CHECK_FAIL(err);
|
err = read_pointer(J, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_data, &array_data);
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
|
/* Read _len field containing the number of code heaps */
|
||||||
OFFSET_VirtualSpace_high, &J->CodeCache_high);
|
err = ps_pread(J->P, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_len,
|
||||||
CHECK_FAIL(err);
|
&J->Number_of_heaps, sizeof(J->Number_of_heaps));
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
|
|
||||||
OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low);
|
/* Allocate memory for heap configurations */
|
||||||
CHECK_FAIL(err);
|
J->Heap_low = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
|
J->Heap_high = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high);
|
J->Heap_segmap_low = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
|
J->Heap_segmap_high = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
|
|
||||||
|
/* Read code heap configurations */
|
||||||
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
|
/* Read address of heap */
|
||||||
|
err = read_pointer(J, array_data, &code_heap_address);
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size,
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
|
||||||
|
OFFSET_VirtualSpace_low, &J->Heap_low[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
|
||||||
|
OFFSET_VirtualSpace_high, &J->Heap_high[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
|
||||||
|
OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
|
||||||
|
OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
|
/* Increment pointer to next entry */
|
||||||
|
array_data = array_data + POINTER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ps_pread(J->P, code_heap_address + OFFSET_CodeHeap_log2_segment_size,
|
||||||
&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
|
&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
|
@ -357,28 +385,38 @@ static int read_volatiles(jvm_agent_t* J) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int codeheap_contains(int heap_num, jvm_agent_t* J, uint64_t ptr) {
|
||||||
|
return (J->Heap_low[heap_num] <= ptr && ptr < J->Heap_high[heap_num]);
|
||||||
|
}
|
||||||
|
|
||||||
static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
|
static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
|
||||||
/* make sure the code cache is up to date */
|
int i;
|
||||||
return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high);
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
|
if (codeheap_contains(i, J, ptr)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t segment_for(jvm_agent_t* J, uint64_t p) {
|
static uint64_t segment_for(int heap_num, jvm_agent_t* J, uint64_t p) {
|
||||||
return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment;
|
return (p - J->Heap_low[heap_num]) >> J->SIZE_CodeCache_log2_segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t block_at(jvm_agent_t* J, int i) {
|
static uint64_t block_at(int heap_num, jvm_agent_t* J, int i) {
|
||||||
return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment);
|
return J->Heap_low[heap_num] + (i << J->SIZE_CodeCache_log2_segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
int err;
|
int err;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
*startp = 0;
|
*startp = 0;
|
||||||
if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) {
|
if (codeheap_contains(i, J, ptr)) {
|
||||||
int32_t used;
|
int32_t used;
|
||||||
uint64_t segment = segment_for(J, ptr);
|
uint64_t segment = segment_for(i, J, ptr);
|
||||||
uint64_t block = J->CodeCache_segmap_low;
|
uint64_t block = J->Heap_segmap_low[i];
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
|
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
@ -389,7 +427,7 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
segment -= tag;
|
segment -= tag;
|
||||||
}
|
}
|
||||||
block = block_at(J, segment);
|
block = block_at(i, J, segment);
|
||||||
err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
|
err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
if (used) {
|
if (used) {
|
||||||
|
@ -397,6 +435,7 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PS_OK;
|
return PS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -82,21 +82,24 @@ StubQueue* AbstractInterpreter::_code = NULL;
|
||||||
#endif /* ASSERT */
|
#endif /* ASSERT */
|
||||||
#endif /* COMPILER1 */
|
#endif /* COMPILER1 */
|
||||||
|
|
||||||
#define GEN_OFFS(Type,Name) \
|
#define GEN_OFFS_NAME(Type,Name,OutputType) \
|
||||||
switch(gen_variant) { \
|
switch(gen_variant) { \
|
||||||
case GEN_OFFSET: \
|
case GEN_OFFSET: \
|
||||||
printf("#define OFFSET_%-33s %d\n", \
|
printf("#define OFFSET_%-33s %d\n", \
|
||||||
#Type #Name, offset_of(Type, Name)); \
|
#OutputType #Name, offset_of(Type, Name)); \
|
||||||
break; \
|
break; \
|
||||||
case GEN_INDEX: \
|
case GEN_INDEX: \
|
||||||
printf("#define IDX_OFFSET_%-33s %d\n", \
|
printf("#define IDX_OFFSET_%-33s %d\n", \
|
||||||
#Type #Name, index++); \
|
#OutputType #Name, index++); \
|
||||||
break; \
|
break; \
|
||||||
case GEN_TABLE: \
|
case GEN_TABLE: \
|
||||||
printf("\tOFFSET_%s,\n", #Type #Name); \
|
printf("\tOFFSET_%s,\n", #OutputType #Name); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GEN_OFFS(Type,Name) \
|
||||||
|
GEN_OFFS_NAME(Type,Name,Type)
|
||||||
|
|
||||||
#define GEN_SIZE(Type) \
|
#define GEN_SIZE(Type) \
|
||||||
switch(gen_variant) { \
|
switch(gen_variant) { \
|
||||||
case GEN_OFFSET: \
|
case GEN_OFFSET: \
|
||||||
|
@ -241,6 +244,11 @@ int generateJvmOffsets(GEN_variant gen_variant) {
|
||||||
GEN_OFFS(VirtualSpace, _high);
|
GEN_OFFS(VirtualSpace, _high);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
/* We need to use different names here because of the template parameter */
|
||||||
|
GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _data, GrowableArray_CodeHeap);
|
||||||
|
GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _len, GrowableArray_CodeHeap);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
GEN_OFFS(CodeBlob, _name);
|
GEN_OFFS(CodeBlob, _name);
|
||||||
GEN_OFFS(CodeBlob, _header_size);
|
GEN_OFFS(CodeBlob, _header_size);
|
||||||
GEN_OFFS(CodeBlob, _content_offset);
|
GEN_OFFS(CodeBlob, _content_offset);
|
||||||
|
|
|
@ -43,7 +43,9 @@
|
||||||
|
|
||||||
extern pointer __JvmOffsets;
|
extern pointer __JvmOffsets;
|
||||||
|
|
||||||
extern pointer __1cJCodeCacheF_heap_;
|
/* GrowableArray<CodeHeaps*>* */
|
||||||
|
extern pointer __1cJCodeCacheG_heaps_;
|
||||||
|
|
||||||
extern pointer __1cIUniverseO_collectedHeap_;
|
extern pointer __1cIUniverseO_collectedHeap_;
|
||||||
|
|
||||||
extern pointer __1cHnmethodG__vtbl_;
|
extern pointer __1cHnmethodG__vtbl_;
|
||||||
|
@ -95,8 +97,8 @@ dtrace:helper:ustack:
|
||||||
/!init_done && !this->done/
|
/!init_done && !this->done/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
init_done = 1;
|
|
||||||
|
|
||||||
|
copyin_offset(POINTER_SIZE);
|
||||||
copyin_offset(COMPILER);
|
copyin_offset(COMPILER);
|
||||||
copyin_offset(OFFSET_CollectedHeap_reserved);
|
copyin_offset(OFFSET_CollectedHeap_reserved);
|
||||||
copyin_offset(OFFSET_MemRegion_start);
|
copyin_offset(OFFSET_MemRegion_start);
|
||||||
|
@ -122,6 +124,9 @@ dtrace:helper:ustack:
|
||||||
copyin_offset(OFFSET_CodeHeap_segmap);
|
copyin_offset(OFFSET_CodeHeap_segmap);
|
||||||
copyin_offset(OFFSET_CodeHeap_log2_segment_size);
|
copyin_offset(OFFSET_CodeHeap_log2_segment_size);
|
||||||
|
|
||||||
|
copyin_offset(OFFSET_GrowableArray_CodeHeap_data);
|
||||||
|
copyin_offset(OFFSET_GrowableArray_CodeHeap_len);
|
||||||
|
|
||||||
copyin_offset(OFFSET_VirtualSpace_low);
|
copyin_offset(OFFSET_VirtualSpace_low);
|
||||||
copyin_offset(OFFSET_VirtualSpace_high);
|
copyin_offset(OFFSET_VirtualSpace_high);
|
||||||
|
|
||||||
|
@ -152,22 +157,11 @@ dtrace:helper:ustack:
|
||||||
#error "Don't know architecture"
|
#error "Don't know architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_);
|
/* Read address of GrowableArray<CodeHeaps*> */
|
||||||
|
this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_);
|
||||||
this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address +
|
/* Read address of _data array field in GrowableArray */
|
||||||
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data);
|
||||||
|
this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len);
|
||||||
this->CodeCache_high = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
|
||||||
|
|
||||||
this->CodeCache_segmap_low = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
|
|
||||||
|
|
||||||
this->CodeCache_segmap_high = copyin_ptr(this->CodeCache_heap_address +
|
|
||||||
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_high);
|
|
||||||
|
|
||||||
this->CodeHeap_log2_segment_size = copyin_uint32(
|
|
||||||
this->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size);
|
|
||||||
|
|
||||||
this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
|
this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
|
||||||
|
|
||||||
|
@ -186,21 +180,152 @@ dtrace:helper:ustack:
|
||||||
this->heap_end = this->heap_start + this->heap_size;
|
this->heap_end = this->heap_start + this->heap_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in
|
||||||
|
* the code cache. If more code heaps are added the following probes have to
|
||||||
|
* be extended. This is done by simply adding a probe to get the heap bounds
|
||||||
|
* and another probe to set the code heap address of the newly created heap.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----- BEGIN: Get bounds of code heaps -----
|
||||||
|
*/
|
||||||
dtrace:helper:ustack:
|
dtrace:helper:ustack:
|
||||||
/!this->done &&
|
/init_done < 1 && this->number_of_heaps >= 1 && !this->done/
|
||||||
this->CodeCache_low <= this->pc && this->pc < this->CodeCache_high/
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/* CodeHeap 1 */
|
||||||
|
init_done = 1;
|
||||||
|
this->code_heap1_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap1_low = copyin_ptr(this->code_heap1_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap1_high = copyin_ptr(this->code_heap1_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 2 && this->number_of_heaps >= 2 && !this->done/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/* CodeHeap 2 */
|
||||||
|
init_done = 2;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap2_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap2_low = copyin_ptr(this->code_heap2_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap2_high = copyin_ptr(this->code_heap2_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 3 && this->number_of_heaps >= 3 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 3 */
|
||||||
|
init_done = 3;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap3_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap3_low = copyin_ptr(this->code_heap3_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap3_high = copyin_ptr(this->code_heap3_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 4 && this->number_of_heaps >= 4 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 4 */
|
||||||
|
init_done = 4;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap4_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap4_low = copyin_ptr(this->code_heap4_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap4_high = copyin_ptr(this->code_heap4_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/init_done < 5 && this->number_of_heaps >= 5 && !this->done/
|
||||||
|
{
|
||||||
|
/* CodeHeap 5 */
|
||||||
|
init_done = 5;
|
||||||
|
this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
|
||||||
|
this->code_heap5_address = copyin_ptr(this->code_heaps_array_address);
|
||||||
|
this->code_heap5_low = copyin_ptr(this->code_heap5_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap5_high = copyin_ptr(this->code_heap5_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ----- END: Get bounds of code heaps -----
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----- BEGIN: Get address of the code heap pc points to -----
|
||||||
|
*/
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
this->codecache = 1;
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap1_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap2_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap3_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap4_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
this->codecache = 1;
|
||||||
|
this->code_heap_address = this->code_heap5_address;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ----- END: Get address of the code heap pc points to -----
|
||||||
|
*/
|
||||||
|
|
||||||
|
dtrace:helper:ustack:
|
||||||
|
/!this->done && this->codecache/
|
||||||
|
{
|
||||||
|
MARK_LINE;
|
||||||
|
/*
|
||||||
|
* Get code heap configuration
|
||||||
|
*/
|
||||||
|
this->code_heap_low = copyin_ptr(this->code_heap_address +
|
||||||
|
OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap_segmap_low = copyin_ptr(this->code_heap_address +
|
||||||
|
OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
|
||||||
|
this->code_heap_log2_segment_size = copyin_uint32(
|
||||||
|
this->code_heap_address + OFFSET_CodeHeap_log2_segment_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find start.
|
* Find start
|
||||||
*/
|
*/
|
||||||
this->segment = (this->pc - this->CodeCache_low) >>
|
this->segment = (this->pc - this->code_heap_low) >>
|
||||||
this->CodeHeap_log2_segment_size;
|
this->code_heap_log2_segment_size;
|
||||||
this->block = this->CodeCache_segmap_low;
|
this->block = this->code_heap_segmap_low;
|
||||||
this->tag = copyin_uchar(this->block + this->segment);
|
this->tag = copyin_uchar(this->block + this->segment);
|
||||||
"second";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dtrace:helper:ustack:
|
dtrace:helper:ustack:
|
||||||
|
@ -255,8 +380,8 @@ dtrace:helper:ustack:
|
||||||
/!this->done && this->codecache/
|
/!this->done && this->codecache/
|
||||||
{
|
{
|
||||||
MARK_LINE;
|
MARK_LINE;
|
||||||
this->block = this->CodeCache_low +
|
this->block = this->code_heap_low +
|
||||||
(this->segment << this->CodeHeap_log2_segment_size);
|
(this->segment << this->code_heap_log2_segment_size);
|
||||||
this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
|
this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,16 +150,18 @@ struct jvm_agent {
|
||||||
uint64_t Use_Compressed_Oops_address;
|
uint64_t Use_Compressed_Oops_address;
|
||||||
uint64_t Universe_narrow_oop_base_address;
|
uint64_t Universe_narrow_oop_base_address;
|
||||||
uint64_t Universe_narrow_oop_shift_address;
|
uint64_t Universe_narrow_oop_shift_address;
|
||||||
uint64_t CodeCache_heap_address;
|
uint64_t CodeCache_heaps_address;
|
||||||
|
|
||||||
/* Volatiles */
|
/* Volatiles */
|
||||||
uint8_t Use_Compressed_Oops;
|
uint8_t Use_Compressed_Oops;
|
||||||
uint64_t Universe_narrow_oop_base;
|
uint64_t Universe_narrow_oop_base;
|
||||||
uint32_t Universe_narrow_oop_shift;
|
uint32_t Universe_narrow_oop_shift;
|
||||||
uint64_t CodeCache_low;
|
// Code cache heaps
|
||||||
uint64_t CodeCache_high;
|
int32_t Number_of_heaps;
|
||||||
uint64_t CodeCache_segmap_low;
|
uint64_t* Heap_low;
|
||||||
uint64_t CodeCache_segmap_high;
|
uint64_t* Heap_high;
|
||||||
|
uint64_t* Heap_segmap_low;
|
||||||
|
uint64_t* Heap_segmap_high;
|
||||||
|
|
||||||
int32_t SIZE_CodeCache_log2_segment;
|
int32_t SIZE_CodeCache_log2_segment;
|
||||||
|
|
||||||
|
@ -278,8 +280,9 @@ static int parse_vmstructs(jvm_agent_t* J) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
|
if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
|
||||||
if (strcmp("_heap", vmp->fieldName) == 0) {
|
/* Read _heaps field of type GrowableArray<CodeHeaps*>* */
|
||||||
err = read_pointer(J, vmp->address, &J->CodeCache_heap_address);
|
if (strcmp("_heaps", vmp->fieldName) == 0) {
|
||||||
|
err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address);
|
||||||
}
|
}
|
||||||
} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
|
} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
|
||||||
if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
|
if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
|
||||||
|
@ -318,7 +321,9 @@ static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_volatiles(jvm_agent_t* J) {
|
static int read_volatiles(jvm_agent_t* J) {
|
||||||
uint64_t ptr;
|
int i;
|
||||||
|
uint64_t array_data;
|
||||||
|
uint64_t code_heap_address;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
|
err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
|
||||||
|
@ -334,20 +339,43 @@ static int read_volatiles(jvm_agent_t* J) {
|
||||||
err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
|
err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
|
/* CodeCache_heaps_address points to GrowableArray<CodeHeaps*>, read _data field
|
||||||
OFFSET_VirtualSpace_low, &J->CodeCache_low);
|
pointing to the first entry of type CodeCache* in the array */
|
||||||
CHECK_FAIL(err);
|
err = read_pointer(J, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_data, &array_data);
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
|
/* Read _len field containing the number of code heaps */
|
||||||
OFFSET_VirtualSpace_high, &J->CodeCache_high);
|
err = ps_pread(J->P, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_len,
|
||||||
CHECK_FAIL(err);
|
&J->Number_of_heaps, sizeof(J->Number_of_heaps));
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
|
|
||||||
OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low);
|
/* Allocate memory for heap configurations */
|
||||||
CHECK_FAIL(err);
|
J->Heap_low = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
|
J->Heap_high = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high);
|
J->Heap_segmap_low = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
|
J->Heap_segmap_high = (jvm_agent_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
|
||||||
|
|
||||||
|
/* Read code heap configurations */
|
||||||
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
|
/* Read address of heap */
|
||||||
|
err = read_pointer(J, array_data, &code_heap_address);
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size,
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
|
||||||
|
OFFSET_VirtualSpace_low, &J->Heap_low[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
|
||||||
|
OFFSET_VirtualSpace_high, &J->Heap_high[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
|
||||||
|
OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
|
||||||
|
OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]);
|
||||||
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
|
/* Increment pointer to next entry */
|
||||||
|
array_data = array_data + POINTER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ps_pread(J->P, code_heap_address + OFFSET_CodeHeap_log2_segment_size,
|
||||||
&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
|
&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
|
||||||
|
@ -357,28 +385,38 @@ static int read_volatiles(jvm_agent_t* J) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int codeheap_contains(int heap_num, jvm_agent_t* J, uint64_t ptr) {
|
||||||
|
return (J->Heap_low[heap_num] <= ptr && ptr < J->Heap_high[heap_num]);
|
||||||
|
}
|
||||||
|
|
||||||
static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
|
static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
|
||||||
/* make sure the code cache is up to date */
|
int i;
|
||||||
return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high);
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
|
if (codeheap_contains(i, J, ptr)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t segment_for(jvm_agent_t* J, uint64_t p) {
|
static uint64_t segment_for(int heap_num, jvm_agent_t* J, uint64_t p) {
|
||||||
return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment;
|
return (p - J->Heap_low[heap_num]) >> J->SIZE_CodeCache_log2_segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t block_at(jvm_agent_t* J, int i) {
|
static uint64_t block_at(int heap_num, jvm_agent_t* J, int i) {
|
||||||
return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment);
|
return J->Heap_low[heap_num] + (i << J->SIZE_CodeCache_log2_segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
int err;
|
int err;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < J->Number_of_heaps; ++i) {
|
||||||
*startp = 0;
|
*startp = 0;
|
||||||
if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) {
|
if (codeheap_contains(i, J, ptr)) {
|
||||||
int32_t used;
|
int32_t used;
|
||||||
uint64_t segment = segment_for(J, ptr);
|
uint64_t segment = segment_for(i, J, ptr);
|
||||||
uint64_t block = J->CodeCache_segmap_low;
|
uint64_t block = J->Heap_segmap_low[i];
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
|
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
|
@ -389,7 +427,7 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
segment -= tag;
|
segment -= tag;
|
||||||
}
|
}
|
||||||
block = block_at(J, segment);
|
block = block_at(i, J, segment);
|
||||||
err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
|
err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
|
||||||
CHECK_FAIL(err);
|
CHECK_FAIL(err);
|
||||||
if (used) {
|
if (used) {
|
||||||
|
@ -397,6 +435,7 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PS_OK;
|
return PS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -76,6 +76,11 @@ void Compiler::initialize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Compiler::code_buffer_size() {
|
||||||
|
assert(SegmentedCodeCache, "Should be only used with a segmented code cache");
|
||||||
|
return Compilation::desired_max_code_buffer_size() + Compilation::desired_max_constant_size();
|
||||||
|
}
|
||||||
|
|
||||||
BufferBlob* Compiler::init_buffer_blob() {
|
BufferBlob* Compiler::init_buffer_blob() {
|
||||||
// Allocate buffer blob once at startup since allocation for each
|
// Allocate buffer blob once at startup since allocation for each
|
||||||
// compilation seems to be too expensive (at least on Intel win32).
|
// compilation seems to be too expensive (at least on Intel win32).
|
||||||
|
|
|
@ -54,6 +54,9 @@ class Compiler: public AbstractCompiler {
|
||||||
|
|
||||||
// Print compilation timers and statistics
|
// Print compilation timers and statistics
|
||||||
virtual void print_timers();
|
virtual void print_timers();
|
||||||
|
|
||||||
|
// Size of the code buffer
|
||||||
|
static int code_buffer_size();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_C1_C1_COMPILER_HPP
|
#endif // SHARE_VM_C1_C1_COMPILER_HPP
|
||||||
|
|
|
@ -287,9 +287,6 @@
|
||||||
develop(bool, InstallMethods, true, \
|
develop(bool, InstallMethods, true, \
|
||||||
"Install methods at the end of successful compilations") \
|
"Install methods at the end of successful compilations") \
|
||||||
\
|
\
|
||||||
product(intx, CompilationRepeat, 0, \
|
|
||||||
"Number of times to recompile method before returning result") \
|
|
||||||
\
|
|
||||||
develop(intx, NMethodSizeLimit, (64*K)*wordSize, \
|
develop(intx, NMethodSizeLimit, (64*K)*wordSize, \
|
||||||
"Maximum size of a compiled method.") \
|
"Maximum size of a compiled method.") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "ci/ciUtilities.hpp"
|
#include "ci/ciUtilities.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "classfile/vmSymbols.hpp"
|
#include "classfile/vmSymbols.hpp"
|
||||||
|
#include "code/codeCache.hpp"
|
||||||
#include "code/scopeDesc.hpp"
|
#include "code/scopeDesc.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
#include "compiler/compileLog.hpp"
|
#include "compiler/compileLog.hpp"
|
||||||
|
@ -1085,7 +1086,7 @@ void ciEnv::register_method(ciMethod* target,
|
||||||
} else {
|
} else {
|
||||||
// The CodeCache is full. Print out warning and disable compilation.
|
// The CodeCache is full. Print out warning and disable compilation.
|
||||||
record_failure("code cache is full");
|
record_failure("code cache is full");
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1694,8 +1694,6 @@ void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_da
|
||||||
constantPoolHandle cp (THREAD, _method->constants());
|
constantPoolHandle cp (THREAD, _method->constants());
|
||||||
|
|
||||||
for(int i = 0; i < exlength; i++) {
|
for(int i = 0; i < exlength; i++) {
|
||||||
//reacquire the table in case a GC happened
|
|
||||||
ExceptionTable exhandlers(_method());
|
|
||||||
u2 start_pc = exhandlers.start_pc(i);
|
u2 start_pc = exhandlers.start_pc(i);
|
||||||
u2 end_pc = exhandlers.end_pc(i);
|
u2 end_pc = exhandlers.end_pc(i);
|
||||||
u2 handler_pc = exhandlers.handler_pc(i);
|
u2 handler_pc = exhandlers.handler_pc(i);
|
||||||
|
@ -1803,8 +1801,6 @@ void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, S
|
||||||
ExceptionTable exhandlers(_method());
|
ExceptionTable exhandlers(_method());
|
||||||
int exlength = exhandlers.length();
|
int exlength = exhandlers.length();
|
||||||
for(int i = 0; i < exlength; i++) {
|
for(int i = 0; i < exlength; i++) {
|
||||||
//reacquire the table in case a GC happened
|
|
||||||
ExceptionTable exhandlers(_method());
|
|
||||||
u2 start_pc = exhandlers.start_pc(i);
|
u2 start_pc = exhandlers.start_pc(i);
|
||||||
u2 end_pc = exhandlers.end_pc(i);
|
u2 end_pc = exhandlers.end_pc(i);
|
||||||
u2 handler_pc = exhandlers.handler_pc(i);
|
u2 handler_pc = exhandlers.handler_pc(i);
|
||||||
|
|
|
@ -229,13 +229,10 @@ BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
|
void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
|
||||||
void* p = CodeCache::allocate(size, is_critical);
|
return CodeCache::allocate(size, CodeBlobType::NonMethod, is_critical);
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BufferBlob::free(BufferBlob *blob) {
|
void BufferBlob::free(BufferBlob *blob) {
|
||||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||||
blob->flush();
|
blob->flush();
|
||||||
|
@ -299,7 +296,6 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
// Implementation of RuntimeStub
|
// Implementation of RuntimeStub
|
||||||
|
|
||||||
|
@ -340,14 +336,14 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
|
||||||
|
|
||||||
|
|
||||||
void* RuntimeStub::operator new(size_t s, unsigned size) throw() {
|
void* RuntimeStub::operator new(size_t s, unsigned size) throw() {
|
||||||
void* p = CodeCache::allocate(size, true);
|
void* p = CodeCache::allocate(size, CodeBlobType::NonMethod, true);
|
||||||
if (!p) fatal("Initial size of CodeCache is too small");
|
if (!p) fatal("Initial size of CodeCache is too small");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// operator new shared by all singletons:
|
// operator new shared by all singletons:
|
||||||
void* SingletonBlob::operator new(size_t s, unsigned size) throw() {
|
void* SingletonBlob::operator new(size_t s, unsigned size) throw() {
|
||||||
void* p = CodeCache::allocate(size, true);
|
void* p = CodeCache::allocate(size, CodeBlobType::NonMethod, true);
|
||||||
if (!p) fatal("Initial size of CodeCache is too small");
|
if (!p) fatal("Initial size of CodeCache is too small");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,18 @@
|
||||||
#include "runtime/frame.hpp"
|
#include "runtime/frame.hpp"
|
||||||
#include "runtime/handles.hpp"
|
#include "runtime/handles.hpp"
|
||||||
|
|
||||||
|
// CodeBlob Types
|
||||||
|
// Used in the CodeCache to assign CodeBlobs to different CodeHeaps
|
||||||
|
struct CodeBlobType {
|
||||||
|
enum {
|
||||||
|
MethodNonProfiled = 0, // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods)
|
||||||
|
MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods
|
||||||
|
NonMethod = 2, // Non-methods like Buffers, Adapters and Runtime Stubs
|
||||||
|
All = 3, // All types (No code cache segmentation)
|
||||||
|
NumTypes = 4 // Number of CodeBlobTypes
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// CodeBlob - superclass for all entries in the CodeCache.
|
// CodeBlob - superclass for all entries in the CodeCache.
|
||||||
//
|
//
|
||||||
// Suptypes are:
|
// Suptypes are:
|
||||||
|
@ -385,9 +397,6 @@ class DeoptimizationBlob: public SingletonBlob {
|
||||||
return (pc == unpack_pc || (pc + frame::pc_return_offset) == unpack_pc);
|
return (pc == unpack_pc || (pc + frame::pc_return_offset) == unpack_pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// GC for args
|
// GC for args
|
||||||
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* Nothing to do */ }
|
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* Nothing to do */ }
|
||||||
|
|
||||||
|
|
|
@ -44,12 +44,21 @@
|
||||||
#include "runtime/icache.hpp"
|
#include "runtime/icache.hpp"
|
||||||
#include "runtime/java.hpp"
|
#include "runtime/java.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
|
#include "runtime/compilationPolicy.hpp"
|
||||||
#include "services/memoryService.hpp"
|
#include "services/memoryService.hpp"
|
||||||
#include "trace/tracing.hpp"
|
#include "trace/tracing.hpp"
|
||||||
#include "utilities/xmlstream.hpp"
|
#include "utilities/xmlstream.hpp"
|
||||||
|
#ifdef COMPILER1
|
||||||
|
#include "c1/c1_Compilation.hpp"
|
||||||
|
#include "c1/c1_Compiler.hpp"
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILER2
|
||||||
|
#include "opto/c2compiler.hpp"
|
||||||
|
#include "opto/compile.hpp"
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Helper class for printing in CodeCache
|
// Helper class for printing in CodeCache
|
||||||
|
|
||||||
class CodeBlob_sizes {
|
class CodeBlob_sizes {
|
||||||
private:
|
private:
|
||||||
int count;
|
int count;
|
||||||
|
@ -115,64 +124,216 @@ class CodeBlob_sizes {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// CodeCache implementation
|
// Iterate over all CodeHeaps
|
||||||
|
#define FOR_ALL_HEAPS(heap) for (GrowableArrayIterator<CodeHeap*> heap = _heaps->begin(); heap != _heaps->end(); ++heap)
|
||||||
|
// Iterate over all CodeBlobs (cb) on the given CodeHeap
|
||||||
|
#define FOR_ALL_BLOBS(cb, heap) for (CodeBlob* cb = first_blob(heap); cb != NULL; cb = next_blob(heap, cb))
|
||||||
|
|
||||||
CodeHeap * CodeCache::_heap = new CodeHeap();
|
address CodeCache::_low_bound = 0;
|
||||||
|
address CodeCache::_high_bound = 0;
|
||||||
int CodeCache::_number_of_blobs = 0;
|
int CodeCache::_number_of_blobs = 0;
|
||||||
int CodeCache::_number_of_adapters = 0;
|
int CodeCache::_number_of_adapters = 0;
|
||||||
int CodeCache::_number_of_nmethods = 0;
|
int CodeCache::_number_of_nmethods = 0;
|
||||||
int CodeCache::_number_of_nmethods_with_dependencies = 0;
|
int CodeCache::_number_of_nmethods_with_dependencies = 0;
|
||||||
bool CodeCache::_needs_cache_clean = false;
|
bool CodeCache::_needs_cache_clean = false;
|
||||||
nmethod* CodeCache::_scavenge_root_nmethods = NULL;
|
nmethod* CodeCache::_scavenge_root_nmethods = NULL;
|
||||||
|
|
||||||
int CodeCache::_codemem_full_count = 0;
|
int CodeCache::_codemem_full_count = 0;
|
||||||
|
|
||||||
CodeBlob* CodeCache::first() {
|
// Initialize array of CodeHeaps
|
||||||
|
GrowableArray<CodeHeap*>* CodeCache::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<CodeHeap*> (CodeBlobType::All, true);
|
||||||
|
|
||||||
|
void CodeCache::initialize_heaps() {
|
||||||
|
// Determine size of compiler buffers
|
||||||
|
size_t code_buffers_size = 0;
|
||||||
|
#ifdef COMPILER1
|
||||||
|
// C1 temporary code buffers (see Compiler::init_buffer_blob())
|
||||||
|
const int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
|
||||||
|
code_buffers_size += c1_count * Compiler::code_buffer_size();
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILER2
|
||||||
|
// C2 scratch buffers (see Compile::init_scratch_buffer_blob())
|
||||||
|
const int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
|
||||||
|
// Initial size of constant table (this may be increased if a compiled method needs more space)
|
||||||
|
code_buffers_size += c2_count * C2Compiler::initial_code_buffer_size();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Calculate default CodeHeap sizes if not set by user
|
||||||
|
if (!FLAG_IS_CMDLINE(NonMethodCodeHeapSize) && !FLAG_IS_CMDLINE(ProfiledCodeHeapSize)
|
||||||
|
&& !FLAG_IS_CMDLINE(NonProfiledCodeHeapSize)) {
|
||||||
|
// Increase default NonMethodCodeHeapSize to account for compiler buffers
|
||||||
|
FLAG_SET_ERGO(uintx, NonMethodCodeHeapSize, NonMethodCodeHeapSize + code_buffers_size);
|
||||||
|
|
||||||
|
// Check if we have enough space for the non-method code heap
|
||||||
|
if (ReservedCodeCacheSize > NonMethodCodeHeapSize) {
|
||||||
|
// Use the default value for NonMethodCodeHeapSize and one half of the
|
||||||
|
// remaining size for non-profiled methods and one half for profiled methods
|
||||||
|
size_t remaining_size = ReservedCodeCacheSize - NonMethodCodeHeapSize;
|
||||||
|
size_t profiled_size = remaining_size / 2;
|
||||||
|
size_t non_profiled_size = remaining_size - profiled_size;
|
||||||
|
FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, profiled_size);
|
||||||
|
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, non_profiled_size);
|
||||||
|
} else {
|
||||||
|
// Use all space for the non-method heap and set other heaps to minimal size
|
||||||
|
FLAG_SET_ERGO(uintx, NonMethodCodeHeapSize, ReservedCodeCacheSize - os::vm_page_size() * 2);
|
||||||
|
FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, os::vm_page_size());
|
||||||
|
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, os::vm_page_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not need the profiled CodeHeap, use all space for the non-profiled CodeHeap
|
||||||
|
if(!heap_available(CodeBlobType::MethodProfiled)) {
|
||||||
|
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, NonProfiledCodeHeapSize + ProfiledCodeHeapSize);
|
||||||
|
FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0);
|
||||||
|
}
|
||||||
|
// We do not need the non-profiled CodeHeap, use all space for the non-method CodeHeap
|
||||||
|
if(!heap_available(CodeBlobType::MethodNonProfiled)) {
|
||||||
|
FLAG_SET_ERGO(uintx, NonMethodCodeHeapSize, NonMethodCodeHeapSize + NonProfiledCodeHeapSize);
|
||||||
|
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have enough space for VM internal code
|
||||||
|
uint min_code_cache_size = (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3)) + CodeCacheMinimumFreeSpace;
|
||||||
|
if (NonMethodCodeHeapSize < (min_code_cache_size + code_buffers_size)) {
|
||||||
|
vm_exit_during_initialization("Not enough space in non-method code heap to run VM.");
|
||||||
|
}
|
||||||
|
guarantee(NonProfiledCodeHeapSize + ProfiledCodeHeapSize + NonMethodCodeHeapSize <= ReservedCodeCacheSize, "Size check");
|
||||||
|
|
||||||
|
// Align reserved sizes of CodeHeaps
|
||||||
|
size_t non_method_size = ReservedCodeSpace::allocation_align_size_up(NonMethodCodeHeapSize);
|
||||||
|
size_t profiled_size = ReservedCodeSpace::allocation_align_size_up(ProfiledCodeHeapSize);
|
||||||
|
size_t non_profiled_size = ReservedCodeSpace::allocation_align_size_up(NonProfiledCodeHeapSize);
|
||||||
|
|
||||||
|
// Compute initial sizes of CodeHeaps
|
||||||
|
size_t init_non_method_size = MIN2(InitialCodeCacheSize, non_method_size);
|
||||||
|
size_t init_profiled_size = MIN2(InitialCodeCacheSize, profiled_size);
|
||||||
|
size_t init_non_profiled_size = MIN2(InitialCodeCacheSize, non_profiled_size);
|
||||||
|
|
||||||
|
// Reserve one continuous chunk of memory for CodeHeaps and split it into
|
||||||
|
// parts for the individual heaps. The memory layout looks like this:
|
||||||
|
// ---------- high -----------
|
||||||
|
// Non-profiled nmethods
|
||||||
|
// Profiled nmethods
|
||||||
|
// Non-methods
|
||||||
|
// ---------- low ------------
|
||||||
|
ReservedCodeSpace rs = reserve_heap_memory(non_profiled_size + profiled_size + non_method_size);
|
||||||
|
ReservedSpace non_method_space = rs.first_part(non_method_size);
|
||||||
|
ReservedSpace rest = rs.last_part(non_method_size);
|
||||||
|
ReservedSpace profiled_space = rest.first_part(profiled_size);
|
||||||
|
ReservedSpace non_profiled_space = rest.last_part(profiled_size);
|
||||||
|
|
||||||
|
// Non-methods (stubs, adapters, ...)
|
||||||
|
add_heap(non_method_space, "non-methods", init_non_method_size, CodeBlobType::NonMethod);
|
||||||
|
// Tier 2 and tier 3 (profiled) methods
|
||||||
|
add_heap(profiled_space, "profiled nmethods", init_profiled_size, CodeBlobType::MethodProfiled);
|
||||||
|
// Tier 1 and tier 4 (non-profiled) methods and native methods
|
||||||
|
add_heap(non_profiled_space, "non-profiled nmethods", init_non_profiled_size, CodeBlobType::MethodNonProfiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) {
|
||||||
|
// Determine alignment
|
||||||
|
const size_t page_size = os::can_execute_large_page_memory() ?
|
||||||
|
MIN2(os::page_size_for_region(InitialCodeCacheSize, 8),
|
||||||
|
os::page_size_for_region(size, 8)) :
|
||||||
|
os::vm_page_size();
|
||||||
|
const size_t granularity = os::vm_allocation_granularity();
|
||||||
|
const size_t r_align = MAX2(page_size, granularity);
|
||||||
|
const size_t r_size = align_size_up(size, r_align);
|
||||||
|
const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 :
|
||||||
|
MAX2(page_size, granularity);
|
||||||
|
|
||||||
|
ReservedCodeSpace rs(r_size, rs_align, rs_align > 0);
|
||||||
|
|
||||||
|
// Initialize bounds
|
||||||
|
_low_bound = (address)rs.base();
|
||||||
|
_high_bound = _low_bound + rs.size();
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CodeCache::heap_available(int code_blob_type) {
|
||||||
|
if (!SegmentedCodeCache) {
|
||||||
|
// No segmentation: use a single code heap
|
||||||
|
return (code_blob_type == CodeBlobType::All);
|
||||||
|
} else if ((Arguments::mode() == Arguments::_int) ||
|
||||||
|
(TieredStopAtLevel == CompLevel_none)) {
|
||||||
|
// Interpreter only: we don't need any method code heaps
|
||||||
|
return (code_blob_type == CodeBlobType::NonMethod);
|
||||||
|
} else if (TieredCompilation && (TieredStopAtLevel > CompLevel_simple)) {
|
||||||
|
// Tiered compilation: use all code heaps
|
||||||
|
return (code_blob_type < CodeBlobType::All);
|
||||||
|
} else {
|
||||||
|
// No TieredCompilation: we only need the non-method and non-profiled code heap
|
||||||
|
return (code_blob_type == CodeBlobType::NonMethod) ||
|
||||||
|
(code_blob_type == CodeBlobType::MethodNonProfiled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeCache::add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type) {
|
||||||
|
// Check if heap is needed
|
||||||
|
if (!heap_available(code_blob_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create CodeHeap
|
||||||
|
CodeHeap* heap = new CodeHeap(name, code_blob_type);
|
||||||
|
_heaps->append(heap);
|
||||||
|
|
||||||
|
// Reserve Space
|
||||||
|
size_initial = round_to(size_initial, os::vm_page_size());
|
||||||
|
|
||||||
|
if (!heap->reserve(rs, size_initial, CodeCacheSegmentSize)) {
|
||||||
|
vm_exit_during_initialization("Could not reserve enough space for code cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the CodeHeap
|
||||||
|
MemoryService::add_code_heap_memory_pool(heap, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeHeap* CodeCache::get_code_heap(CodeBlob* cb) {
|
||||||
|
assert(cb != NULL, "CodeBlob is null");
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
if ((*heap)->contains(cb)) {
|
||||||
|
return *heap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShouldNotReachHere();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeHeap* CodeCache::get_code_heap(int code_blob_type) {
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
if ((*heap)->accepts(code_blob_type)) {
|
||||||
|
return *heap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeBlob* CodeCache::first_blob(CodeHeap* heap) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
return (CodeBlob*)_heap->first();
|
assert(heap != NULL, "heap is null");
|
||||||
|
return (CodeBlob*)heap->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeBlob* CodeCache::first_blob(int code_blob_type) {
|
||||||
|
if (heap_available(code_blob_type)) {
|
||||||
|
return first_blob(get_code_heap(code_blob_type));
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CodeBlob* CodeCache::next(CodeBlob* cb) {
|
CodeBlob* CodeCache::next_blob(CodeHeap* heap, CodeBlob* cb) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
return (CodeBlob*)_heap->next(cb);
|
assert(heap != NULL, "heap is null");
|
||||||
|
return (CodeBlob*)heap->next(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeBlob* CodeCache::next_blob(CodeBlob* cb) {
|
||||||
CodeBlob* CodeCache::alive(CodeBlob *cb) {
|
return next_blob(get_code_heap(cb), cb);
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
|
||||||
while (cb != NULL && !cb->is_alive()) cb = next(cb);
|
|
||||||
return cb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool is_critical) {
|
||||||
nmethod* CodeCache::alive_nmethod(CodeBlob* cb) {
|
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
|
||||||
while (cb != NULL && (!cb->is_alive() || !cb->is_nmethod())) cb = next(cb);
|
|
||||||
return (nmethod*)cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
nmethod* CodeCache::first_nmethod() {
|
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
|
||||||
CodeBlob* cb = first();
|
|
||||||
while (cb != NULL && !cb->is_nmethod()) {
|
|
||||||
cb = next(cb);
|
|
||||||
}
|
|
||||||
return (nmethod*)cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
nmethod* CodeCache::next_nmethod (CodeBlob* cb) {
|
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
|
||||||
cb = next(cb);
|
|
||||||
while (cb != NULL && !cb->is_nmethod()) {
|
|
||||||
cb = next(cb);
|
|
||||||
}
|
|
||||||
return (nmethod*)cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t maxCodeCacheUsed = 0;
|
|
||||||
|
|
||||||
CodeBlob* CodeCache::allocate(int size, bool is_critical) {
|
|
||||||
// Do not seize the CodeCache lock here--if the caller has not
|
// Do not seize the CodeCache lock here--if the caller has not
|
||||||
// already done so, we are going to lose bigtime, since the code
|
// already done so, we are going to lose bigtime, since the code
|
||||||
// cache will contain a garbage CodeBlob until the caller can
|
// cache will contain a garbage CodeBlob until the caller can
|
||||||
|
@ -184,22 +345,34 @@ CodeBlob* CodeCache::allocate(int size, bool is_critical) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CodeBlob* cb = NULL;
|
CodeBlob* cb = NULL;
|
||||||
|
|
||||||
|
// Get CodeHeap for the given CodeBlobType
|
||||||
|
CodeHeap* heap = get_code_heap(SegmentedCodeCache ? code_blob_type : CodeBlobType::All);
|
||||||
|
assert (heap != NULL, "heap is null");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
cb = (CodeBlob*)_heap->allocate(size, is_critical);
|
cb = (CodeBlob*)heap->allocate(size, is_critical);
|
||||||
if (cb != NULL) break;
|
if (cb != NULL) break;
|
||||||
if (!_heap->expand_by(CodeCacheExpansionSize)) {
|
if (!heap->expand_by(CodeCacheExpansionSize)) {
|
||||||
// Expansion failed
|
// Expansion failed
|
||||||
|
if (SegmentedCodeCache && (code_blob_type == CodeBlobType::NonMethod)) {
|
||||||
|
// Fallback solution: Store non-method code in the non-profiled code heap
|
||||||
|
return allocate(size, CodeBlobType::MethodNonProfiled, is_critical);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (PrintCodeCacheExtension) {
|
if (PrintCodeCacheExtension) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
tty->print_cr("code cache extended to [" INTPTR_FORMAT ", " INTPTR_FORMAT "] (" SSIZE_FORMAT " bytes)",
|
if (SegmentedCodeCache) {
|
||||||
(intptr_t)_heap->low_boundary(), (intptr_t)_heap->high(),
|
tty->print("Code heap '%s'", heap->name());
|
||||||
(address)_heap->high() - (address)_heap->low_boundary());
|
} else {
|
||||||
|
tty->print("Code cache");
|
||||||
|
}
|
||||||
|
tty->print_cr(" extended to [" INTPTR_FORMAT ", " INTPTR_FORMAT "] (" SSIZE_FORMAT " bytes)",
|
||||||
|
(intptr_t)heap->low_boundary(), (intptr_t)heap->high(),
|
||||||
|
(address)heap->high() - (address)heap->low_boundary());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maxCodeCacheUsed = MAX2(maxCodeCacheUsed, ((address)_heap->high_boundary() -
|
|
||||||
(address)_heap->low_boundary()) - unallocated_capacity());
|
|
||||||
print_trace("allocation", cb, size);
|
print_trace("allocation", cb, size);
|
||||||
_number_of_blobs++;
|
_number_of_blobs++;
|
||||||
return cb;
|
return cb;
|
||||||
|
@ -220,12 +393,12 @@ void CodeCache::free(CodeBlob* cb) {
|
||||||
}
|
}
|
||||||
_number_of_blobs--;
|
_number_of_blobs--;
|
||||||
|
|
||||||
_heap->deallocate(cb);
|
// Get heap for given CodeBlob and deallocate
|
||||||
|
get_code_heap(cb)->deallocate(cb);
|
||||||
|
|
||||||
assert(_number_of_blobs >= 0, "sanity check");
|
assert(_number_of_blobs >= 0, "sanity check");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeCache::commit(CodeBlob* cb) {
|
void CodeCache::commit(CodeBlob* cb) {
|
||||||
// this is called by nmethod::nmethod, which must already own CodeCache_lock
|
// this is called by nmethod::nmethod, which must already own CodeCache_lock
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
|
@ -243,83 +416,94 @@ void CodeCache::commit(CodeBlob* cb) {
|
||||||
ICache::invalidate_range(cb->content_begin(), cb->content_size());
|
ICache::invalidate_range(cb->content_begin(), cb->content_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Iteration over CodeBlobs
|
|
||||||
|
|
||||||
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
|
|
||||||
#define FOR_ALL_ALIVE_BLOBS(var) for (CodeBlob *var = alive(first()); var != NULL; var = alive(next(var)))
|
|
||||||
#define FOR_ALL_ALIVE_NMETHODS(var) for (nmethod *var = alive_nmethod(first()); var != NULL; var = alive_nmethod(next(var)))
|
|
||||||
#define FOR_ALL_NMETHODS(var) for (nmethod *var = first_nmethod(); var != NULL; var = next_nmethod(var))
|
|
||||||
|
|
||||||
|
|
||||||
bool CodeCache::contains(void *p) {
|
bool CodeCache::contains(void *p) {
|
||||||
// It should be ok to call contains without holding a lock
|
// It should be ok to call contains without holding a lock
|
||||||
return _heap->contains(p);
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
if ((*heap)->contains(p)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method is safe to call without holding the CodeCache_lock, as long as a dead CodeBlob is not
|
||||||
// This method is safe to call without holding the CodeCache_lock, as long as a dead codeblob is not
|
// looked up (i.e., one that has been marked for deletion). It only depends on the _segmap to contain
|
||||||
// looked up (i.e., one that has been marked for deletion). It only dependes on the _segmap to contain
|
|
||||||
// valid indices, which it will always do, as long as the CodeBlob is not in the process of being recycled.
|
// valid indices, which it will always do, as long as the CodeBlob is not in the process of being recycled.
|
||||||
CodeBlob* CodeCache::find_blob(void* start) {
|
CodeBlob* CodeCache::find_blob(void* start) {
|
||||||
CodeBlob* result = find_blob_unsafe(start);
|
CodeBlob* result = find_blob_unsafe(start);
|
||||||
if (result == NULL) return NULL;
|
|
||||||
// We could potentially look up non_entrant methods
|
// We could potentially look up non_entrant methods
|
||||||
guarantee(!result->is_zombie() || result->is_locked_by_vm() || is_error_reported(), "unsafe access to zombie method");
|
guarantee(result == NULL || !result->is_zombie() || result->is_locked_by_vm() || is_error_reported(), "unsafe access to zombie method");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lookup that does not fail if you lookup a zombie method (if you call this, be sure to know
|
||||||
|
// what you are doing)
|
||||||
|
CodeBlob* CodeCache::find_blob_unsafe(void* start) {
|
||||||
|
// NMT can walk the stack before code cache is created
|
||||||
|
if (_heaps == NULL || _heaps->is_empty()) return NULL;
|
||||||
|
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
CodeBlob* result = (CodeBlob*) (*heap)->find_start(start);
|
||||||
|
if (result != NULL && result->blob_contains((address)start)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
nmethod* CodeCache::find_nmethod(void* start) {
|
nmethod* CodeCache::find_nmethod(void* start) {
|
||||||
CodeBlob* cb = find_blob(start);
|
CodeBlob* cb = find_blob(start);
|
||||||
assert(cb == NULL || cb->is_nmethod(), "did not find an nmethod");
|
assert(cb->is_nmethod(), "did not find an nmethod");
|
||||||
return (nmethod*)cb;
|
return (nmethod*)cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeCache::blobs_do(void f(CodeBlob* nm)) {
|
void CodeCache::blobs_do(void f(CodeBlob* nm)) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_BLOBS(p) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
f(p);
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
|
f(cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeCache::nmethods_do(void f(nmethod* nm)) {
|
void CodeCache::nmethods_do(void f(nmethod* nm)) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_BLOBS(nm) {
|
NMethodIterator iter;
|
||||||
if (nm->is_nmethod()) f((nmethod*)nm);
|
while(iter.next()) {
|
||||||
|
f(iter.method());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::alive_nmethods_do(void f(nmethod* nm)) {
|
void CodeCache::alive_nmethods_do(void f(nmethod* nm)) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
f(nm);
|
while(iter.next_alive()) {
|
||||||
|
f(iter.method());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CodeCache::alignment_unit() {
|
int CodeCache::alignment_unit() {
|
||||||
return (int)_heap->alignment_unit();
|
return (int)_heaps->first()->alignment_unit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CodeCache::alignment_offset() {
|
int CodeCache::alignment_offset() {
|
||||||
return (int)_heap->alignment_offset();
|
return (int)_heaps->first()->alignment_offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark nmethods for unloading if they contain otherwise unreachable oops.
|
||||||
// Mark nmethods for unloading if they contain otherwise unreachable
|
|
||||||
// oops.
|
|
||||||
void CodeCache::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
|
void CodeCache::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
nm->do_unloading(is_alive, unloading_occurred);
|
while(iter.next_alive()) {
|
||||||
|
iter.method()->do_unloading(is_alive, unloading_occurred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::blobs_do(CodeBlobClosure* f) {
|
void CodeCache::blobs_do(CodeBlobClosure* f) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
|
if (cb->is_alive()) {
|
||||||
f->do_code_blob(cb);
|
f->do_code_blob(cb);
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
|
@ -328,6 +512,8 @@ void CodeCache::blobs_do(CodeBlobClosure* f) {
|
||||||
#endif //ASSERT
|
#endif //ASSERT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Walk the list of methods which might contain non-perm oops.
|
// Walk the list of methods which might contain non-perm oops.
|
||||||
void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) {
|
void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) {
|
||||||
|
@ -453,45 +639,40 @@ void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) {
|
||||||
|
|
||||||
// Temporarily mark nmethods that are claimed to be on the non-perm list.
|
// Temporarily mark nmethods that are claimed to be on the non-perm list.
|
||||||
void CodeCache::mark_scavenge_root_nmethods() {
|
void CodeCache::mark_scavenge_root_nmethods() {
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
NMethodIterator iter;
|
||||||
if (cb->is_nmethod()) {
|
while(iter.next_alive()) {
|
||||||
nmethod *nm = (nmethod*)cb;
|
nmethod* nm = iter.method();
|
||||||
assert(nm->scavenge_root_not_marked(), "clean state");
|
assert(nm->scavenge_root_not_marked(), "clean state");
|
||||||
if (nm->on_scavenge_root_list())
|
if (nm->on_scavenge_root_list())
|
||||||
nm->set_scavenge_root_marked();
|
nm->set_scavenge_root_marked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If the closure is given, run it on the unlisted nmethods.
|
// If the closure is given, run it on the unlisted nmethods.
|
||||||
// Also make sure that the effects of mark_scavenge_root_nmethods is gone.
|
// Also make sure that the effects of mark_scavenge_root_nmethods is gone.
|
||||||
void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
|
void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
bool call_f = (f_or_null != NULL);
|
bool call_f = (f_or_null != NULL);
|
||||||
if (cb->is_nmethod()) {
|
|
||||||
nmethod *nm = (nmethod*)cb;
|
|
||||||
assert(nm->scavenge_root_not_marked(), "must be already processed");
|
assert(nm->scavenge_root_not_marked(), "must be already processed");
|
||||||
if (nm->on_scavenge_root_list())
|
if (nm->on_scavenge_root_list())
|
||||||
call_f = false; // don't show this one to the client
|
call_f = false; // don't show this one to the client
|
||||||
nm->verify_scavenge_root_oops();
|
nm->verify_scavenge_root_oops();
|
||||||
} else {
|
if (call_f) f_or_null->do_code_blob(nm);
|
||||||
call_f = false; // not an nmethod
|
|
||||||
}
|
|
||||||
if (call_f) f_or_null->do_code_blob(cb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //PRODUCT
|
#endif //PRODUCT
|
||||||
|
|
||||||
void CodeCache::verify_clean_inline_caches() {
|
void CodeCache::verify_clean_inline_caches() {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
NMethodIterator iter;
|
||||||
if (cb->is_nmethod()) {
|
while(iter.next_alive()) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = iter.method();
|
||||||
assert(!nm->is_unloaded(), "Tautology");
|
assert(!nm->is_unloaded(), "Tautology");
|
||||||
nm->verify_clean_inline_caches();
|
nm->verify_clean_inline_caches();
|
||||||
nm->verify();
|
nm->verify();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,12 +680,14 @@ void CodeCache::verify_icholder_relocations() {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// make sure that we aren't leaking icholders
|
// make sure that we aren't leaking icholders
|
||||||
int count = 0;
|
int count = 0;
|
||||||
FOR_ALL_BLOBS(cb) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
if (cb->is_nmethod()) {
|
if (cb->is_nmethod()) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
count += nm->verify_icholder_relocations();
|
count += nm->verify_icholder_relocations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(count + InlineCacheBuffer::pending_icholder_count() + CompiledICHolder::live_not_claimed_count() ==
|
assert(count + InlineCacheBuffer::pending_icholder_count() + CompiledICHolder::live_not_claimed_count() ==
|
||||||
CompiledICHolder::live_count(), "must agree");
|
CompiledICHolder::live_count(), "must agree");
|
||||||
|
@ -516,9 +699,9 @@ void CodeCache::gc_prologue() {
|
||||||
|
|
||||||
void CodeCache::gc_epilogue() {
|
void CodeCache::gc_epilogue() {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
NMethodIterator iter;
|
||||||
if (cb->is_nmethod()) {
|
while(iter.next_alive()) {
|
||||||
nmethod *nm = (nmethod*)cb;
|
nmethod* nm = iter.method();
|
||||||
assert(!nm->is_unloaded(), "Tautology");
|
assert(!nm->is_unloaded(), "Tautology");
|
||||||
if (needs_cache_clean()) {
|
if (needs_cache_clean()) {
|
||||||
nm->cleanup_inline_caches();
|
nm->cleanup_inline_caches();
|
||||||
|
@ -526,7 +709,6 @@ void CodeCache::gc_epilogue() {
|
||||||
DEBUG_ONLY(nm->verify());
|
DEBUG_ONLY(nm->verify());
|
||||||
DEBUG_ONLY(nm->verify_oop_relocations());
|
DEBUG_ONLY(nm->verify_oop_relocations());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
set_needs_cache_clean(false);
|
set_needs_cache_clean(false);
|
||||||
prune_scavenge_root_nmethods();
|
prune_scavenge_root_nmethods();
|
||||||
|
|
||||||
|
@ -536,37 +718,89 @@ void CodeCache::gc_epilogue() {
|
||||||
void CodeCache::verify_oops() {
|
void CodeCache::verify_oops() {
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
VerifyOopClosure voc;
|
VerifyOopClosure voc;
|
||||||
FOR_ALL_ALIVE_BLOBS(cb) {
|
NMethodIterator iter;
|
||||||
if (cb->is_nmethod()) {
|
while(iter.next_alive()) {
|
||||||
nmethod *nm = (nmethod*)cb;
|
nmethod* nm = iter.method();
|
||||||
nm->oops_do(&voc);
|
nm->oops_do(&voc);
|
||||||
nm->verify_oop_relocations();
|
nm->verify_oop_relocations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CodeCache::capacity() {
|
||||||
|
size_t cap = 0;
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
cap += (*heap)->capacity();
|
||||||
|
}
|
||||||
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CodeCache::unallocated_capacity() {
|
||||||
address CodeCache::first_address() {
|
size_t unallocated_cap = 0;
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
FOR_ALL_HEAPS(heap) {
|
||||||
return (address)_heap->low_boundary();
|
unallocated_cap += (*heap)->unallocated_capacity();
|
||||||
|
}
|
||||||
|
return unallocated_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CodeCache::max_capacity() {
|
||||||
address CodeCache::last_address() {
|
size_t max_cap = 0;
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
FOR_ALL_HEAPS(heap) {
|
||||||
return (address)_heap->high();
|
max_cap += (*heap)->max_capacity();
|
||||||
|
}
|
||||||
|
return max_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the reverse free ratio. E.g., if 25% (1/4) of the code cache
|
* Returns true if a CodeHeap is full and sets code_blob_type accordingly.
|
||||||
|
*/
|
||||||
|
bool CodeCache::is_full(int* code_blob_type) {
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
if ((*heap)->unallocated_capacity() < CodeCacheMinimumFreeSpace) {
|
||||||
|
*code_blob_type = (*heap)->code_blob_type();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reverse free ratio. E.g., if 25% (1/4) of the code heap
|
||||||
* is free, reverse_free_ratio() returns 4.
|
* is free, reverse_free_ratio() returns 4.
|
||||||
*/
|
*/
|
||||||
double CodeCache::reverse_free_ratio() {
|
double CodeCache::reverse_free_ratio(int code_blob_type) {
|
||||||
double unallocated_capacity = (double)(CodeCache::unallocated_capacity() - CodeCacheMinimumFreeSpace);
|
CodeHeap* heap = get_code_heap(code_blob_type);
|
||||||
double max_capacity = (double)CodeCache::max_capacity();
|
if (heap == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
double unallocated_capacity = (double)(heap->unallocated_capacity() - CodeCacheMinimumFreeSpace);
|
||||||
|
double max_capacity = (double)heap->max_capacity();
|
||||||
return max_capacity / unallocated_capacity;
|
return max_capacity / unallocated_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CodeCache::bytes_allocated_in_freelists() {
|
||||||
|
size_t allocated_bytes = 0;
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
allocated_bytes += (*heap)->allocated_in_freelist();
|
||||||
|
}
|
||||||
|
return allocated_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CodeCache::allocated_segments() {
|
||||||
|
int number_of_segments = 0;
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
number_of_segments += (*heap)->allocated_segments();
|
||||||
|
}
|
||||||
|
return number_of_segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CodeCache::freelists_length() {
|
||||||
|
size_t length = 0;
|
||||||
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
length += (*heap)->freelist_length();
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
void icache_init();
|
void icache_init();
|
||||||
|
|
||||||
void CodeCache::initialize() {
|
void CodeCache::initialize() {
|
||||||
|
@ -579,13 +813,15 @@ void CodeCache::initialize() {
|
||||||
// the code cache to the page size. In particular, Solaris is moving to a larger
|
// the code cache to the page size. In particular, Solaris is moving to a larger
|
||||||
// default page size.
|
// default page size.
|
||||||
CodeCacheExpansionSize = round_to(CodeCacheExpansionSize, os::vm_page_size());
|
CodeCacheExpansionSize = round_to(CodeCacheExpansionSize, os::vm_page_size());
|
||||||
InitialCodeCacheSize = round_to(InitialCodeCacheSize, os::vm_page_size());
|
|
||||||
ReservedCodeCacheSize = round_to(ReservedCodeCacheSize, os::vm_page_size());
|
|
||||||
if (!_heap->reserve(ReservedCodeCacheSize, InitialCodeCacheSize, CodeCacheSegmentSize)) {
|
|
||||||
vm_exit_during_initialization("Could not reserve enough space for code cache");
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryService::add_code_heap_memory_pool(_heap);
|
if (SegmentedCodeCache) {
|
||||||
|
// Use multiple code heaps
|
||||||
|
initialize_heaps();
|
||||||
|
} else {
|
||||||
|
// Use a single code heap
|
||||||
|
ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize);
|
||||||
|
add_heap(rs, "Code heap", InitialCodeCacheSize, CodeBlobType::All);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize ICache flush mechanism
|
// Initialize ICache flush mechanism
|
||||||
// This service is needed for os::register_code_area
|
// This service is needed for os::register_code_area
|
||||||
|
@ -594,10 +830,9 @@ void CodeCache::initialize() {
|
||||||
// Give OS a chance to register generated code area.
|
// Give OS a chance to register generated code area.
|
||||||
// This is used on Windows 64 bit platforms to register
|
// This is used on Windows 64 bit platforms to register
|
||||||
// Structured Exception Handlers for our generated code.
|
// Structured Exception Handlers for our generated code.
|
||||||
os::register_code_area(_heap->low_boundary(), _heap->high_boundary());
|
os::register_code_area((char*)low_bound(), (char*)high_bound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void codeCache_init() {
|
void codeCache_init() {
|
||||||
CodeCache::initialize();
|
CodeCache::initialize();
|
||||||
}
|
}
|
||||||
|
@ -610,8 +845,9 @@ int CodeCache::number_of_nmethods_with_dependencies() {
|
||||||
|
|
||||||
void CodeCache::clear_inline_caches() {
|
void CodeCache::clear_inline_caches() {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
nm->clear_inline_caches();
|
while(iter.next_alive()) {
|
||||||
|
iter.method()->clear_inline_caches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +902,9 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
if (nm->is_marked_for_deoptimization()) {
|
if (nm->is_marked_for_deoptimization()) {
|
||||||
// ...Already marked in the previous pass; don't count it again.
|
// ...Already marked in the previous pass; don't count it again.
|
||||||
} else if (nm->is_evol_dependent_on(dependee())) {
|
} else if (nm->is_evol_dependent_on(dependee())) {
|
||||||
|
@ -687,19 +925,22 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
|
||||||
// Deoptimize all methods
|
// Deoptimize all methods
|
||||||
void CodeCache::mark_all_nmethods_for_deoptimization() {
|
void CodeCache::mark_all_nmethods_for_deoptimization() {
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
if (!nm->method()->is_method_handle_intrinsic()) {
|
if (!nm->method()->is_method_handle_intrinsic()) {
|
||||||
nm->mark_for_deoptimization();
|
nm->mark_for_deoptimization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CodeCache::mark_for_deoptimization(Method* dependee) {
|
int CodeCache::mark_for_deoptimization(Method* dependee) {
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
int number_of_marked_CodeBlobs = 0;
|
int number_of_marked_CodeBlobs = 0;
|
||||||
|
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
if (nm->is_dependent_on_method(dependee)) {
|
if (nm->is_dependent_on_method(dependee)) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
nm->mark_for_deoptimization();
|
nm->mark_for_deoptimization();
|
||||||
|
@ -712,7 +953,9 @@ int CodeCache::mark_for_deoptimization(Method* dependee) {
|
||||||
|
|
||||||
void CodeCache::make_marked_nmethods_zombies() {
|
void CodeCache::make_marked_nmethods_zombies() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
if (nm->is_marked_for_deoptimization()) {
|
if (nm->is_marked_for_deoptimization()) {
|
||||||
|
|
||||||
// If the nmethod has already been made non-entrant and it can be converted
|
// If the nmethod has already been made non-entrant and it can be converted
|
||||||
|
@ -733,7 +976,9 @@ void CodeCache::make_marked_nmethods_zombies() {
|
||||||
|
|
||||||
void CodeCache::make_marked_nmethods_not_entrant() {
|
void CodeCache::make_marked_nmethods_not_entrant() {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
if (nm->is_marked_for_deoptimization()) {
|
if (nm->is_marked_for_deoptimization()) {
|
||||||
nm->make_not_entrant();
|
nm->make_not_entrant();
|
||||||
}
|
}
|
||||||
|
@ -741,23 +986,55 @@ void CodeCache::make_marked_nmethods_not_entrant() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::verify() {
|
void CodeCache::verify() {
|
||||||
_heap->verify();
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
FOR_ALL_ALIVE_BLOBS(p) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
p->verify();
|
(*heap)->verify();
|
||||||
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
|
if (cb->is_alive()) {
|
||||||
|
cb->verify();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::report_codemem_full() {
|
// A CodeHeap is full. Print out warning and report event.
|
||||||
|
void CodeCache::report_codemem_full(int code_blob_type, bool print) {
|
||||||
|
// Get nmethod heap for the given CodeBlobType and build CodeCacheFull event
|
||||||
|
CodeHeap* heap = get_code_heap(SegmentedCodeCache ? code_blob_type : CodeBlobType::All);
|
||||||
|
|
||||||
|
if (!heap->was_full() || print) {
|
||||||
|
// Not yet reported for this heap, report
|
||||||
|
heap->report_full();
|
||||||
|
if (SegmentedCodeCache) {
|
||||||
|
warning("CodeHeap for %s is full. Compiler has been disabled.", CodeCache::get_code_heap_name(code_blob_type));
|
||||||
|
warning("Try increasing the code heap size using -XX:%s=",
|
||||||
|
(code_blob_type == CodeBlobType::MethodNonProfiled) ? "NonProfiledCodeHeapSize" : "ProfiledCodeHeapSize");
|
||||||
|
} else {
|
||||||
|
warning("CodeCache is full. Compiler has been disabled.");
|
||||||
|
warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize=");
|
||||||
|
}
|
||||||
|
ResourceMark rm;
|
||||||
|
stringStream s;
|
||||||
|
// Dump code cache into a buffer before locking the tty,
|
||||||
|
{
|
||||||
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
print_summary(&s);
|
||||||
|
}
|
||||||
|
ttyLocker ttyl;
|
||||||
|
tty->print("%s", s.as_string());
|
||||||
|
}
|
||||||
|
|
||||||
_codemem_full_count++;
|
_codemem_full_count++;
|
||||||
EventCodeCacheFull event;
|
EventCodeCacheFull event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_startAddress((u8)low_bound());
|
event.set_codeBlobType((u1)code_blob_type);
|
||||||
event.set_commitedTopAddress((u8)high());
|
event.set_startAddress((u8)heap->low_boundary());
|
||||||
event.set_reservedTopAddress((u8)high_bound());
|
event.set_commitedTopAddress((u8)heap->high());
|
||||||
|
event.set_reservedTopAddress((u8)heap->high_boundary());
|
||||||
event.set_entryCount(nof_blobs());
|
event.set_entryCount(nof_blobs());
|
||||||
event.set_methodCount(nof_nmethods());
|
event.set_methodCount(nof_nmethods());
|
||||||
event.set_adaptorCount(nof_adapters());
|
event.set_adaptorCount(nof_adapters());
|
||||||
event.set_unallocatedCapacity(unallocated_capacity()/K);
|
event.set_unallocatedCapacity(heap->unallocated_capacity()/K);
|
||||||
event.set_fullCount(_codemem_full_count);
|
event.set_fullCount(_codemem_full_count);
|
||||||
event.commit();
|
event.commit();
|
||||||
}
|
}
|
||||||
|
@ -765,15 +1042,17 @@ void CodeCache::report_codemem_full() {
|
||||||
|
|
||||||
void CodeCache::print_memory_overhead() {
|
void CodeCache::print_memory_overhead() {
|
||||||
size_t wasted_bytes = 0;
|
size_t wasted_bytes = 0;
|
||||||
CodeBlob *cb;
|
FOR_ALL_HEAPS(heap) {
|
||||||
for (cb = first(); cb != NULL; cb = next(cb)) {
|
CodeHeap* curr_heap = *heap;
|
||||||
|
for (CodeBlob* cb = (CodeBlob*)curr_heap->first(); cb != NULL; cb = (CodeBlob*)curr_heap->next(cb)) {
|
||||||
HeapBlock* heap_block = ((HeapBlock*)cb) - 1;
|
HeapBlock* heap_block = ((HeapBlock*)cb) - 1;
|
||||||
wasted_bytes += heap_block->length() * CodeCacheSegmentSize - cb->size();
|
wasted_bytes += heap_block->length() * CodeCacheSegmentSize - cb->size();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Print bytes that are allocated in the freelist
|
// Print bytes that are allocated in the freelist
|
||||||
ttyLocker ttl;
|
ttyLocker ttl;
|
||||||
tty->print_cr("Number of elements in freelist: " SSIZE_FORMAT, freelist_length());
|
tty->print_cr("Number of elements in freelist: " SSIZE_FORMAT, freelists_length());
|
||||||
tty->print_cr("Allocated in freelist: " SSIZE_FORMAT "kB", bytes_allocated_in_freelist()/K);
|
tty->print_cr("Allocated in freelist: " SSIZE_FORMAT "kB", bytes_allocated_in_freelists()/K);
|
||||||
tty->print_cr("Unused bytes in CodeBlobs: " SSIZE_FORMAT "kB", (wasted_bytes/K));
|
tty->print_cr("Unused bytes in CodeBlobs: " SSIZE_FORMAT "kB", (wasted_bytes/K));
|
||||||
tty->print_cr("Segment map size: " SSIZE_FORMAT "kB", allocated_segments()/K); // 1 byte per segment
|
tty->print_cr("Segment map size: " SSIZE_FORMAT "kB", allocated_segments()/K); // 1 byte per segment
|
||||||
}
|
}
|
||||||
|
@ -808,8 +1087,12 @@ void CodeCache::print_internals() {
|
||||||
int max_nm_size = 0;
|
int max_nm_size = 0;
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
|
|
||||||
CodeBlob *cb;
|
int i = 0;
|
||||||
for (cb = first(); cb != NULL; cb = next(cb)) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
|
if (SegmentedCodeCache && Verbose) {
|
||||||
|
tty->print_cr("-- Code heap '%s' --", (*heap)->name());
|
||||||
|
}
|
||||||
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
total++;
|
total++;
|
||||||
if (cb->is_nmethod()) {
|
if (cb->is_nmethod()) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
|
@ -847,20 +1130,20 @@ void CodeCache::print_internals() {
|
||||||
bufferBlobCount++;
|
bufferBlobCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int bucketSize = 512;
|
int bucketSize = 512;
|
||||||
int bucketLimit = max_nm_size / bucketSize + 1;
|
int bucketLimit = max_nm_size / bucketSize + 1;
|
||||||
int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode);
|
int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode);
|
||||||
memset(buckets, 0, sizeof(int) * bucketLimit);
|
memset(buckets, 0, sizeof(int) * bucketLimit);
|
||||||
|
|
||||||
for (cb = first(); cb != NULL; cb = next(cb)) {
|
NMethodIterator iter;
|
||||||
if (cb->is_nmethod()) {
|
while(iter.next()) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = iter.method();
|
||||||
if(nm->is_java_method()) {
|
if(nm->method() != NULL && nm->is_java_method()) {
|
||||||
buckets[nm->size() / bucketSize]++;
|
buckets[nm->size() / bucketSize]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tty->print_cr("Code Cache Entries (total of %d)",total);
|
tty->print_cr("Code Cache Entries (total of %d)",total);
|
||||||
tty->print_cr("-------------------------------------------------");
|
tty->print_cr("-------------------------------------------------");
|
||||||
|
@ -902,11 +1185,13 @@ void CodeCache::print() {
|
||||||
CodeBlob_sizes live;
|
CodeBlob_sizes live;
|
||||||
CodeBlob_sizes dead;
|
CodeBlob_sizes dead;
|
||||||
|
|
||||||
FOR_ALL_BLOBS(p) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
if (!p->is_alive()) {
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
dead.add(p);
|
if (!cb->is_alive()) {
|
||||||
|
dead.add(cb);
|
||||||
} else {
|
} else {
|
||||||
live.add(p);
|
live.add(cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,24 +1205,25 @@ void CodeCache::print() {
|
||||||
dead.print("dead");
|
dead.print("dead");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (WizardMode) {
|
if (WizardMode) {
|
||||||
// print the oop_map usage
|
// print the oop_map usage
|
||||||
int code_size = 0;
|
int code_size = 0;
|
||||||
int number_of_blobs = 0;
|
int number_of_blobs = 0;
|
||||||
int number_of_oop_maps = 0;
|
int number_of_oop_maps = 0;
|
||||||
int map_size = 0;
|
int map_size = 0;
|
||||||
FOR_ALL_BLOBS(p) {
|
FOR_ALL_HEAPS(heap) {
|
||||||
if (p->is_alive()) {
|
FOR_ALL_BLOBS(cb, *heap) {
|
||||||
|
if (cb->is_alive()) {
|
||||||
number_of_blobs++;
|
number_of_blobs++;
|
||||||
code_size += p->code_size();
|
code_size += cb->code_size();
|
||||||
OopMapSet* set = p->oop_maps();
|
OopMapSet* set = cb->oop_maps();
|
||||||
if (set != NULL) {
|
if (set != NULL) {
|
||||||
number_of_oop_maps += set->size();
|
number_of_oop_maps += set->size();
|
||||||
map_size += set->heap_size();
|
map_size += set->heap_size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tty->print_cr("OopMaps");
|
tty->print_cr("OopMaps");
|
||||||
tty->print_cr(" #blobs = %d", number_of_blobs);
|
tty->print_cr(" #blobs = %d", number_of_blobs);
|
||||||
tty->print_cr(" code size = %d", code_size);
|
tty->print_cr(" code size = %d", code_size);
|
||||||
|
@ -949,17 +1235,28 @@ void CodeCache::print() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::print_summary(outputStream* st, bool detailed) {
|
void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||||
size_t total = (_heap->high_boundary() - _heap->low_boundary());
|
FOR_ALL_HEAPS(heap_iterator) {
|
||||||
st->print_cr("CodeCache: size=" SIZE_FORMAT "Kb used=" SIZE_FORMAT
|
CodeHeap* heap = (*heap_iterator);
|
||||||
|
size_t total = (heap->high_boundary() - heap->low_boundary());
|
||||||
|
if (SegmentedCodeCache) {
|
||||||
|
st->print("CodeHeap '%s':", heap->name());
|
||||||
|
} else {
|
||||||
|
st->print("CodeCache:");
|
||||||
|
}
|
||||||
|
st->print_cr(" size=" SIZE_FORMAT "Kb used=" SIZE_FORMAT
|
||||||
"Kb max_used=" SIZE_FORMAT "Kb free=" SIZE_FORMAT "Kb",
|
"Kb max_used=" SIZE_FORMAT "Kb free=" SIZE_FORMAT "Kb",
|
||||||
total/K, (total - unallocated_capacity())/K,
|
total/K, (total - heap->unallocated_capacity())/K,
|
||||||
maxCodeCacheUsed/K, unallocated_capacity()/K);
|
heap->max_allocated_capacity()/K, heap->unallocated_capacity()/K);
|
||||||
|
|
||||||
if (detailed) {
|
if (detailed) {
|
||||||
st->print_cr(" bounds [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT "]",
|
st->print_cr(" bounds [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT "]",
|
||||||
p2i(_heap->low_boundary()),
|
p2i(heap->low_boundary()),
|
||||||
p2i(_heap->high()),
|
p2i(heap->high()),
|
||||||
p2i(_heap->high_boundary()));
|
p2i(heap->high_boundary()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detailed) {
|
||||||
st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT
|
st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT
|
||||||
" adapters=" UINT32_FORMAT,
|
" adapters=" UINT32_FORMAT,
|
||||||
nof_blobs(), nof_nmethods(), nof_adapters());
|
nof_blobs(), nof_nmethods(), nof_adapters());
|
||||||
|
@ -973,12 +1270,14 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||||
void CodeCache::print_codelist(outputStream* st) {
|
void CodeCache::print_codelist(outputStream* st) {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
|
|
||||||
FOR_ALL_NMETHODS(p) {
|
NMethodIterator iter;
|
||||||
|
while(iter.next_alive()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
char *method_name = p->method()->name_and_sig_as_C_string();
|
char *method_name = nm->method()->name_and_sig_as_C_string();
|
||||||
st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
|
st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
|
||||||
p->compile_id(), p->comp_level(), method_name, (intptr_t)p->header_begin(),
|
nm->compile_id(), nm->comp_level(), method_name, (intptr_t)nm->header_begin(),
|
||||||
(intptr_t)p->code_begin(), (intptr_t)p->code_end());
|
(intptr_t)nm->code_begin(), (intptr_t)nm->code_end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,4 +1294,3 @@ void CodeCache::log_state(outputStream* st) {
|
||||||
nof_blobs(), nof_nmethods(), nof_adapters(),
|
nof_blobs(), nof_nmethods(), nof_adapters(),
|
||||||
unallocated_capacity());
|
unallocated_capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,55 +26,99 @@
|
||||||
#define SHARE_VM_CODE_CODECACHE_HPP
|
#define SHARE_VM_CODE_CODECACHE_HPP
|
||||||
|
|
||||||
#include "code/codeBlob.hpp"
|
#include "code/codeBlob.hpp"
|
||||||
|
#include "code/nmethod.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/heap.hpp"
|
#include "memory/heap.hpp"
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/oopsHierarchy.hpp"
|
#include "oops/oopsHierarchy.hpp"
|
||||||
|
#include "runtime/mutexLocker.hpp"
|
||||||
|
|
||||||
// The CodeCache implements the code cache for various pieces of generated
|
// The CodeCache implements the code cache for various pieces of generated
|
||||||
// code, e.g., compiled java methods, runtime stubs, transition frames, etc.
|
// code, e.g., compiled java methods, runtime stubs, transition frames, etc.
|
||||||
// The entries in the CodeCache are all CodeBlob's.
|
// The entries in the CodeCache are all CodeBlob's.
|
||||||
|
|
||||||
// Implementation:
|
// -- Implementation --
|
||||||
// - Each CodeBlob occupies one chunk of memory.
|
// The CodeCache consists of one or more CodeHeaps, each of which contains
|
||||||
// - Like the offset table in oldspace the zone has at table for
|
// CodeBlobs of a specific CodeBlobType. Currently heaps for the following
|
||||||
// locating a method given a addess of an instruction.
|
// types are available:
|
||||||
|
// - Non-methods: Non-methods like Buffers, Adapters and Runtime Stubs
|
||||||
|
// - Profiled nmethods: nmethods that are profiled, i.e., those
|
||||||
|
// executed at level 2 or 3
|
||||||
|
// - Non-Profiled nmethods: nmethods that are not profiled, i.e., those
|
||||||
|
// executed at level 1 or 4 and native methods
|
||||||
|
// - All: Used for code of all types if code cache segmentation is disabled.
|
||||||
|
//
|
||||||
|
// In the rare case of the non-method code heap getting full, non-method code
|
||||||
|
// will be stored in the non-profiled code heap as a fallback solution.
|
||||||
|
//
|
||||||
|
// Depending on the availability of compilers and TieredCompilation there
|
||||||
|
// may be fewer heaps. The size of the code heaps depends on the values of
|
||||||
|
// ReservedCodeCacheSize, NonProfiledCodeHeapSize and ProfiledCodeHeapSize
|
||||||
|
// (see CodeCache::heap_available(..) and CodeCache::initialize_heaps(..)
|
||||||
|
// for details).
|
||||||
|
//
|
||||||
|
// Code cache segmentation is controlled by the flag SegmentedCodeCache.
|
||||||
|
// If turned off, all code types are stored in a single code heap. By default
|
||||||
|
// code cache segmentation is turned on if TieredCompilation is enabled and
|
||||||
|
// ReservedCodeCacheSize >= 240 MB.
|
||||||
|
//
|
||||||
|
// All methods of the CodeCache accepting a CodeBlobType only apply to
|
||||||
|
// CodeBlobs of the given type. For example, iteration over the
|
||||||
|
// CodeBlobs of a specific type can be done by using CodeCache::first_blob(..)
|
||||||
|
// and CodeCache::next_blob(..) and providing the corresponding CodeBlobType.
|
||||||
|
//
|
||||||
|
// IMPORTANT: If you add new CodeHeaps to the code cache or change the
|
||||||
|
// existing ones, make sure to adapt the dtrace scripts (jhelper.d) for
|
||||||
|
// Solaris and BSD.
|
||||||
|
|
||||||
class OopClosure;
|
class OopClosure;
|
||||||
class DepChange;
|
class DepChange;
|
||||||
|
|
||||||
class CodeCache : AllStatic {
|
class CodeCache : AllStatic {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
|
friend class NMethodIterator;
|
||||||
private:
|
private:
|
||||||
// CodeHeap is malloc()'ed at startup and never deleted during shutdown,
|
// CodeHeaps of the cache
|
||||||
// so that the generated assembly code is always there when it's needed.
|
static GrowableArray<CodeHeap*>* _heaps;
|
||||||
// This may cause memory leak, but is necessary, for now. See 4423824,
|
|
||||||
// 4422213 or 4436291 for details.
|
static address _low_bound; // Lower bound of CodeHeap addresses
|
||||||
static CodeHeap * _heap;
|
static address _high_bound; // Upper bound of CodeHeap addresses
|
||||||
static int _number_of_blobs;
|
static int _number_of_blobs; // Total number of CodeBlobs in the cache
|
||||||
static int _number_of_adapters;
|
static int _number_of_adapters; // Total number of Adapters in the cache
|
||||||
static int _number_of_nmethods;
|
static int _number_of_nmethods; // Total number of nmethods in the cache
|
||||||
static int _number_of_nmethods_with_dependencies;
|
static int _number_of_nmethods_with_dependencies; // Total number of nmethods with dependencies
|
||||||
static bool _needs_cache_clean;
|
static bool _needs_cache_clean; // True if inline caches of the nmethods needs to be flushed
|
||||||
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
|
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
|
||||||
|
static int _codemem_full_count; // Number of times a CodeHeap in the cache was full
|
||||||
|
|
||||||
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
|
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
|
||||||
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
|
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
|
||||||
|
|
||||||
static int _codemem_full_count;
|
// CodeHeap management
|
||||||
static size_t bytes_allocated_in_freelist() { return _heap->allocated_in_freelist(); }
|
static void initialize_heaps(); // Initializes the CodeHeaps
|
||||||
static int allocated_segments() { return _heap->allocated_segments(); }
|
// Creates a new heap with the given name and size, containing CodeBlobs of the given type
|
||||||
static size_t freelist_length() { return _heap->freelist_length(); }
|
static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type);
|
||||||
|
static CodeHeap* get_code_heap(CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob
|
||||||
|
static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType
|
||||||
|
static bool heap_available(int code_blob_type); // Returns true if a CodeHeap for the given CodeBlobType is available
|
||||||
|
static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps
|
||||||
|
|
||||||
|
// Iteration
|
||||||
|
static CodeBlob* first_blob(CodeHeap* heap); // Returns the first CodeBlob on the given CodeHeap
|
||||||
|
static CodeBlob* first_blob(int code_blob_type); // Returns the first CodeBlob of the given type
|
||||||
|
static CodeBlob* next_blob(CodeHeap* heap, CodeBlob* cb); // Returns the first alive CodeBlob on the given CodeHeap
|
||||||
|
static CodeBlob* next_blob(CodeBlob* cb); // Returns the next CodeBlob of the given type succeeding the given CodeBlob
|
||||||
|
|
||||||
|
static size_t bytes_allocated_in_freelists();
|
||||||
|
static int allocated_segments();
|
||||||
|
static size_t freelists_length();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
static void report_codemem_full();
|
|
||||||
|
|
||||||
// Allocation/administration
|
// Allocation/administration
|
||||||
static CodeBlob* allocate(int size, bool is_critical = false); // allocates a new CodeBlob
|
static CodeBlob* allocate(int size, int code_blob_type, bool is_critical = false); // allocates a new CodeBlob
|
||||||
static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled
|
static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled
|
||||||
static int alignment_unit(); // guaranteed alignment of all CodeBlobs
|
static int alignment_unit(); // guaranteed alignment of all CodeBlobs
|
||||||
static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
|
static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
|
||||||
|
@ -86,45 +130,13 @@ class CodeCache : AllStatic {
|
||||||
static void alive_nmethods_do(void f(nmethod* nm)); // iterates over all alive nmethods
|
static void alive_nmethods_do(void f(nmethod* nm)); // iterates over all alive nmethods
|
||||||
|
|
||||||
// Lookup
|
// Lookup
|
||||||
static CodeBlob* find_blob(void* start);
|
static CodeBlob* find_blob(void* start); // Returns the CodeBlob containing the given address
|
||||||
static nmethod* find_nmethod(void* start);
|
static CodeBlob* find_blob_unsafe(void* start); // Same as find_blob but does not fail if looking up a zombie method
|
||||||
|
static nmethod* find_nmethod(void* start); // Returns the nmethod containing the given address
|
||||||
|
|
||||||
// Lookup that does not fail if you lookup a zombie method (if you call this, be sure to know
|
static int nof_blobs() { return _number_of_blobs; } // Returns the total number of CodeBlobs in the cache
|
||||||
// what you are doing)
|
static int nof_adapters() { return _number_of_adapters; } // Returns the total number of Adapters in the cache
|
||||||
static CodeBlob* find_blob_unsafe(void* start) {
|
static int nof_nmethods() { return _number_of_nmethods; } // Returns the total number of nmethods in the cache
|
||||||
// NMT can walk the stack before code cache is created
|
|
||||||
if (_heap == NULL) return NULL;
|
|
||||||
|
|
||||||
CodeBlob* result = (CodeBlob*)_heap->find_start(start);
|
|
||||||
// this assert is too strong because the heap code will return the
|
|
||||||
// heapblock containing start. That block can often be larger than
|
|
||||||
// the codeBlob itself. If you look up an address that is within
|
|
||||||
// the heapblock but not in the codeBlob you will assert.
|
|
||||||
//
|
|
||||||
// Most things will not lookup such bad addresses. However
|
|
||||||
// AsyncGetCallTrace can see intermediate frames and get that kind
|
|
||||||
// of invalid address and so can a developer using hsfind.
|
|
||||||
//
|
|
||||||
// The more correct answer is to return NULL if blob_contains() returns
|
|
||||||
// false.
|
|
||||||
// assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob");
|
|
||||||
|
|
||||||
if (result != NULL && !result->blob_contains((address)start)) {
|
|
||||||
result = NULL;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iteration
|
|
||||||
static CodeBlob* first();
|
|
||||||
static CodeBlob* next (CodeBlob* cb);
|
|
||||||
static CodeBlob* alive(CodeBlob *cb);
|
|
||||||
static nmethod* alive_nmethod(CodeBlob *cb);
|
|
||||||
static nmethod* first_nmethod();
|
|
||||||
static nmethod* next_nmethod (CodeBlob* cb);
|
|
||||||
static int nof_blobs() { return _number_of_blobs; }
|
|
||||||
static int nof_adapters() { return _number_of_adapters; }
|
|
||||||
static int nof_nmethods() { return _number_of_nmethods; }
|
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
static void gc_epilogue();
|
static void gc_epilogue();
|
||||||
|
@ -151,28 +163,48 @@ class CodeCache : AllStatic {
|
||||||
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
|
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
|
||||||
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||||||
static void log_state(outputStream* st);
|
static void log_state(outputStream* st);
|
||||||
|
static const char* get_code_heap_name(int code_blob_type) { return (heap_available(code_blob_type) ? get_code_heap(code_blob_type)->name() : "Unused"); }
|
||||||
|
static void report_codemem_full(int code_blob_type, bool print);
|
||||||
|
|
||||||
// Dcmd (Diagnostic commands)
|
// Dcmd (Diagnostic commands)
|
||||||
static void print_codelist(outputStream* st);
|
static void print_codelist(outputStream* st);
|
||||||
static void print_layout(outputStream* st);
|
static void print_layout(outputStream* st);
|
||||||
|
|
||||||
// The full limits of the codeCache
|
// The full limits of the codeCache
|
||||||
static address low_bound() { return (address) _heap->low_boundary(); }
|
static address low_bound() { return _low_bound; }
|
||||||
static address high_bound() { return (address) _heap->high_boundary(); }
|
static address high_bound() { return _high_bound; }
|
||||||
static address high() { return (address) _heap->high(); }
|
|
||||||
|
|
||||||
// Profiling
|
// Profiling
|
||||||
static address first_address(); // first address used for CodeBlobs
|
static size_t capacity(int code_blob_type) { return heap_available(code_blob_type) ? get_code_heap(code_blob_type)->capacity() : 0; }
|
||||||
static address last_address(); // last address used for CodeBlobs
|
static size_t capacity();
|
||||||
static size_t capacity() { return _heap->capacity(); }
|
static size_t unallocated_capacity(int code_blob_type) { return heap_available(code_blob_type) ? get_code_heap(code_blob_type)->unallocated_capacity() : 0; }
|
||||||
static size_t max_capacity() { return _heap->max_capacity(); }
|
static size_t unallocated_capacity();
|
||||||
static size_t unallocated_capacity() { return _heap->unallocated_capacity(); }
|
static size_t max_capacity(int code_blob_type) { return heap_available(code_blob_type) ? get_code_heap(code_blob_type)->max_capacity() : 0; }
|
||||||
static double reverse_free_ratio();
|
static size_t max_capacity();
|
||||||
|
|
||||||
|
static bool is_full(int* code_blob_type);
|
||||||
|
static double reverse_free_ratio(int code_blob_type);
|
||||||
|
|
||||||
static bool needs_cache_clean() { return _needs_cache_clean; }
|
static bool needs_cache_clean() { return _needs_cache_clean; }
|
||||||
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
|
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
|
||||||
static void clear_inline_caches(); // clear all inline caches
|
static void clear_inline_caches(); // clear all inline caches
|
||||||
|
|
||||||
|
// Returns the CodeBlobType for nmethods of the given compilation level
|
||||||
|
static int get_code_blob_type(int comp_level) {
|
||||||
|
if (comp_level == CompLevel_none ||
|
||||||
|
comp_level == CompLevel_simple ||
|
||||||
|
comp_level == CompLevel_full_optimization) {
|
||||||
|
// Non profiled methods
|
||||||
|
return CodeBlobType::MethodNonProfiled;
|
||||||
|
} else if (comp_level == CompLevel_limited_profile ||
|
||||||
|
comp_level == CompLevel_full_profile) {
|
||||||
|
// Profiled methods
|
||||||
|
return CodeBlobType::MethodProfiled;
|
||||||
|
}
|
||||||
|
ShouldNotReachHere();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void verify_clean_inline_caches();
|
static void verify_clean_inline_caches();
|
||||||
static void verify_icholder_relocations();
|
static void verify_icholder_relocations();
|
||||||
|
|
||||||
|
@ -193,4 +225,81 @@ class CodeCache : AllStatic {
|
||||||
static int get_codemem_full_count() { return _codemem_full_count; }
|
static int get_codemem_full_count() { return _codemem_full_count; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Iterator to iterate over nmethods in the CodeCache.
|
||||||
|
class NMethodIterator : public StackObj {
|
||||||
|
private:
|
||||||
|
CodeBlob* _code_blob; // Current CodeBlob
|
||||||
|
int _code_blob_type; // Refers to current CodeHeap
|
||||||
|
|
||||||
|
public:
|
||||||
|
NMethodIterator() {
|
||||||
|
initialize(NULL); // Set to NULL, initialized by first call to next()
|
||||||
|
}
|
||||||
|
|
||||||
|
NMethodIterator(nmethod* nm) {
|
||||||
|
initialize(nm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance iterator to next nmethod
|
||||||
|
bool next() {
|
||||||
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
|
assert(_code_blob_type < CodeBlobType::NumTypes, "end reached");
|
||||||
|
|
||||||
|
bool result = next_nmethod();
|
||||||
|
while (!result && (_code_blob_type < CodeBlobType::MethodProfiled)) {
|
||||||
|
// Advance to next code heap if segmented code cache
|
||||||
|
_code_blob_type++;
|
||||||
|
result = next_nmethod();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance iterator to next alive nmethod
|
||||||
|
bool next_alive() {
|
||||||
|
bool result = next();
|
||||||
|
while(result && !_code_blob->is_alive()) {
|
||||||
|
result = next();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end() const { return _code_blob == NULL; }
|
||||||
|
nmethod* method() const { return (nmethod*)_code_blob; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Initialize iterator to given nmethod
|
||||||
|
void initialize(nmethod* nm) {
|
||||||
|
_code_blob = (CodeBlob*)nm;
|
||||||
|
if (!SegmentedCodeCache) {
|
||||||
|
// Iterate over all CodeBlobs
|
||||||
|
_code_blob_type = CodeBlobType::All;
|
||||||
|
} else if (nm != NULL) {
|
||||||
|
_code_blob_type = CodeCache::get_code_blob_type(nm->comp_level());
|
||||||
|
} else {
|
||||||
|
// Only iterate over method code heaps, starting with non-profiled
|
||||||
|
_code_blob_type = CodeBlobType::MethodNonProfiled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance iterator to the next nmethod in the current code heap
|
||||||
|
bool next_nmethod() {
|
||||||
|
// Get first method CodeBlob
|
||||||
|
if (_code_blob == NULL) {
|
||||||
|
_code_blob = CodeCache::first_blob(_code_blob_type);
|
||||||
|
if (_code_blob == NULL) {
|
||||||
|
return false;
|
||||||
|
} else if (_code_blob->is_nmethod()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Search for next method CodeBlob
|
||||||
|
_code_blob = CodeCache::next_blob(_code_blob);
|
||||||
|
while (_code_blob != NULL && !_code_blob->is_nmethod()) {
|
||||||
|
_code_blob = CodeCache::next_blob(_code_blob);
|
||||||
|
}
|
||||||
|
return _code_blob != NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_CODE_CODECACHE_HPP
|
#endif // SHARE_VM_CODE_CODECACHE_HPP
|
||||||
|
|
|
@ -500,7 +500,7 @@ nmethod* nmethod::new_native_nmethod(methodHandle method,
|
||||||
CodeOffsets offsets;
|
CodeOffsets offsets;
|
||||||
offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
|
offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
|
||||||
offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
|
offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
|
||||||
nm = new (native_nmethod_size) nmethod(method(), native_nmethod_size,
|
nm = new (native_nmethod_size, CompLevel_none) nmethod(method(), native_nmethod_size,
|
||||||
compile_id, &offsets,
|
compile_id, &offsets,
|
||||||
code_buffer, frame_size,
|
code_buffer, frame_size,
|
||||||
basic_lock_owner_sp_offset,
|
basic_lock_owner_sp_offset,
|
||||||
|
@ -538,7 +538,7 @@ nmethod* nmethod::new_dtrace_nmethod(methodHandle method,
|
||||||
offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset);
|
offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset);
|
||||||
offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
|
offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
|
||||||
|
|
||||||
nm = new (nmethod_size) nmethod(method(), nmethod_size,
|
nm = new (nmethod_size, CompLevel_none) nmethod(method(), nmethod_size,
|
||||||
&offsets, code_buffer, frame_size);
|
&offsets, code_buffer, frame_size);
|
||||||
|
|
||||||
NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm));
|
NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm));
|
||||||
|
@ -586,7 +586,7 @@ nmethod* nmethod::new_nmethod(methodHandle method,
|
||||||
+ round_to(nul_chk_table->size_in_bytes(), oopSize)
|
+ round_to(nul_chk_table->size_in_bytes(), oopSize)
|
||||||
+ round_to(debug_info->data_size() , oopSize);
|
+ round_to(debug_info->data_size() , oopSize);
|
||||||
|
|
||||||
nm = new (nmethod_size)
|
nm = new (nmethod_size, comp_level)
|
||||||
nmethod(method(), nmethod_size, compile_id, entry_bci, offsets,
|
nmethod(method(), nmethod_size, compile_id, entry_bci, offsets,
|
||||||
orig_pc_offset, debug_info, dependencies, code_buffer, frame_size,
|
orig_pc_offset, debug_info, dependencies, code_buffer, frame_size,
|
||||||
oop_maps,
|
oop_maps,
|
||||||
|
@ -803,9 +803,11 @@ nmethod::nmethod(
|
||||||
}
|
}
|
||||||
#endif // def HAVE_DTRACE_H
|
#endif // def HAVE_DTRACE_H
|
||||||
|
|
||||||
void* nmethod::operator new(size_t size, int nmethod_size) throw() {
|
void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () {
|
||||||
// Not critical, may return null if there is too little continuous memory
|
// With a SegmentedCodeCache, nmethods are allocated on separate heaps and therefore do not share memory
|
||||||
return CodeCache::allocate(nmethod_size);
|
// with critical CodeBlobs. We define the allocation as critical to make sure all code heap memory is used.
|
||||||
|
bool is_critical = SegmentedCodeCache;
|
||||||
|
return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level), is_critical);
|
||||||
}
|
}
|
||||||
|
|
||||||
nmethod::nmethod(
|
nmethod::nmethod(
|
||||||
|
@ -1530,7 +1532,7 @@ void nmethod::flush() {
|
||||||
Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this);
|
Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this);
|
||||||
if (PrintMethodFlushing) {
|
if (PrintMethodFlushing) {
|
||||||
tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb",
|
tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb",
|
||||||
_compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()/1024);
|
_compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(_comp_level))/1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to deallocate any ExceptionCache data.
|
// We need to deallocate any ExceptionCache data.
|
||||||
|
@ -1557,7 +1559,6 @@ void nmethod::flush() {
|
||||||
CodeCache::free(this);
|
CodeCache::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Notify all classes this nmethod is dependent on that it is no
|
// Notify all classes this nmethod is dependent on that it is no
|
||||||
// longer dependent. This should only be called in two situations.
|
// longer dependent. This should only be called in two situations.
|
||||||
|
@ -2425,8 +2426,11 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
||||||
|
|
||||||
// Iterate over live nmethods and check dependencies of all nmethods that are not
|
// Iterate over live nmethods and check dependencies of all nmethods that are not
|
||||||
// marked for deoptimization. A particular dependency is only checked once.
|
// marked for deoptimization. A particular dependency is only checked once.
|
||||||
for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) {
|
NMethodIterator iter;
|
||||||
if (!nm->is_marked_for_deoptimization()) {
|
while(iter.next()) {
|
||||||
|
nmethod* nm = iter.method();
|
||||||
|
// Only notify for live nmethods
|
||||||
|
if (nm->is_alive() && !nm->is_marked_for_deoptimization()) {
|
||||||
for (Dependencies::DepStream deps(nm); deps.next(); ) {
|
for (Dependencies::DepStream deps(nm); deps.next(); ) {
|
||||||
// Construct abstraction of a dependency.
|
// Construct abstraction of a dependency.
|
||||||
DependencySignature* current_sig = new DependencySignature(deps);
|
DependencySignature* current_sig = new DependencySignature(deps);
|
||||||
|
|
|
@ -288,7 +288,7 @@ class nmethod : public CodeBlob {
|
||||||
int comp_level);
|
int comp_level);
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
void* operator new(size_t size, int nmethod_size) throw();
|
void* operator new(size_t size, int nmethod_size, int comp_level) throw();
|
||||||
|
|
||||||
const char* reloc_string_for(u_char* begin, u_char* end);
|
const char* reloc_string_for(u_char* begin, u_char* end);
|
||||||
// Returns true if this thread changed the state of the nmethod or
|
// Returns true if this thread changed the state of the nmethod or
|
||||||
|
|
|
@ -63,7 +63,7 @@ void* VtableStub::operator new(size_t size, int code_size) throw() {
|
||||||
// If changing the name, update the other file accordingly.
|
// If changing the name, update the other file accordingly.
|
||||||
BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
|
BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
|
||||||
if (blob == NULL) {
|
if (blob == NULL) {
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
_chunk = blob->content_begin();
|
_chunk = blob->content_begin();
|
||||||
|
|
|
@ -783,18 +783,22 @@ CompileQueue* CompileBroker::compile_queue(int comp_level) {
|
||||||
|
|
||||||
|
|
||||||
void CompileBroker::print_compile_queues(outputStream* st) {
|
void CompileBroker::print_compile_queues(outputStream* st) {
|
||||||
|
MutexLocker locker(MethodCompileQueue_lock);
|
||||||
|
if (_c1_compile_queue != NULL) {
|
||||||
_c1_compile_queue->print(st);
|
_c1_compile_queue->print(st);
|
||||||
|
}
|
||||||
|
if (_c2_compile_queue != NULL) {
|
||||||
_c2_compile_queue->print(st);
|
_c2_compile_queue->print(st);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CompileQueue::print(outputStream* st) {
|
void CompileQueue::print(outputStream* st) {
|
||||||
assert_locked_or_safepoint(lock());
|
assert(lock()->owned_by_self(), "must own lock");
|
||||||
st->print_cr("Contents of %s", name());
|
st->print_cr("Contents of %s", name());
|
||||||
st->print_cr("----------------------------");
|
st->print_cr("----------------------------");
|
||||||
CompileTask* task = _first;
|
CompileTask* task = _first;
|
||||||
if (task == NULL) {
|
if (task == NULL) {
|
||||||
st->print_cr("Empty");;
|
st->print_cr("Empty");
|
||||||
} else {
|
} else {
|
||||||
while (task != NULL) {
|
while (task != NULL) {
|
||||||
task->print_compilation(st, NULL, true, true);
|
task->print_compilation(st, NULL, true, true);
|
||||||
|
@ -1206,6 +1210,12 @@ void CompileBroker::compile_method_base(methodHandle method,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TieredCompilation) {
|
||||||
|
// Tiered policy requires MethodCounters to exist before adding a method to
|
||||||
|
// the queue. Create if we don't have them yet.
|
||||||
|
method->get_method_counters(thread);
|
||||||
|
}
|
||||||
|
|
||||||
// Outputs from the following MutexLocker block:
|
// Outputs from the following MutexLocker block:
|
||||||
CompileTask* task = NULL;
|
CompileTask* task = NULL;
|
||||||
bool blocking = false;
|
bool blocking = false;
|
||||||
|
@ -1747,9 +1757,11 @@ void CompileBroker::compiler_thread_loop() {
|
||||||
// We need this HandleMark to avoid leaking VM handles.
|
// We need this HandleMark to avoid leaking VM handles.
|
||||||
HandleMark hm(thread);
|
HandleMark hm(thread);
|
||||||
|
|
||||||
if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) {
|
// Check if the CodeCache is full
|
||||||
// the code cache is really full
|
int code_blob_type = 0;
|
||||||
handle_full_code_cache();
|
if (CodeCache::is_full(&code_blob_type)) {
|
||||||
|
// The CodeHeap for code_blob_type is really full
|
||||||
|
handle_full_code_cache(code_blob_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileTask* task = queue->get();
|
CompileTask* task = queue->get();
|
||||||
|
@ -1777,22 +1789,6 @@ void CompileBroker::compiler_thread_loop() {
|
||||||
if (method()->number_of_breakpoints() == 0) {
|
if (method()->number_of_breakpoints() == 0) {
|
||||||
// Compile the method.
|
// Compile the method.
|
||||||
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
|
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
|
||||||
#ifdef COMPILER1
|
|
||||||
// Allow repeating compilations for the purpose of benchmarking
|
|
||||||
// compile speed. This is not useful for customers.
|
|
||||||
if (CompilationRepeat != 0) {
|
|
||||||
int compile_count = CompilationRepeat;
|
|
||||||
while (compile_count > 0) {
|
|
||||||
invoke_compiler_on_method(task);
|
|
||||||
nmethod* nm = method->code();
|
|
||||||
if (nm != NULL) {
|
|
||||||
nm->make_zombie();
|
|
||||||
method->clear_code();
|
|
||||||
}
|
|
||||||
compile_count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* COMPILER1 */
|
|
||||||
invoke_compiler_on_method(task);
|
invoke_compiler_on_method(task);
|
||||||
} else {
|
} else {
|
||||||
// After compilation is disabled, remove remaining methods from queue
|
// After compilation is disabled, remove remaining methods from queue
|
||||||
|
@ -2079,7 +2075,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||||
* The CodeCache is full. Print out warning and disable compilation
|
* The CodeCache is full. Print out warning and disable compilation
|
||||||
* or try code cache cleaning so compilation can continue later.
|
* or try code cache cleaning so compilation can continue later.
|
||||||
*/
|
*/
|
||||||
void CompileBroker::handle_full_code_cache() {
|
void CompileBroker::handle_full_code_cache(int code_blob_type) {
|
||||||
UseInterpreter = true;
|
UseInterpreter = true;
|
||||||
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
||||||
if (xtty != NULL) {
|
if (xtty != NULL) {
|
||||||
|
@ -2096,8 +2092,6 @@ void CompileBroker::handle_full_code_cache() {
|
||||||
xtty->end_elem();
|
xtty->end_elem();
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeCache::report_codemem_full();
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (CompileTheWorld || ExitOnFullCodeCache) {
|
if (CompileTheWorld || ExitOnFullCodeCache) {
|
||||||
codecache_print(/* detailed= */ true);
|
codecache_print(/* detailed= */ true);
|
||||||
|
@ -2119,12 +2113,7 @@ void CompileBroker::handle_full_code_cache() {
|
||||||
disable_compilation_forever();
|
disable_compilation_forever();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print warning only once
|
CodeCache::report_codemem_full(code_blob_type, should_print_compiler_warning());
|
||||||
if (should_print_compiler_warning()) {
|
|
||||||
warning("CodeCache is full. Compiler has been disabled.");
|
|
||||||
warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize=");
|
|
||||||
codecache_print(/* detailed= */ true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -434,7 +434,7 @@ class CompileBroker: AllStatic {
|
||||||
static bool is_compilation_disabled_forever() {
|
static bool is_compilation_disabled_forever() {
|
||||||
return _should_compile_new_jobs == shutdown_compilaton;
|
return _should_compile_new_jobs == shutdown_compilaton;
|
||||||
}
|
}
|
||||||
static void handle_full_code_cache();
|
static void handle_full_code_cache(int code_blob_type);
|
||||||
// Ensures that warning is only printed once.
|
// Ensures that warning is only printed once.
|
||||||
static bool should_print_compiler_warning() {
|
static bool should_print_compiler_warning() {
|
||||||
jint old = Atomic::cmpxchg(1, &_print_compilation_warning, 0);
|
jint old = Atomic::cmpxchg(1, &_print_compilation_warning, 0);
|
||||||
|
|
|
@ -5013,7 +5013,11 @@ private:
|
||||||
_num_entered_barrier(0)
|
_num_entered_barrier(0)
|
||||||
{
|
{
|
||||||
nmethod::increase_unloading_clock();
|
nmethod::increase_unloading_clock();
|
||||||
_first_nmethod = CodeCache::alive_nmethod(CodeCache::first());
|
// Get first alive nmethod
|
||||||
|
NMethodIterator iter = NMethodIterator();
|
||||||
|
if(iter.next_alive()) {
|
||||||
|
_first_nmethod = iter.method();
|
||||||
|
}
|
||||||
_claimed_nmethod = (volatile nmethod*)_first_nmethod;
|
_claimed_nmethod = (volatile nmethod*)_first_nmethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5056,27 +5060,26 @@ private:
|
||||||
|
|
||||||
void claim_nmethods(nmethod** claimed_nmethods, int *num_claimed_nmethods) {
|
void claim_nmethods(nmethod** claimed_nmethods, int *num_claimed_nmethods) {
|
||||||
nmethod* first;
|
nmethod* first;
|
||||||
nmethod* last;
|
NMethodIterator last;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
*num_claimed_nmethods = 0;
|
*num_claimed_nmethods = 0;
|
||||||
|
|
||||||
first = last = (nmethod*)_claimed_nmethod;
|
first = (nmethod*)_claimed_nmethod;
|
||||||
|
last = NMethodIterator(first);
|
||||||
|
|
||||||
if (first != NULL) {
|
if (first != NULL) {
|
||||||
for (int i = 0; i < MaxClaimNmethods; i++) {
|
|
||||||
last = CodeCache::alive_nmethod(CodeCache::next(last));
|
|
||||||
|
|
||||||
if (last == NULL) {
|
for (int i = 0; i < MaxClaimNmethods; i++) {
|
||||||
|
if (!last.next_alive()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
claimed_nmethods[i] = last.method();
|
||||||
claimed_nmethods[i] = last;
|
|
||||||
(*num_claimed_nmethods)++;
|
(*num_claimed_nmethods)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while ((nmethod*)Atomic::cmpxchg_ptr(last, &_claimed_nmethod, first) != first);
|
} while ((nmethod*)Atomic::cmpxchg_ptr(last.method(), &_claimed_nmethod, first) != first);
|
||||||
}
|
}
|
||||||
|
|
||||||
nmethod* claim_postponed_nmethod() {
|
nmethod* claim_postponed_nmethod() {
|
||||||
|
|
|
@ -1077,7 +1077,7 @@ IRT_END
|
||||||
address SignatureHandlerLibrary::set_handler_blob() {
|
address SignatureHandlerLibrary::set_handler_blob() {
|
||||||
BufferBlob* handler_blob = BufferBlob::create("native signature handlers", blob_size);
|
BufferBlob* handler_blob = BufferBlob::create("native signature handlers", blob_size);
|
||||||
if (handler_blob == NULL) {
|
if (handler_blob == NULL) {
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
address handler = handler_blob->code_begin();
|
address handler = handler_blob->code_begin();
|
||||||
|
|
|
@ -693,14 +693,16 @@ void* Arena::internal_malloc_4(size_t x) {
|
||||||
// compilers and they should be upwards compatible with C++11/14. Therefore
|
// compilers and they should be upwards compatible with C++11/14. Therefore
|
||||||
// PLEASE BE CAREFUL if you change the signature of the following operators!
|
// PLEASE BE CAREFUL if you change the signature of the following operators!
|
||||||
|
|
||||||
|
static void * zero = (void *) 0;
|
||||||
|
|
||||||
void* operator new(size_t size) /* throw(std::bad_alloc) */ {
|
void* operator new(size_t size) /* throw(std::bad_alloc) */ {
|
||||||
fatal("Should not call global operator new");
|
fatal("Should not call global operator new");
|
||||||
return 0;
|
return zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new [](size_t size) /* throw(std::bad_alloc) */ {
|
void* operator new [](size_t size) /* throw(std::bad_alloc) */ {
|
||||||
fatal("Should not call global operator new[]");
|
fatal("Should not call global operator new[]");
|
||||||
return 0;
|
return zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
|
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
|
||||||
|
|
|
@ -35,7 +35,9 @@ size_t CodeHeap::header_size() {
|
||||||
|
|
||||||
// Implementation of Heap
|
// Implementation of Heap
|
||||||
|
|
||||||
CodeHeap::CodeHeap() {
|
CodeHeap::CodeHeap(const char* name, const int code_blob_type)
|
||||||
|
: _code_blob_type(code_blob_type) {
|
||||||
|
_name = name;
|
||||||
_number_of_committed_segments = 0;
|
_number_of_committed_segments = 0;
|
||||||
_number_of_reserved_segments = 0;
|
_number_of_reserved_segments = 0;
|
||||||
_segment_size = 0;
|
_segment_size = 0;
|
||||||
|
@ -44,6 +46,8 @@ CodeHeap::CodeHeap() {
|
||||||
_freelist = NULL;
|
_freelist = NULL;
|
||||||
_freelist_segments = 0;
|
_freelist_segments = 0;
|
||||||
_freelist_length = 0;
|
_freelist_length = 0;
|
||||||
|
_max_allocated_capacity = 0;
|
||||||
|
_was_full = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,9 +92,8 @@ void CodeHeap::on_code_mapping(char* base, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
|
bool CodeHeap::reserve(ReservedSpace rs, size_t committed_size, size_t segment_size) {
|
||||||
size_t segment_size) {
|
assert(rs.size() >= committed_size, "reserved < committed");
|
||||||
assert(reserved_size >= committed_size, "reserved < committed");
|
|
||||||
assert(segment_size >= sizeof(FreeBlock), "segment size is too small");
|
assert(segment_size >= sizeof(FreeBlock), "segment size is too small");
|
||||||
assert(is_power_of_2(segment_size), "segment_size must be a power of 2");
|
assert(is_power_of_2(segment_size), "segment_size must be a power of 2");
|
||||||
|
|
||||||
|
@ -102,18 +105,13 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
|
||||||
if (os::can_execute_large_page_memory()) {
|
if (os::can_execute_large_page_memory()) {
|
||||||
const size_t min_pages = 8;
|
const size_t min_pages = 8;
|
||||||
page_size = MIN2(os::page_size_for_region(committed_size, min_pages),
|
page_size = MIN2(os::page_size_for_region(committed_size, min_pages),
|
||||||
os::page_size_for_region(reserved_size, min_pages));
|
os::page_size_for_region(rs.size(), min_pages));
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t granularity = os::vm_allocation_granularity();
|
const size_t granularity = os::vm_allocation_granularity();
|
||||||
const size_t r_align = MAX2(page_size, granularity);
|
|
||||||
const size_t r_size = align_size_up(reserved_size, r_align);
|
|
||||||
const size_t c_size = align_size_up(committed_size, page_size);
|
const size_t c_size = align_size_up(committed_size, page_size);
|
||||||
|
|
||||||
const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 :
|
os::trace_page_sizes(_name, committed_size, rs.size(), page_size,
|
||||||
MAX2(page_size, granularity);
|
|
||||||
ReservedCodeSpace rs(r_size, rs_align, rs_align > 0);
|
|
||||||
os::trace_page_sizes("code heap", committed_size, reserved_size, page_size,
|
|
||||||
rs.base(), rs.size());
|
rs.base(), rs.size());
|
||||||
if (!_memory.initialize(rs, c_size)) {
|
if (!_memory.initialize(rs, c_size)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -186,6 +184,7 @@ void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
|
||||||
assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
|
assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
|
||||||
assert(!block->free(), "must be marked free");
|
assert(!block->free(), "must be marked free");
|
||||||
DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
|
DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
|
||||||
|
_max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
|
||||||
return block->allocated_space();
|
return block->allocated_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +206,7 @@ void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
|
||||||
b->initialize(number_of_segments);
|
b->initialize(number_of_segments);
|
||||||
_next_segment += number_of_segments;
|
_next_segment += number_of_segments;
|
||||||
DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
|
DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
|
||||||
|
_max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
|
||||||
return b->allocated_space();
|
return b->allocated_space();
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#ifndef SHARE_VM_MEMORY_HEAP_HPP
|
#ifndef SHARE_VM_MEMORY_HEAP_HPP
|
||||||
#define SHARE_VM_MEMORY_HEAP_HPP
|
#define SHARE_VM_MEMORY_HEAP_HPP
|
||||||
|
|
||||||
|
#include "code/codeBlob.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "runtime/virtualspace.hpp"
|
#include "runtime/virtualspace.hpp"
|
||||||
|
|
||||||
|
@ -93,6 +94,11 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||||
FreeBlock* _freelist;
|
FreeBlock* _freelist;
|
||||||
size_t _freelist_segments; // No. of segments in freelist
|
size_t _freelist_segments; // No. of segments in freelist
|
||||||
int _freelist_length;
|
int _freelist_length;
|
||||||
|
size_t _max_allocated_capacity; // Peak capacity that was allocated during lifetime of the heap
|
||||||
|
|
||||||
|
const char* _name; // Name of the CodeHeap
|
||||||
|
const int _code_blob_type; // CodeBlobType it contains
|
||||||
|
bool _was_full; // True if the code heap was full
|
||||||
|
|
||||||
enum { free_sentinel = 0xFF };
|
enum { free_sentinel = 0xFF };
|
||||||
|
|
||||||
|
@ -127,10 +133,10 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||||
void clear(); // clears all heap contents
|
void clear(); // clears all heap contents
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeHeap();
|
CodeHeap(const char* name, const int code_blob_type);
|
||||||
|
|
||||||
// Heap extents
|
// Heap extents
|
||||||
bool reserve(size_t reserved_size, size_t committed_size, size_t segment_size);
|
bool reserve(ReservedSpace rs, size_t committed_size, size_t segment_size);
|
||||||
bool expand_by(size_t size); // expands committed memory by size
|
bool expand_by(size_t size); // expands committed memory by size
|
||||||
|
|
||||||
// Memory allocation
|
// Memory allocation
|
||||||
|
@ -161,8 +167,18 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||||
size_t max_capacity() const;
|
size_t max_capacity() const;
|
||||||
int allocated_segments() const;
|
int allocated_segments() const;
|
||||||
size_t allocated_capacity() const;
|
size_t allocated_capacity() const;
|
||||||
|
size_t max_allocated_capacity() const { return _max_allocated_capacity; }
|
||||||
size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); }
|
size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); }
|
||||||
|
|
||||||
|
// Returns true if the CodeHeap contains CodeBlobs of the given type
|
||||||
|
bool accepts(int code_blob_type) const { return (_code_blob_type == code_blob_type); }
|
||||||
|
int code_blob_type() const { return _code_blob_type; }
|
||||||
|
|
||||||
|
// Debugging / Profiling
|
||||||
|
const char* name() const { return _name; }
|
||||||
|
bool was_full() { return _was_full; }
|
||||||
|
void report_full() { _was_full = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t heap_unallocated_capacity() const;
|
size_t heap_unallocated_capacity() const;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) {
|
||||||
set_hidden(false);
|
set_hidden(false);
|
||||||
set_dont_inline(false);
|
set_dont_inline(false);
|
||||||
set_method_data(NULL);
|
set_method_data(NULL);
|
||||||
set_method_counters(NULL);
|
clear_method_counters();
|
||||||
set_vtable_index(Method::garbage_vtable_index);
|
set_vtable_index(Method::garbage_vtable_index);
|
||||||
|
|
||||||
// Fix and bury in Method*
|
// Fix and bury in Method*
|
||||||
|
@ -117,7 +117,7 @@ void Method::deallocate_contents(ClassLoaderData* loader_data) {
|
||||||
MetadataFactory::free_metadata(loader_data, method_data());
|
MetadataFactory::free_metadata(loader_data, method_data());
|
||||||
set_method_data(NULL);
|
set_method_data(NULL);
|
||||||
MetadataFactory::free_metadata(loader_data, method_counters());
|
MetadataFactory::free_metadata(loader_data, method_counters());
|
||||||
set_method_counters(NULL);
|
clear_method_counters();
|
||||||
// The nmethod will be gone when we get here.
|
// The nmethod will be gone when we get here.
|
||||||
if (code() != NULL) _code = NULL;
|
if (code() != NULL) _code = NULL;
|
||||||
}
|
}
|
||||||
|
@ -395,9 +395,7 @@ MethodCounters* Method::build_method_counters(Method* m, TRAPS) {
|
||||||
methodHandle mh(m);
|
methodHandle mh(m);
|
||||||
ClassLoaderData* loader_data = mh->method_holder()->class_loader_data();
|
ClassLoaderData* loader_data = mh->method_holder()->class_loader_data();
|
||||||
MethodCounters* counters = MethodCounters::allocate(loader_data, CHECK_NULL);
|
MethodCounters* counters = MethodCounters::allocate(loader_data, CHECK_NULL);
|
||||||
if (mh->method_counters() == NULL) {
|
if (!mh->init_method_counters(counters)) {
|
||||||
mh->set_method_counters(counters);
|
|
||||||
} else {
|
|
||||||
MetadataFactory::free_metadata(loader_data, counters);
|
MetadataFactory::free_metadata(loader_data, counters);
|
||||||
}
|
}
|
||||||
return mh->method_counters();
|
return mh->method_counters();
|
||||||
|
@ -859,7 +857,7 @@ void Method::unlink_method() {
|
||||||
assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?");
|
assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?");
|
||||||
|
|
||||||
set_method_data(NULL);
|
set_method_data(NULL);
|
||||||
set_method_counters(NULL);
|
clear_method_counters();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the method_holder is getting linked. Setup entrypoints so the method
|
// Called when the method_holder is getting linked. Setup entrypoints so the method
|
||||||
|
|
|
@ -333,11 +333,13 @@ class Method : public Metadata {
|
||||||
return _method_counters;
|
return _method_counters;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_method_counters(MethodCounters* counters) {
|
void clear_method_counters() {
|
||||||
// The store into method must be released. On platforms without
|
_method_counters = NULL;
|
||||||
// total store order (TSO) the reference may become visible before
|
}
|
||||||
// the initialization of data otherwise.
|
|
||||||
OrderAccess::release_store_ptr((volatile void *)&_method_counters, counters);
|
bool init_method_counters(MethodCounters* counters) {
|
||||||
|
// Try to install a pointer to MethodCounters, return true on success.
|
||||||
|
return Atomic::cmpxchg_ptr(counters, (volatile void*)&_method_counters, NULL) == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TIERED
|
#ifdef TIERED
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "opto/c2compiler.hpp"
|
#include "opto/c2compiler.hpp"
|
||||||
|
#include "opto/compile.hpp"
|
||||||
#include "opto/optoreg.hpp"
|
#include "opto/optoreg.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
|
|
||||||
// register information defined by ADLC
|
// register information defined by ADLC
|
||||||
|
@ -147,3 +149,8 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
|
||||||
void C2Compiler::print_timers() {
|
void C2Compiler::print_timers() {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int C2Compiler::initial_code_buffer_size() {
|
||||||
|
assert(SegmentedCodeCache, "Should be only used with a segmented code cache");
|
||||||
|
return Compile::MAX_inst_size + Compile::MAX_locs_size + initial_const_capacity;
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ public:
|
||||||
|
|
||||||
// Print compilation timers and statistics
|
// Print compilation timers and statistics
|
||||||
void print_timers();
|
void print_timers();
|
||||||
|
|
||||||
|
// Initial size of the code buffer (may be increased at runtime)
|
||||||
|
static int initial_code_buffer_size();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_OPTO_C2COMPILER_HPP
|
#endif // SHARE_VM_OPTO_C2COMPILER_HPP
|
||||||
|
|
|
@ -535,7 +535,7 @@ void Compile::init_scratch_buffer_blob(int const_size) {
|
||||||
if (scratch_buffer_blob() == NULL) {
|
if (scratch_buffer_blob() == NULL) {
|
||||||
// Let CompilerBroker disable further compilations.
|
// Let CompilerBroker disable further compilations.
|
||||||
record_failure("Not enough space for scratch buffer in CodeCache");
|
record_failure("Not enough space for scratch buffer in CodeCache");
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1166,7 +1166,7 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) {
|
||||||
// Have we run out of code space?
|
// Have we run out of code space?
|
||||||
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
||||||
C->record_failure("CodeCache is full");
|
C->record_failure("CodeCache is full");
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Configure the code buffer.
|
// Configure the code buffer.
|
||||||
|
@ -1491,7 +1491,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||||
cb->insts()->maybe_expand_to_ensure_remaining(MAX_inst_size);
|
cb->insts()->maybe_expand_to_ensure_remaining(MAX_inst_size);
|
||||||
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
||||||
C->record_failure("CodeCache is full");
|
C->record_failure("CodeCache is full");
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1648,7 +1648,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||||
// One last check for failed CodeBuffer::expand:
|
// One last check for failed CodeBuffer::expand:
|
||||||
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
|
||||||
C->record_failure("CodeCache is full");
|
C->record_failure("CodeCache is full");
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,10 +228,10 @@ jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* e
|
||||||
// created nmethod will notify normally and nmethods which are freed
|
// created nmethod will notify normally and nmethods which are freed
|
||||||
// can be safely skipped.
|
// can be safely skipped.
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
nmethod* current = CodeCache::first_nmethod();
|
// Iterate over non-profiled and profiled nmethods
|
||||||
while (current != NULL) {
|
NMethodIterator iter;
|
||||||
// Only notify for live nmethods
|
while(iter.next_alive()) {
|
||||||
if (current->is_alive()) {
|
nmethod* current = iter.method();
|
||||||
// Lock the nmethod so it can't be freed
|
// Lock the nmethod so it can't be freed
|
||||||
nmethodLocker nml(current);
|
nmethodLocker nml(current);
|
||||||
|
|
||||||
|
@ -240,8 +240,6 @@ jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* e
|
||||||
current->get_and_cache_jmethod_id();
|
current->get_and_cache_jmethod_id();
|
||||||
JvmtiExport::post_compiled_method_load(current);
|
JvmtiExport::post_compiled_method_load(current);
|
||||||
}
|
}
|
||||||
current = CodeCache::next_nmethod(current);
|
|
||||||
}
|
|
||||||
return JVMTI_ERROR_NONE;
|
return JVMTI_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ double AdvancedThresholdPolicy::threshold_scale(CompLevel level, int feedback_k)
|
||||||
// The main intention is to keep enough free space for C2 compiled code
|
// The main intention is to keep enough free space for C2 compiled code
|
||||||
// to achieve peak performance if the code cache is under stress.
|
// to achieve peak performance if the code cache is under stress.
|
||||||
if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) {
|
if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) {
|
||||||
double current_reverse_free_ratio = CodeCache::reverse_free_ratio();
|
double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level));
|
||||||
if (current_reverse_free_ratio > _increase_threshold_at_ratio) {
|
if (current_reverse_free_ratio > _increase_threshold_at_ratio) {
|
||||||
k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio);
|
k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1146,7 +1146,27 @@ void Arguments::set_tiered_flags() {
|
||||||
}
|
}
|
||||||
// Increase the code cache size - tiered compiles a lot more.
|
// Increase the code cache size - tiered compiles a lot more.
|
||||||
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
|
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
|
||||||
FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 5);
|
FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, ReservedCodeCacheSize * 5);
|
||||||
|
}
|
||||||
|
// Enable SegmentedCodeCache if TieredCompilation is enabled and ReservedCodeCacheSize >= 240M
|
||||||
|
if (FLAG_IS_DEFAULT(SegmentedCodeCache) && ReservedCodeCacheSize >= 240*M) {
|
||||||
|
FLAG_SET_ERGO(bool, SegmentedCodeCache, true);
|
||||||
|
|
||||||
|
// Multiply sizes by 5 but fix NonMethodCodeHeapSize (distribute among non-profiled and profiled code heap)
|
||||||
|
if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) {
|
||||||
|
FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, ProfiledCodeHeapSize * 5 + NonMethodCodeHeapSize * 2);
|
||||||
|
}
|
||||||
|
if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) {
|
||||||
|
FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, NonProfiledCodeHeapSize * 5 + NonMethodCodeHeapSize * 2);
|
||||||
|
}
|
||||||
|
// Check consistency of code heap sizes
|
||||||
|
if ((NonMethodCodeHeapSize + NonProfiledCodeHeapSize + ProfiledCodeHeapSize) != ReservedCodeCacheSize) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid code heap sizes: NonMethodCodeHeapSize(%dK) + ProfiledCodeHeapSize(%dK) + NonProfiledCodeHeapSize(%dK) = %dK. Must be equal to ReservedCodeCacheSize = %uK.\n",
|
||||||
|
NonMethodCodeHeapSize/K, ProfiledCodeHeapSize/K, NonProfiledCodeHeapSize/K,
|
||||||
|
(NonMethodCodeHeapSize + ProfiledCodeHeapSize + NonProfiledCodeHeapSize)/K, ReservedCodeCacheSize/K);
|
||||||
|
vm_exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!UseInterpreter) { // -Xcomp
|
if (!UseInterpreter) { // -Xcomp
|
||||||
Tier3InvokeNotifyFreqLog = 0;
|
Tier3InvokeNotifyFreqLog = 0;
|
||||||
|
@ -2482,6 +2502,18 @@ bool Arguments::check_vm_args_consistency() {
|
||||||
"Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M,
|
"Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M,
|
||||||
(2*G)/M);
|
(2*G)/M);
|
||||||
status = false;
|
status = false;
|
||||||
|
} else if (NonMethodCodeHeapSize < min_code_cache_size){
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid NonMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonMethodCodeHeapSize/K,
|
||||||
|
min_code_cache_size/K);
|
||||||
|
status = false;
|
||||||
|
} else if ((!FLAG_IS_DEFAULT(NonMethodCodeHeapSize) || !FLAG_IS_DEFAULT(ProfiledCodeHeapSize) || !FLAG_IS_DEFAULT(NonProfiledCodeHeapSize))
|
||||||
|
&& (NonMethodCodeHeapSize + NonProfiledCodeHeapSize + ProfiledCodeHeapSize) != ReservedCodeCacheSize) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid code heap sizes: NonMethodCodeHeapSize(%dK) + ProfiledCodeHeapSize(%dK) + NonProfiledCodeHeapSize(%dK) = %dK. Must be equal to ReservedCodeCacheSize = %uK.\n",
|
||||||
|
NonMethodCodeHeapSize/K, ProfiledCodeHeapSize/K, NonProfiledCodeHeapSize/K,
|
||||||
|
(NonMethodCodeHeapSize + ProfiledCodeHeapSize + NonProfiledCodeHeapSize)/K, ReservedCodeCacheSize/K);
|
||||||
|
status = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
|
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
|
||||||
|
@ -2906,6 +2938,39 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
|
||||||
return JNI_EINVAL;
|
return JNI_EINVAL;
|
||||||
}
|
}
|
||||||
FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize);
|
FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize);
|
||||||
|
// -XX:NonMethodCodeHeapSize=
|
||||||
|
} else if (match_option(option, "-XX:NonMethodCodeHeapSize=", &tail)) {
|
||||||
|
julong long_NonMethodCodeHeapSize = 0;
|
||||||
|
|
||||||
|
ArgsRange errcode = parse_memory_size(tail, &long_NonMethodCodeHeapSize, 1);
|
||||||
|
if (errcode != arg_in_range) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid maximum non-method code heap size: %s.\n", option->optionString);
|
||||||
|
return JNI_EINVAL;
|
||||||
|
}
|
||||||
|
FLAG_SET_CMDLINE(uintx, NonMethodCodeHeapSize, (uintx)long_NonMethodCodeHeapSize);
|
||||||
|
// -XX:ProfiledCodeHeapSize=
|
||||||
|
} else if (match_option(option, "-XX:ProfiledCodeHeapSize=", &tail)) {
|
||||||
|
julong long_ProfiledCodeHeapSize = 0;
|
||||||
|
|
||||||
|
ArgsRange errcode = parse_memory_size(tail, &long_ProfiledCodeHeapSize, 1);
|
||||||
|
if (errcode != arg_in_range) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid maximum profiled code heap size: %s.\n", option->optionString);
|
||||||
|
return JNI_EINVAL;
|
||||||
|
}
|
||||||
|
FLAG_SET_CMDLINE(uintx, ProfiledCodeHeapSize, (uintx)long_ProfiledCodeHeapSize);
|
||||||
|
// -XX:NonProfiledCodeHeapSizee=
|
||||||
|
} else if (match_option(option, "-XX:NonProfiledCodeHeapSize=", &tail)) {
|
||||||
|
julong long_NonProfiledCodeHeapSize = 0;
|
||||||
|
|
||||||
|
ArgsRange errcode = parse_memory_size(tail, &long_NonProfiledCodeHeapSize, 1);
|
||||||
|
if (errcode != arg_in_range) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Invalid maximum non-profiled code heap size: %s.\n", option->optionString);
|
||||||
|
return JNI_EINVAL;
|
||||||
|
}
|
||||||
|
FLAG_SET_CMDLINE(uintx, NonProfiledCodeHeapSize, (uintx)long_NonProfiledCodeHeapSize);
|
||||||
//-XX:IncreaseFirstTierCompileThresholdAt=
|
//-XX:IncreaseFirstTierCompileThresholdAt=
|
||||||
} else if (match_option(option, "-XX:IncreaseFirstTierCompileThresholdAt=", &tail)) {
|
} else if (match_option(option, "-XX:IncreaseFirstTierCompileThresholdAt=", &tail)) {
|
||||||
uintx uint_IncreaseFirstTierCompileThresholdAt = 0;
|
uintx uint_IncreaseFirstTierCompileThresholdAt = 0;
|
||||||
|
|
|
@ -165,7 +165,7 @@ void PCRecorder::init() {
|
||||||
for (int index = 0; index < s; index++) {
|
for (int index = 0; index < s; index++) {
|
||||||
counters[index] = 0;
|
counters[index] = 0;
|
||||||
}
|
}
|
||||||
base = CodeCache::first_address();
|
base = CodeCache::low_bound();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCRecorder::record(address pc) {
|
void PCRecorder::record(address pc) {
|
||||||
|
|
|
@ -186,6 +186,10 @@ define_pd_global(intx, InlineClassNatives, true);
|
||||||
define_pd_global(intx, InlineUnsafeOps, true);
|
define_pd_global(intx, InlineUnsafeOps, true);
|
||||||
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
||||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M);
|
define_pd_global(intx, ReservedCodeCacheSize, 32*M);
|
||||||
|
define_pd_global(intx, NonProfiledCodeHeapSize, 0);
|
||||||
|
define_pd_global(intx, ProfiledCodeHeapSize, 0);
|
||||||
|
define_pd_global(intx, NonMethodCodeHeapSize, 32*M);
|
||||||
|
|
||||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K);
|
define_pd_global(intx, CodeCacheExpansionSize, 32*K);
|
||||||
define_pd_global(intx, CodeCacheMinBlockLength, 1);
|
define_pd_global(intx, CodeCacheMinBlockLength, 1);
|
||||||
define_pd_global(intx, CodeCacheMinimumUseSpace, 200*K);
|
define_pd_global(intx, CodeCacheMinimumUseSpace, 200*K);
|
||||||
|
@ -3354,9 +3358,21 @@ class CommandLineFlags {
|
||||||
develop_pd(uintx, CodeCacheMinimumUseSpace, \
|
develop_pd(uintx, CodeCacheMinimumUseSpace, \
|
||||||
"Minimum code cache size (in bytes) required to start VM.") \
|
"Minimum code cache size (in bytes) required to start VM.") \
|
||||||
\
|
\
|
||||||
|
product(bool, SegmentedCodeCache, false, \
|
||||||
|
"Use a segmented code cache") \
|
||||||
|
\
|
||||||
product_pd(uintx, ReservedCodeCacheSize, \
|
product_pd(uintx, ReservedCodeCacheSize, \
|
||||||
"Reserved code cache size (in bytes) - maximum code cache size") \
|
"Reserved code cache size (in bytes) - maximum code cache size") \
|
||||||
\
|
\
|
||||||
|
product_pd(uintx, NonProfiledCodeHeapSize, \
|
||||||
|
"Size of code heap with non-profiled methods (in bytes)") \
|
||||||
|
\
|
||||||
|
product_pd(uintx, ProfiledCodeHeapSize, \
|
||||||
|
"Size of code heap with profiled methods (in bytes)") \
|
||||||
|
\
|
||||||
|
product_pd(uintx, NonMethodCodeHeapSize, \
|
||||||
|
"Size of code heap with non-methods (in bytes)") \
|
||||||
|
\
|
||||||
product(uintx, CodeCacheMinimumFreeSpace, 500*K, \
|
product(uintx, CodeCacheMinimumFreeSpace, 500*K, \
|
||||||
"When less than X space left, we stop compiling") \
|
"When less than X space left, we stop compiling") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -49,6 +49,7 @@ void perfMemory_init();
|
||||||
void management_init();
|
void management_init();
|
||||||
void bytecodes_init();
|
void bytecodes_init();
|
||||||
void classLoader_init();
|
void classLoader_init();
|
||||||
|
void compilationPolicy_init();
|
||||||
void codeCache_init();
|
void codeCache_init();
|
||||||
void VM_Version_init();
|
void VM_Version_init();
|
||||||
void os_init_globals(); // depends on VM_Version_init, before universe_init
|
void os_init_globals(); // depends on VM_Version_init, before universe_init
|
||||||
|
@ -68,7 +69,6 @@ void vmStructs_init();
|
||||||
void vtableStubs_init();
|
void vtableStubs_init();
|
||||||
void InlineCacheBuffer_init();
|
void InlineCacheBuffer_init();
|
||||||
void compilerOracle_init();
|
void compilerOracle_init();
|
||||||
void compilationPolicy_init();
|
|
||||||
void compileBroker_init();
|
void compileBroker_init();
|
||||||
|
|
||||||
// Initialization after compiler initialization
|
// Initialization after compiler initialization
|
||||||
|
@ -97,6 +97,7 @@ jint init_globals() {
|
||||||
management_init();
|
management_init();
|
||||||
bytecodes_init();
|
bytecodes_init();
|
||||||
classLoader_init();
|
classLoader_init();
|
||||||
|
compilationPolicy_init();
|
||||||
codeCache_init();
|
codeCache_init();
|
||||||
VM_Version_init();
|
VM_Version_init();
|
||||||
os_init_globals();
|
os_init_globals();
|
||||||
|
@ -123,7 +124,6 @@ jint init_globals() {
|
||||||
vtableStubs_init();
|
vtableStubs_init();
|
||||||
InlineCacheBuffer_init();
|
InlineCacheBuffer_init();
|
||||||
compilerOracle_init();
|
compilerOracle_init();
|
||||||
compilationPolicy_init();
|
|
||||||
compileBroker_init();
|
compileBroker_init();
|
||||||
VMRegImpl::set_regName();
|
VMRegImpl::set_regName();
|
||||||
|
|
||||||
|
|
|
@ -2422,7 +2422,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
||||||
// Ought to log this but compile log is only per compile thread
|
// Ought to log this but compile log is only per compile thread
|
||||||
// and we're some non descript Java thread.
|
// and we're some non descript Java thread.
|
||||||
MutexUnlocker mu(AdapterHandlerLibrary_lock);
|
MutexUnlocker mu(AdapterHandlerLibrary_lock);
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::NonMethod);
|
||||||
return NULL; // Out of CodeCache space
|
return NULL; // Out of CodeCache space
|
||||||
}
|
}
|
||||||
entry->relocate(new_adapter->content_begin());
|
entry->relocate(new_adapter->content_begin());
|
||||||
|
@ -2596,7 +2596,7 @@ void AdapterHandlerLibrary::create_native_wrapper(methodHandle method) {
|
||||||
nm->post_compiled_method_load_event();
|
nm->post_compiled_method_load_event();
|
||||||
} else {
|
} else {
|
||||||
// CodeCache is full, disable compilation
|
// CodeCache is full, disable compilation
|
||||||
CompileBroker::handle_full_code_cache();
|
CompileBroker::handle_full_code_cache(CodeBlobType::MethodNonProfiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ void NMethodSweeper::record_sweep(nmethod* nm, int line) {
|
||||||
#define SWEEP(nm)
|
#define SWEEP(nm)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nmethod* NMethodSweeper::_current = NULL; // Current nmethod
|
NMethodIterator NMethodSweeper::_current; // Current nmethod
|
||||||
long NMethodSweeper::_traversals = 0; // Stack scan count, also sweep ID.
|
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::_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::_time_counter = 0; // Virtual time used to periodically invoke sweeper
|
||||||
|
@ -159,11 +159,10 @@ Tickspan NMethodSweeper::_peak_sweep_time; // Peak time for
|
||||||
Tickspan NMethodSweeper::_peak_sweep_fraction_time; // Peak time sweeping one fraction
|
Tickspan NMethodSweeper::_peak_sweep_fraction_time; // Peak time sweeping one fraction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MarkActivationClosure: public CodeBlobClosure {
|
class MarkActivationClosure: public CodeBlobClosure {
|
||||||
public:
|
public:
|
||||||
virtual void do_code_blob(CodeBlob* cb) {
|
virtual void do_code_blob(CodeBlob* cb) {
|
||||||
if (cb->is_nmethod()) {
|
assert(cb->is_nmethod(), "CodeBlob should be nmethod");
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val());
|
nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val());
|
||||||
// If we see an activation belonging to a non_entrant nmethod, we mark it.
|
// If we see an activation belonging to a non_entrant nmethod, we mark it.
|
||||||
|
@ -171,18 +170,16 @@ public:
|
||||||
nm->mark_as_seen_on_stack();
|
nm->mark_as_seen_on_stack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static MarkActivationClosure mark_activation_closure;
|
static MarkActivationClosure mark_activation_closure;
|
||||||
|
|
||||||
class SetHotnessClosure: public CodeBlobClosure {
|
class SetHotnessClosure: public CodeBlobClosure {
|
||||||
public:
|
public:
|
||||||
virtual void do_code_blob(CodeBlob* cb) {
|
virtual void do_code_blob(CodeBlob* cb) {
|
||||||
if (cb->is_nmethod()) {
|
assert(cb->is_nmethod(), "CodeBlob should be nmethod");
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val());
|
nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static SetHotnessClosure set_hotness_closure;
|
static SetHotnessClosure set_hotness_closure;
|
||||||
|
|
||||||
|
@ -194,7 +191,7 @@ int NMethodSweeper::hotness_counter_reset_val() {
|
||||||
return _hotness_counter_reset_val;
|
return _hotness_counter_reset_val;
|
||||||
}
|
}
|
||||||
bool NMethodSweeper::sweep_in_progress() {
|
bool NMethodSweeper::sweep_in_progress() {
|
||||||
return (_current != NULL);
|
return !_current.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scans the stacks of all Java threads and marks activations of not-entrant methods.
|
// Scans the stacks of all Java threads and marks activations of not-entrant methods.
|
||||||
|
@ -212,11 +209,13 @@ void NMethodSweeper::mark_active_nmethods() {
|
||||||
_time_counter++;
|
_time_counter++;
|
||||||
|
|
||||||
// Check for restart
|
// Check for restart
|
||||||
assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid");
|
assert(CodeCache::find_blob_unsafe(_current.method()) == _current.method(), "Sweeper nmethod cached state invalid");
|
||||||
if (!sweep_in_progress()) {
|
if (!sweep_in_progress()) {
|
||||||
_seen = 0;
|
_seen = 0;
|
||||||
_sweep_fractions_left = NmethodSweepFraction;
|
_sweep_fractions_left = NmethodSweepFraction;
|
||||||
_current = CodeCache::first_nmethod();
|
_current = NMethodIterator();
|
||||||
|
// Initialize to first nmethod
|
||||||
|
_current.next();
|
||||||
_traversals += 1;
|
_traversals += 1;
|
||||||
_total_time_this_sweep = Tickspan();
|
_total_time_this_sweep = Tickspan();
|
||||||
|
|
||||||
|
@ -271,7 +270,9 @@ void NMethodSweeper::possibly_sweep() {
|
||||||
// an unsigned type would cause an underflow (wait_until_next_sweep becomes a large positive
|
// an unsigned type would cause an underflow (wait_until_next_sweep becomes a large positive
|
||||||
// value) that disables the intended periodic sweeps.
|
// value) that disables the intended periodic sweeps.
|
||||||
const int max_wait_time = ReservedCodeCacheSize / (16 * M);
|
const int max_wait_time = ReservedCodeCacheSize / (16 * M);
|
||||||
double wait_until_next_sweep = max_wait_time - time_since_last_sweep - CodeCache::reverse_free_ratio();
|
double wait_until_next_sweep = max_wait_time - time_since_last_sweep -
|
||||||
|
MAX2(CodeCache::reverse_free_ratio(CodeBlobType::MethodProfiled),
|
||||||
|
CodeCache::reverse_free_ratio(CodeBlobType::MethodNonProfiled));
|
||||||
assert(wait_until_next_sweep <= (double)max_wait_time, "Calculation of code cache sweeper interval is incorrect");
|
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()) {
|
if ((wait_until_next_sweep <= 0.0) || !CompileBroker::should_compile_new_jobs()) {
|
||||||
|
@ -353,7 +354,7 @@ void NMethodSweeper::sweep_code_cache() {
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
|
||||||
// The last invocation iterates until there are no more nmethods
|
// The last invocation iterates until there are no more nmethods
|
||||||
for (int i = 0; (i < todo || _sweep_fractions_left == 1) && _current != NULL; i++) {
|
while ((swept_count < todo || _sweep_fractions_left == 1) && !_current.end()) {
|
||||||
swept_count++;
|
swept_count++;
|
||||||
if (SafepointSynchronize::is_synchronizing()) { // Safepoint request
|
if (SafepointSynchronize::is_synchronizing()) { // Safepoint request
|
||||||
if (PrintMethodFlushing && Verbose) {
|
if (PrintMethodFlushing && Verbose) {
|
||||||
|
@ -369,19 +370,19 @@ void NMethodSweeper::sweep_code_cache() {
|
||||||
// Since we will give up the CodeCache_lock, always skip ahead
|
// Since we will give up the CodeCache_lock, always skip ahead
|
||||||
// to the next nmethod. Other blobs can be deleted by other
|
// to the next nmethod. Other blobs can be deleted by other
|
||||||
// threads but nmethods are only reclaimed by the sweeper.
|
// threads but nmethods are only reclaimed by the sweeper.
|
||||||
nmethod* next = CodeCache::next_nmethod(_current);
|
nmethod* nm = _current.method();
|
||||||
|
_current.next();
|
||||||
|
|
||||||
// Now ready to process nmethod and give up CodeCache_lock
|
// Now ready to process nmethod and give up CodeCache_lock
|
||||||
{
|
{
|
||||||
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
freed_memory += process_nmethod(_current);
|
freed_memory += process_nmethod(nm);
|
||||||
}
|
}
|
||||||
_seen++;
|
_seen++;
|
||||||
_current = next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_sweep_fractions_left > 1 || _current == NULL, "must have scanned the whole cache");
|
assert(_sweep_fractions_left > 1 || _current.end(), "must have scanned the whole cache");
|
||||||
|
|
||||||
const Ticks sweep_end_counter = Ticks::now();
|
const Ticks sweep_end_counter = Ticks::now();
|
||||||
const Tickspan sweep_time = sweep_end_counter - sweep_start_counter;
|
const Tickspan sweep_time = sweep_end_counter - sweep_start_counter;
|
||||||
|
@ -594,7 +595,8 @@ void NMethodSweeper::possibly_flush(nmethod* nm) {
|
||||||
// ReservedCodeCacheSize
|
// ReservedCodeCacheSize
|
||||||
int reset_val = hotness_counter_reset_val();
|
int reset_val = hotness_counter_reset_val();
|
||||||
int time_since_reset = reset_val - nm->hotness_counter();
|
int time_since_reset = reset_val - nm->hotness_counter();
|
||||||
double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity);
|
int code_blob_type = (CodeCache::get_code_blob_type(nm->comp_level()));
|
||||||
|
double threshold = -reset_val + (CodeCache::reverse_free_ratio(code_blob_type) * NmethodSweepActivity);
|
||||||
// The less free space in the code cache we have - the bigger reverse_free_ratio() is.
|
// The less free space in the code cache we have - the bigger reverse_free_ratio() is.
|
||||||
// I.e., 'threshold' increases with lower available space in the code cache and a higher
|
// I.e., 'threshold' increases with lower available space in the code cache and a higher
|
||||||
// NmethodSweepActivity. If the current hotness counter - which decreases from its initial
|
// NmethodSweepActivity. If the current hotness counter - which decreases from its initial
|
||||||
|
@ -614,12 +616,7 @@ void NMethodSweeper::possibly_flush(nmethod* nm) {
|
||||||
// The stack-scanning low-cost detection may not see the method was used (which can happen for
|
// The stack-scanning low-cost detection may not see the method was used (which can happen for
|
||||||
// flat profiles). Check the age counter for possible data.
|
// flat profiles). Check the age counter for possible data.
|
||||||
if (UseCodeAging && make_not_entrant && (nm->is_compiled_by_c2() || nm->is_compiled_by_c1())) {
|
if (UseCodeAging && make_not_entrant && (nm->is_compiled_by_c2() || nm->is_compiled_by_c1())) {
|
||||||
MethodCounters* mc = nm->method()->method_counters();
|
MethodCounters* mc = nm->method()->get_method_counters(Thread::current());
|
||||||
if (mc == NULL) {
|
|
||||||
// Sometimes we can get here without MethodCounters. For example if we run with -Xcomp.
|
|
||||||
// Try to allocate them.
|
|
||||||
mc = nm->method()->get_method_counters(Thread::current());
|
|
||||||
}
|
|
||||||
if (mc != NULL) {
|
if (mc != NULL) {
|
||||||
// Snapshot the value as it's changed concurrently
|
// Snapshot the value as it's changed concurrently
|
||||||
int age = mc->nmethod_age();
|
int age = mc->nmethod_age();
|
||||||
|
|
|
@ -58,7 +58,7 @@ class NMethodSweeper : public AllStatic {
|
||||||
static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache
|
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 _time_counter; // Virtual time used to periodically invoke sweeper
|
||||||
static long _last_sweep; // Value of _time_counter when the last sweep happened
|
static long _last_sweep; // Value of _time_counter when the last sweep happened
|
||||||
static nmethod* _current; // Current nmethod
|
static NMethodIterator _current; // Current nmethod
|
||||||
static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
|
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 _flushed_count; // Nof. nmethods flushed in current sweep
|
||||||
static int _zombified_count; // Nof. nmethods made zombie in current sweep
|
static int _zombified_count; // Nof. nmethods made zombie in current sweep
|
||||||
|
@ -98,7 +98,7 @@ class NMethodSweeper : public AllStatic {
|
||||||
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
static bool is_sweeping(nmethod* which) { return _current == which; }
|
static bool is_sweeping(nmethod* which) { return _current.method() == which; }
|
||||||
// Keep track of sweeper activity in the ring buffer
|
// Keep track of sweeper activity in the ring buffer
|
||||||
static void record_sweep(nmethod* nm, int line);
|
static void record_sweep(nmethod* nm, int line);
|
||||||
static void report_events(int id, address entry);
|
static void report_events(int id, address entry);
|
||||||
|
|
|
@ -765,7 +765,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||||
/* CodeCache (NOTE: incomplete) */ \
|
/* CodeCache (NOTE: incomplete) */ \
|
||||||
/********************************/ \
|
/********************************/ \
|
||||||
\
|
\
|
||||||
static_field(CodeCache, _heap, CodeHeap*) \
|
static_field(CodeCache, _heaps, GrowableArray<CodeHeap*>*) \
|
||||||
static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \
|
static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \
|
||||||
\
|
\
|
||||||
/*******************************/ \
|
/*******************************/ \
|
||||||
|
|
|
@ -427,7 +427,7 @@ public:
|
||||||
return "Compiler.codelist";
|
return "Compiler.codelist";
|
||||||
}
|
}
|
||||||
static const char* description() {
|
static const char* description() {
|
||||||
return "Print all compiled methods in code cache.";
|
return "Print all compiled methods in code cache that are alive";
|
||||||
}
|
}
|
||||||
static const char* impact() {
|
static const char* impact() {
|
||||||
return "Medium";
|
return "Medium";
|
||||||
|
|
|
@ -63,7 +63,9 @@ GrowableArray<MemoryManager*>* MemoryService::_managers_list =
|
||||||
|
|
||||||
GCMemoryManager* MemoryService::_minor_gc_manager = NULL;
|
GCMemoryManager* MemoryService::_minor_gc_manager = NULL;
|
||||||
GCMemoryManager* MemoryService::_major_gc_manager = NULL;
|
GCMemoryManager* MemoryService::_major_gc_manager = NULL;
|
||||||
MemoryPool* MemoryService::_code_heap_pool = NULL;
|
MemoryManager* MemoryService::_code_cache_manager = NULL;
|
||||||
|
GrowableArray<MemoryPool*>* MemoryService::_code_heap_pools =
|
||||||
|
new (ResourceObj::C_HEAP, mtInternal) GrowableArray<MemoryPool*>(init_code_heap_pools_size, true);
|
||||||
MemoryPool* MemoryService::_metaspace_pool = NULL;
|
MemoryPool* MemoryService::_metaspace_pool = NULL;
|
||||||
MemoryPool* MemoryService::_compressed_class_pool = NULL;
|
MemoryPool* MemoryService::_compressed_class_pool = NULL;
|
||||||
|
|
||||||
|
@ -388,15 +390,21 @@ void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h,
|
||||||
}
|
}
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
|
|
||||||
void MemoryService::add_code_heap_memory_pool(CodeHeap* heap) {
|
void MemoryService::add_code_heap_memory_pool(CodeHeap* heap, const char* name) {
|
||||||
_code_heap_pool = new CodeHeapPool(heap,
|
// Create new memory pool for this heap
|
||||||
"Code Cache",
|
MemoryPool* code_heap_pool = new CodeHeapPool(heap, name, true /* support_usage_threshold */);
|
||||||
true /* support_usage_threshold */);
|
|
||||||
MemoryManager* mgr = MemoryManager::get_code_cache_memory_manager();
|
|
||||||
mgr->add_pool(_code_heap_pool);
|
|
||||||
|
|
||||||
_pools_list->append(_code_heap_pool);
|
// Append to lists
|
||||||
_managers_list->append(mgr);
|
_code_heap_pools->append(code_heap_pool);
|
||||||
|
_pools_list->append(code_heap_pool);
|
||||||
|
|
||||||
|
if (_code_cache_manager == NULL) {
|
||||||
|
// Create CodeCache memory manager
|
||||||
|
_code_cache_manager = MemoryManager::get_code_cache_memory_manager();
|
||||||
|
_managers_list->append(_code_cache_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
_code_cache_manager->add_pool(code_heap_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryService::add_metaspace_memory_pools() {
|
void MemoryService::add_metaspace_memory_pools() {
|
||||||
|
|
|
@ -53,7 +53,8 @@ class MemoryService : public AllStatic {
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
init_pools_list_size = 10,
|
init_pools_list_size = 10,
|
||||||
init_managers_list_size = 5
|
init_managers_list_size = 5,
|
||||||
|
init_code_heap_pools_size = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
// index for minor and major generations
|
// index for minor and major generations
|
||||||
|
@ -70,8 +71,9 @@ private:
|
||||||
static GCMemoryManager* _major_gc_manager;
|
static GCMemoryManager* _major_gc_manager;
|
||||||
static GCMemoryManager* _minor_gc_manager;
|
static GCMemoryManager* _minor_gc_manager;
|
||||||
|
|
||||||
// Code heap memory pool
|
// memory manager and code heap pools for the CodeCache
|
||||||
static MemoryPool* _code_heap_pool;
|
static MemoryManager* _code_cache_manager;
|
||||||
|
static GrowableArray<MemoryPool*>* _code_heap_pools;
|
||||||
|
|
||||||
static MemoryPool* _metaspace_pool;
|
static MemoryPool* _metaspace_pool;
|
||||||
static MemoryPool* _compressed_class_pool;
|
static MemoryPool* _compressed_class_pool;
|
||||||
|
@ -123,7 +125,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void set_universe_heap(CollectedHeap* heap);
|
static void set_universe_heap(CollectedHeap* heap);
|
||||||
static void add_code_heap_memory_pool(CodeHeap* heap);
|
static void add_code_heap_memory_pool(CodeHeap* heap, const char* name);
|
||||||
static void add_metaspace_memory_pools();
|
static void add_metaspace_memory_pools();
|
||||||
|
|
||||||
static MemoryPool* get_memory_pool(instanceHandle pool);
|
static MemoryPool* get_memory_pool(instanceHandle pool);
|
||||||
|
@ -146,7 +148,10 @@ public:
|
||||||
|
|
||||||
static void track_memory_usage();
|
static void track_memory_usage();
|
||||||
static void track_code_cache_memory_usage() {
|
static void track_code_cache_memory_usage() {
|
||||||
track_memory_pool_usage(_code_heap_pool);
|
// Track memory pool usage of all CodeCache memory pools
|
||||||
|
for (int i = 0; i < _code_heap_pools->length(); ++i) {
|
||||||
|
track_memory_pool_usage(_code_heap_pools->at(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void track_metaspace_memory_usage() {
|
static void track_metaspace_memory_usage() {
|
||||||
track_memory_pool_usage(_metaspace_pool);
|
track_memory_pool_usage(_metaspace_pool);
|
||||||
|
|
|
@ -394,6 +394,7 @@ Declares a structure type that can be used in other events.
|
||||||
|
|
||||||
<event id="CodeCacheFull" path="vm/code_cache/full" label="Code Cache Full"
|
<event id="CodeCacheFull" path="vm/code_cache/full" label="Code Cache Full"
|
||||||
has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
|
has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
|
||||||
|
<value type="CODEBLOBTYPE" field="codeBlobType" label="Code Heap"/>
|
||||||
<value type="ADDRESS" field="startAddress" label="Start Address"/>
|
<value type="ADDRESS" field="startAddress" label="Start Address"/>
|
||||||
<value type="ADDRESS" field="commitedTopAddress" label="Commited Top"/>
|
<value type="ADDRESS" field="commitedTopAddress" label="Commited Top"/>
|
||||||
<value type="ADDRESS" field="reservedTopAddress" label="Reserved Top"/>
|
<value type="ADDRESS" field="reservedTopAddress" label="Reserved Top"/>
|
||||||
|
|
|
@ -171,6 +171,11 @@ Now we can use the content + data type in declaring event fields.
|
||||||
<value type="UTF8" field="origin" label="origin" />
|
<value type="UTF8" field="origin" label="origin" />
|
||||||
</content_type>
|
</content_type>
|
||||||
|
|
||||||
|
<content_type id="CodeBlobType" hr_name="Code Blob Type"
|
||||||
|
type="U1" jvm_type="CODEBLOBTYPE">
|
||||||
|
<value type="UTF8" field="type" label="type" />
|
||||||
|
</content_type>
|
||||||
|
|
||||||
</content_types>
|
</content_types>
|
||||||
|
|
||||||
|
|
||||||
|
@ -372,5 +377,9 @@ Now we can use the content + data type in declaring event fields.
|
||||||
<primary_type symbol="FLAGVALUEORIGIN" datatype="U1"
|
<primary_type symbol="FLAGVALUEORIGIN" datatype="U1"
|
||||||
contenttype="FLAGVALUEORIGIN" type="u1" sizeop="sizeof(u1)" />
|
contenttype="FLAGVALUEORIGIN" type="u1" sizeop="sizeof(u1)" />
|
||||||
|
|
||||||
|
<!-- CODEBLOBTYPE -->
|
||||||
|
<primary_type symbol="CODEBLOBTYPE" datatype="U1"
|
||||||
|
contenttype="CODEBLOBTYPE" type="u1" sizeop="sizeof(u1)" />
|
||||||
|
|
||||||
</primary_types>
|
</primary_types>
|
||||||
</types>
|
</types>
|
||||||
|
|
|
@ -323,8 +323,243 @@ applicable_cmsgc = \
|
||||||
hotspot_wbapitest = \
|
hotspot_wbapitest = \
|
||||||
sanity/
|
sanity/
|
||||||
|
|
||||||
hotspot_compiler = \
|
hotspot_compiler_1 = \
|
||||||
sanity/ExecuteInternalVMTests.java
|
compiler/5057225/Test5057225.java \
|
||||||
|
compiler/5091921/Test5091921.java \
|
||||||
|
compiler/5091921/Test6186134.java \
|
||||||
|
compiler/5091921/Test6196102.java \
|
||||||
|
compiler/5091921/Test6357214.java \
|
||||||
|
compiler/5091921/Test6559156.java \
|
||||||
|
compiler/5091921/Test6753639.java \
|
||||||
|
compiler/5091921/Test6935022.java \
|
||||||
|
compiler/5091921/Test6959129.java \
|
||||||
|
compiler/5091921/Test6985295.java \
|
||||||
|
compiler/5091921/Test6992759.java \
|
||||||
|
compiler/5091921/Test7005594.java \
|
||||||
|
compiler/5091921/Test7020614.java \
|
||||||
|
compiler/6378821/Test6378821.java \
|
||||||
|
compiler/6431242/Test.java \
|
||||||
|
compiler/6443505/Test6443505.java \
|
||||||
|
compiler/6478991/NullCheckTest.java \
|
||||||
|
compiler/6539464/Test.java \
|
||||||
|
compiler/6579789/Test6579789.java \
|
||||||
|
compiler/6636138/ \
|
||||||
|
compiler/6646019/Test.java \
|
||||||
|
compiler/6659207/Test.java \
|
||||||
|
compiler/6661247/Test.java \
|
||||||
|
compiler/6663621/IVTest.java \
|
||||||
|
compiler/6689060/Test.java \
|
||||||
|
compiler/6695810/Test.java \
|
||||||
|
compiler/6700047/Test6700047.java \
|
||||||
|
compiler/6711100/Test.java \
|
||||||
|
compiler/6724218/Test.java \
|
||||||
|
compiler/6732154/Test6732154.java \
|
||||||
|
compiler/6758234/Test6758234.java \
|
||||||
|
compiler/6769124/ \
|
||||||
|
compiler/6772683/InterruptedTest.java \
|
||||||
|
compiler/6778657/Test.java \
|
||||||
|
compiler/6795161/Test.java \
|
||||||
|
compiler/6795362/Test6795362.java \
|
||||||
|
compiler/6795465/Test6795465.java \
|
||||||
|
compiler/6796786/Test6796786.java \
|
||||||
|
compiler/6799693/Test.java \
|
||||||
|
compiler/6805724/Test6805724.java \
|
||||||
|
compiler/6814842/Test6814842.java \
|
||||||
|
compiler/6823453/Test.java \
|
||||||
|
compiler/6833129/Test.java \
|
||||||
|
compiler/6837011/Test6837011.java \
|
||||||
|
compiler/6843752/Test.java \
|
||||||
|
compiler/6849574/Test.java \
|
||||||
|
compiler/6855164/Test.java \
|
||||||
|
compiler/6855215/Test6855215.java \
|
||||||
|
compiler/6857159/Test6857159.java \
|
||||||
|
compiler/6860469/Test.java \
|
||||||
|
compiler/6863155/Test6863155.java \
|
||||||
|
compiler/6863420/Test.java \
|
||||||
|
compiler/6865265/StackOverflowBug.java \
|
||||||
|
compiler/6879902/Test6879902.java \
|
||||||
|
compiler/6880034/Test6880034.java \
|
||||||
|
compiler/6891750/Test6891750.java \
|
||||||
|
compiler/6892265/Test.java \
|
||||||
|
compiler/6894807/IsInstanceTest.java \
|
||||||
|
compiler/6901572/Test.java \
|
||||||
|
compiler/6909839/Test6909839.java \
|
||||||
|
compiler/6910484/Test.java \
|
||||||
|
compiler/6910605/Test.java \
|
||||||
|
compiler/6910618/Test.java \
|
||||||
|
compiler/6916644/Test6916644.java \
|
||||||
|
compiler/6921969/TestMultiplyLongHiZero.java \
|
||||||
|
compiler/6930043/Test6930043.java \
|
||||||
|
compiler/6932496/Test6932496.java \
|
||||||
|
compiler/6956668/Test6956668.java \
|
||||||
|
compiler/6968348/Test6968348.java \
|
||||||
|
compiler/6973329/Test.java
|
||||||
|
|
||||||
|
hotspot_compiler_2 = \
|
||||||
|
compiler/6982370/Test6982370.java \
|
||||||
|
compiler/7009231/Test7009231.java \
|
||||||
|
compiler/7009359/Test7009359.java \
|
||||||
|
compiler/7017746/Test.java \
|
||||||
|
compiler/7024475/Test7024475.java \
|
||||||
|
compiler/7041100/Test7041100.java \
|
||||||
|
compiler/7044738/Test7044738.java \
|
||||||
|
compiler/7046096/Test7046096.java \
|
||||||
|
compiler/7048332/Test7048332.java \
|
||||||
|
compiler/7068051/Test7068051.java \
|
||||||
|
compiler/7082949/Test7082949.java \
|
||||||
|
compiler/7088020/Test7088020.java \
|
||||||
|
compiler/7090976/Test7090976.java \
|
||||||
|
compiler/7103261/Test7103261.java \
|
||||||
|
compiler/7110586/Test7110586.java \
|
||||||
|
compiler/7119644/ \
|
||||||
|
compiler/7141637/SpreadNullArg.java \
|
||||||
|
compiler/7169782/Test7169782.java \
|
||||||
|
compiler/7174363/Test7174363.java \
|
||||||
|
compiler/7179138/ \
|
||||||
|
compiler/7190310/ \
|
||||||
|
compiler/7192963/ \
|
||||||
|
compiler/7200264/TestIntVect.java \
|
||||||
|
compiler/8000805/Test8000805.java \
|
||||||
|
compiler/8002069/Test8002069.java \
|
||||||
|
compiler/8004741/Test8004741.java \
|
||||||
|
compiler/8005033/Test8005033.java \
|
||||||
|
compiler/8005419/Test8005419.java \
|
||||||
|
compiler/8005956/PolynomialRoot.java \
|
||||||
|
compiler/8007294/Test8007294.java
|
||||||
|
|
||||||
|
hotspot_compiler_3 = \
|
||||||
|
compiler/8007722/Test8007722.java \
|
||||||
|
compiler/8009761/Test8009761.java \
|
||||||
|
compiler/8010927/Test8010927.java \
|
||||||
|
compiler/8011706/Test8011706.java \
|
||||||
|
compiler/8011771/Test8011771.java \
|
||||||
|
compiler/8011901/Test8011901.java \
|
||||||
|
compiler/arraycopy/TestMissingControl.java \
|
||||||
|
compiler/ciReplay/TestVM_no_comp_level.sh \
|
||||||
|
compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java \
|
||||||
|
compiler/codecache/CheckUpperLimit.java \
|
||||||
|
compiler/codegen/ \
|
||||||
|
compiler/cpuflags/RestoreMXCSR.java \
|
||||||
|
compiler/EscapeAnalysis/ \
|
||||||
|
compiler/exceptions/TestRecursiveReplacedException.java \
|
||||||
|
compiler/floatingpoint/ModNaN.java \
|
||||||
|
compiler/gcbarriers/G1CrashTest.java \
|
||||||
|
compiler/inlining/ \
|
||||||
|
compiler/IntegerArithmetic/TestIntegerComparison.java \
|
||||||
|
compiler/intrinsics/bmi/TestAndnI.java \
|
||||||
|
compiler/intrinsics/bmi/TestAndnI.java \
|
||||||
|
compiler/intrinsics/bmi/TestAndnL.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsiI.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsiL.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsmskI.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsmskL.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsrI.java \
|
||||||
|
compiler/intrinsics/bmi/TestBlsrL.java \
|
||||||
|
compiler/intrinsics/bmi/TestLzcntI.java \
|
||||||
|
compiler/intrinsics/bmi/TestLzcntL.java \
|
||||||
|
compiler/intrinsics/bmi/TestTzcntI.java \
|
||||||
|
compiler/intrinsics/bmi/TestTzcntL.java \
|
||||||
|
compiler/intrinsics/clone/TestObjectClone.java \
|
||||||
|
compiler/intrinsics/hashcode/TestHashCode.java \
|
||||||
|
compiler/intrinsics/mathexact/CompareTest.java \
|
||||||
|
compiler/intrinsics/mathexact/GVNTest.java \
|
||||||
|
compiler/intrinsics/mathexact/NegExactILoadTest.java \
|
||||||
|
compiler/intrinsics/mathexact/NegExactILoopDependentTest.java \
|
||||||
|
compiler/intrinsics/mathexact/NegExactINonConstantTest.java \
|
||||||
|
compiler/intrinsics/mathexact/SubExactICondTest.java \
|
||||||
|
compiler/intrinsics/mathexact/SubExactILoadTest.java \
|
||||||
|
compiler/intrinsics/mathexact/SubExactILoopDependentTest.java \
|
||||||
|
compiler/intrinsics/stringequals/TestStringEqualsBadLength.java \
|
||||||
|
compiler/intrinsics/unsafe/UnsafeGetAddressTest.java \
|
||||||
|
compiler/jsr292/ConcurrentClassLoadingTest.java \
|
||||||
|
compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java \
|
||||||
|
compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java \
|
||||||
|
compiler/loopopts/TestLogSum.java \
|
||||||
|
compiler/macronodes/TestEliminateAllocationPhi.java \
|
||||||
|
compiler/membars/TestMemBarAcquire.java \
|
||||||
|
compiler/osr/TestOSRWithNonEmptyStack.java \
|
||||||
|
compiler/profiling/TestMethodHandleInvokesIntrinsic.java \
|
||||||
|
compiler/profiling/TestSpecTrapClassUnloading.java \
|
||||||
|
compiler/profiling/TestUnexpectedProfilingMismatch.java \
|
||||||
|
compiler/regalloc/C1ObjectSpillInLogicOp.java \
|
||||||
|
compiler/startup/NumCompilerThreadsCheck.java \
|
||||||
|
compiler/startup/SmallCodeCacheStartup.java \
|
||||||
|
compiler/types/TestSpeculationFailedHigherEqual.java \
|
||||||
|
compiler/types/TypeSpeculation.java \
|
||||||
|
compiler/uncommontrap/StackOverflowGuardPagesOff.java \
|
||||||
|
compiler/uncommontrap/TestStackBangMonitorOwned.java \
|
||||||
|
compiler/uncommontrap/TestStackBangRbp.java \
|
||||||
|
compiler/unsafe/GetUnsafeObjectG1PreBarrier.java
|
||||||
|
|
||||||
|
hotspot_compiler_closed = \
|
||||||
|
closed/compiler/4292742/Test.java \
|
||||||
|
closed/compiler/4474154/Test4474154.java \
|
||||||
|
closed/compiler/4482613/Test4482613.java \
|
||||||
|
closed/compiler/4490177/tctest.java \
|
||||||
|
closed/compiler/4495990/Application.java \
|
||||||
|
closed/compiler/4522874/Test4522874.sh \
|
||||||
|
closed/compiler/4629512/Test4629512.java \
|
||||||
|
closed/compiler/4647299/Looper.java \
|
||||||
|
closed/compiler/4655758/TestClass.java \
|
||||||
|
closed/compiler/4671453/LongCompTest.java \
|
||||||
|
closed/compiler/4671460/CharArrTest.java \
|
||||||
|
closed/compiler/4709105/StringTest2.java \
|
||||||
|
closed/compiler/4732721/Bug.java \
|
||||||
|
closed/compiler/4750681/ReadTest.java \
|
||||||
|
closed/compiler/4787943/LongCrash.java \
|
||||||
|
closed/compiler/4819903/Base64Test.java \
|
||||||
|
closed/compiler/4903383/Test.java \
|
||||||
|
closed/compiler/4906393/Test.java \
|
||||||
|
closed/compiler/4907999/Uidtest.java \
|
||||||
|
closed/compiler/4917709/Tester.java \
|
||||||
|
closed/compiler/4957832/Test.java \
|
||||||
|
closed/compiler/4965430/LoopTest.java \
|
||||||
|
closed/compiler/4979449/T4979449.java \
|
||||||
|
closed/compiler/5031274/Test.java \
|
||||||
|
closed/compiler/5043395/T5043395.java \
|
||||||
|
closed/compiler/5049410/Test.java \
|
||||||
|
closed/compiler/5098422/Test.java \
|
||||||
|
closed/compiler/6173783/Test.java \
|
||||||
|
closed/compiler/6272923/Test6272923.sh \
|
||||||
|
closed/compiler/6290963/Test.java \
|
||||||
|
closed/compiler/6305546/Test.java \
|
||||||
|
closed/compiler/6309806/Test.java \
|
||||||
|
closed/compiler/6311859/Test.java \
|
||||||
|
closed/compiler/6321689/Test.java \
|
||||||
|
closed/compiler/6326935/Test.java \
|
||||||
|
closed/compiler/6367889/Test.java \
|
||||||
|
closed/compiler/6371167/Test.java \
|
||||||
|
closed/compiler/6389127/Test.java \
|
||||||
|
closed/compiler/6397650/Test.java \
|
||||||
|
closed/compiler/6414932/Test.java \
|
||||||
|
closed/compiler/6421619/Test_6421619.java \
|
||||||
|
closed/compiler/6427750/UnsafeVolatile.java \
|
||||||
|
closed/compiler/6431243/Test.java \
|
||||||
|
closed/compiler/6433572/TestSyncJSR.java \
|
||||||
|
closed/compiler/6433840/clinit.java \
|
||||||
|
closed/compiler/6457854/Test.java \
|
||||||
|
closed/compiler/6476804/Test.java \
|
||||||
|
closed/compiler/6512111/CorruptFinalLong.java \
|
||||||
|
closed/compiler/6551887/Test.java \
|
||||||
|
closed/compiler/6571539/Test.java \
|
||||||
|
closed/compiler/6587132/Test.java \
|
||||||
|
closed/compiler/6588045/Test.java \
|
||||||
|
closed/compiler/6588598/etype.java \
|
||||||
|
closed/compiler/6661918/Test6661918.java \
|
||||||
|
closed/compiler/6707044/Test.java \
|
||||||
|
closed/compiler/6730716/Test.java \
|
||||||
|
closed/compiler/6772368/Test6772368.sh \
|
||||||
|
closed/compiler/6897150/Test6897150.java \
|
||||||
|
closed/compiler/6931567/Test6931567.java \
|
||||||
|
closed/compiler/7196857/Test7196857.java \
|
||||||
|
closed/compiler/8009699/Test8009699.java \
|
||||||
|
closed/compiler/8009699/Test8009699B.java \
|
||||||
|
closed/compiler/8014811/Test8014811.java \
|
||||||
|
closed/compiler/8029507/InvokePrivate.java \
|
||||||
|
closed/compiler/callingConvention/Arg9Double.java \
|
||||||
|
closed/compiler/deoptimization/DeoptArithmetic.java \
|
||||||
|
closed/compiler/deoptimization/TestDoubleLocals.java \
|
||||||
|
closed/compiler/deoptimization/TestDoubleMerge.java
|
||||||
|
|
||||||
hotspot_gc = \
|
hotspot_gc = \
|
||||||
sanity/ExecuteInternalVMTests.java
|
sanity/ExecuteInternalVMTests.java
|
||||||
|
@ -343,7 +578,7 @@ hotspot_runtime = \
|
||||||
-runtime/SharedArchiveFile/CdsSameObjectAlignment.java \
|
-runtime/SharedArchiveFile/CdsSameObjectAlignment.java \
|
||||||
-runtime/SharedArchiveFile/DefaultUseWithClient.java \
|
-runtime/SharedArchiveFile/DefaultUseWithClient.java \
|
||||||
-runtime/Thread/CancellableThreadTest.java \
|
-runtime/Thread/CancellableThreadTest.java \
|
||||||
-runtime/runtime/7158988/FieldMonitor.java
|
-runtime/7158988/FieldMonitor.java
|
||||||
|
|
||||||
hotspot_runtime_closed = \
|
hotspot_runtime_closed = \
|
||||||
sanity/ExecuteInternalVMTests.java
|
sanity/ExecuteInternalVMTests.java
|
||||||
|
@ -352,7 +587,10 @@ hotspot_serviceability = \
|
||||||
sanity/ExecuteInternalVMTests.java
|
sanity/ExecuteInternalVMTests.java
|
||||||
|
|
||||||
hotspot_all = \
|
hotspot_all = \
|
||||||
:hotspot_compiler \
|
:hotspot_compiler_1 \
|
||||||
|
:hotspot_compiler_2 \
|
||||||
|
:hotspot_compiler_3 \
|
||||||
|
:hotspot_compiler_closed \
|
||||||
:hotspot_gc \
|
:hotspot_gc \
|
||||||
:hotspot_runtime \
|
:hotspot_runtime \
|
||||||
:hotspot_serviceability
|
:hotspot_serviceability
|
||||||
|
|
132
hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java
Normal file
132
hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test CheckSegmentedCodeCache
|
||||||
|
* @bug 8015774
|
||||||
|
* @summary "Checks VM options related to the segmented code cache"
|
||||||
|
* @library /testlibrary
|
||||||
|
* @run main/othervm CheckSegmentedCodeCache
|
||||||
|
*/
|
||||||
|
public class CheckSegmentedCodeCache {
|
||||||
|
// Code heap names
|
||||||
|
private static final String NON_METHOD = "CodeHeap 'non-methods'";
|
||||||
|
private static final String PROFILED = "CodeHeap 'profiled nmethods'";
|
||||||
|
private static final String NON_PROFILED = "CodeHeap 'non-profiled nmethods'";
|
||||||
|
|
||||||
|
private static void verifySegmentedCodeCache(ProcessBuilder pb, boolean enabled) throws Exception {
|
||||||
|
OutputAnalyzer out = new OutputAnalyzer(pb.start());
|
||||||
|
if (enabled) {
|
||||||
|
try {
|
||||||
|
// Non-method code heap should be always available with the segmented code cache
|
||||||
|
out.shouldContain(NON_METHOD);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// TieredCompilation is disabled in a client VM
|
||||||
|
out.shouldContain("TieredCompilation is disabled in this release.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.shouldNotContain(NON_METHOD);
|
||||||
|
}
|
||||||
|
out.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyCodeHeapNotExists(ProcessBuilder pb, String... heapNames) throws Exception {
|
||||||
|
OutputAnalyzer out = new OutputAnalyzer(pb.start());
|
||||||
|
for (String name : heapNames) {
|
||||||
|
out.shouldNotContain(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void failsWith(ProcessBuilder pb, String message) throws Exception {
|
||||||
|
OutputAnalyzer out = new OutputAnalyzer(pb.start());
|
||||||
|
out.shouldContain(message);
|
||||||
|
out.shouldHaveExitValue(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the result of segmented code cache related VM options.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ProcessBuilder pb;
|
||||||
|
|
||||||
|
// Disabled with ReservedCodeCacheSize < 240MB
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=239m",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifySegmentedCodeCache(pb, false);
|
||||||
|
|
||||||
|
// Disabled without TieredCompilation
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifySegmentedCodeCache(pb, false);
|
||||||
|
|
||||||
|
// Enabled with TieredCompilation and ReservedCodeCacheSize >= 240MB
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+TieredCompilation",
|
||||||
|
"-XX:ReservedCodeCacheSize=240m",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifySegmentedCodeCache(pb, true);
|
||||||
|
|
||||||
|
// Always enabled if SegmentedCodeCache is set
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-XX:-TieredCompilation",
|
||||||
|
"-XX:ReservedCodeCacheSize=239m",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifySegmentedCodeCache(pb, true);
|
||||||
|
|
||||||
|
// The profiled and non-profiled code heaps should not be available in
|
||||||
|
// interpreter-only mode
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-Xint",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifyCodeHeapNotExists(pb, PROFILED, NON_PROFILED);
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-XX:TieredStopAtLevel=0",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifyCodeHeapNotExists(pb, PROFILED, NON_PROFILED);
|
||||||
|
|
||||||
|
// If we stop compilation at CompLevel_simple
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-XX:TieredStopAtLevel=1",
|
||||||
|
"-XX:+PrintCodeCache", "-version");
|
||||||
|
verifyCodeHeapNotExists(pb, PROFILED);
|
||||||
|
|
||||||
|
// Fails with too small non-method code heap size
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:NonMethodCodeHeapSize=100K");
|
||||||
|
failsWith(pb, "Invalid NonMethodCodeHeapSize");
|
||||||
|
|
||||||
|
// Fails if code heap sizes do not add up
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-XX:ReservedCodeCacheSize=10M",
|
||||||
|
"-XX:NonMethodCodeHeapSize=5M",
|
||||||
|
"-XX:ProfiledCodeHeapSize=5M",
|
||||||
|
"-XX:NonProfiledCodeHeapSize=5M");
|
||||||
|
failsWith(pb, "Invalid code heap sizes");
|
||||||
|
|
||||||
|
// Fails if not enough space for VM internal code
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+SegmentedCodeCache",
|
||||||
|
"-XX:ReservedCodeCacheSize=1700K",
|
||||||
|
"-XX:InitialCodeCacheSize=100K");
|
||||||
|
failsWith(pb, "Not enough space in non-method code heap to run VM");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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 8057758
|
||||||
|
* @summary MultiplyToLen sets its return type to have a bottom offset which confuses code generation
|
||||||
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 TestMultiplyToLenReturnProfile
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.math.*;
|
||||||
|
|
||||||
|
public class TestMultiplyToLenReturnProfile {
|
||||||
|
|
||||||
|
static BigInteger m(BigInteger i1, BigInteger i2) {
|
||||||
|
BigInteger res = BigInteger.valueOf(0);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
res.add(i1.multiply(i2));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main(String[] args) {
|
||||||
|
BigInteger v = BigInteger.valueOf(Integer.MAX_VALUE).pow(2);
|
||||||
|
for (int i = 0; i < 20000; i++) {
|
||||||
|
m(v, v.add(BigInteger.valueOf(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,18 +52,17 @@ public class UseCompressedOops {
|
||||||
.shouldContain("Compressed Oops mode")
|
.shouldContain("Compressed Oops mode")
|
||||||
.shouldHaveExitValue(0);
|
.shouldHaveExitValue(0);
|
||||||
|
|
||||||
|
// Skip the following three test cases if we're on OSX or Solaris.
|
||||||
|
//
|
||||||
|
// OSX doesn't seem to care about HeapBaseMinAddress and Solaris
|
||||||
|
// puts the heap way up, forcing different behaviour.
|
||||||
|
if (!Platform.isOSX() && !Platform.isSolaris()) {
|
||||||
// Larger than 4gb heap should result in zero based with shift 3
|
// Larger than 4gb heap should result in zero based with shift 3
|
||||||
testCompressedOops("-XX:+UseCompressedOops", "-Xmx5g")
|
testCompressedOops("-XX:+UseCompressedOops", "-Xmx5g")
|
||||||
.shouldContain("Zero based")
|
.shouldContain("Zero based")
|
||||||
.shouldContain("Oop shift amount: 3")
|
.shouldContain("Oop shift amount: 3")
|
||||||
.shouldHaveExitValue(0);
|
.shouldHaveExitValue(0);
|
||||||
|
|
||||||
// Skip the following three test cases if we're on OSX or Solaris Sparc.
|
|
||||||
//
|
|
||||||
// OSX doesn't seem to care about HeapBaseMinAddress and Solaris Sparc
|
|
||||||
// puts the heap way up, forcing different behaviour.
|
|
||||||
|
|
||||||
if (!Platform.isOSX() && !(Platform.isSolaris() && Platform.isSparc())) {
|
|
||||||
// Small heap above 4gb should result in zero based with shift 3
|
// Small heap above 4gb should result in zero based with shift 3
|
||||||
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
|
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
|
||||||
.shouldContain("Zero based")
|
.shouldContain("Zero based")
|
||||||
|
@ -83,6 +82,12 @@ public class UseCompressedOops {
|
||||||
.shouldContain("Non-zero based")
|
.shouldContain("Non-zero based")
|
||||||
.shouldContain("Oop shift amount: 4")
|
.shouldContain("Oop shift amount: 4")
|
||||||
.shouldHaveExitValue(0);
|
.shouldHaveExitValue(0);
|
||||||
|
|
||||||
|
// 32gb heap with object alignment set to 16 bytes should result in zero based with shift 4
|
||||||
|
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
|
||||||
|
.shouldContain("Zero based")
|
||||||
|
.shouldContain("Oop shift amount: 4")
|
||||||
|
.shouldHaveExitValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly enabling compressed oops with 32gb heap should result a warning
|
// Explicitly enabling compressed oops with 32gb heap should result a warning
|
||||||
|
@ -106,12 +111,6 @@ public class UseCompressedOops {
|
||||||
.shouldContain("Max heap size too large for Compressed Oops")
|
.shouldContain("Max heap size too large for Compressed Oops")
|
||||||
.shouldHaveExitValue(0);
|
.shouldHaveExitValue(0);
|
||||||
|
|
||||||
// 32gb heap with object alignment set to 16 bytes should result in zero based with shift 4
|
|
||||||
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
|
|
||||||
.shouldContain("Zero based")
|
|
||||||
.shouldContain("Oop shift amount: 4")
|
|
||||||
.shouldHaveExitValue(0);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Compressed oops should only apply to 64bit platforms
|
// Compressed oops should only apply to 64bit platforms
|
||||||
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
|
testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
* @test CodeCacheTest
|
* @test CodeCacheTest
|
||||||
* @bug 8054889
|
* @bug 8054889
|
||||||
* @build DcmdUtil CodeCacheTest
|
* @build DcmdUtil CodeCacheTest
|
||||||
* @run main CodeCacheTest
|
* @run main/othervm -XX:+SegmentedCodeCache CodeCacheTest
|
||||||
|
* @run main/othervm -XX:-SegmentedCodeCache CodeCacheTest
|
||||||
* @summary Test of diagnostic command Compiler.codecache
|
* @summary Test of diagnostic command Compiler.codecache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -39,34 +40,78 @@ public class CodeCacheTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output,
|
* This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output,
|
||||||
* making sure that all number look ok
|
* making sure that all numbers look ok
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Expected output:
|
* Expected output without code cache segmentation:
|
||||||
*
|
*
|
||||||
* CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb
|
* CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb
|
||||||
* bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000]
|
* bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000]
|
||||||
* total_blobs=575 nmethods=69 adapters=423
|
* total_blobs=575 nmethods=69 adapters=423
|
||||||
* compilation: enabled
|
* compilation: enabled
|
||||||
|
*
|
||||||
|
* Expected output with code cache segmentation (number of segments may change):
|
||||||
|
*
|
||||||
|
* CodeHeap 'non-methods': size=5696Kb used=2236Kb max_used=2238Kb free=3459Kb
|
||||||
|
* bounds [0x00007fa0f0ffe000, 0x00007fa0f126e000, 0x00007fa0f158e000]
|
||||||
|
* CodeHeap 'profiled nmethods': size=120036Kb used=8Kb max_used=8Kb free=120027Kb
|
||||||
|
* bounds [0x00007fa0f158e000, 0x00007fa0f17fe000, 0x00007fa0f8ac7000]
|
||||||
|
* CodeHeap 'non-profiled nmethods': size=120036Kb used=2Kb max_used=2Kb free=120034Kb
|
||||||
|
* bounds [0x00007fa0f8ac7000, 0x00007fa0f8d37000, 0x00007fa100000000]
|
||||||
|
* total_blobs=486 nmethods=8 adapters=399
|
||||||
|
* compilation: enabled
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static Pattern line1 = Pattern.compile("CodeCache: size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb");
|
static Pattern line1 = Pattern.compile("(CodeCache|CodeHeap.*): size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb");
|
||||||
static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]");
|
static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]");
|
||||||
static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)");
|
static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)");
|
||||||
static Pattern line4 = Pattern.compile(" compilation: (\\w*)");
|
static Pattern line4 = Pattern.compile(" compilation: (.*)");
|
||||||
|
|
||||||
|
private static boolean getFlagBool(String flag, String where) {
|
||||||
|
Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where);
|
||||||
|
if (!m.find()) {
|
||||||
|
throw new RuntimeException("Could not find value for flag " + flag + " in output string");
|
||||||
|
}
|
||||||
|
return m.group(1).equals("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getFlagInt(String flag, String where) {
|
||||||
|
Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where);
|
||||||
|
if (!m.find()) {
|
||||||
|
throw new RuntimeException("Could not find value for flag " + flag + " in output string");
|
||||||
|
}
|
||||||
|
String match = m.group();
|
||||||
|
return Integer.parseInt(match.substring(match.lastIndexOf(" ") + 1, match.length()));
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String arg[]) throws Exception {
|
public static void main(String arg[]) throws Exception {
|
||||||
|
// Get number of code cache segments
|
||||||
|
int segmentsCount = 0;
|
||||||
|
String flags = DcmdUtil.executeDcmd("VM.flags", "-all");
|
||||||
|
if (!getFlagBool("SegmentedCodeCache", flags) || !getFlagBool("UseCompiler", flags)) {
|
||||||
|
// No segmentation
|
||||||
|
segmentsCount = 1;
|
||||||
|
} else if (getFlagBool("TieredCompilation", flags) && getFlagInt("TieredStopAtLevel", flags) > 1) {
|
||||||
|
// Tiered compilation: use all segments
|
||||||
|
segmentsCount = 3;
|
||||||
|
} else {
|
||||||
|
// No TieredCompilation: only non-method and non-profiled segment
|
||||||
|
segmentsCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Get output from dcmd (diagnostic command)
|
// Get output from dcmd (diagnostic command)
|
||||||
String result = DcmdUtil.executeDcmd("Compiler.codecache");
|
String result = DcmdUtil.executeDcmd("Compiler.codecache");
|
||||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||||
|
|
||||||
// Validate first line
|
// Validate code cache segments
|
||||||
String line;
|
String line;
|
||||||
|
Matcher m;
|
||||||
|
for (int s = 0; s < segmentsCount; ++s) {
|
||||||
|
// Validate first line
|
||||||
line = r.readLine();
|
line = r.readLine();
|
||||||
Matcher m = line1.matcher(line);
|
m = line1.matcher(line);
|
||||||
if (m.matches()) {
|
if (m.matches()) {
|
||||||
for(int i = 1; i <= 4; i++) {
|
for (int i = 2; i <= 5; i++) {
|
||||||
int val = Integer.parseInt(m.group(i));
|
int val = Integer.parseInt(m.group(i));
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
throw new Exception("Failed parsing dcmd codecache output");
|
||||||
|
@ -80,27 +125,21 @@ public class CodeCacheTest {
|
||||||
line = r.readLine();
|
line = r.readLine();
|
||||||
m = line2.matcher(line);
|
m = line2.matcher(line);
|
||||||
if (m.matches()) {
|
if (m.matches()) {
|
||||||
long start = Long.parseLong(m.group(1), 16);
|
String start = m.group(1);
|
||||||
if (start < 0) {
|
String mark = m.group(2);
|
||||||
|
String top = m.group(3);
|
||||||
|
|
||||||
|
// Lexical compare of hex numbers to check that they look sane.
|
||||||
|
if (start.compareTo(mark) > 1) {
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
throw new Exception("Failed parsing dcmd codecache output");
|
||||||
}
|
}
|
||||||
long mark = Long.parseLong(m.group(2), 16);
|
if (mark.compareTo(top) > 1) {
|
||||||
if (mark < 0) {
|
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
|
||||||
}
|
|
||||||
long top = Long.parseLong(m.group(3), 16);
|
|
||||||
if (top < 0) {
|
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
|
||||||
}
|
|
||||||
if (start > mark) {
|
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
|
||||||
}
|
|
||||||
if (mark > top) {
|
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
throw new Exception("Failed parsing dcmd codecache output");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("Regexp 2 failed line: " + line);
|
throw new Exception("Regexp 2 failed line: " + line);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate third line
|
// Validate third line
|
||||||
line = r.readLine();
|
line = r.readLine();
|
||||||
|
@ -111,7 +150,7 @@ public class CodeCacheTest {
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
throw new Exception("Failed parsing dcmd codecache output");
|
||||||
}
|
}
|
||||||
int nmethods = Integer.parseInt(m.group(2));
|
int nmethods = Integer.parseInt(m.group(2));
|
||||||
if (nmethods <= 0) {
|
if (nmethods < 0) {
|
||||||
throw new Exception("Failed parsing dcmd codecache output");
|
throw new Exception("Failed parsing dcmd codecache output");
|
||||||
}
|
}
|
||||||
int adapters = Integer.parseInt(m.group(3));
|
int adapters = Integer.parseInt(m.group(3));
|
||||||
|
@ -128,11 +167,7 @@ public class CodeCacheTest {
|
||||||
// Validate fourth line
|
// Validate fourth line
|
||||||
line = r.readLine();
|
line = r.readLine();
|
||||||
m = line4.matcher(line);
|
m = line4.matcher(line);
|
||||||
if (m.matches()) {
|
if (!m.matches()) {
|
||||||
if (!m.group(1).equals("enabled")) {
|
|
||||||
throw new Exception("Invalid message: '" + m.group(1) + "'");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Exception("Regexp 4 failed");
|
throw new Exception("Regexp 4 failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue