This commit is contained in:
Alejandro Murillo 2016-09-10 12:18:34 -07:00
commit 8957d8798f
22 changed files with 898 additions and 395 deletions

View File

@ -176,6 +176,9 @@ SUNWprivate_1.1 {
Java_java_lang_ProcessHandleImpl_00024Info_info0;
Java_java_lang_ProcessImpl_init;
Java_java_lang_ProcessImpl_forkAndExec;
Java_java_lang_ref_Reference_getAndClearReferencePendingList;
Java_java_lang_ref_Reference_hasReferencePendingList;
Java_java_lang_ref_Reference_waitForReferencePendingList;
Java_java_lang_reflect_Array_get;
Java_java_lang_reflect_Array_getBoolean;
Java_java_lang_reflect_Array_getByte;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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
@ -110,22 +110,6 @@ public abstract class Reference<T> {
private transient Reference<T> discovered; /* used by VM */
/* Object used to synchronize with the garbage collector. The collector
* must acquire this lock at the beginning of each collection cycle. It is
* therefore critical that any code holding this lock complete as quickly
* as possible, allocate no new objects, and avoid calling user code.
*/
private static class Lock { }
private static Lock lock = new Lock();
/* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
*/
private static Reference<Object> pending = null;
/* High-priority thread to enqueue pending References
*/
private static class ReferenceHandler extends Thread {
@ -139,10 +123,9 @@ public abstract class Reference<T> {
}
static {
// pre-load and initialize InterruptedException and Cleaner classes
// so that we don't get into trouble later in the run loop if there's
// memory shortage while loading/initializing them lazily.
ensureClassInitialized(InterruptedException.class);
// pre-load and initialize Cleaner class so that we don't
// get into trouble later in the run loop if there's
// memory shortage while loading/initializing it lazily.
ensureClassInitialized(Cleaner.class);
}
@ -152,72 +135,80 @@ public abstract class Reference<T> {
public void run() {
while (true) {
tryHandlePending(true);
processPendingReferences();
}
}
}
/**
* Try handle pending {@link Reference} if there is one.<p>
* Return {@code true} as a hint that there might be another
* {@link Reference} pending or {@code false} when there are no more pending
* {@link Reference}s at the moment and the program can do some other
* useful work instead of looping.
*
* @param waitForNotify if {@code true} and there was no pending
* {@link Reference}, wait until notified from VM
* or interrupted; if {@code false}, return immediately
* when there is no pending {@link Reference}.
* @return {@code true} if there was a {@link Reference} pending and it
* was processed, or we waited for notification and either got it
* or thread was interrupted before being notified;
* {@code false} otherwise.
/* Atomically get and clear (set to null) the VM's pending list.
*/
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
synchronized (lock) {
if (pending != null) {
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
pending = r.discovered;
r.discovered = null;
} else {
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
private static native Reference<Object> getAndClearReferencePendingList();
/* Test whether the VM's pending list contains any entries.
*/
private static native boolean hasReferencePendingList();
/* Wait until the VM's pending list may be non-null.
*/
private static native void waitForReferencePendingList();
private static final Object processPendingLock = new Object();
private static boolean processPendingActive = false;
private static void processPendingReferences() {
// Only the singleton reference processing thread calls
// waitForReferencePendingList() and getAndClearReferencePendingList().
// These are separate operations to avoid a race with other threads
// that are calling waitForReferenceProcessing().
waitForReferencePendingList();
Reference<Object> pendingList;
synchronized (processPendingLock) {
pendingList = getAndClearReferencePendingList();
processPendingActive = true;
}
while (pendingList != null) {
Reference<Object> ref = pendingList;
pendingList = ref.discovered;
ref.discovered = null;
if (ref instanceof Cleaner) {
((Cleaner)ref).clean();
// Notify any waiters that progress has been made.
// This improves latency for nio.Bits waiters, which
// are the only important ones.
synchronized (processPendingLock) {
processPendingLock.notifyAll();
}
} else {
ReferenceQueue<? super Object> q = ref.queue;
if (q != ReferenceQueue.NULL) q.enqueue(ref);
}
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
// Fast path for cleaners
if (c != null) {
c.clean();
return true;
// Notify any waiters of completion of current round.
synchronized (processPendingLock) {
processPendingActive = false;
processPendingLock.notifyAll();
}
}
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
// Wait for progress in reference processing.
//
// Returns true after waiting (for notification from the reference
// processing thread) if either (1) the VM has any pending
// references, or (2) the reference processing thread is
// processing references. Otherwise, returns false immediately.
private static boolean waitForReferenceProcessing()
throws InterruptedException
{
synchronized (processPendingLock) {
if (processPendingActive || hasReferencePendingList()) {
// Wait for progress, not necessarily completion.
processPendingLock.wait();
return true;
} else {
return false;
}
}
}
static {
@ -236,8 +227,10 @@ public abstract class Reference<T> {
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
public boolean waitForReferenceProcessing()
throws InterruptedException
{
return Reference.waitForReferenceProcessing();
}
});
}

View File

@ -131,23 +131,38 @@ class Bits { // package-private
}
final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
// retry while helping enqueue pending Reference objects
// which includes executing pending Cleaner(s) which includes
// Cleaner(s) that free direct buffer memory
while (jlra.tryHandlePendingReference()) {
if (tryReserveMemory(size, cap)) {
return;
}
}
// trigger VM's Reference processing
System.gc();
// a retry loop with exponential back-off delays
// (this gives VM some time to do it's job)
boolean interrupted = false;
try {
// Retry allocation until success or there are no more
// references (including Cleaners that might free direct
// buffer memory) to process and allocation still fails.
boolean refprocActive;
do {
try {
refprocActive = jlra.waitForReferenceProcessing();
} catch (InterruptedException e) {
// Defer interrupts and keep trying.
interrupted = true;
refprocActive = true;
}
if (tryReserveMemory(size, cap)) {
return;
}
} while (refprocActive);
// trigger VM's Reference processing
System.gc();
// A retry loop with exponential back-off delays.
// Sometimes it would suffice to give up once reference
// processing is complete. But if there are many threads
// competing for memory, this gives more opportunities for
// any given thread to make progress. In particular, this
// seems to be enough for a stress test like
// DirectBufferAllocTest to (usually) succeed, while
// without it that test likely fails. Since failure here
// ends in OOME, there's no need to hurry.
long sleepTime = 1;
int sleeps = 0;
while (true) {
@ -157,14 +172,14 @@ class Bits { // package-private
if (sleeps >= MAX_SLEEPS) {
break;
}
if (!jlra.tryHandlePendingReference()) {
try {
try {
if (!jlra.waitForReferenceProcessing()) {
Thread.sleep(sleepTime);
sleepTime <<= 1;
sleeps++;
} catch (InterruptedException e) {
interrupted = true;
}
} catch (InterruptedException e) {
interrupted = true;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016, 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
@ -28,12 +28,12 @@ package jdk.internal.misc;
public interface JavaLangRefAccess {
/**
* Help ReferenceHandler thread process next pending
* {@link java.lang.ref.Reference}
* Wait for progress in {@link java.lang.ref.Reference}
* processing. If there aren't any pending {@link
* java.lang.ref.Reference}s, return immediately.
*
* @return {@code true} if there was a pending reference and it
* was enqueue-ed or {@code false} if there was no
* pending reference
* @return {@code true} if there were any pending
* {@link java.lang.ref.Reference}s, {@code false} otherwise.
*/
boolean tryHandlePendingReference();
boolean waitForReferenceProcessing() throws InterruptedException;
}

View File

@ -1197,6 +1197,9 @@ public final class Unsafe {
if (hostClass == null || data == null) {
throw new NullPointerException();
}
if (hostClass.isArray() || hostClass.isPrimitive()) {
throw new IllegalArgumentException();
}
return defineAnonymousClass0(hostClass, data, cpPatches);
}

View File

@ -281,6 +281,18 @@ JVM_GetSystemPackage(JNIEnv *env, jstring name);
JNIEXPORT jobjectArray JNICALL
JVM_GetSystemPackages(JNIEnv *env);
/*
* java.lang.ref.Reference
*/
JNIEXPORT jobject JNICALL
JVM_GetAndClearReferencePendingList(JNIEnv *env);
JNIEXPORT jboolean JNICALL
JVM_HasReferencePendingList(JNIEnv *env);
JNIEXPORT void JNICALL
JVM_WaitForReferencePendingList(JNIEnv *env);
/*
* java.io.ObjectInputStream
*/

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jvm.h"
#include "java_lang_ref_Reference.h"
JNIEXPORT jobject JNICALL
Java_java_lang_ref_Reference_getAndClearReferencePendingList(JNIEnv *env, jclass ignore)
{
return JVM_GetAndClearReferencePendingList(env);
}
JNIEXPORT jboolean JNICALL
Java_java_lang_ref_Reference_hasReferencePendingList(JNIEnv *env, jclass ignore)
{
return JVM_HasReferencePendingList(env);
}
JNIEXPORT void JNICALL
Java_java_lang_ref_Reference_waitForReferencePendingList(JNIEnv *env, jclass ignore)
{
JVM_WaitForReferencePendingList(env);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -1707,25 +1707,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
throw new UnsupportedOperationException("Not supported yet.");
}
@SuppressWarnings("deprecation")
public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
OperationsException {
throw new UnsupportedOperationException("Not supported yet.");
}
@SuppressWarnings("deprecation")
public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException,
ReflectionException {
throw new UnsupportedOperationException("Not supported yet.");
}
@SuppressWarnings("deprecation")
public ObjectInputStream deserialize(String className, ObjectName loaderName,
byte[] data) throws InstanceNotFoundException, OperationsException,
ReflectionException {
throw new UnsupportedOperationException("Not supported yet.");
}
public ClassLoaderRepository getClassLoaderRepository() {
throw new UnsupportedOperationException("Not supported yet.");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2016, 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
@ -94,32 +94,6 @@ public interface MBeanServerInterceptor extends MBeanServer {
throws ReflectionException, MBeanException,
InstanceNotFoundException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException;
/**
* This method should never be called.
* Usually hrows UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(String className,
ObjectName loaderName, byte[] data)
throws InstanceNotFoundException, OperationsException,
ReflectionException;
/**
* This method should never be called.
* Usually throws UnsupportedOperationException.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, 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
@ -655,6 +655,8 @@ public interface MBeanServer extends MBeanServerConnection {
* used for the de-serialization.
* @param data The byte array to be de-sererialized.
*
* @implSpec This method throws {@link UnsupportedOperationException} by default.
*
* @return The de-serialized object stream.
*
* @exception InstanceNotFoundException The MBean specified is not
@ -665,10 +667,11 @@ public interface MBeanServer extends MBeanServerConnection {
* @deprecated Use {@link #getClassLoaderFor getClassLoaderFor} to
* obtain the appropriate class loader for deserialization.
*/
@Deprecated
public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException;
@Deprecated(since="1.5")
default public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException {
throw new UnsupportedOperationException("Not supported.");
}
/**
* <p>De-serializes a byte array in the context of a given MBean
@ -682,6 +685,8 @@ public interface MBeanServer extends MBeanServerConnection {
* used for the de-serialization.
* @param data The byte array to be de-sererialized.
*
* @implSpec This method throws {@link UnsupportedOperationException} by default.
*
* @return The de-serialized object stream.
*
* @exception OperationsException Any of the usual Input/Output
@ -692,9 +697,11 @@ public interface MBeanServer extends MBeanServerConnection {
* @deprecated Use {@link #getClassLoaderRepository} to obtain the
* class loader repository and use it to deserialize.
*/
@Deprecated
public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException;
@Deprecated(since="1.5")
default public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException {
throw new UnsupportedOperationException("Not supported.");
}
/**
@ -711,6 +718,8 @@ public interface MBeanServer extends MBeanServerConnection {
* loading the specified class. If null, the MBean Server's class
* loader will be used.
*
* @implSpec This method throws {@link UnsupportedOperationException} by default.
*
* @return The de-serialized object stream.
*
* @exception InstanceNotFoundException The specified class loader
@ -723,12 +732,14 @@ public interface MBeanServer extends MBeanServerConnection {
* @deprecated Use {@link #getClassLoader getClassLoader} to obtain
* the class loader for deserialization.
*/
@Deprecated
public ObjectInputStream deserialize(String className,
@Deprecated(since="1.5")
default public ObjectInputStream deserialize(String className,
ObjectName loaderName,
byte[] data)
throws InstanceNotFoundException, OperationsException,
ReflectionException;
ReflectionException {
throw new UnsupportedOperationException("Not supported.");
}
/**
* <p>Return the {@link java.lang.ClassLoader} that was used for

View File

@ -993,32 +993,39 @@ implements ReferenceType {
return minorVersion;
}
private void getConstantPoolInfo() {
private byte[] getConstantPoolInfo() {
JDWP.ReferenceType.ConstantPool jdwpCPool;
if (!vm.canGetConstantPool()) {
throw new UnsupportedOperationException();
}
if (constantPoolInfoGotten) {
return;
} else {
try {
jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
} catch (JDWPException exc) {
if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
constanPoolCount = 0;
constantPoolBytesRef = null;
constantPoolInfoGotten = true;
return;
} else {
throw exc.toJDIException();
}
if (constantPoolBytesRef == null) {
return null;
}
byte[] cpbytes = constantPoolBytesRef.get();
if (cpbytes != null) {
return cpbytes;
}
byte[] cpbytes;
constanPoolCount = jdwpCPool.count;
cpbytes = jdwpCPool.bytes;
constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
constantPoolInfoGotten = true;
}
try {
jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
} catch (JDWPException exc) {
if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
constanPoolCount = 0;
constantPoolBytesRef = null;
constantPoolInfoGotten = true;
return null;
} else {
throw exc.toJDIException();
}
}
byte[] cpbytes;
constanPoolCount = jdwpCPool.count;
cpbytes = jdwpCPool.bytes;
constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
constantPoolInfoGotten = true;
return cpbytes;
}
public int constantPoolCount() {
@ -1031,13 +1038,13 @@ implements ReferenceType {
}
public byte[] constantPool() {
byte[] cpbytes;
try {
getConstantPoolInfo();
cpbytes = getConstantPoolInfo();
} catch (RuntimeException exc) {
throw exc;
}
if (constantPoolBytesRef != null) {
byte[] cpbytes = constantPoolBytesRef.get();
if (cpbytes != null) {
/*
* Arrays are always modifiable, so it is a little unsafe
* to return the cached bytecodes directly; instead, we

View File

@ -328,9 +328,6 @@ com/sun/jdi/GetLocalVariables4Test.sh 8067354 windows-
com/sun/jdi/sde/SourceDebugExtensionTest.java 8158066 windows-all
com/sun/jdi/ClassesByName2Test.java 8160833 generic-all
com/sun/jdi/RedefineCrossEvent.java 8160833 generic-all
############################################################################
# jdk_time
@ -357,9 +354,11 @@ sun/tools/jcmd/TestJcmdSanity.java 8031482 windows-
sun/tools/jhsdb/BasicLauncherTest.java 8160376 macosx-all
sun/tools/jhsdb/HeapDumpTest.java 8160376 macosx-all
sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8160376 macosx-all
sun/tools/jps/TestJpsJar.java 8160923 generic-all
sun/tools/jps/TestJpsJar.java 8165500 generic-all
sun/tools/jps/TestJpsJarRelative.java 6456333 generic-all

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2016, 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 6822627
* @summary Test that ReferenceType.constantPool does not produce an NPE
*
* @author Egor Ushakov
*
* @modules jdk.jdi/com.sun.tools.jdi
* @run build TestScaffold VMConnection
* @run compile -g ConstantPoolInfoGC.java
* @run main/othervm ConstantPoolInfoGC
*/
import com.sun.jdi.ReferenceType;
import com.sun.tools.jdi.ReferenceTypeImpl;
import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.util.Arrays;
/********** target program **********/
class ConstantPoolGCTarg {
public static void main(String[] args){
System.out.println("Anything");
}
}
/********** test program **********/
public class ConstantPoolInfoGC extends TestScaffold {
ReferenceType targetClass;
ConstantPoolInfoGC(String args[]) {
super(args);
}
public static void main(String[] args) throws Exception {
new ConstantPoolInfoGC(args).startTests();
}
/********** test core **********/
protected void runTests() throws Exception {
targetClass = startToMain("ConstantPoolGCTarg").location().declaringType();
if (vm().canGetConstantPool()) {
byte[] cpbytes = targetClass.constantPool();
// imitate SoftReference cleared
Field constantPoolBytesRef = ReferenceTypeImpl.class.getDeclaredField("constantPoolBytesRef");
constantPoolBytesRef.setAccessible(true);
Reference softRef = (Reference) constantPoolBytesRef.get(targetClass);
softRef.clear();
byte[] cpbytes2 = targetClass.constantPool();
if (!Arrays.equals(cpbytes, cpbytes2)) {
failure("Consequent constantPool results vary, first was : " + cpbytes + ", now: " + cpbytes2);
};
} else {
System.out.println("can get constant pool version not supported");
}
/*
* resume until end
*/
listenUntilVMDisconnect();
/*
* deal with results of test
* if anything has called failure("foo") testFailed will be true
*/
if (!testFailed) {
println("ConstantPoolInfoGC: passed");
} else {
throw new Exception("ConstantPoolInfoGC: failed");
}
}
}

View File

@ -101,11 +101,8 @@ public class GetModuleTest {
return new Object[][] {
{ GetModuleTest.class, null },
{ GetModuleTest[].class, null },
{ Object.class, null },
{ Object[].class, null },
{ Component.class, null },
{ Component[].class, null },
};
}
@ -117,7 +114,7 @@ public class GetModuleTest {
public void testGetModuleOnVMAnonymousClass(Class<?> hostClass, String ignore) {
// choose a class name in the same package as the host class
String prefix = packageName(hostClass);
String prefix = hostClass.getPackageName();
if (prefix.length() > 0)
prefix = prefix.replace('.', '/') + "/";
String className = prefix + "Anon";
@ -136,17 +133,6 @@ public class GetModuleTest {
assertTrue(anonClass.getModule() == hostClass.getModule());
}
private static String packageName(Class<?> c) {
if (c.isArray()) {
return packageName(c.getComponentType());
} else {
String name = c.getName();
int dot = name.lastIndexOf('.');
if (dot == -1) return "";
return name.substring(0, dot);
}
}
private static int constantPoolSize(byte[] classFile) {
return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
}

View File

@ -57,9 +57,9 @@ public class VMAnonymousClass {
@Test public void testJavaLangInvoke() throws Throwable { test("java/lang/invoke"); }
@Test public void testProhibitedJavaPkg() throws Throwable {
try {
test("java/prohibited");
} catch (SecurityException e) {
return;
test("java/prohibited");
} catch (IllegalArgumentException e) {
return;
}
throw new RuntimeException("Expected SecurityException");
}
@ -72,10 +72,17 @@ public class VMAnonymousClass {
if (pkg.equals("java/prohibited")) {
VMAnonymousClass sampleclass = new VMAnonymousClass();
host_class = (Class)sampleclass.getClass();
} else if (pkg.equals("java/lang")) {
host_class = Object.class;
} else if (pkg.equals("java/util")) {
host_class = java.util.ArrayList.class;
} else if (pkg.equals("jdk/internal/misc")) {
host_class = jdk.internal.misc.Signal.class;
} else if (pkg.equals("java/lang/invoke")) {
host_class = java.lang.invoke.CallSite.class;
} else {
host_class = Object.class;
throw new RuntimeException("Unexpected pkg: " + pkg);
}
// Define VM anonymous class
Class anonClass = unsafe.defineAnonymousClass(host_class, bytes, null);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, 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
@ -26,27 +26,28 @@
* @bug 4530538
* @summary Basic unit test of ThreadInfo.getLockName()
* and ThreadInfo.getLockOwnerName()
* @library /lib/testlibrary
* @author Mandy Chung
* @author Jaroslav Bachorik
*
* @library /lib/testlibrary
* @modules java.management
* @build jdk.testlibrary.*
* @run main/othervm Locks
*/
import java.lang.management.*;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.Phaser;
import java.util.function.Predicate;
import jdk.testlibrary.LockFreeLogManager;
public class Locks {
private static final Object objA = new Object();
private static final Object objB = new Object();
private static final Object objC = new Object();
private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean();
private static final LockFreeLogManager logger = new LockFreeLogManager();
private static boolean testFailed = false;
private static final Object OBJA = new Object();
private static final Object OBJB = new Object();
private static final EnhancedWaiter OBJC = new EnhancedWaiter();
private static final ThreadMXBean TM = ManagementFactory.getThreadMXBean();
private static final LockFreeLogManager LOGGER = new LockFreeLogManager();
private static String getLockName(Object lock) {
if (lock == null) return null;
@ -56,67 +57,103 @@ public class Locks {
}
private static void assertNoLock(Thread t) {
long tid = t.getId();
ThreadInfo info = tm.getThreadInfo(tid);
String result = info.getLockName();
if (result != null) {
throw new RuntimeException("Thread " + t.getName() + " is not supposed to hold any lock. " +
"Currently owning lock: " + result);
if (t == null) {
return;
}
Optional<ThreadInfo> result = Arrays.asList(
TM.getThreadInfo(TM.getAllThreadIds(), true, true)).
stream().
filter(tInfo -> (tInfo != null && tInfo.getLockOwnerName() != null)
? tInfo.getLockOwnerName().equals(t.getName()) : false).
findAny();
if (result.isPresent()) {
throw new RuntimeException("Thread " + t.getName() + " is not "
+ "supposed to be hold any lock. Currently owning lock : "
+ result.get().getLockName());
}
}
private static void checkBlockedObject(Thread t, Object lock, Thread owner,
Thread.State expectedState) {
long tid = t.getId();
ThreadInfo info = tm.getThreadInfo(tid);
String result = info.getLockName();
String expectedLock = (lock != null ? getLockName(lock) : null);
String expectedOwner = (owner != null ? owner.getName() : null);
/*
* Handy debug function to check if error condition is because of test code or not.
*/
private static void printStackTrace(Thread thread) {
if (thread == null) {
return;
}
StackTraceElement[] stackTrace = thread.getStackTrace();
log("Stack dump : Thread -> " + thread.getName());
for (StackTraceElement stackTraceEl : stackTrace) {
log("\t" + stackTraceEl.toString());
}
}
if (lock != null) {
if (expectedState == Thread.State.BLOCKED) {
int retryCount=0;
while(info.getThreadState() != Thread.State.BLOCKED) {
if (retryCount++ > 500) {
throw new RuntimeException("Thread " + t.getName() +
" is expected to block on " + expectedLock +
" but got " + result +
" Thread.State = " + info.getThreadState());
}
goSleep(100);
info = tm.getThreadInfo(tid);
result = info.getLockName();
private static void assertThreadState(Thread t, Thread.State expectedState) {
long tid = t.getId();
if (expectedState == Thread.State.BLOCKED
&& TM.getThreadInfo(tid).getThreadState() != Thread.State.BLOCKED) {
int retryCount = 0;
printStackTrace(t);
while (TM.getThreadInfo(tid).getThreadState() != Thread.State.BLOCKED) {
if (retryCount++ > 500) {
printStackTrace(t);
throw new RuntimeException("Thread " + t.getName() + " is at "
+ TM.getThreadInfo(tid).getThreadState() + " state but is expected to "
+ "be in Thread.State = " + expectedState);
}
}
if (expectedState == Thread.State.WAITING &&
info.getThreadState() != Thread.State.WAITING) {
throw new RuntimeException("Thread " + t.getName() +
" is expected to wait on " + expectedLock +
" but got " + result +
" Thread.State = " + info.getThreadState());
goSleep(100);
}
}
if ((result != null && !result.equals(expectedLock)) ||
(result == null && expectedLock != null)) {
throw new RuntimeException("Thread " + t.getName() + " is blocked on " +
expectedLock + " but got " + result);
}
result = info.getLockOwnerName();
if ((result != null && !result.equals(expectedOwner)) ||
(result == null && expectedOwner != null)) {
throw new RuntimeException("Owner of " + lock + " should be " +
expectedOwner + " but got " + result);
if (!TM.getThreadInfo(tid).getThreadState().equals(expectedState)) {
printStackTrace(t);
throw new RuntimeException("Thread " + t.getName() + " is at "
+ TM.getThreadInfo(tid).getThreadState() + " state but is expected to "
+ "be in Thread.State = " + expectedState);
}
}
private static void goSleep(long ms) {
/*
* Do slow check if thread is blocked on a lock. It is possible that last thread
* to come out of Phaser might still be in Phaser call stack (Unsafe.park) and
* hence might eventually acquire expected lock.
*/
private static void checkBlockedObject(Thread t, Object lock, Thread owner) {
long tid = t.getId();
String result = TM.getThreadInfo(tid).getLockName();
final String expectedLock = (lock != null ? getLockName(lock) : null);
Predicate<String> p = (res) -> ((res != null && !res.equals(expectedLock))
|| (res == null && expectedLock != null));
if (p.test(result)) {
printStackTrace(t);
int retryCount = 0;
while (p.test(result)) {
if (retryCount++ > 500) {
printStackTrace(t);
throw new RuntimeException("Thread " + t.getName() + " is blocked on "
+ expectedLock + " but got " + result);
}
goSleep(100);
result = TM.getThreadInfo(tid).getLockName();
}
}
result = TM.getThreadInfo(tid).getLockOwnerName();
final String expectedOwner = (owner != null ? owner.getName() : null);
p = (res) -> ((res != null && !res.equals(expectedOwner))
|| (res == null && expectedOwner != null));
if (p.test(result)) {
printStackTrace(t);
throw new RuntimeException("Owner of " + lock + " should be "
+ expectedOwner + " but got " + result);
}
}
private static void goSleep(long ms){
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
testFailed = true;
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
@ -128,14 +165,15 @@ public class Locks {
super("LockAThread");
this.p = p;
}
@Override
public void run() {
synchronized(objA) {
// stop here for LockBThread to hold objB
log("LockAThread about to block on objB");
synchronized(OBJA) {
// block here while LockBThread holds OBJB
log("LockAThread about to block on OBJB");
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
synchronized(objB) {
synchronized(OBJB) {
dummyCounter++;
};
}
}
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
log("LockAThread about to exit");
@ -150,14 +188,15 @@ public class Locks {
super("LockBThread");
this.p = p;
}
@Override
public void run() {
synchronized(objB) {
log("LockBThread about to block on objC");
synchronized(OBJB) {
log("LockBThread about to block on OBJC");
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
// Signal main thread about to block on objC
synchronized(objC) {
// Signal main thread about to block on OBJC
synchronized(OBJC) {
dummyCounter++;
};
}
}
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
log("LockBThread about to exit");
@ -166,9 +205,30 @@ public class Locks {
}
}
/*
* Must be invoked from within a synchronized context
*/
private static class EnhancedWaiter {
boolean isNotified = false;
public void doWait() throws InterruptedException {
while (!isNotified) {
wait();
}
isNotified = false;
}
public void doNotify() {
isNotified = true;
notify();
}
}
private static WaitingThread waiter;
private static final Object ready = new Object();
private static CheckerThread checker;
static class WaitingThread extends Thread {
private final Phaser p;
@ -180,17 +240,16 @@ public class Locks {
}
@Override
public void run() {
synchronized(objC) {
log("WaitingThread about to wait on objC");
synchronized(OBJC) {
log("WaitingThread about to wait on OBJC");
try {
// Signal checker thread, about to wait on objC.
// Signal checker thread, about to wait on OBJC.
waiting = false;
p.arriveAndAwaitAdvance(); // Phase 1 (waiting)
waiting = true;
objC.wait();
OBJC.doWait();
} catch (InterruptedException e) {
e.printStackTrace();
testFailed = true;
throw new RuntimeException(e); // Do not continue test
}
// block until CheckerThread finishes checking
@ -202,19 +261,18 @@ public class Locks {
dummyCounter++;
}
}
synchronized(objC) {
synchronized(OBJC) {
try {
// signal checker thread, about to wait on objC
// signal checker thread, about to wait on OBJC
waiting = false;
p.arriveAndAwaitAdvance(); // Phase 3 (waiting)
waiting = true;
objC.wait();
OBJC.doWait();
} catch (InterruptedException e) {
e.printStackTrace();
testFailed = true;
throw new RuntimeException(e);
}
}
log("WaitingThread about to exit waiting on objC 2");
log("WaitingThread about to exit waiting on OBJC 2");
}
public void waitForWaiting() {
@ -241,85 +299,87 @@ public class Locks {
super("CheckerThread");
}
@Override
public void run() {
synchronized (ready) {
// wait until WaitingThread about to wait for objC
synchronized(ready) {
// wait until WaitingThread about to wait for OBJC
waiter.waitForWaiting(); // Phase 1 (waiting)
checkBlockedObject(waiter, objC, null, Thread.State.WAITING);
assertThreadState(waiter, Thread.State.WAITING);
checkBlockedObject(waiter, OBJC, null);
synchronized (objC) {
objC.notify();
synchronized(OBJC) {
OBJC.doNotify();
}
// wait for waiter thread to about to enter
// synchronized object ready.
waiter.waitForBlocked(); // Phase 2 (waiting)
checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);
assertThreadState(waiter, Thread.State.BLOCKED);
checkBlockedObject(waiter, ready, this);
}
// wait for signal from waiting thread that it is about
// wait for objC.
// wait for OBJC.
waiter.waitForWaiting(); // Phase 3 (waiting)
synchronized(objC) {
checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);
objC.notify();
synchronized(OBJC) {
assertThreadState(waiter, Thread.State.WAITING);
checkBlockedObject(waiter, OBJC, Thread.currentThread());
OBJC.doNotify();
}
}
}
public static void main(String args[]) throws Exception {
Thread mainThread = Thread.currentThread();
// Test uncontested case
LockAThread t1;
LockBThread t2;
Phaser p = new Phaser(3);
synchronized(objC) {
// Make sure the main thread is not holding any lock
assertNoLock(mainThread);
// Test deadlock case
// t1 holds lockA and attempts to lock B
// t2 holds lockB and attempts to lock C
t1 = new LockAThread(p);
t1.start();
t2 = new LockBThread(p);
t2.start();
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
checkBlockedObject(t2, objC, mainThread, Thread.State.BLOCKED);
checkBlockedObject(t1, objB, t2, Thread.State.BLOCKED);
long[] expectedThreads = new long[3];
expectedThreads[0] = t1.getId(); // blocked on lockB
expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC
expectedThreads[2] = mainThread.getId(); // owner of lockC
findThreadsBlockedOn(objB, expectedThreads);
}
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
p = new Phaser(2);
// Test Object.wait() case
waiter = new WaitingThread(p);
waiter.start();
checker = new CheckerThread();
checker.start();
try {
waiter.join();
checker.join();
} catch (InterruptedException e) {
e.printStackTrace();
testFailed = true;
}
Thread mainThread = Thread.currentThread();
if (testFailed) {
throw new RuntimeException("TEST FAILED.");
// Test uncontested case
LockAThread t1;
LockBThread t2;
Phaser p = new Phaser(3);
synchronized(OBJC) {
// Make sure the main thread is not holding any lock
assertNoLock(mainThread);
// Test deadlock case
// t1 holds lockA and attempts to lock B
// t2 holds lockB and attempts to lock C
t1 = new LockAThread(p);
t1.start();
t2 = new LockBThread(p);
t2.start();
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
assertThreadState(t2, Thread.State.BLOCKED);
checkBlockedObject(t2, OBJC, mainThread);
assertThreadState(t1, Thread.State.BLOCKED);
checkBlockedObject(t1, OBJB, t2);
long[] expectedThreads = new long[3];
expectedThreads[0] = t1.getId(); // blocked on lockB
expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC
expectedThreads[2] = mainThread.getId(); // owner of lockC
findThreadsBlockedOn(OBJB, expectedThreads);
}
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
p = new Phaser(2);
// Test Object.wait() case
waiter = new WaitingThread(p);
waiter.start();
checker = new CheckerThread();
checker.start();
try {
waiter.join();
checker.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} finally { // log all the messages to STDOUT
System.out.println(LOGGER.toString());
}
System.out.println("Test passed.");
}
@ -335,9 +395,9 @@ public class Locks {
throw new RuntimeException("TEST FAILED: " +
lock + " expected to have owner");
}
for (int j = 0; j < infos.length; j++) {
if (infos[j].getThreadId() == threadId) {
ownerInfo = infos[j];
for (ThreadInfo info1 : infos) {
if (info1.getThreadId() == threadId) {
ownerInfo = info1;
break;
}
}
@ -349,11 +409,11 @@ public class Locks {
throws Exception {
String lock = getLockName(o);
// Check with ThreadInfo with no stack trace (i.e. no safepoint)
ThreadInfo[] infos = tm.getThreadInfo(tm.getAllThreadIds());
ThreadInfo[] infos = TM.getThreadInfo(TM.getAllThreadIds());
doCheck(infos, lock, expectedThreads);
// Check with ThreadInfo with stack trace
infos = tm.getThreadInfo(tm.getAllThreadIds(), 1);
infos = TM.getThreadInfo(TM.getAllThreadIds(), 1);
doCheck(infos, lock, expectedThreads);
}
@ -376,7 +436,7 @@ public class Locks {
long[] threads = new long[10];
int count = 0;
threads[count++] = ownerInfo.getThreadId();
while (ownerInfo != null && ownerInfo.getThreadState() == Thread.State.BLOCKED) {
while (ownerInfo.getThreadState() == Thread.State.BLOCKED) {
ownerInfo = findOwnerInfo(infos, lock);
threads[count++] = ownerInfo.getThreadId();
log(" Owner = %s id = %d",
@ -407,6 +467,6 @@ public class Locks {
}
private static void log(String format, Object ... args) {
logger.log(format + "%n", args);
LOGGER.log(format + "%n", args);
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2016, 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 8058575
* @summary Test that bad host classes cause exceptions to get thrown.
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.base/jdk.internal.org.objectweb.asm
* @run main TestBadHostClass
*/
import java.lang.*;
import java.lang.reflect.Field;
import jdk.internal.misc.Unsafe;
import jdk.test.lib.unsafe.UnsafeHelper;
import jdk.internal.org.objectweb.asm.ClassWriter;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
// Test that bad host classes cause exceptions.
public class TestBadHostClass {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static String packageName(Class<?> c) {
if (c.isArray()) {
return packageName(c.getComponentType());
} else {
String name = c.getName();
int dot = name.lastIndexOf('.');
if (dot == -1) return "";
return name.substring(0, dot);
}
}
private static int constantPoolSize(byte[] classFile) {
return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
}
static public void badHostClass(Class<?> hostClass) {
// choose a class name in the same package as the host class
String className;
if (hostClass != null) {
String prefix = packageName(hostClass);
if (prefix.length() > 0)
prefix = prefix.replace('.', '/') + "/";
className = prefix + "Anon";
} else {
className = "Anon";
}
// create the class
String superName = "java/lang/Object";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER,
className, null, superName, null);
byte[] classBytes = cw.toByteArray();
int cpPoolSize = constantPoolSize(classBytes);
Class<?> anonClass
= unsafe.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]);
}
public static void main(String args[]) throws Exception {
// host class is an array of java.lang.Objects.
try {
badHostClass(Object[].class);
} catch (IllegalArgumentException ex) {
}
// host class is an array of objects of this class.
try {
badHostClass(TestBadHostClass[].class);
} catch (IllegalArgumentException ex) {
}
// host class is null.
try {
badHostClass(null);
} catch (NullPointerException ex) {
}
// host class is a primitive array class.
try {
badHostClass(int[].class);
} catch (IllegalArgumentException ex) {
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016, 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
@ -69,7 +69,7 @@ public class FileInputStreamPoolTest {
// make JVM process References
System.gc();
// help ReferenceHandler thread enqueue References
while (TestProxy.Reference_tryHandlePending(false)) {}
while (TestProxy.Reference_waitForReferenceProcessing()) { }
// help run Finalizers
System.runFinalization();
}
@ -103,11 +103,11 @@ public class FileInputStreamPoolTest {
/**
* A proxy for (package)private static methods:
* sun.security.provider.FileInputStreamPool.getInputStream
* java.lang.ref.Reference.tryHandlePending
* java.lang.ref.Reference.waitForReferenceProcessing
*/
static class TestProxy {
private static final Method getInputStreamMethod;
private static final Method tryHandlePendingMethod;
private static final Method waitForReferenceProcessingMethod;
static {
try {
@ -118,9 +118,9 @@ public class FileInputStreamPoolTest {
"getInputStream", File.class);
getInputStreamMethod.setAccessible(true);
tryHandlePendingMethod = Reference.class.getDeclaredMethod(
"tryHandlePending", boolean.class);
tryHandlePendingMethod.setAccessible(true);
waitForReferenceProcessingMethod =
Reference.class.getDeclaredMethod("waitForReferenceProcessing");
waitForReferenceProcessingMethod.setAccessible(true);
} catch (Exception e) {
throw new Error(e);
}
@ -146,13 +146,14 @@ public class FileInputStreamPoolTest {
}
}
static boolean Reference_tryHandlePending(boolean waitForNotify) {
static boolean Reference_waitForReferenceProcessing() {
try {
return (boolean) tryHandlePendingMethod
.invoke(null, waitForNotify);
return (boolean) waitForReferenceProcessingMethod.invoke(null);
} catch (InvocationTargetException e) {
Throwable te = e.getTargetException();
if (te instanceof RuntimeException) {
if (te instanceof InterruptedException) {
return true;
} else if (te instanceof RuntimeException) {
throw (RuntimeException) te;
} else if (te instanceof Error) {
throw (Error) te;

View File

@ -31,12 +31,10 @@
* @run main BasicLauncherTest
*/
import static jdk.testlibrary.Asserts.assertTrue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
@ -84,15 +82,56 @@ public class BasicLauncherTest {
ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
Process toolProcess = processBuilder.start();
toolProcess.getOutputStream().write("quit\n".getBytes());
toolProcess.getOutputStream().close();
try (OutputStream out = toolProcess.getOutputStream()) {
out.write("universe\n".getBytes());
out.write("printmdo -a\n".getBytes());
out.write("quit\n".getBytes());
}
// By default child process output stream redirected to pipe, so we are reading it in foreground.
BufferedReader reader = new BufferedReader(new InputStreamReader(toolProcess.getInputStream()));
Exception unexpected = null;
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(toolProcess.getInputStream()))) {
String line;
String unexpectedMsg =
"One or more of 'VirtualCallData', 'CounterData', " +
"'ReceiverTypeData', 'bci', 'MethodData' " +
"or 'java/lang/Object' not found";
boolean knownClassFound = false;
boolean knownProfileDataTypeFound = false;
boolean knownTokensFound = false;
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line.trim());
while ((line = reader.readLine()) != null) {
line = line.trim();
System.out.println(line);
if (line.contains("unknown subtype of CollectedHeap")) {
unexpected = new RuntimeException("CollectedHeap type should be known.");
break;
}
else if (line.contains("missing reason for ")) {
unexpected = new RuntimeException("missing reason for ");
break;
}
if (line.contains("VirtualCallData") ||
line.contains("CounterData") ||
line.contains("ReceiverTypeData")) {
knownProfileDataTypeFound = true;
}
if (line.contains("bci") ||
line.contains("MethodData")) {
knownTokensFound = true;
}
if (line.contains("java/lang/Object")) {
knownClassFound = true;
}
}
if ((knownClassFound == false) ||
(knownTokensFound == false) ||
(knownProfileDataTypeFound == false)) {
unexpected = new RuntimeException(unexpectedMsg);
}
}
toolProcess.waitFor();
@ -100,6 +139,14 @@ public class BasicLauncherTest {
if (toolProcess.exitValue() != 0) {
throw new RuntimeException("FAILED CLHSDB terminated with non-zero exit code " + toolProcess.exitValue());
}
if (unexpected != null) {
throw unexpected;
}
if (unexpected != null) {
throw unexpected;
}
} catch (Exception ex) {
throw new RuntimeException("Test ERROR " + ex, ex);
} finally {
@ -183,21 +230,6 @@ public class BasicLauncherTest {
Arrays.asList(toolArgs));
}
public static void testHeapDump() throws IOException {
File dump = new File("jhsdb.jmap.dump." +
System.currentTimeMillis() + ".hprof");
if (dump.exists()) {
dump.delete();
}
dump.deleteOnExit();
launch("heap written to", null, "jmap",
"--binaryheap", "--dumpfile=" + dump.getAbsolutePath());
assertTrue(dump.exists() && dump.isFile(),
"Could not create dump file " + dump.getAbsolutePath());
}
public static void main(String[] args)
throws IOException {
@ -216,8 +248,6 @@ public class BasicLauncherTest {
"System Properties info not available", "jinfo");
launch("java.threads", null, "jsnap");
testHeapDump();
// The test throws RuntimeException on error.
// IOException is thrown if LingeredApp can't start because of some bad
// environment condition

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2016, 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 8163346
* @summary Test hashing of extended characters in Serviceability Agent.
* @library /test/lib
* @library /lib/testlibrary
* @compile -encoding utf8 HeapDumpTest.java
* @run main/timeout=240 HeapDumpTest
*/
import static jdk.testlibrary.Asserts.assertTrue;
import java.io.IOException;
import java.io.File;
import java.util.List;
import java.util.Arrays;
import jdk.testlibrary.JDKToolLauncher;
import jdk.testlibrary.OutputAnalyzer;
import jdk.testlibrary.ProcessTools;
import jdk.test.lib.apps.LingeredApp;
import jdk.testlibrary.Platform;
public class HeapDumpTest {
private static LingeredAppWithExtendedChars theApp = null;
/**
*
* @param vmArgs - tool arguments to launch jhsdb
* @return exit code of tool
*/
public static void launch(String expectedMessage, List<String> toolArgs)
throws IOException {
System.out.println("Starting LingeredApp");
try {
theApp = new LingeredAppWithExtendedChars();
LingeredApp.startApp(Arrays.asList("-Xmx256m"), theApp);
System.out.println(theApp.\u00CB);
System.out.println("Starting " + toolArgs.get(0) + " against " + theApp.getPid());
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
for (String cmd : toolArgs) {
launcher.addToolArg(cmd);
}
launcher.addToolArg("--pid=" + Long.toString(theApp.getPid()));
ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
System.out.println("stdout:");
System.out.println(output.getStdout());
System.out.println("stderr:");
System.out.println(output.getStderr());
output.shouldContain(expectedMessage);
output.shouldHaveExitValue(0);
} catch (Exception ex) {
throw new RuntimeException("Test ERROR " + ex, ex);
} finally {
LingeredApp.stopApp(theApp);
}
}
public static void launch(String expectedMessage, String... toolArgs)
throws IOException {
launch(expectedMessage, Arrays.asList(toolArgs));
}
public static void testHeapDump() throws IOException {
File dump = new File("jhsdb.jmap.heap." +
System.currentTimeMillis() + ".hprof");
if (dump.exists()) {
dump.delete();
}
launch("heap written to", "jmap",
"--binaryheap", "--dumpfile=" + dump.getAbsolutePath());
assertTrue(dump.exists() && dump.isFile(),
"Could not create dump file " + dump.getAbsolutePath());
dump.delete();
}
public static void main(String[] args)
throws IOException {
if (!Platform.shouldSAAttach()) {
// Silently skip the test if we don't have enough permissions to attach
System.err.println("Error! Insufficient permissions to attach - test skipped.");
return;
}
testHeapDump();
// The test throws RuntimeException on error.
// IOException is thrown if LingeredApp can't start because of some bad
// environment condition
System.out.println("Test PASSED");
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 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 jdk.test.lib.apps.LingeredApp;
public class LingeredAppWithExtendedChars extends LingeredApp {
public static int \u00CB = 1;
public static void main(String args[]) {
LingeredApp.main(args);
}
}

View File

@ -38,7 +38,7 @@ import jdk.testlibrary.ProcessTools;
* @library /lib/testlibrary
* @modules jdk.jartool/sun.tools.jar
* java.management
* @build jdk.testlibrary.* JpsHelper JpsBase
* @build JpsHelper JpsBase
* @run main/othervm TestJpsJar
*/
public class TestJpsJar {