diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java index 0cfb3c53fbad524f1b67499cf5da0c3165fec748..04c4abbe0a9b836653e9d523498bd62296e36e28 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java @@ -28,10 +28,10 @@ import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.debugger.cdbg.basic.x86.*; -import sun.jvm.hotspot.debugger.cdbg.basic.amd64.*; import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.amd64.*; +import sun.jvm.hotspot.debugger.windows.x86.*; +import sun.jvm.hotspot.debugger.windows.amd64.*; import sun.jvm.hotspot.utilities.AddressOps; class WindbgCDebugger implements CDebugger { @@ -75,14 +75,14 @@ class WindbgCDebugger implements CDebugger { if (ebp == null) return null; Address pc = context.getRegisterAsAddress(X86ThreadContext.EIP); if (pc == null) return null; - return new X86CFrame(this, ebp, pc); + return new WindowsX86CFrame(dbg, ebp, pc); } else if (dbg.getCPU().equals("amd64")) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); Address rbp = context.getRegisterAsAddress(AMD64ThreadContext.RBP); if (rbp == null) return null; Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); if (pc == null) return null; - return new AMD64CFrame(this, rbp, pc); + return new WindowsAMD64CFrame(dbg, rbp, pc); } else { // unsupported CPU! return null; diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/amd64/AMD64CFrame.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java similarity index 78% rename from agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/amd64/AMD64CFrame.java rename to agent/src/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java index d6ec6b45003e6b4517027d702f56c6e33e5a7246..fe4052f35125e1df9baf9641eb45896096779d1b 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/amd64/AMD64CFrame.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java @@ -22,26 +22,26 @@ * */ -package sun.jvm.hotspot.debugger.cdbg.basic.amd64; +package sun.jvm.hotspot.debugger.windows.amd64; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.debugger.windbg.*; -/** Basic AMD64 frame functionality providing sender() functionality. */ - -public class AMD64CFrame extends BasicCFrame { +public class WindowsAMD64CFrame extends BasicCFrame { private Address rbp; private Address pc; private static final int ADDRESS_SIZE = 8; /** Constructor for topmost frame */ - public AMD64CFrame(CDebugger dbg, Address rbp, Address pc) { - super(dbg); + public WindowsAMD64CFrame(WindbgDebugger dbg, Address rbp, Address pc) { + super(dbg.getCDebugger()); this.rbp = rbp; this.pc = pc; + this.dbg = dbg; } public CFrame sender(ThreadProxy thread) { @@ -52,15 +52,20 @@ public class AMD64CFrame extends BasicCFrame { return null; } + // Check alignment of rbp + if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextRBP == null) { + if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) { return null; } Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE); if (nextPC == null) { return null; } - return new AMD64CFrame(dbg(), nextRBP, nextPC); + return new WindowsAMD64CFrame(dbg, nextRBP, nextPC); } public Address pc() { @@ -70,4 +75,6 @@ public class AMD64CFrame extends BasicCFrame { public Address localVariableBase() { return rbp; } + + private WindbgDebugger dbg; } diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/x86/X86CFrame.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java similarity index 78% rename from agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/x86/X86CFrame.java rename to agent/src/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java index 76b101bef972d75c4d13c8578b09d02e2e4db650..5c5f1f161e7d619fbdfb0e9ddc1e20d17bd8ca06 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/x86/X86CFrame.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java @@ -22,26 +22,26 @@ * */ -package sun.jvm.hotspot.debugger.cdbg.basic.x86; +package sun.jvm.hotspot.debugger.windows.x86; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.debugger.windbg.*; -/** Basic X86 frame functionality providing sender() functionality. */ - -public class X86CFrame extends BasicCFrame { +public class WindowsX86CFrame extends BasicCFrame { private Address ebp; private Address pc; private static final int ADDRESS_SIZE = 4; /** Constructor for topmost frame */ - public X86CFrame(CDebugger dbg, Address ebp, Address pc) { - super(dbg); + public WindowsX86CFrame(WindbgDebugger dbg, Address ebp, Address pc) { + super(dbg.getCDebugger()); this.ebp = ebp; this.pc = pc; + this.dbg = dbg; } public CFrame sender(ThreadProxy thread) { @@ -52,15 +52,20 @@ public class X86CFrame extends BasicCFrame { return null; } + // Check alignment of ebp + if ( dbg.getAddressValue(ebp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextEBP = ebp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextEBP == null) { + if (nextEBP == null || nextEBP.lessThanOrEqual(ebp)) { return null; } Address nextPC = ebp.getAddressAt( 1 * ADDRESS_SIZE); if (nextPC == null) { return null; } - return new X86CFrame(dbg(), nextEBP, nextPC); + return new WindowsX86CFrame(dbg, nextEBP, nextPC); } public Address pc() { @@ -70,4 +75,6 @@ public class X86CFrame extends BasicCFrame { public Address localVariableBase() { return ebp; } + + private WindbgDebugger dbg; } diff --git a/make/bsd/makefiles/arm.make b/make/bsd/makefiles/arm.make index e22d5c375dc4e94f90ec7b40529d89be268a72f6..f35f70a579bef7c3fb2026203bcdba9068069f0f 100644 --- a/make/bsd/makefiles/arm.make +++ b/make/bsd/makefiles/arm.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ Obj_Files += bsd_arm.o -LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a +ifneq ($(EXT_LIBS_PATH),) + LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a +endif CFLAGS += -DVM_LITTLE_ENDIAN diff --git a/make/linux/makefiles/arm.make b/make/linux/makefiles/arm.make index 6d7079e5619172d347603fb31c880bf1c07a08b8..ff8e3c519f9d521a34ffa7f9ce56ab5cc6ba5789 100644 --- a/make/linux/makefiles/arm.make +++ b/make/linux/makefiles/arm.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ Obj_Files += linux_arm.o -LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a +ifneq ($(EXT_LIBS_PATH),) + LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a +endif CFLAGS += -DVM_LITTLE_ENDIAN diff --git a/make/linux/makefiles/jsig.make b/make/linux/makefiles/jsig.make index a0c72453f546694b73f0c70534471e421880a217..1064a9652494de457e69961e8723e206bf86b660 100644 --- a/make/linux/makefiles/jsig.make +++ b/make/linux/makefiles/jsig.make @@ -54,7 +54,7 @@ endif $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< -ldl + $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) $(EXTRA_CFLAGS) -o $@ $< -ldl ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO) $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ diff --git a/make/linux/makefiles/saproc.make b/make/linux/makefiles/saproc.make index c2a82d717c96208ca03c34632740a3bd05f0acce..90c91136185d31c88ad4b4a176b801f0e4fcf603 100644 --- a/make/linux/makefiles/saproc.make +++ b/make/linux/makefiles/saproc.make @@ -92,6 +92,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) $(SASRCFILES) \ $(SA_LFLAGS) \ $(SA_DEBUG_CFLAGS) \ + $(EXTRA_CFLAGS) \ -o $@ \ -lthread_db ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) diff --git a/make/sa.files b/make/sa.files index c4414be60c1499a9488d90c47a8f1231679200b9..44308c2a217767c8ae3cce6ce23436ef72814849 100644 --- a/make/sa.files +++ b/make/sa.files @@ -48,8 +48,6 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ @@ -70,6 +68,8 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/gc_implementation/g1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/gc_implementation/parallelScavenge/*.java \ diff --git a/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/src/cpu/x86/vm/stubGenerator_x86_32.cpp index f3a91d03c9991bbf34187457f8f00fa623cae9b2..7422ed39d242bcd78caf189ace3d369f1fe43e24 100644 --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -1498,27 +1498,29 @@ class StubGenerator: public StubCodeGenerator { __ movptr(elem_klass, elem_klass_addr); // query the object klass generate_type_check(elem_klass, ckoff_arg, ckval_arg, temp, &L_store_element, NULL); - // (On fall-through, we have failed the element type check.) + // (On fall-through, we have failed the element type check.) // ======== end loop ======== // It was a real error; we must depend on the caller to finish the job. // Register "count" = -1 * number of *remaining* oops, length_arg = *total* oops. // Emit GC store barriers for the oops we have copied (length_arg + count), // and report their number to the caller. + assert_different_registers(to, count, rax); + Label L_post_barrier; __ addl(count, length_arg); // transfers = (length - remaining) __ movl2ptr(rax, count); // save the value - __ notptr(rax); // report (-1^K) to caller - __ movptr(to, to_arg); // reload - assert_different_registers(to, count, rax); - gen_write_ref_array_post_barrier(to, count); - __ jmpb(L_done); + __ notptr(rax); // report (-1^K) to caller (does not affect flags) + __ jccb(Assembler::notZero, L_post_barrier); + __ jmp(L_done); // K == 0, nothing was copied, skip post barrier // Come here on success only. __ BIND(L_do_card_marks); + __ xorptr(rax, rax); // return 0 on success __ movl2ptr(count, length_arg); - __ movptr(to, to_arg); // reload + + __ BIND(L_post_barrier); + __ movptr(to, to_arg); // reload gen_write_ref_array_post_barrier(to, count); - __ xorptr(rax, rax); // return 0 on success // Common exit point (success or failure). __ BIND(L_done); diff --git a/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/src/cpu/x86/vm/stubGenerator_x86_64.cpp index ace545383d7030682b2d4c398b92273124886c1a..fb9c1ddd4b9a93cbddfeacae2c86cd99ba1e8f12 100644 --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -1217,27 +1217,28 @@ class StubGenerator: public StubCodeGenerator { // // Input: // start - register containing starting address of destination array - // end - register containing ending address of destination array + // count - elements count // scratch - scratch register // // The input registers are overwritten. - // The ending address is inclusive. - void gen_write_ref_array_post_barrier(Register start, Register end, Register scratch) { - assert_different_registers(start, end, scratch); + // + void gen_write_ref_array_post_barrier(Register start, Register count, Register scratch) { + assert_different_registers(start, count, scratch); BarrierSet* bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: - { - __ pusha(); // push registers (overkill) - // must compute element count unless barrier set interface is changed (other platforms supply count) - assert_different_registers(start, end, scratch); - __ lea(scratch, Address(end, BytesPerHeapOop)); - __ subptr(scratch, start); // subtract start to get #bytes - __ shrptr(scratch, LogBytesPerHeapOop); // convert to element count - __ mov(c_rarg0, start); - __ mov(c_rarg1, scratch); + __ pusha(); // push registers (overkill) + if (c_rarg0 == count) { // On win64 c_rarg0 == rcx + assert_different_registers(c_rarg1, start); + __ mov(c_rarg1, count); + __ mov(c_rarg0, start); + } else { + assert_different_registers(c_rarg0, count); + __ mov(c_rarg0, start); + __ mov(c_rarg1, count); + } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2); __ popa(); } @@ -1249,22 +1250,16 @@ class StubGenerator: public StubCodeGenerator { assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); Label L_loop; + const Register end = count; - __ shrptr(start, CardTableModRefBS::card_shift); - __ addptr(end, BytesPerHeapOop); - __ shrptr(end, CardTableModRefBS::card_shift); - __ subptr(end, start); // number of bytes to copy - - intptr_t disp = (intptr_t) ct->byte_map_base; - if (Assembler::is_simm32(disp)) { - Address cardtable(noreg, noreg, Address::no_scale, disp); - __ lea(scratch, cardtable); - } else { - ExternalAddress cardtable((address)disp); - __ lea(scratch, cardtable); - } + __ leaq(end, Address(start, count, TIMES_OOP, 0)); // end == start+count*oop_size + __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive + __ shrptr(start, CardTableModRefBS::card_shift); + __ shrptr(end, CardTableModRefBS::card_shift); + __ subptr(end, start); // end --> cards count - const Register count = end; // 'end' register contains bytes count now + int64_t disp = (int64_t) ct->byte_map_base; + __ mov64(scratch, disp); __ addptr(start, scratch); __ BIND(L_loop); __ movb(Address(start, count, Address::times_1), 0); @@ -1916,8 +1911,7 @@ class StubGenerator: public StubCodeGenerator { __ BIND(L_exit); if (is_oop) { - __ leaq(end_to, Address(saved_to, dword_count, Address::times_4, -4)); - gen_write_ref_array_post_barrier(saved_to, end_to, rax); + gen_write_ref_array_post_barrier(saved_to, dword_count, rax); } restore_arg_regs(); inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free @@ -2012,12 +2006,10 @@ class StubGenerator: public StubCodeGenerator { // Copy in multi-bytes chunks copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes); - __ bind(L_exit); - if (is_oop) { - Register end_to = rdx; - __ leaq(end_to, Address(to, dword_count, Address::times_4, -4)); - gen_write_ref_array_post_barrier(to, end_to, rax); - } + __ BIND(L_exit); + if (is_oop) { + gen_write_ref_array_post_barrier(to, dword_count, rax); + } restore_arg_regs(); inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 @@ -2055,6 +2047,7 @@ class StubGenerator: public StubCodeGenerator { const Register end_from = from; // source array end address const Register end_to = rcx; // destination array end address const Register saved_to = to; + const Register saved_count = r11; // End pointers are inclusive, and if count is not zero they point // to the last unit copied: end_to[0] := end_from[0] @@ -2072,6 +2065,8 @@ class StubGenerator: public StubCodeGenerator { // r9 and r10 may be used to save non-volatile registers // 'from', 'to' and 'qword_count' are now valid if (is_oop) { + // Save to and count for store barrier + __ movptr(saved_count, qword_count); // no registers are destroyed by this call gen_write_ref_array_pre_barrier(to, qword_count, dest_uninitialized); } @@ -2104,7 +2099,7 @@ class StubGenerator: public StubCodeGenerator { if (is_oop) { __ BIND(L_exit); - gen_write_ref_array_post_barrier(saved_to, end_to, rax); + gen_write_ref_array_post_barrier(saved_to, saved_count, rax); } restore_arg_regs(); if (is_oop) { @@ -2187,8 +2182,7 @@ class StubGenerator: public StubCodeGenerator { if (is_oop) { __ BIND(L_exit); - __ lea(rcx, Address(to, saved_count, Address::times_8, -8)); - gen_write_ref_array_post_barrier(to, rcx, rax); + gen_write_ref_array_post_barrier(to, saved_count, rax); } restore_arg_regs(); if (is_oop) { @@ -2375,20 +2369,20 @@ class StubGenerator: public StubCodeGenerator { // Register rdx = -1 * number of *remaining* oops, r14 = *total* oops. // Emit GC store barriers for the oops we have copied (r14 + rdx), // and report their number to the caller. - assert_different_registers(rax, r14_length, count, to, end_to, rcx); - __ lea(end_to, to_element_addr); - __ addptr(end_to, -heapOopSize); // make an inclusive end pointer - gen_write_ref_array_post_barrier(to, end_to, rscratch1); - __ movptr(rax, r14_length); // original oops - __ addptr(rax, count); // K = (original - remaining) oops - __ notptr(rax); // report (-1^K) to caller - __ jmp(L_done); + assert_different_registers(rax, r14_length, count, to, end_to, rcx, rscratch1); + Label L_post_barrier; + __ addptr(r14_length, count); // K = (original - remaining) oops + __ movptr(rax, r14_length); // save the value + __ notptr(rax); // report (-1^K) to caller (does not affect flags) + __ jccb(Assembler::notZero, L_post_barrier); + __ jmp(L_done); // K == 0, nothing was copied, skip post barrier // Come here on success only. __ BIND(L_do_card_marks); - __ addptr(end_to, -heapOopSize); // make an inclusive end pointer - gen_write_ref_array_post_barrier(to, end_to, rscratch1); - __ xorptr(rax, rax); // return 0 on success + __ xorptr(rax, rax); // return 0 on success + + __ BIND(L_post_barrier); + gen_write_ref_array_post_barrier(to, r14_length, rscratch1); // Common exit point (success or failure). __ BIND(L_done); diff --git a/src/share/tools/hsdis/hsdis.c b/src/share/tools/hsdis/hsdis.c index 397793021c0e95bacf90c4a7550a4c606ff45843..162e2aba3e7162b620da2ea4040cfd3b37b18add 100644 --- a/src/share/tools/hsdis/hsdis.c +++ b/src/share/tools/hsdis/hsdis.c @@ -27,6 +27,7 @@ HotSpot PrintAssembly option. */ +#include /* required by bfd.h */ #include #include #include diff --git a/src/share/vm/c1/c1_Compiler.cpp b/src/share/vm/c1/c1_Compiler.cpp index 2820506182a8b30756222fc5fa3936a0733011ee..ecace4dad072ebc07eecbaf1fd1d1584aa300e27 100644 --- a/src/share/vm/c1/c1_Compiler.cpp +++ b/src/share/vm/c1/c1_Compiler.cpp @@ -77,30 +77,42 @@ void Compiler::initialize() { } -BufferBlob* Compiler::build_buffer_blob() { +BufferBlob* Compiler::get_buffer_blob(ciEnv* env) { + // Allocate buffer blob once at startup since allocation for each + // compilation seems to be too expensive (at least on Intel win32). + BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + if (buffer_blob != NULL) { + return buffer_blob; + } + // setup CodeBuffer. Preallocate a BufferBlob of size // NMethodSizeLimit plus some extra space for constants. int code_buffer_size = Compilation::desired_max_code_buffer_size() + Compilation::desired_max_constant_size(); - BufferBlob* blob = BufferBlob::create("Compiler1 temporary CodeBuffer", - code_buffer_size); - guarantee(blob != NULL, "must create initial code buffer"); - return blob; + + buffer_blob = BufferBlob::create("Compiler1 temporary CodeBuffer", + code_buffer_size); + if (buffer_blob == NULL) { + CompileBroker::handle_full_code_cache(); + env->record_failure("CodeCache is full"); + } else { + CompilerThread::current()->set_buffer_blob(buffer_blob); + } + + return buffer_blob; } void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { - // Allocate buffer blob once at startup since allocation for each - // compilation seems to be too expensive (at least on Intel win32). - BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + BufferBlob* buffer_blob = Compiler::get_buffer_blob(env); if (buffer_blob == NULL) { - buffer_blob = build_buffer_blob(); - CompilerThread::current()->set_buffer_blob(buffer_blob); + return; } if (!is_initialized()) { initialize(); } + // invoke compilation { // We are nested here because we need for the destructor diff --git a/src/share/vm/c1/c1_Compiler.hpp b/src/share/vm/c1/c1_Compiler.hpp index 9702a15ee4bcd2d3483ad9fc7ec2e5e268938151..6e209d0034f0addb261ea9ae9daf44061ebf3165 100644 --- a/src/share/vm/c1/c1_Compiler.hpp +++ b/src/share/vm/c1/c1_Compiler.hpp @@ -46,7 +46,7 @@ class Compiler: public AbstractCompiler { virtual bool is_c1() { return true; }; - BufferBlob* build_buffer_blob(); + BufferBlob* get_buffer_blob(ciEnv* env); // Missing feature tests virtual bool supports_native() { return true; } diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp index 19aaa8bc5e416caa43254bde4dae55bc71a1c4bc..6b2ddd140c65802bf18c572cd55080f33f937fc2 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp @@ -1719,15 +1719,28 @@ void ClassFileParser::parse_annotations(u1* buffer, int limit, coll->set_annotation(id); if (id == AnnotationCollector::_sun_misc_Contended) { + // @Contended can optionally specify the contention group. + // + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not treated distinct. + // The only exception is default group, which does not incur the + // equivalence. Naturally, contention group for classes is meaningless. + // + // While the contention group is specified as String, annotation + // values are already interned, and we might as well use the constant + // pool index as the group tag. + // + u2 group_index = 0; // default contended group if (count == 1 && s_size == (index - index0) // match size && s_tag_val == *(abase + tag_off) && member == vmSymbols::value_name()) { - u2 group_index = Bytes::get_Java_u2(abase + s_con_off); - coll->set_contended_group(group_index); - } else { - coll->set_contended_group(0); // default contended group + group_index = Bytes::get_Java_u2(abase + s_con_off); + if (_cp->symbol_at(group_index)->utf8_length() == 0) { + group_index = 0; // default contended group + } } + coll->set_contended_group(group_index); } } } @@ -3108,10 +3121,6 @@ void ClassFileParser::layout_fields(Handle class_loader, FieldLayoutInfo* info, TRAPS) { - // get the padding width from the option - // TODO: Ask VM about specific CPU we are running on - int pad_size = ContendedPaddingWidth; - // Field size and offset computation int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size(); int next_static_oop_offset; @@ -3124,13 +3133,14 @@ void ClassFileParser::layout_fields(Handle class_loader, int next_nonstatic_word_offset; int next_nonstatic_short_offset; int next_nonstatic_byte_offset; - int next_nonstatic_type_offset; int first_nonstatic_oop_offset; - int first_nonstatic_field_offset; int next_nonstatic_field_offset; int next_nonstatic_padded_offset; // Count the contended fields by type. + // + // We ignore static fields, because @Contended is not supported for them. + // The layout code below will also ignore the static fields. int nonstatic_contended_count = 0; FieldAllocationCount fac_contended; for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { @@ -3162,16 +3172,17 @@ void ClassFileParser::layout_fields(Handle class_loader, next_static_byte_offset = next_static_short_offset + ((fac->count[STATIC_SHORT]) * BytesPerShort); - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; + int nonstatic_fields_start = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + + next_nonstatic_field_offset = nonstatic_fields_start; - // class is contended, pad before all the fields + // Class is contended, pad before all the fields if (parsed_annotations->is_contended()) { - first_nonstatic_field_offset += pad_size; + next_nonstatic_field_offset += ContendedPaddingWidth; } - next_nonstatic_field_offset = first_nonstatic_field_offset; - + // Compute the non-contended fields count unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; @@ -3229,6 +3240,7 @@ void ClassFileParser::layout_fields(Handle class_loader, compact_fields = false; // Don't compact fields } + // Rearrange fields for a given allocation style if( allocation_style == 0 ) { // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields next_nonstatic_oop_offset = next_nonstatic_field_offset; @@ -3269,6 +3281,8 @@ void ClassFileParser::layout_fields(Handle class_loader, int nonstatic_short_space_offset; int nonstatic_byte_space_offset; + // Try to squeeze some of the fields into the gaps due to + // long/double alignment. if( nonstatic_double_count > 0 ) { int offset = next_nonstatic_double_offset; next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); @@ -3442,7 +3456,7 @@ void ClassFileParser::layout_fields(Handle class_loader, // if there is at least one contended field, we need to have pre-padding for them if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += pad_size; + next_nonstatic_padded_offset += ContendedPaddingWidth; } // collect all contended groups @@ -3521,7 +3535,7 @@ void ClassFileParser::layout_fields(Handle class_loader, // the fields within the same contended group are not inter-padded. // The only exception is default group, which does not incur the // equivalence, and so requires intra-padding. - next_nonstatic_padded_offset += pad_size; + next_nonstatic_padded_offset += ContendedPaddingWidth; } fs.set_offset(real_offset); @@ -3533,7 +3547,7 @@ void ClassFileParser::layout_fields(Handle class_loader, // subclass fields and/or adjacent object. // If this was the default group, the padding is already in place. if (current_group != 0) { - next_nonstatic_padded_offset += pad_size; + next_nonstatic_padded_offset += ContendedPaddingWidth; } } @@ -3547,22 +3561,22 @@ void ClassFileParser::layout_fields(Handle class_loader, // This helps to alleviate memory contention effects for subclass fields // and/or adjacent object. if (parsed_annotations->is_contended()) { - notaligned_offset += pad_size; + notaligned_offset += ContendedPaddingWidth; } - int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); - int static_field_size = (next_static_type_offset - - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + int nonstatic_fields_end = align_size_up(notaligned_offset, heapOopSize); + int instance_end = align_size_up(notaligned_offset, wordSize); + int static_fields_end = align_size_up(next_static_byte_offset, wordSize); - next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); - nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/heapOopSize); + int static_field_size = (static_fields_end - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + nonstatic_field_size = nonstatic_field_size + + (nonstatic_fields_end - nonstatic_fields_start) / heapOopSize; - next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); - int instance_size = align_object_size(next_nonstatic_type_offset / wordSize); + int instance_size = align_object_size(instance_end / wordSize); assert(instance_size == align_object_size(align_size_up( - (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations->is_contended()) ? pad_size : 0)), + (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value"); // Number of non-static oop map blocks allocated at end of klass. @@ -3576,9 +3590,9 @@ void ClassFileParser::layout_fields(Handle class_loader, _fields, _cp, instance_size, - first_nonstatic_field_offset, - next_nonstatic_field_offset, - next_static_type_offset); + nonstatic_fields_start, + nonstatic_fields_end, + static_fields_end); } #endif diff --git a/src/share/vm/classfile/symbolTable.cpp b/src/share/vm/classfile/symbolTable.cpp index b36432a3c1055e4e71d364aa6e7fa564f451d6ba..5fbd184a421ce5390daacea1e9b0366f9da6a72b 100644 --- a/src/share/vm/classfile/symbolTable.cpp +++ b/src/share/vm/classfile/symbolTable.cpp @@ -35,7 +35,6 @@ #include "oops/oop.inline2.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" -#include "utilities/numberSeq.hpp" // -------------------------------------------------------------------------- @@ -451,21 +450,7 @@ void SymbolTable::verify() { } void SymbolTable::dump(outputStream* st) { - NumberSeq summary; - for (int i = 0; i < the_table()->table_size(); ++i) { - int count = 0; - for (HashtableEntry* e = the_table()->bucket(i); - e != NULL; e = e->next()) { - count++; - } - summary.add((double)count); - } - st->print_cr("SymbolTable statistics:"); - st->print_cr("Number of buckets : %7d", summary.num()); - st->print_cr("Average bucket size : %7.0f", summary.avg()); - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); + the_table()->dump_table(st, "SymbolTable"); } @@ -814,21 +799,7 @@ void StringTable::verify() { } void StringTable::dump(outputStream* st) { - NumberSeq summary; - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry* p = the_table()->bucket(i); - int count = 0; - for ( ; p != NULL; p = p->next()) { - count++; - } - summary.add((double)count); - } - st->print_cr("StringTable statistics:"); - st->print_cr("Number of buckets : %7d", summary.num()); - st->print_cr("Average bucket size : %7.0f", summary.avg()); - st->print_cr("Variance of bucket size : %7.0f", summary.variance()); - st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); - st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); + the_table()->dump_table(st, "StringTable"); } diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp index f7be307b254f71a0a03ffd199dc446683435f11a..44d65e23345f175831ec315fce0c0df5c3c8d8f6 100644 --- a/src/share/vm/code/codeCache.cpp +++ b/src/share/vm/code/codeCache.cpp @@ -622,6 +622,15 @@ address CodeCache::last_address() { return (address)_heap->high(); } +/** + * Returns the reverse free ratio. E.g., if 25% (1/4) of the code cache + * is free, reverse_free_ratio() returns 4. + */ +double CodeCache::reverse_free_ratio() { + double unallocated_capacity = (double)(CodeCache::unallocated_capacity() - CodeCacheMinimumFreeSpace); + double max_capacity = (double)CodeCache::max_capacity(); + return max_capacity / unallocated_capacity; +} void icache_init(); diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp index 38799019b8fe91ddc69bf7f2d7474ba2419565cf..3dde92702e34c1b3ec725f21f43d4261e3b69243 100644 --- a/src/share/vm/code/codeCache.hpp +++ b/src/share/vm/code/codeCache.hpp @@ -163,6 +163,7 @@ class CodeCache : AllStatic { static size_t max_capacity() { return _heap->max_capacity(); } static size_t unallocated_capacity() { return _heap->unallocated_capacity(); } static bool needs_flushing() { return unallocated_capacity() < CodeCacheFlushingMinimumFreeSpace; } + static double reverse_free_ratio(); static bool needs_cache_clean() { return _needs_cache_clean; } static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } diff --git a/src/share/vm/opto/loopnode.hpp b/src/share/vm/opto/loopnode.hpp index c45ea8421f1dd71103a9c2ac8037c8b75604aa72..df3eb4c0520426d45086ecba4f1a4e771dfb42ec 100644 --- a/src/share/vm/opto/loopnode.hpp +++ b/src/share/vm/opto/loopnode.hpp @@ -965,7 +965,7 @@ public: // Has use internal to the vector set (ie. not in a phi at the loop head) bool has_use_internal_to_set( Node* n, VectorSet& vset, IdealLoopTree *loop ); // clone "n" for uses that are outside of loop - void clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ); + int clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ); // clone "n" for special uses that are in the not_peeled region void clone_for_special_use_inside_loop( IdealLoopTree *loop, Node* n, VectorSet& not_peel, Node_List& sink_list, Node_List& worklist ); diff --git a/src/share/vm/opto/loopopts.cpp b/src/share/vm/opto/loopopts.cpp index 1db82d4ceb14955fc57287004090941000f69efd..31b5d8a5b7b0780f5f3cdd087ab09a522a08f60a 100644 --- a/src/share/vm/opto/loopopts.cpp +++ b/src/share/vm/opto/loopopts.cpp @@ -1939,8 +1939,8 @@ bool PhaseIdealLoop::has_use_internal_to_set( Node* n, VectorSet& vset, IdealLoo //------------------------------ clone_for_use_outside_loop ------------------------------------- // clone "n" for uses that are outside of loop -void PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ) { - +int PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ) { + int cloned = 0; assert(worklist.size() == 0, "should be empty"); for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { Node* use = n->fast_out(j); @@ -1960,6 +1960,7 @@ void PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, N // clone "n" and insert it between the inputs of "n" and the use outside the loop Node* n_clone = n->clone(); _igvn.replace_input_of(use, j, n_clone); + cloned++; Node* use_c; if (!use->is_Phi()) { use_c = has_ctrl(use) ? get_ctrl(use) : use->in(0); @@ -1977,6 +1978,7 @@ void PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, N } #endif } + return cloned; } @@ -2495,6 +2497,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { // Evacuate nodes in peel region into the not_peeled region if possible uint new_phi_cnt = 0; + uint cloned_for_outside_use = 0; for (i = 0; i < peel_list.size();) { Node* n = peel_list.at(i); #if !defined(PRODUCT) @@ -2513,8 +2516,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { // if not pinned and not a load (which maybe anti-dependent on a store) // and not a CMove (Matcher expects only bool->cmove). if ( n->in(0) == NULL && !n->is_Load() && !n->is_CMove() ) { - clone_for_use_outside_loop( loop, n, worklist ); - + cloned_for_outside_use += clone_for_use_outside_loop( loop, n, worklist ); sink_list.push(n); peel >>= n->_idx; // delete n from peel set. not_peel <<= n->_idx; // add n to not_peel set. @@ -2551,6 +2553,12 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { // Inhibit more partial peeling on this loop assert(!head->is_partial_peel_loop(), "not partial peeled"); head->mark_partial_peel_failed(); + if (cloned_for_outside_use > 0) { + // Terminate this round of loop opts because + // the graph outside this loop was changed. + C->set_major_progress(); + return true; + } return false; } diff --git a/src/share/vm/prims/jvmtiExport.cpp b/src/share/vm/prims/jvmtiExport.cpp index 1e430e96b9ad32c18f117c1998d09ef15bd0da72..f20dd4e492ae65e4513293106fbc20a36742e99d 100644 --- a/src/share/vm/prims/jvmtiExport.cpp +++ b/src/share/vm/prims/jvmtiExport.cpp @@ -1624,15 +1624,19 @@ void JvmtiExport::post_raw_field_modification(JavaThread *thread, Method* method } } + assert(sig_type != '[', "array should have sig_type == 'L'"); + bool handle_created = false; + // convert oop to JNI handle. - if (sig_type == 'L' || sig_type == '[') { + if (sig_type == 'L') { + handle_created = true; value->l = (jobject)JNIHandles::make_local(thread, (oop)value->l); } post_field_modification(thread, method, location, field_klass, object, field, sig_type, value); // Destroy the JNI handle allocated above. - if (sig_type == 'L') { + if (handle_created) { JNIHandles::destroy_local(value->l); } } diff --git a/src/share/vm/runtime/advancedThresholdPolicy.cpp b/src/share/vm/runtime/advancedThresholdPolicy.cpp index 81c2b74739d8dbf68407cdf81255fc14167d7840..7d72ca7f3eaa01264f186187c5192e80209d36b3 100644 --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp @@ -68,7 +68,7 @@ void AdvancedThresholdPolicy::initialize() { } #endif - + set_increase_threshold_at_ratio(); set_start_time(os::javaTimeMillis()); } @@ -205,6 +205,17 @@ double AdvancedThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) double queue_size = CompileBroker::queue_size(level); int comp_count = compiler_count(level); double k = queue_size / (feedback_k * comp_count) + 1; + + // Increase C1 compile threshold when the code cache is filled more + // than specified by IncreaseFirstTierCompileThresholdAt percentage. + // The main intention is to keep enough free space for C2 compiled code + // to achieve peak performance if the code cache is under stress. + if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) { + double current_reverse_free_ratio = CodeCache::reverse_free_ratio(); + if (current_reverse_free_ratio > _increase_threshold_at_ratio) { + k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio); + } + } return k; } diff --git a/src/share/vm/runtime/advancedThresholdPolicy.hpp b/src/share/vm/runtime/advancedThresholdPolicy.hpp index 90a1ca174b9cc43e4f699a8f58c3fcc1053c5b40..4ab7653581b505f854d98f0016002207ee9b9f9b 100644 --- a/src/share/vm/runtime/advancedThresholdPolicy.hpp +++ b/src/share/vm/runtime/advancedThresholdPolicy.hpp @@ -201,9 +201,12 @@ class AdvancedThresholdPolicy : public SimpleThresholdPolicy { // Is method profiled enough? bool is_method_profiled(Method* method); + double _increase_threshold_at_ratio; + protected: void print_specific(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level); + void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); } void set_start_time(jlong t) { _start_time = t; } jlong start_time() const { return _start_time; } diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp index b1cfb3cc3627f48d0951272babcba63b19382e94..83f4660a0c7b5a2082a7fbcc02370b8e08fb7871 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -2629,6 +2629,16 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize); + //-XX:IncreaseFirstTierCompileThresholdAt= + } else if (match_option(option, "-XX:IncreaseFirstTierCompileThresholdAt=", &tail)) { + uintx uint_IncreaseFirstTierCompileThresholdAt = 0; + if (!parse_uintx(tail, &uint_IncreaseFirstTierCompileThresholdAt, 0) || uint_IncreaseFirstTierCompileThresholdAt > 99) { + jio_fprintf(defaultStream::error_stream(), + "Invalid value for IncreaseFirstTierCompileThresholdAt: %s. Should be between 0 and 99.\n", + option->optionString); + return JNI_EINVAL; + } + FLAG_SET_CMDLINE(uintx, IncreaseFirstTierCompileThresholdAt, (uintx)uint_IncreaseFirstTierCompileThresholdAt); // -green } else if (match_option(option, "-green", &tail)) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index 1131c8e103b123468299e823fe75f364941949ea..aec1736a43ca39dba2c230265ba1976d3ed03648 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -3436,6 +3436,10 @@ class CommandLineFlags { "Start profiling in interpreter if the counters exceed tier 3" \ "thresholds by the specified percentage") \ \ + product(uintx, IncreaseFirstTierCompileThresholdAt, 50, \ + "Increase the compile threshold for C1 compilation if the code" \ + "cache is filled by the specified percentage.") \ + \ product(intx, TieredRateUpdateMinTime, 1, \ "Minimum rate sampling interval (in milliseconds)") \ \ diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp index a675c27bfadf1e6b75f4eecef6d074899b4476d4..1062b525fd5d1c5e3e495b4d084b3ae3a8c076b5 100644 --- a/src/share/vm/utilities/debug.cpp +++ b/src/share/vm/utilities/debug.cpp @@ -665,152 +665,4 @@ void help() { tty->print_cr(" ndebug() - undo debug"); } -#if 0 - -// BobV's command parser for debugging on windows when nothing else works. - -enum CommandID { - CMDID_HELP, - CMDID_QUIT, - CMDID_HSFIND, - CMDID_PSS, - CMDID_PS, - CMDID_PSF, - CMDID_FINDM, - CMDID_FINDNM, - CMDID_PP, - CMDID_BPT, - CMDID_EXIT, - CMDID_VERIFY, - CMDID_THREADS, - CMDID_ILLEGAL = 99 -}; - -struct CommandParser { - char *name; - CommandID code; - char *description; -}; - -struct CommandParser CommandList[] = { - (char *)"help", CMDID_HELP, " Dump this list", - (char *)"quit", CMDID_QUIT, " Return from this routine", - (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address", - (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace", - (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace", - (char *)"psf", CMDID_PSF, " Print All Stack Frames", - (char *)"findm", CMDID_FINDM, " Find a Method* from a PC", - (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC", - (char *)"pp", CMDID_PP, " Find out something about a pointer", - (char *)"break", CMDID_BPT, " Execute a breakpoint", - (char *)"exitvm", CMDID_EXIT, "Exit the VM", - (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify", - (char *)"thread", CMDID_THREADS, "Dump Info on all Threads", - (char *)0, CMDID_ILLEGAL -}; - - -// get_debug_command() -// -// Read a command from standard input. -// This is useful when you have a debugger -// which doesn't support calling into functions. -// -void get_debug_command() -{ - ssize_t count; - int i,j; - bool gotcommand; - intptr_t addr; - char buffer[256]; - nmethod *nm; - Method* m; - - tty->print_cr("You have entered the diagnostic command interpreter"); - tty->print("The supported commands are:\n"); - for ( i=0; ; i++ ) { - if ( CommandList[i].code == CMDID_ILLEGAL ) - break; - tty->print_cr(" %s \n", CommandList[i].name ); - } - - while ( 1 ) { - gotcommand = false; - tty->print("Please enter a command: "); - count = scanf("%s", buffer) ; - if ( count >=0 ) { - for ( i=0; ; i++ ) { - if ( CommandList[i].code == CMDID_ILLEGAL ) { - if (!gotcommand) tty->print("Invalid command, please try again\n"); - break; - } - if ( strcmp(buffer, CommandList[i].name) == 0 ) { - gotcommand = true; - switch ( CommandList[i].code ) { - case CMDID_PS: - ps(); - break; - case CMDID_PSS: - pss(); - break; - case CMDID_PSF: - psf(); - break; - case CMDID_FINDM: - tty->print("Please enter the hex addr to pass to findm: "); - scanf("%I64X", &addr); - m = (Method*)findm(addr); - tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m); - break; - case CMDID_FINDNM: - tty->print("Please enter the hex addr to pass to findnm: "); - scanf("%I64X", &addr); - nm = (nmethod*)findnm(addr); - tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm); - break; - case CMDID_PP: - tty->print("Please enter the hex addr to pass to pp: "); - scanf("%I64X", &addr); - pp((void*)addr); - break; - case CMDID_EXIT: - exit(0); - case CMDID_HELP: - tty->print("Here are the supported commands: "); - for ( j=0; ; j++ ) { - if ( CommandList[j].code == CMDID_ILLEGAL ) - break; - tty->print_cr(" %s -- %s\n", CommandList[j].name, - CommandList[j].description ); - } - break; - case CMDID_QUIT: - return; - break; - case CMDID_BPT: - BREAKPOINT; - break; - case CMDID_VERIFY: - verify();; - break; - case CMDID_THREADS: - threads();; - break; - case CMDID_HSFIND: - tty->print("Please enter the hex addr to pass to hsfind: "); - scanf("%I64X", &addr); - tty->print("Calling hsfind(0x%I64X)\n", addr); - hsfind(addr); - break; - default: - case CMDID_ILLEGAL: - break; - } - } - } - } - } -} -#endif - #endif // !PRODUCT diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp index 960474ababd89d0e51f11a9261607ccd8e9c65cc..ecb43da83b0298f1e2e0584da5a27b918c13d5f2 100644 --- a/src/share/vm/utilities/hashtable.cpp +++ b/src/share/vm/utilities/hashtable.cpp @@ -33,6 +33,7 @@ #include "utilities/dtrace.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "utilities/numberSeq.hpp" // This is a generic hashtable, designed to be used for the symbol @@ -237,6 +238,57 @@ template void Hashtable::reverse(void* boundary) { } } +template int Hashtable::literal_size(Symbol *symbol) { + return symbol->size() * HeapWordSize; +} + +template int Hashtable::literal_size(oop oop) { + // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, + // and the String.value array is shared by several Strings. However, starting from JDK8, + // the String.value array is not shared anymore. + assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported"); + return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; +} + +// Dump footprint and bucket length statistics +// +// Note: if you create a new subclass of Hashtable, you will need to +// add a new function Hashtable::literal_size(MyNewType lit) + +template void Hashtable::dump_table(outputStream* st, const char *table_name) { + NumberSeq summary; + int literal_bytes = 0; + for (int i = 0; i < this->table_size(); ++i) { + int count = 0; + for (HashtableEntry* e = bucket(i); + e != NULL; e = e->next()) { + count++; + literal_bytes += literal_size(e->literal()); + } + summary.add((double)count); + } + double num_buckets = summary.num(); + double num_entries = summary.sum(); + + int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); + int entry_bytes = (int)num_entries * sizeof(HashtableEntry); + int total_bytes = literal_bytes + bucket_bytes + entry_bytes; + + double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets); + double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries); + double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries); + + st->print_cr("%s statistics:", table_name); + st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg); + st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); + st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); + st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); + st->print_cr("Average bucket size : %9.3f", summary.avg()); + st->print_cr("Variance of bucket size : %9.3f", summary.variance()); + st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); + st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); +} + // Dump the hash table buckets. diff --git a/src/share/vm/utilities/hashtable.hpp b/src/share/vm/utilities/hashtable.hpp index f170e6018e9cf66e96c57ded89b374d5ea32eef3..826823bdc1393029c9bf20cdca5db896df782d35 100644 --- a/src/share/vm/utilities/hashtable.hpp +++ b/src/share/vm/utilities/hashtable.hpp @@ -282,6 +282,19 @@ protected: static bool use_alternate_hashcode() { return _seed != 0; } static jint seed() { return _seed; } + static int literal_size(Symbol *symbol); + static int literal_size(oop oop); + + // The following two are currently not used, but are needed anyway because some + // C++ compilers (MacOS and Solaris) force the instantiation of + // Hashtable::dump_table() even though we never call this function + // in the VM code. + static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} + static int literal_size(Klass *k) {Unimplemented(); return 0;} + +public: + void dump_table(outputStream* st, const char *table_name); + private: static jint _seed; }; diff --git a/test/compiler/8010927/Test8010927.java b/test/compiler/8010927/Test8010927.java new file mode 100644 index 0000000000000000000000000000000000000000..6c9d9ab3d696d7350d77ecb1b733cf245c7efbe0 --- /dev/null +++ b/test/compiler/8010927/Test8010927.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8010927 + * @summary Kitchensink crashed with SIGSEGV, Problematic frame: v ~StubRoutines::checkcast_arraycopy + * @library /testlibrary/whitebox /testlibrary + * @build Test8010927 + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xmx64m -XX:NewSize=20971520 -XX:MaxNewSize=32m -XX:-UseTLAB -XX:-UseParNewGC -XX:-UseAdaptiveSizePolicy Test8010927 + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +/** + * The test creates uncommitted space between oldgen and young gen + * by specifying MaxNewSize bigger than NewSize. + * NewSize = 20971520 = (512*4K) * 10 for 4k pages + * Then it tries to execute arraycopy() with elements type check + * to the array at the end of survive space near unused space. + */ + +public class Test8010927 { + + private static final Unsafe U; + + static { + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (Exception e) { + throw new Error(e); + } + } + + public static Object[] o; + + public static final boolean debug = Boolean.getBoolean("debug"); + + // 2 different obect arrays but same element types + static Test8010927[] masterA; + static Object[] masterB; + static final Test8010927 elem = new Test8010927(); + static final WhiteBox wb = WhiteBox.getWhiteBox(); + + static final int obj_header_size = U.ARRAY_OBJECT_BASE_OFFSET; + static final int heap_oop_size = wb.getHeapOopSize(); + static final int card_size = 512; + static final int one_card = (card_size - obj_header_size)/heap_oop_size; + + static final int surv_size = 2112 * 1024; + + // The size is big to not fit into survive space. + static final Object[] cache = new Object[(surv_size / card_size)]; + + public static void main(String[] args) { + masterA = new Test8010927[one_card]; + masterB = new Object[one_card]; + for (int i = 0; i < one_card; ++i) { + masterA[i] = elem; + masterB[i] = elem; + } + + // Move cache[] to the old gen. + long low_limit = wb.getObjectAddress(cache); + System.gc(); + // Move 'cache' to oldgen. + long upper_limit = wb.getObjectAddress(cache); + if ((low_limit - upper_limit) > 0) { // substaction works with unsigned values + // OldGen is placed before youngger for ParallelOldGC. + upper_limit = low_limit + 21000000l; // +20971520 + } + // Each A[one_card] size is 512 bytes, + // it will take about 40000 allocations to trigger GC. + // cache[] has 8192 elements so GC should happen + // each 5th iteration. + for(long l = 0; l < 20; l++) { + fill_heap(); + if (debug) { + System.out.println("test oop_disjoint_arraycopy"); + } + testA_arraycopy(); + if (debug) { + System.out.println("test checkcast_arraycopy"); + } + testB_arraycopy(); + // Execute arraycopy to the topmost array in young gen + if (debug) { + int top_index = get_top_address(low_limit, upper_limit); + if (top_index >= 0) { + long addr = wb.getObjectAddress(cache[top_index]); + System.out.println("top_addr: 0x" + Long.toHexString(addr) + ", 0x" + Long.toHexString(addr + 512)); + } + } + } + } + static void fill_heap() { + for (int i = 0; i < cache.length; ++i) { + o = new Test8010927[one_card]; + System.arraycopy(masterA, 0, o, 0, masterA.length); + cache[i] = o; + } + for (long j = 0; j < 256; ++j) { + o = new Long[10000]; // to trigger GC + } + } + static void testA_arraycopy() { + for (int i = 0; i < cache.length; ++i) { + System.arraycopy(masterA, 0, cache[i], 0, masterA.length); + } + } + static void testB_arraycopy() { + for (int i = 0; i < cache.length; ++i) { + System.arraycopy(masterB, 0, cache[i], 0, masterB.length); + } + } + static int get_top_address(long min, long max) { + int index = -1; + long addr = min; + for (int i = 0; i < cache.length; ++i) { + long test = wb.getObjectAddress(cache[i]); + if (((test - addr) > 0) && ((max - test) > 0)) { // substaction works with unsigned values + addr = test; + index = i; + } + } + return index; + } +} diff --git a/test/runtime/7158804/Test7158804.sh b/test/runtime/7158804/Test7158804.sh deleted file mode 100644 index b5380ec8eb4ad4a08a651e016fe53ba10ccb141b..0000000000000000000000000000000000000000 --- a/test/runtime/7158804/Test7158804.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# - -## -## @test Test7158804.sh -## @bug 7158804 -## @summary Improve config file parsing -## @run shell Test7158804.sh -## -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -rm -f .hotspotrc -echo -XX:+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >.hotspotrc -${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:+IgnoreUnrecognizedVMOptions -XX:Flags=.hotspotrc -version -if [ $? -ne 0 ] -then - echo "Test Failed" - exit 1 -fi -rm -f .hotspotrc -exit 0 diff --git a/test/runtime/CommandLine/ConfigFileParsing.java b/test/runtime/CommandLine/ConfigFileParsing.java new file mode 100644 index 0000000000000000000000000000000000000000..10a8c0b46d7d0b55ef1484ed18b1d881df7e8409 --- /dev/null +++ b/test/runtime/CommandLine/ConfigFileParsing.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ConfigFileParsing + * @bug 7158804 + * @summary Improve config file parsing + * @library /testlibrary + */ + +import java.io.PrintWriter; +import com.oracle.java.testlibrary.*; + +public class ConfigFileParsing { + public static void main(String[] args) throws Exception { + String testFileName = ".hotspotrc"; + + // Create really long invalid option + String reallyLongInvalidOption = ""; + for (int i=0; i<5000; i++) + reallyLongInvalidOption+='a'; + + // Populate the options file with really long string + PrintWriter pw = new PrintWriter(testFileName); + pw.println("-XX:+" + reallyLongInvalidOption); + pw.close(); + + // start VM + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-XX:Flags=.hotspotrc", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} diff --git a/test/runtime/RedefineObject/TestRedefineObject.java b/test/runtime/RedefineObject/TestRedefineObject.java index 37ba6a32f7913ac78b0eaa916a08281782852b80..bd5003a588a8a2dc13cf42d45ac7040c91309e73 100644 --- a/test/runtime/RedefineObject/TestRedefineObject.java +++ b/test/runtime/RedefineObject/TestRedefineObject.java @@ -32,10 +32,10 @@ import com.oracle.java.testlibrary.*; * @library /testlibrary * @build Agent * @run main ClassFileInstaller Agent - * @run main Test + * @run main TestRedefineObject * @run main/othervm -javaagent:agent.jar Agent */ -public class Test { +public class TestRedefineObject { public static void main(String[] args) throws Exception { PrintWriter pw = new PrintWriter("MANIFEST.MF"); diff --git a/test/runtime/8003985/Test8003985.java b/test/runtime/contended/Basic.java similarity index 99% rename from test/runtime/8003985/Test8003985.java rename to test/runtime/contended/Basic.java index 5e30f670257b21d59fabc39067fd63386342e392..e15461451a7b066926b7e63def22151bc98f9083 100644 --- a/test/runtime/8003985/Test8003985.java +++ b/test/runtime/contended/Basic.java @@ -43,9 +43,9 @@ import sun.misc.Contended; * @bug 8003985 * @summary Support Contended Annotation - JEP 142 * - * @run main/othervm -XX:-RestrictContended Test8003985 + * @run main/othervm -XX:-RestrictContended Basic */ -public class Test8003985 { +public class Basic { private static final Unsafe U; private static int ADDRESS_SIZE; diff --git a/test/runtime/contended/DefaultValue.java b/test/runtime/contended/DefaultValue.java new file mode 100644 index 0000000000000000000000000000000000000000..6f60672428b4b3da59669e82d29eed7b988e754b --- /dev/null +++ b/test/runtime/contended/DefaultValue.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8014509 + * @summary \@Contended: explicit default value behaves differently from the implicit value + * + * @run main/othervm -XX:-RestrictContended DefaultValue + */ +public class DefaultValue { + + private static final Unsafe U; + private static int ADDRESS_SIZE; + private static int HEADER_SIZE; + + static { + // steal Unsafe + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + ADDRESS_SIZE = -1; + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getField(field1); + Field f2 = klass.getField(field2); + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + boolean endResult = true; + + if (!arePaddedPairwise(R1.class, "int1", "int2")) { + System.err.println("R1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(R2.class, "int1", "int2")) { + System.err.println("R2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(R3.class, "int1", "int2")) { + System.err.println("R3 failed"); + endResult &= false; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + public static class R1 { + @Contended + public int int1; + @Contended + public int int2; + } + + public static class R2 { + @Contended("") + public int int1; + @Contended("") + public int int2; + } + + public static class R3 { + @Contended() + public int int1; + @Contended() + public int int2; + } + +} + diff --git a/test/runtime/contended/Inheritance1.java b/test/runtime/contended/Inheritance1.java new file mode 100644 index 0000000000000000000000000000000000000000..70b8e4c71bc0a8645606d496f93e99a73222254d --- /dev/null +++ b/test/runtime/contended/Inheritance1.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8012939 + * @summary \@Contended doesn't work correctly with inheritance + * + * @run main/othervm -XX:-RestrictContended Inheritance1 + */ +public class Inheritance1 { + + private static final Unsafe U; + private static int ADDRESS_SIZE; + private static int HEADER_SIZE; + + static { + // steal Unsafe + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + ADDRESS_SIZE = -1; + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getField(field1); + Field f2 = klass.getField(field2); + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + boolean endResult = true; + + // --------------- INSTANCE FIELDS --------------------- + + if (!arePaddedPairwise(A2_R1.class, "int1", "int2")) { + System.err.println("A2_R1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A3_R1.class, "int1", "int2")) { + System.err.println("A3_R1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A1_R2.class, "int1", "int2")) { + System.err.println("A1_R2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A2_R2.class, "int1", "int2")) { + System.err.println("A2_R2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A3_R2.class, "int1", "int2")) { + System.err.println("A3_R2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A1_R3.class, "int1", "int2")) { + System.err.println("A1_R3 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A2_R3.class, "int1", "int2")) { + System.err.println("A2_R3 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(A3_R3.class, "int1", "int2")) { + System.err.println("A3_R3 failed"); + endResult &= false; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + public static class R1 { + public int int1; + } + + public static class R2 { + @Contended + public int int1; + } + + @Contended + public static class R3 { + public int int1; + } + + public static class A1_R1 extends R1 { + public int int2; + } + + public static class A2_R1 extends R1 { + @Contended + public int int2; + } + + @Contended + public static class A3_R1 extends R1 { + public int int2; + } + + public static class A1_R2 extends R2 { + public int int2; + } + + public static class A2_R2 extends R2 { + @Contended + public int int2; + } + + @Contended + public static class A3_R2 extends R2 { + public int int2; + } + + public static class A1_R3 extends R3 { + public int int2; + } + + public static class A2_R3 extends R3 { + @Contended + public int int2; + } + + @Contended + public static class A3_R3 extends R3 { + public int int2; + } + + +} +