This commit is contained in:
Zhengyu Gu 2010-11-12 09:37:13 -05:00
commit 6fd53f05d1
848 changed files with 32487 additions and 16221 deletions

View file

@ -89,3 +89,7 @@ a6442d6bc38a44152e0662688213ce4d2701f42a jdk7-b110
f960f117f1623629f64203e2b09a92a8f6f14ff5 jdk7-b112 f960f117f1623629f64203e2b09a92a8f6f14ff5 jdk7-b112
1fee41c7ed2b3388970a756a85aa693c0de8407a jdk7-b113 1fee41c7ed2b3388970a756a85aa693c0de8407a jdk7-b113
750c1ccb2f2d1ddfa95ab6c7f897fdab2f87f7e9 jdk7-b114 750c1ccb2f2d1ddfa95ab6c7f897fdab2f87f7e9 jdk7-b114
9cb24917216bc68997154f6e9566c3de62acb2f4 jdk7-b115
a4e6aa1f45ad23a6f083ed98d970b5006ea4d292 jdk7-b116
228e73f288c543a8c34e2a54227103ae5649e6af jdk7-b117
2e876e59938a853934aa738c811b26c452bd9fe8 jdk7-b118

View file

@ -89,3 +89,7 @@ f8be576feefce0c6695f188ef97ec16b73ad9cfd jdk7-b104
b852103caf73da70068473777ae867a457bb3ae1 jdk7-b112 b852103caf73da70068473777ae867a457bb3ae1 jdk7-b112
c1df968c4527bfab5f97662a89245f15d12d378b jdk7-b113 c1df968c4527bfab5f97662a89245f15d12d378b jdk7-b113
27985a5c6e5268014d25d55886e0ecb96af4763d jdk7-b114 27985a5c6e5268014d25d55886e0ecb96af4763d jdk7-b114
e8ebdf41b9c01a26642848f4134f5504e8fb3233 jdk7-b115
94e9a1bfba8b8d1fe0bfd43b88629b1f27b02a76 jdk7-b116
7220e60b097fa027e922f1aeecdd330f3e37409f jdk7-b117
a12a9e78df8a9d534da0b4a244ed68f0de0bd58e jdk7-b118

View file

@ -89,3 +89,7 @@ c3dd858e09b20206459d9e7b0ead99d27ab00eab jdk7-b109
cc67fdc4fee9a5b25caee4e71b51a8ff24ae7d1a jdk7-b112 cc67fdc4fee9a5b25caee4e71b51a8ff24ae7d1a jdk7-b112
a89a6c5be9d1a754868d3d359cbf7ad36aa95631 jdk7-b113 a89a6c5be9d1a754868d3d359cbf7ad36aa95631 jdk7-b113
88fddb73c5c4a4b50c319cbae9380caf5172ab45 jdk7-b114 88fddb73c5c4a4b50c319cbae9380caf5172ab45 jdk7-b114
da7561d479e0ddaa4650d8023ac0fc7294e014e3 jdk7-b115
98c028de4301106f2285ac0e128a1bb9b4c24f5c jdk7-b116
fa502e4834dac2176499cc1f44794d5dc32a11b9 jdk7-b117
42e77836fded7c2a3080d27316b96634ea9e33c6 jdk7-b118

View file

@ -34,7 +34,7 @@ com_sun_corba_se_impl_io_java = \
com/sun/corba/se/impl/io/ObjectStreamField.java \ com/sun/corba/se/impl/io/ObjectStreamField.java \
com/sun/corba/se/impl/io/OptionalDataException.java \ com/sun/corba/se/impl/io/OptionalDataException.java \
com/sun/corba/se/impl/io/ValueHandlerImpl.java \ com/sun/corba/se/impl/io/ValueHandlerImpl.java \
com/sun/corba/se/impl/io/IIOPInputStream.java \ com/sun/corba/se/impl/io/IIOPInputStream.java \
com/sun/corba/se/impl/io/IIOPOutputStream.java \ com/sun/corba/se/impl/io/IIOPOutputStream.java \
com/sun/corba/se/impl/io/TypeMismatchException.java \ com/sun/corba/se/impl/io/TypeMismatchException.java \
com/sun/corba/se/impl/io/InputStreamHook.java \ com/sun/corba/se/impl/io/InputStreamHook.java \

View file

@ -2553,8 +2553,8 @@ public class IIOPInputStream
bridge.putObject( o, key, v ) ; bridge.putObject( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetObjectField( e, fieldName, throw utilWrapper.errorSetObjectField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
ObjectUtility.compactObjectToString( v )) ; v.toString() ) ;
} }
} }
@ -2566,7 +2566,7 @@ public class IIOPInputStream
bridge.putBoolean( o, key, v ) ; bridge.putBoolean( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetBooleanField( e, fieldName, throw utilWrapper.errorSetBooleanField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Boolean(v) ) ; new Boolean(v) ) ;
} }
} }
@ -2579,7 +2579,7 @@ public class IIOPInputStream
bridge.putByte( o, key, v ) ; bridge.putByte( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetByteField( e, fieldName, throw utilWrapper.errorSetByteField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Byte(v) ) ; new Byte(v) ) ;
} }
} }
@ -2592,7 +2592,7 @@ public class IIOPInputStream
bridge.putChar( o, key, v ) ; bridge.putChar( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetCharField( e, fieldName, throw utilWrapper.errorSetCharField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Character(v) ) ; new Character(v) ) ;
} }
} }
@ -2605,7 +2605,7 @@ public class IIOPInputStream
bridge.putShort( o, key, v ) ; bridge.putShort( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetShortField( e, fieldName, throw utilWrapper.errorSetShortField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Short(v) ) ; new Short(v) ) ;
} }
} }
@ -2618,7 +2618,7 @@ public class IIOPInputStream
bridge.putInt( o, key, v ) ; bridge.putInt( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetIntField( e, fieldName, throw utilWrapper.errorSetIntField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Integer(v) ) ; new Integer(v) ) ;
} }
} }
@ -2631,7 +2631,7 @@ public class IIOPInputStream
bridge.putLong( o, key, v ) ; bridge.putLong( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetLongField( e, fieldName, throw utilWrapper.errorSetLongField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Long(v) ) ; new Long(v) ) ;
} }
} }
@ -2644,7 +2644,7 @@ public class IIOPInputStream
bridge.putFloat( o, key, v ) ; bridge.putFloat( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetFloatField( e, fieldName, throw utilWrapper.errorSetFloatField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Float(v) ) ; new Float(v) ) ;
} }
} }
@ -2657,7 +2657,7 @@ public class IIOPInputStream
bridge.putDouble( o, key, v ) ; bridge.putDouble( o, key, v ) ;
} catch (Exception e) { } catch (Exception e) {
throw utilWrapper.errorSetDoubleField( e, fieldName, throw utilWrapper.errorSetDoubleField( e, fieldName,
ObjectUtility.compactObjectToString( o ), o.toString(),
new Double(v) ) ; new Double(v) ) ;
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,32 +32,22 @@
package com.sun.corba.se.impl.io; package com.sun.corba.se.impl.io;
import javax.rmi.CORBA.Util; import javax.rmi.CORBA.Util;
import javax.rmi.PortableRemoteObject;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Stack;
import java.io.IOException; import java.io.IOException;
import java.util.EmptyStackException;
import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.io.IIOPInputStream;
import com.sun.corba.se.impl.io.IIOPOutputStream;
import com.sun.corba.se.impl.util.RepositoryId; import com.sun.corba.se.impl.util.RepositoryId;
import com.sun.corba.se.impl.util.Utility; import com.sun.corba.se.impl.util.Utility;
import org.omg.CORBA.TCKind; import org.omg.CORBA.TCKind;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.portable.IndirectionException; import org.omg.CORBA.portable.IndirectionException;
import com.sun.org.omg.SendingContext.CodeBase; import com.sun.org.omg.SendingContext.CodeBase;
import com.sun.org.omg.SendingContext.CodeBaseHelper; import com.sun.org.omg.SendingContext.CodeBaseHelper;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import com.sun.corba.se.impl.io.IIOPInputStream.ActiveRecursionManager;
import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.impl.logging.OMGSystemException; import com.sun.corba.se.impl.logging.OMGSystemException;
@ -809,65 +799,163 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat
return "com.sun.corba.se.impl.io.IIOPOutputStream"; return "com.sun.corba.se.impl.io.IIOPOutputStream";
} }
private com.sun.corba.se.impl.io.IIOPOutputStream createOutputStream() { private IIOPOutputStream createOutputStream() {
return (com.sun.corba.se.impl.io.IIOPOutputStream)AccessController.doPrivileged( final String name = getOutputStreamClassName();
new StreamFactory(getOutputStreamClassName())); try {
IIOPOutputStream stream = createOutputStreamBuiltIn(name);
if (stream != null) {
return stream;
}
return createCustom(IIOPOutputStream.class, name);
} catch (Throwable t) {
// Throw exception under the carpet.
InternalError ie = new InternalError(
"Error loading " + name
);
ie.initCause(t);
throw ie;
}
}
/**
* Construct a built in implementation with priveleges.
* Returning null indicates a non-built is specified.
*/
private IIOPOutputStream createOutputStreamBuiltIn(
final String name
) throws Throwable {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<IIOPOutputStream>() {
public IIOPOutputStream run() throws IOException {
return createOutputStreamBuiltInNoPriv(name);
}
}
);
} catch (java.security.PrivilegedActionException exc) {
throw exc.getCause();
}
}
/**
* Returning null indicates a non-built is specified.
*/
private IIOPOutputStream createOutputStreamBuiltInNoPriv(
final String name
) throws IOException {
return
name.equals(
IIOPOutputStream
.class.getName()
) ?
new IIOPOutputStream() :
name.equals(
com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3
.class.getName()
) ?
new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3() :
name.equals(
com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1
.class.getName()
) ?
new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1() :
null;
} }
protected String getInputStreamClassName() { protected String getInputStreamClassName() {
return "com.sun.corba.se.impl.io.IIOPInputStream"; return "com.sun.corba.se.impl.io.IIOPInputStream";
} }
private com.sun.corba.se.impl.io.IIOPInputStream createInputStream() { private IIOPInputStream createInputStream() {
return (com.sun.corba.se.impl.io.IIOPInputStream)AccessController.doPrivileged( final String name = getInputStreamClassName();
new StreamFactory(getInputStreamClassName())); try {
IIOPInputStream stream = createInputStreamBuiltIn(name);
if (stream != null) {
return stream;
}
return createCustom(IIOPInputStream.class, name);
} catch (Throwable t) {
// Throw exception under the carpet.
InternalError ie = new InternalError(
"Error loading " + name
);
ie.initCause(t);
throw ie;
}
} }
/** /**
* Instantiates a class of the given name using the system ClassLoader * Construct a built in implementation with priveleges.
* as part of a PrivilegedAction. * Returning null indicates a non-built is specified.
*
* It's private final so hopefully people can't grab it outside of
* this class.
*
* If you're worried that someone could subclass ValueHandlerImpl,
* install his own streams, and snoop what's on the wire:
* Someone can do that only if he's allowed to use the feature
* of installing his own javax.rmi.CORBA.Util delegate (via a
* JVM property or orb.properties file, read the first time the
* Util class is used). If he can do that, he can snoop
* anything on the wire, anyway, without abusing the
* StreamFactory class.
*/ */
private static final class StreamFactory implements PrivilegedAction { private IIOPInputStream createInputStreamBuiltIn(
private String className; final String name
) throws Throwable {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<IIOPInputStream>() {
public IIOPInputStream run() throws IOException {
return createInputStreamBuiltInNoPriv(name);
}
}
);
} catch (java.security.PrivilegedActionException exc) {
throw exc.getCause();
}
}
public StreamFactory (String _className) { /**
className = _className; * Returning null indicates a non-built is specified.
} */
private IIOPInputStream createInputStreamBuiltInNoPriv(
final String name
) throws IOException {
return
name.equals(
IIOPInputStream
.class.getName()
) ?
new IIOPInputStream() :
public Object run() { name.equals(
try { com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3
// Note: We must use the system ClassLoader here .class.getName()
// since we want to load classes outside of the ) ?
// core JDK when running J2EE Pure ORB and new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3() :
// talking to Kestrel.
name.equals(
com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1
.class.getName()
) ?
new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1() :
null;
}
/**
* Create a custom implementation without privileges.
*/
private <T> T createCustom(
final Class<T> type, final String className
) throws Throwable {
// Note: We use the thread context or system ClassLoader here
// since we want to load classes outside of the
// core JDK when running J2EE Pure ORB and
// talking to Kestrel.
ClassLoader cl = Thread.currentThread().getContextClassLoader(); ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) if (cl == null)
cl = ClassLoader.getSystemClassLoader(); cl = ClassLoader.getSystemClassLoader();
Class streamClass = cl.loadClass(className); Class<?> clazz = cl.loadClass(className);
Class<? extends T> streamClass = clazz.asSubclass(type);
// Since the ClassLoader should cache the class, this isn't // Since the ClassLoader should cache the class, this isn't
// as expensive as it looks. // as expensive as it looks.
return streamClass.newInstance(); return streamClass.newInstance();
} catch(Throwable t) {
InternalError ie = new InternalError( "Error loading " + className ) ;
ie.initCause( t ) ;
throw ie ;
}
}
} }
/** /**

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -110,7 +110,7 @@ public class PrefixParserAction extends ParserActionBase {
throw wrapper.couldNotSetArray( thr, throw wrapper.couldNotSetArray( thr,
getPropertyName(), new Integer(ctr), getPropertyName(), new Integer(ctr),
componentType, new Integer(size), componentType, new Integer(size),
ObjectUtility.compactObjectToString( obj )) ; obj.toString() ) ;
} }
ctr++ ; ctr++ ;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -50,103 +50,8 @@ import java.math.BigInteger ;
import java.math.BigDecimal ; import java.math.BigDecimal ;
public final class ObjectUtility { public final class ObjectUtility {
private boolean useToString ; private ObjectUtility() {}
private boolean isIndenting ;
private int initialLevel ;
private int increment ;
private ClassMap classToPrinter = new ClassMap() ;
private static ObjectUtility standard = new ObjectUtility( false, true,
0, 4 ) ;
private static ObjectUtility compact = new ObjectUtility( true, false,
0, 4 ) ;
private ObjectUtility( boolean useToString, boolean isIndenting,
int initialLevel, int increment )
{
this.useToString = useToString ;
this.isIndenting = isIndenting ;
this.initialLevel = initialLevel ;
this.increment = increment ;
classToPrinter.put( Properties.class, propertiesPrinter ) ;
classToPrinter.put( Collection.class, collectionPrinter ) ;
classToPrinter.put( Map.class, mapPrinter ) ;
}
/** Construct an Utility instance with the desired objectToString
* behavior.
*/
public static ObjectUtility make( boolean useToString, boolean isIndenting,
int initialLevel, int increment )
{
return new ObjectUtility( useToString, isIndenting, initialLevel,
increment ) ;
}
/** Construct an Utility instance with the desired objectToString
* behavior.
*/
public static ObjectUtility make( boolean useToString, boolean isIndenting )
{
return new ObjectUtility( useToString, isIndenting, 0, 4 ) ;
}
/** Get the standard Utility object that supports objectToString with
* indented display and no use of toString() methods.
*/
public static ObjectUtility make()
{
return standard ;
}
/** A convenience method that gives the default behavior: use indenting
* to display the object's structure and do not use built-in toString
* methods.
*/
public static String defaultObjectToString( java.lang.Object object )
{
return standard.objectToString( object ) ;
}
public static String compactObjectToString( java.lang.Object object )
{
return compact.objectToString( object ) ;
}
/** objectToString handles display of arbitrary objects. It correctly
* handles objects whose elements form an arbitrary graph. It uses
* reflection to display the contents of any kind of object.
* An object's toString() method may optionally be used, but the default
* is to ignore all toString() methods except for those defined for
* primitive types, primitive type wrappers, and strings.
*/
public String objectToString(java.lang.Object obj)
{
IdentityHashMap printed = new IdentityHashMap() ;
ObjectWriter result = ObjectWriter.make( isIndenting, initialLevel,
increment ) ;
objectToStringHelper( printed, result, obj ) ;
return result.toString() ;
}
// Perform a deep structural equality comparison of the two objects.
// This handles all arrays, maps, and sets specially, otherwise
// it just calls the object's equals() method.
public static boolean equals( java.lang.Object obj1, java.lang.Object obj2 )
{
// Set of pairs of objects that have been (or are being) considered for
// equality. Such pairs are presumed to be equals. If they are not,
// this will be detected eventually and the equals method will return
// false.
Set considered = new HashSet() ;
// Map that gives the corresponding component of obj2 for a component
// of obj1. This is used to check for the same aliasing and use of
// equal objects in both objects.
Map counterpart = new IdentityHashMap() ;
return equalsHelper( counterpart, considered, obj1, obj2 ) ;
}
/** If arr1 and arr2 are both arrays of the same component type, /** If arr1 and arr2 are both arrays of the same component type,
* return an array of that component type that consists of the * return an array of that component type that consists of the
@ -179,544 +84,4 @@ public final class ObjectUtility {
return result ; return result ;
} }
//===========================================================================
// Implementation
//===========================================================================
private void objectToStringHelper( IdentityHashMap printed,
ObjectWriter result, java.lang.Object obj)
{
if (obj==null) {
result.append( "null" ) ;
result.endElement() ;
} else {
Class cls = obj.getClass() ;
result.startObject( obj ) ;
if (printed.keySet().contains( obj )) {
result.endObject( "*VISITED*" ) ;
} else {
printed.put( obj, null ) ;
if (mustUseToString(cls)) {
result.endObject( obj.toString() ) ;
} else {
// First, handle any classes that have special printer
// methods defined. This is useful when the class
// overrides toString with something that
// is not sufficiently detailed.
ObjectPrinter printer = (ObjectPrinter)(classToPrinter.get(
cls )) ;
if (printer != null) {
printer.print( printed, result, obj ) ;
result.endObject() ;
} else {
Class compClass = cls.getComponentType() ;
if (compClass == null)
// handleObject always calls endObject
handleObject( printed, result, obj ) ;
else {
handleArray( printed, result, obj ) ;
result.endObject() ;
}
}
}
}
}
}
private static interface ObjectPrinter {
void print( IdentityHashMap printed, ObjectWriter buff,
java.lang.Object obj ) ;
}
private ObjectPrinter propertiesPrinter = new ObjectPrinter() {
public void print( IdentityHashMap printed, ObjectWriter buff,
java.lang.Object obj )
{
if (!(obj instanceof Properties))
throw new Error() ;
Properties props = (Properties)obj ;
Enumeration keys = props.propertyNames() ;
while (keys.hasMoreElements()) {
String key = (String)(keys.nextElement()) ;
String value = props.getProperty( key ) ;
buff.startElement() ;
buff.append( key ) ;
buff.append( "=" ) ;
buff.append( value ) ;
buff.endElement() ;
}
}
} ;
private ObjectPrinter collectionPrinter = new ObjectPrinter() {
public void print( IdentityHashMap printed, ObjectWriter buff,
java.lang.Object obj )
{
if (!(obj instanceof Collection))
throw new Error() ;
Collection coll = (Collection)obj ;
Iterator iter = coll.iterator() ;
while (iter.hasNext()) {
java.lang.Object element = iter.next() ;
buff.startElement() ;
objectToStringHelper( printed, buff, element ) ;
buff.endElement() ;
}
}
} ;
private ObjectPrinter mapPrinter = new ObjectPrinter() {
public void print( IdentityHashMap printed, ObjectWriter buff,
java.lang.Object obj )
{
if (!(obj instanceof Map))
throw new Error() ;
Map map = (Map)obj ;
Iterator iter = map.entrySet().iterator() ;
while (iter.hasNext()) {
Entry entry = (Entry)(iter.next()) ;
buff.startElement() ;
objectToStringHelper( printed, buff, entry.getKey() ) ;
buff.append( "=>" ) ;
objectToStringHelper( printed, buff, entry.getValue() ) ;
buff.endElement() ;
}
}
} ;
private static class ClassMap {
ArrayList data ;
public ClassMap()
{
data = new ArrayList() ;
}
/** Return the first element of the ClassMap that is assignable to cls.
* The order is determined by the order in which the put method was
* called. Returns null if there is no match.
*/
public java.lang.Object get( Class cls )
{
Iterator iter = data.iterator() ;
while (iter.hasNext()) {
java.lang.Object[] arr = (java.lang.Object[])(iter.next()) ;
Class key = (Class)(arr[0]) ;
if (key.isAssignableFrom( cls ))
return arr[1] ;
}
return null ;
}
/** Add obj to the map with key cls. Note that order matters,
* as the first match is returned.
*/
public void put( Class cls, java.lang.Object obj )
{
java.lang.Object[] pair = { cls, obj } ;
data.add( pair ) ;
}
}
private boolean mustUseToString( Class cls )
{
// These probably never occur
if (cls.isPrimitive())
return true ;
// We must use toString for all primitive wrappers, since
// otherwise the code recurses endlessly (access value field
// inside Integer, returns another Integer through reflection).
if ((cls == Integer.class) ||
(cls == BigInteger.class) ||
(cls == BigDecimal.class) ||
(cls == String.class) ||
(cls == StringBuffer.class) ||
(cls == Long.class) ||
(cls == Short.class) ||
(cls == Byte.class) ||
(cls == Character.class) ||
(cls == Float.class) ||
(cls == Double.class) ||
(cls == Boolean.class))
return true ;
if (useToString) {
try {
cls.getDeclaredMethod( "toString", (Class[])null ) ;
return true ;
} catch (Exception exc) {
return false ;
}
}
return false ;
}
private void handleObject( IdentityHashMap printed, ObjectWriter result,
java.lang.Object obj )
{
Class cls = obj.getClass() ;
try {
Field[] fields;
SecurityManager security = System.getSecurityManager();
if (security != null && !Modifier.isPublic(cls.getModifiers())) {
fields = new Field[0];
} else {
fields = cls.getDeclaredFields();
}
for (int ctr=0; ctr<fields.length; ctr++ ) {
final Field fld = fields[ctr] ;
int modifiers = fld.getModifiers() ;
// Do not display field if it is static, since these fields
// are always the same for every instances. This could
// be made configurable, but I don't think it is
// useful to do so.
if (!Modifier.isStatic( modifiers )) {
if (security != null) {
if (!Modifier.isPublic(modifiers))
continue;
}
result.startElement() ;
result.append( fld.getName() ) ;
result.append( ":" ) ;
try {
// Make sure that we can read the field if it is
// not public
AccessController.doPrivileged( new PrivilegedAction() {
public Object run() {
fld.setAccessible( true ) ;
return null ;
}
} ) ;
java.lang.Object value = fld.get( obj ) ;
objectToStringHelper( printed, result, value ) ;
} catch (Exception exc2) {
result.append( "???" ) ;
}
result.endElement() ;
}
}
result.endObject() ;
} catch (Exception exc2) {
result.endObject( obj.toString() ) ;
}
}
private void handleArray( IdentityHashMap printed, ObjectWriter result,
java.lang.Object obj )
{
Class compClass = obj.getClass().getComponentType() ;
if (compClass == boolean.class) {
boolean[] arr = (boolean[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == byte.class) {
byte[] arr = (byte[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == short.class) {
short[] arr = (short[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == int.class) {
int[] arr = (int[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == long.class) {
long[] arr = (long[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == char.class) {
char[] arr = (char[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == float.class) {
float[] arr = (float[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else if (compClass == double.class) {
double[] arr = (double[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
result.append( arr[ctr] ) ;
result.endElement() ;
}
} else { // array of object
java.lang.Object[] arr = (java.lang.Object[])obj ;
for (int ctr=0; ctr<arr.length; ctr++) {
result.startElement() ;
objectToStringHelper( printed, result, arr[ctr] ) ;
result.endElement() ;
}
}
}
private static class Pair
{
private java.lang.Object obj1 ;
private java.lang.Object obj2 ;
Pair( java.lang.Object obj1, java.lang.Object obj2 )
{
this.obj1 = obj1 ;
this.obj2 = obj2 ;
}
public boolean equals( java.lang.Object obj )
{
if (!(obj instanceof Pair))
return false ;
Pair other = (Pair)obj ;
return other.obj1 == obj1 && other.obj2 == obj2 ;
}
public int hashCode()
{
return System.identityHashCode( obj1 ) ^
System.identityHashCode( obj2 ) ;
}
}
private static boolean equalsHelper( Map counterpart, Set considered,
java.lang.Object obj1, java.lang.Object obj2 )
{
if ((obj1 == null) || (obj2 == null))
return obj1 == obj2 ;
java.lang.Object other2 = counterpart.get( obj1 ) ;
if (other2 == null) {
other2 = obj2 ;
counterpart.put( obj1, other2 ) ;
}
if (obj1 == other2)
return true ;
if (obj2 != other2)
return false ;
Pair pair = new Pair( obj1, obj2 ) ;
if (considered.contains( pair ))
return true ;
else
considered.add( pair ) ;
if (obj1 instanceof java.lang.Object[] &&
obj2 instanceof java.lang.Object[])
return equalArrays( counterpart, considered,
(java.lang.Object[])obj1, (java.lang.Object[])obj2 ) ;
else if (obj1 instanceof Map && obj2 instanceof Map)
return equalMaps( counterpart, considered,
(Map)obj1, (Map)obj2 ) ;
else if (obj1 instanceof Set && obj2 instanceof Set)
return equalSets( counterpart, considered,
(Set)obj1, (Set)obj2 ) ;
else if (obj1 instanceof List && obj2 instanceof List)
return equalLists( counterpart, considered,
(List)obj1, (List)obj2 ) ;
else if (obj1 instanceof boolean[] && obj2 instanceof boolean[])
return Arrays.equals( (boolean[])obj1, (boolean[])obj2 ) ;
else if (obj1 instanceof byte[] && obj2 instanceof byte[])
return Arrays.equals( (byte[])obj1, (byte[])obj2 ) ;
else if (obj1 instanceof char[] && obj2 instanceof char[])
return Arrays.equals( (char[])obj1, (char[])obj2 ) ;
else if (obj1 instanceof double[] && obj2 instanceof double[])
return Arrays.equals( (double[])obj1, (double[])obj2 ) ;
else if (obj1 instanceof float[] && obj2 instanceof float[])
return Arrays.equals( (float[])obj1, (float[])obj2 ) ;
else if (obj1 instanceof int[] && obj2 instanceof int[])
return Arrays.equals( (int[])obj1, (int[])obj2 ) ;
else if (obj1 instanceof long[] && obj2 instanceof long[])
return Arrays.equals( (long[])obj1, (long[])obj2 ) ;
else {
Class cls = obj1.getClass() ;
if (cls != obj2.getClass())
return obj1.equals( obj2 ) ;
else
return equalsObject( counterpart, considered, cls, obj1, obj2 ) ;
}
}
private static boolean equalsObject( Map counterpart, Set considered,
Class cls, java.lang.Object obj1, java.lang.Object obj2 )
{
Class objectClass = java.lang.Object.class ;
if (cls == objectClass)
return true ;
Class[] equalsTypes = { objectClass } ;
try {
Method equalsMethod = cls.getDeclaredMethod( "equals",
equalsTypes ) ;
return obj1.equals( obj2 ) ;
} catch (Exception exc) {
if (equalsObjectFields( counterpart, considered,
cls, obj1, obj2 ))
return equalsObject( counterpart, considered,
cls.getSuperclass(), obj1, obj2 ) ;
else
return false ;
}
}
private static boolean equalsObjectFields( Map counterpart, Set considered,
Class cls, java.lang.Object obj1, java.lang.Object obj2 )
{
Field[] fields = cls.getDeclaredFields() ;
for (int ctr=0; ctr<fields.length; ctr++) {
try {
final Field field = fields[ctr] ;
// Ignore static fields
if (!Modifier.isStatic( field.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
field.setAccessible( true ) ;
return null ;
}
} ) ;
java.lang.Object value1 = field.get( obj1 ) ;
java.lang.Object value2 = field.get( obj2 ) ;
if (!equalsHelper( counterpart, considered, value1,
value2 ))
return false ;
}
} catch (IllegalAccessException exc) {
return false ;
}
}
return true ;
}
private static boolean equalArrays( Map counterpart, Set considered,
java.lang.Object[] arr1, java.lang.Object[] arr2 )
{
int len = arr1.length ;
if (len != arr2.length)
return false ;
for (int ctr = 0; ctr<len; ctr++ )
if (!equalsHelper( counterpart, considered, arr1[ctr], arr2[ctr] ))
return false ;
return true ;
}
private static boolean equalMaps( Map counterpart, Set considered,
Map map1, Map map2 )
{
if (map2.size() != map1.size())
return false;
try {
Iterator i = map1.entrySet().iterator();
while (i.hasNext()) {
Entry e = (Entry) i.next();
java.lang.Object key = e.getKey();
java.lang.Object value = e.getValue();
if (value == null) {
if (!(map2.get(key)==null && map2.containsKey(key)))
return false;
} else {
if (!equalsHelper( counterpart, considered,
value, map2.get(key)))
return false;
}
}
} catch(ClassCastException unused) {
return false;
} catch(NullPointerException unused) {
return false;
}
return true;
}
// Obviously this is an inefficient quadratic algorithm.
// This is taken pretty directly from AbstractSet and AbstractCollection
// in the JDK.
// For HashSet, an O(n) (with a good hash function) algorithm
// is possible, and likewise TreeSet, since it is
// ordered, is O(n). But this is not worth the effort here.
// Note that the inner loop uses equals, not equalsHelper.
// This is needed because of the searching behavior of this test.
// However, note that this will NOT correctly handle sets that
// contain themselves as members, or that have members that reference
// themselves. These cases will cause infinite regress!
private static boolean equalSets( Map counterpart, Set considered,
Set set1, Set set2 )
{
if (set1.size() != set2.size())
return false ;
Iterator e1 = set1.iterator() ;
while (e1.hasNext()) {
java.lang.Object obj1 = e1.next() ;
boolean found = false ;
Iterator e2 = set2.iterator() ;
while (e2.hasNext() && !found) {
java.lang.Object obj2 = e2.next() ;
found = equals( obj1, obj2 ) ;
}
if (!found)
return false ;
}
return true ;
}
private static boolean equalLists( Map counterpart, Set considered,
List list1, List list2 )
{
ListIterator e1 = list1.listIterator();
ListIterator e2 = list2.listIterator();
while(e1.hasNext() && e2.hasNext()) {
java.lang.Object o1 = e1.next();
java.lang.Object o2 = e2.next();
if (!(o1==null ? o2==null : equalsHelper(
counterpart, considered, o1, o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -33,14 +33,7 @@ import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey; import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.INTERNAL;
import com.sun.corba.se.pept.broker.Broker; import com.sun.corba.se.pept.broker.Broker;
import com.sun.corba.se.pept.encoding.InputObject; import com.sun.corba.se.pept.encoding.InputObject;
@ -61,18 +54,12 @@ import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ; import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion ; import com.sun.corba.se.spi.ior.iiop.GIOPVersion ;
import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent; import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent;
import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.monitoring.LongMonitoredAttributeBase;
import com.sun.corba.se.spi.monitoring.MonitoringConstants;
import com.sun.corba.se.spi.monitoring.MonitoringFactories;
import com.sun.corba.se.spi.monitoring.MonitoredObject;
import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orbutil.threadpool.Work; import com.sun.corba.se.spi.orbutil.threadpool.Work;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator; import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.transport.CorbaAcceptor; import com.sun.corba.se.spi.transport.CorbaAcceptor;
import com.sun.corba.se.spi.transport.CorbaConnection; import com.sun.corba.se.spi.transport.CorbaConnection;
import com.sun.corba.se.spi.transport.CorbaContactInfo;
import com.sun.corba.se.spi.transport.SocketInfo; import com.sun.corba.se.spi.transport.SocketInfo;
import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor; import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;
@ -82,7 +69,6 @@ import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.oa.poa.Policies; // REVISIT impl/poa specific import com.sun.corba.se.impl.oa.poa.Policies; // REVISIT impl/poa specific
import com.sun.corba.se.impl.orbutil.ORBConstants; import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.ORBUtility; import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.ior.iiop.JavaSerializationComponent;
// BEGIN Legacy support. // BEGIN Legacy support.
import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo; import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
@ -442,12 +428,7 @@ public class SocketOrChannelAcceptorImpl
dprint(".doWork->: " + this); dprint(".doWork->: " + this);
} }
if (selectionKey.isAcceptable()) { if (selectionKey.isAcceptable()) {
AccessController.doPrivileged(new PrivilegedAction() {
public java.lang.Object run() {
accept(); accept();
return null;
}
});
} else { } else {
if (orb.transportDebugFlag) { if (orb.transportDebugFlag) {
dprint(".doWork: ! selectionKey.isAcceptable: " + this); dprint(".doWork: ! selectionKey.isAcceptable: " + this);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package com.sun.corba.se.spi.orb ; package com.sun.corba.se.spi.orb ;
import java.util.StringTokenizer ; import java.util.StringTokenizer ;
import java.util.Arrays ;
import java.lang.reflect.Array ; import java.lang.reflect.Array ;
@ -446,7 +447,7 @@ public abstract class OperationFactory {
public String toString() { public String toString() {
return "sequenceAction(separator=\"" + sep + return "sequenceAction(separator=\"" + sep +
"\",actions=" + "\",actions=" +
ObjectUtility.compactObjectToString(actions) + ")" ; Arrays.toString(actions) + ")" ;
} }
} }
@ -533,7 +534,7 @@ public abstract class OperationFactory {
public String toString() { public String toString() {
return "mapSequenceAction(" + return "mapSequenceAction(" +
ObjectUtility.compactObjectToString(op) + ")" ; Arrays.toString(op) + ")" ;
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -125,7 +125,7 @@ public abstract class ParserImplBase {
// Since exc wraps the actual exception, use exc.getCause() // Since exc wraps the actual exception, use exc.getCause()
// instead of exc. // instead of exc.
throw wrapper.errorSettingField( exc.getCause(), name, throw wrapper.errorSettingField( exc.getCause(), name,
ObjectUtility.compactObjectToString(value) ) ; value.toString() ) ;
} }
} }

View file

@ -125,3 +125,9 @@ cc4bb3022b3144dc5db0805b9ef6c7eff2aa3b81 jdk7-b109
beef35b96b81129c375d572357fb9548d9020db1 jdk7-b113 beef35b96b81129c375d572357fb9548d9020db1 jdk7-b113
68d6141ea19de3a9ba98ef753f0da41a61f736a0 jdk7-b114 68d6141ea19de3a9ba98ef753f0da41a61f736a0 jdk7-b114
5511edd5d719f3fc9fdd04879482026a3d2c8652 hs20-b01 5511edd5d719f3fc9fdd04879482026a3d2c8652 hs20-b01
bdbc48857210a509b3c50a3291ecb9dd6a72e016 jdk7-b115
96b3f2a7add0b445b8aa421f6823cff5a2e2fe03 jdk7-b116
52f19c724d9634af79044a2e0defbe4a5f1adbda hs20-b02
806d0c037e6bbb88dac0699673f4ba55ee8c02da jdk7-b117
698b7b727e12de44139d8cca6ab9a494ead13253 jdk7-b118
3ef7426b4deac5dcfd4afb35cabe9ab3d666df91 hs20-b02

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -188,7 +188,7 @@ public class BytecodeLoadConstant extends BytecodeWithCPIndex {
} else { } else {
throw new RuntimeException("should not reach here"); throw new RuntimeException("should not reach here");
} }
} else if (ctag.isMethodHandle() || ctag.isMethodType()) { } else if (ctag.isMethodHandle()) {
Oop x = getCachedConstant(); Oop x = getCachedConstant();
int refidx = cpool.getMethodHandleIndexAt(cpIndex); int refidx = cpool.getMethodHandleIndexAt(cpIndex);
int refkind = cpool.getMethodHandleRefKindAt(cpIndex); int refkind = cpool.getMethodHandleRefKindAt(cpIndex);

View file

@ -53,11 +53,19 @@ public class ConstantPool extends Oop implements ClassConstants {
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("constantPoolOopDesc"); Type type = db.lookupType("constantPoolOopDesc");
tags = new OopField(type.getOopField("_tags"), 0); tags = new OopField(type.getOopField("_tags"), 0);
operands = new OopField(type.getOopField("_operands"), 0);
cache = new OopField(type.getOopField("_cache"), 0); cache = new OopField(type.getOopField("_cache"), 0);
poolHolder = new OopField(type.getOopField("_pool_holder"), 0); poolHolder = new OopField(type.getOopField("_pool_holder"), 0);
length = new CIntField(type.getCIntegerField("_length"), 0); length = new CIntField(type.getCIntegerField("_length"), 0);
headerSize = type.getSize(); headerSize = type.getSize();
elementSize = 0; elementSize = 0;
// fetch constants:
MULTI_OPERAND_COUNT_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_multi_operand_count_offset").intValue();
MULTI_OPERAND_BASE_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_multi_operand_base_offset").intValue();
INDY_BSM_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_bsm_offset").intValue();
INDY_NT_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_nt_offset").intValue();
INDY_ARGC_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argc_offset").intValue();
INDY_ARGV_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argv_offset").intValue();
} }
ConstantPool(OopHandle handle, ObjectHeap heap) { ConstantPool(OopHandle handle, ObjectHeap heap) {
@ -67,6 +75,7 @@ public class ConstantPool extends Oop implements ClassConstants {
public boolean isConstantPool() { return true; } public boolean isConstantPool() { return true; }
private static OopField tags; private static OopField tags;
private static OopField operands;
private static OopField cache; private static OopField cache;
private static OopField poolHolder; private static OopField poolHolder;
private static CIntField length; // number of elements in oop private static CIntField length; // number of elements in oop
@ -74,7 +83,15 @@ public class ConstantPool extends Oop implements ClassConstants {
private static long headerSize; private static long headerSize;
private static long elementSize; private static long elementSize;
private static int MULTI_OPERAND_COUNT_OFFSET;
private static int MULTI_OPERAND_BASE_OFFSET;
private static int INDY_BSM_OFFSET;
private static int INDY_NT_OFFSET;
private static int INDY_ARGC_OFFSET;
private static int INDY_ARGV_OFFSET;
public TypeArray getTags() { return (TypeArray) tags.getValue(this); } public TypeArray getTags() { return (TypeArray) tags.getValue(this); }
public TypeArray getOperands() { return (TypeArray) operands.getValue(this); }
public ConstantPoolCache getCache() { return (ConstantPoolCache) cache.getValue(this); } public ConstantPoolCache getCache() { return (ConstantPoolCache) cache.getValue(this); }
public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); } public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); }
public int getLength() { return (int)length.getValue(this); } public int getLength() { return (int)length.getValue(this); }
@ -278,6 +295,25 @@ public class ConstantPool extends Oop implements ClassConstants {
return res; return res;
} }
/** Lookup for multi-operand (InvokeDynamic) entries. */
public int[] getMultiOperandsAt(int i) {
if (Assert.ASSERTS_ENABLED) {
Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
}
int pos = this.getIntAt(i);
int countPos = pos + MULTI_OPERAND_COUNT_OFFSET; // == pos-1
int basePos = pos + MULTI_OPERAND_BASE_OFFSET; // == pos
if (countPos < 0) return null; // safety first
TypeArray operands = getOperands();
if (operands == null) return null; // safety first
int length = operands.getIntAt(countPos);
int[] values = new int[length];
for (int j = 0; j < length; j++) {
values[j] = operands.getIntAt(basePos+j);
}
return values;
}
final private static String[] nameForTag = new String[] { final private static String[] nameForTag = new String[] {
}; };
@ -522,15 +558,20 @@ public class ConstantPool extends Oop implements ClassConstants {
case JVM_CONSTANT_InvokeDynamic: { case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType); dos.writeByte(cpConstType);
int value = getIntAt(ci); int[] values = getMultiOperandsAt(ci);
short bootstrapMethodIndex = (short) extractLowShortFromInt(value); for (int vn = 0; vn < values.length; vn++) {
short nameAndTypeIndex = (short) extractHighShortFromInt(value); dos.writeShort(values[vn]);
dos.writeShort(bootstrapMethodIndex); }
dos.writeShort(nameAndTypeIndex); int bootstrapMethodIndex = values[INDY_BSM_OFFSET];
int nameAndTypeIndex = values[INDY_NT_OFFSET];
int argumentCount = values[INDY_ARGC_OFFSET];
assert(INDY_ARGV_OFFSET + argumentCount == values.length);
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex
+ ", N&T = " + nameAndTypeIndex); + ", N&T = " + nameAndTypeIndex
+ ", argc = " + argumentCount);
break; break;
} }
default: default:
throw new InternalError("unknown tag: " + cpConstType); throw new InternalError("unknown tag: " + cpConstType);
} // switch } // switch

View file

@ -42,7 +42,8 @@ public interface ClassConstants
public static final int JVM_CONSTANT_NameAndType = 12; public static final int JVM_CONSTANT_NameAndType = 12;
public static final int JVM_CONSTANT_MethodHandle = 15; public static final int JVM_CONSTANT_MethodHandle = 15;
public static final int JVM_CONSTANT_MethodType = 16; public static final int JVM_CONSTANT_MethodType = 16;
public static final int JVM_CONSTANT_InvokeDynamic = 17; public static final int JVM_CONSTANT_InvokeDynamicTrans = 17; // only occurs in old class files
public static final int JVM_CONSTANT_InvokeDynamic = 18;
// JVM_CONSTANT_MethodHandle subtypes // JVM_CONSTANT_MethodHandle subtypes
public static final int JVM_REF_getField = 1; public static final int JVM_REF_getField = 1;

View file

@ -303,12 +303,12 @@ public class ClassWriter implements /* imports */ ClassConstants
case JVM_CONSTANT_MethodHandle: { case JVM_CONSTANT_MethodHandle: {
dos.writeByte(cpConstType); dos.writeByte(cpConstType);
int value = cpool.getIntAt(ci); int value = cpool.getIntAt(ci);
short bootstrapMethodIndex = (short) extractLowShortFromInt(value); byte refKind = (byte) extractLowShortFromInt(value);
short nameAndTypeIndex = (short) extractHighShortFromInt(value); short memberIndex = (short) extractHighShortFromInt(value);
dos.writeShort(bootstrapMethodIndex); dos.writeByte(refKind);
dos.writeShort(nameAndTypeIndex); dos.writeShort(memberIndex);
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " +
bootstrapMethodIndex + ", N&T = " + nameAndTypeIndex); refKind + ", mem = " + memberIndex);
break; break;
} }
@ -323,10 +323,11 @@ public class ClassWriter implements /* imports */ ClassConstants
case JVM_CONSTANT_InvokeDynamic: { case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType); dos.writeByte(cpConstType);
int value = cpool.getIntAt(ci); int[] values = cpool.getMultiOperandsAt(ci);
short refIndex = (short) value; for (int vn = 0; vn < values.length; vn++) {
dos.writeShort(refIndex); dos.writeShort(values[vn]);
if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex); }
if (DEBUG) debugMessage("CP[" + ci + "] = INDY indexes = " + Arrays.toString(values));
break; break;
} }

View file

@ -460,6 +460,18 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
return buf.toString(); return buf.toString();
} }
private String genListOfShort(int[] values) {
Formatter buf = new Formatter(genHTML);
buf.append('[');
for (int i = 0; i < values.length; i++) {
if (i > 0) buf.append(' ');
buf.append('#');
buf.append(Integer.toString(values[i]));
}
buf.append(']');
return buf.toString();
}
protected String genHTMLTableForConstantPool(ConstantPool cpool) { protected String genHTMLTableForConstantPool(ConstantPool cpool) {
Formatter buf = new Formatter(genHTML); Formatter buf = new Formatter(genHTML);
buf.beginTable(1); buf.beginTable(1);
@ -584,7 +596,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_InvokeDynamic:
buf.cell("JVM_CONSTANT_InvokeDynamic"); buf.cell("JVM_CONSTANT_InvokeDynamic");
buf.cell(genLowHighShort(cpool.getIntAt(index))); buf.cell(genListOfShort(cpool.getMultiOperandsAt(index)));
break; break;
default: default:

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -40,7 +40,8 @@ public class ConstantTag {
private static int JVM_CONSTANT_NameAndType = 12; private static int JVM_CONSTANT_NameAndType = 12;
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292 private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
private static int JVM_CONSTANT_MethodType = 16; // JSR 292 private static int JVM_CONSTANT_MethodType = 16; // JSR 292
private static int JVM_CONSTANT_InvokeDynamic = 17; // JSR 292 // static int JVM_CONSTANT_InvokeDynamicTrans = 17; // JSR 292, only occurs in old class files
private static int JVM_CONSTANT_InvokeDynamic = 18; // JSR 292
private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization
private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use
private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool

View file

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2010
HS_MAJOR_VER=20 HS_MAJOR_VER=20
HS_MINOR_VER=0 HS_MINOR_VER=0
HS_BUILD_NUMBER=02 HS_BUILD_NUMBER=03
JDK_MAJOR_VER=1 JDK_MAJOR_VER=1
JDK_MINOR_VER=7 JDK_MINOR_VER=7

View file

@ -62,7 +62,9 @@ endif
include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make
ifndef CC_INTERP ifndef CC_INTERP
FORCE_TIERED=1 ifndef FORCE_TIERED
FORCE_TIERED=1
endif
endif endif
ifdef LP64 ifdef LP64
@ -254,7 +256,7 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
$(BUILDTREE) VARIANT=tiered $(BUILDTREE) VARIANT=tiered
$(SUBDIRS_C2): $(BUILDTREE_MAKE) $(SUBDIRS_C2): $(BUILDTREE_MAKE)
ifdef FORCE_TIERED ifeq ($(FORCE_TIERED),1)
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
else else

View file

@ -53,7 +53,9 @@ endif
include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make
ifndef CC_INTERP ifndef CC_INTERP
FORCE_TIERED=1 ifndef FORCE_TIERED
FORCE_TIERED=1
endif
endif endif
ifdef LP64 ifdef LP64
@ -210,7 +212,7 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
$(BUILDTREE) VARIANT=tiered $(BUILDTREE) VARIANT=tiered
$(SUBDIRS_C2): $(BUILDTREE_MAKE) $(SUBDIRS_C2): $(BUILDTREE_MAKE)
ifdef FORCE_TIERED ifeq ($(FORCE_TIERED),1)
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
else else

View file

@ -74,9 +74,11 @@ BUILDARCH=ia64
!if "$(BUILDARCH)" != "ia64" !if "$(BUILDARCH)" != "ia64"
!ifndef CC_INTERP !ifndef CC_INTERP
!ifndef FORCE_TIERED
FORCE_TIERED=1 FORCE_TIERED=1
!endif !endif
!endif !endif
!endif
!if "$(BUILDARCH)" == "amd64" !if "$(BUILDARCH)" == "amd64"
Platform_arch=x86 Platform_arch=x86
@ -100,7 +102,7 @@ VARIANT_TEXT=Core
!if "$(Variant)" == "compiler1" !if "$(Variant)" == "compiler1"
VARIANT_TEXT=Client VARIANT_TEXT=Client
!elseif "$(Variant)" == "compiler2" !elseif "$(Variant)" == "compiler2"
!ifdef FORCE_TIERED !if "$(FORCE_TIERED)" == "1"
VARIANT_TEXT=Server VARIANT_TEXT=Server
realVariant=tiered realVariant=tiered
!else !else

View file

@ -1126,7 +1126,7 @@ public:
inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none); inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec); inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec);
inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0); inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
inline void add(const Address& a, Register d, int offset = 0) { add( a.base(), a.disp() + offset, d, a.rspec(offset)); } inline void add(const Address& a, Register d, int offset = 0);
void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -206,6 +206,11 @@ inline void Assembler::ld( Register s1, RegisterOrConstant s2, Register d) { ld
inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); } inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); }
// form effective addresses this way: // form effective addresses this way:
inline void Assembler::add(const Address& a, Register d, int offset) {
if (a.has_index()) add(a.base(), a.index(), d);
else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; }
if (offset != 0) add(d, offset, d);
}
inline void Assembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) { inline void Assembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) {
if (s2.is_register()) add(s1, s2.as_register(), d); if (s2.is_register()) add(s1, s2.as_register(), d);
else { add(s1, s2.as_constant() + offset, d); offset = 0; } else { add(s1, s2.as_constant() + offset, d); offset = 0; }

View file

@ -70,17 +70,29 @@ MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _mas
// Code generation // Code generation
address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
// I5_savedSP: sender SP (must preserve) // I5_savedSP/O5_savedSP: sender SP (must preserve)
// G4 (Gargs): incoming argument list (must preserve) // G4 (Gargs): incoming argument list (must preserve)
// G5_method: invoke methodOop; becomes method type. // G5_method: invoke methodOop
// G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots]) // G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots])
// O0, O1: garbage temps, blown away // O0, O1, O2, O3, O4: garbage temps, blown away
Register O0_argslot = O0; Register O0_mtype = O0;
Register O1_scratch = O1; Register O1_scratch = O1;
Register O2_scratch = O2;
Register O3_scratch = O3;
Register O4_argslot = O4;
Register O4_argbase = O4;
// emit WrongMethodType path first, to enable back-branch from main path // emit WrongMethodType path first, to enable back-branch from main path
Label wrong_method_type; Label wrong_method_type;
__ bind(wrong_method_type); __ bind(wrong_method_type);
Label invoke_generic_slow_path;
assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");;
__ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch);
__ cmp(O1_scratch, (int) vmIntrinsics::_invokeExact);
__ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path);
__ delayed()->nop();
__ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType
// mov(G3_method_handle, G3_method_handle); // already in this register
__ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch);
__ delayed()->nop(); __ delayed()->nop();
@ -88,23 +100,74 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
__ align(CodeEntryAlignment); __ align(CodeEntryAlignment);
address entry_point = __ pc(); address entry_point = __ pc();
// fetch the MethodType from the method handle into G5_method_type // fetch the MethodType from the method handle
{ {
Register tem = G5_method; Register tem = G5_method;
assert(tem == G5_method_type, "yes, it's the same register");
for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
__ ld_ptr(Address(tem, *pchase), G5_method_type); __ ld_ptr(Address(tem, *pchase), O0_mtype);
tem = O0_mtype; // in case there is another indirection
} }
} }
// given the MethodType, find out where the MH argument is buried // given the MethodType, find out where the MH argument is buried
__ load_heap_oop(Address(G5_method_type, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot); __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O4_argslot);
__ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot); __ ldsw( Address(O4_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O4_argslot);
__ ld_ptr(__ argument_address(O0_argslot), G3_method_handle); __ add(Gargs, __ argument_offset(O4_argslot, 1), O4_argbase);
// Note: argument_address uses its input as a scratch register!
__ ld_ptr(Address(O4_argbase, -Interpreter::stackElementSize), G3_method_handle);
__ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type); trace_method_handle(_masm, "invokeExact");
__ check_method_handle_type(O0_mtype, G3_method_handle, O1_scratch, wrong_method_type);
__ jump_to_method_handle_entry(G3_method_handle, O1_scratch); __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
// for invokeGeneric (only), apply argument and result conversions on the fly
__ bind(invoke_generic_slow_path);
#ifdef ASSERT
{ Label L;
__ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch);
__ cmp(O1_scratch, (int) vmIntrinsics::_invokeGeneric);
__ brx(Assembler::equal, false, Assembler::pt, L);
__ delayed()->nop();
__ stop("bad methodOop::intrinsic_id");
__ bind(L);
}
#endif //ASSERT
// make room on the stack for another pointer:
insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, O4_argbase, O1_scratch, O2_scratch, O3_scratch);
// load up an adapter from the calling type (Java weaves this)
Register O2_form = O2_scratch;
Register O3_adapter = O3_scratch;
__ load_heap_oop(Address(O0_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O2_form);
// load_heap_oop(Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
// deal with old JDK versions:
__ add( Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
__ cmp(O3_adapter, O2_form);
Label sorry_no_invoke_generic;
__ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic);
__ delayed()->nop();
__ load_heap_oop(Address(O3_adapter, 0), O3_adapter);
__ tst(O3_adapter);
__ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic);
__ delayed()->nop();
__ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize));
// As a trusted first argument, pass the type being called, so the adapter knows
// the actual types of the arguments and return values.
// (Generic invokers are shared among form-families of method-type.)
__ st_ptr(O0_mtype, Address(O4_argbase, 0 * Interpreter::stackElementSize));
// FIXME: assert that O3_adapter is of the right method-type.
__ mov(O3_adapter, G3_method_handle);
trace_method_handle(_masm, "invokeGeneric");
__ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
__ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available!
__ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType
// mov(G3_method_handle, G3_method_handle); // already in this register
__ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch);
__ delayed()->nop();
return entry_point; return entry_point;
} }
@ -630,10 +693,16 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
switch (ek) { switch (ek) {
case _adapter_opt_i2i: case _adapter_opt_i2i:
case _adapter_opt_l2i:
__ unimplemented(entry_name(ek));
value = vmarg; value = vmarg;
break; break;
case _adapter_opt_l2i:
{
// just delete the extra slot
__ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch);
value = vmarg = Address(O0_argslot, 0);
}
break;
case _adapter_opt_unboxi: case _adapter_opt_unboxi:
{ {
// Load the value up from the heap. // Load the value up from the heap.

View file

@ -1843,6 +1843,12 @@ bool Matcher::is_spillable_arg( int reg ) {
return can_be_java_arg(reg); return can_be_java_arg(reg);
} }
bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
// Use hardware SDIVX instruction when it is
// faster than a code which use multiply.
return VM_Version::has_fast_idiv();
}
// Register for DIVI projection of divmodI // Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() { RegMask Matcher::divI_proj_mask() {
ShouldNotReachHere(); ShouldNotReachHere();
@ -9510,16 +9516,16 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
Register Rdst = $dst$$Register; Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register; Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register; Register Rtmp = $tmp$$Register;
__ srl(Rsrc, 1, Rtmp); __ srl(Rsrc, 1, Rtmp);
__ srl(Rsrc, 0, Rdst); __ srl(Rsrc, 0, Rdst);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 2, Rtmp); __ srl(Rdst, 2, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 4, Rtmp); __ srl(Rdst, 4, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 8, Rtmp); __ srl(Rdst, 8, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 16, Rtmp); __ srl(Rdst, 16, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ popc(Rdst, Rdst); __ popc(Rdst, Rdst);
__ mov(BitsPerInt, Rtmp); __ mov(BitsPerInt, Rtmp);
@ -9528,7 +9534,7 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
ins_pipe(ialu_reg); ins_pipe(ialu_reg);
%} %}
instruct countLeadingZerosL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{ instruct countLeadingZerosL(iRegIsafe dst, iRegL src, iRegL tmp, flagsReg cr) %{
predicate(UsePopCountInstruction); // See Matcher::match_rule_supported predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
match(Set dst (CountLeadingZerosL src)); match(Set dst (CountLeadingZerosL src));
effect(TEMP dst, TEMP tmp, KILL cr); effect(TEMP dst, TEMP tmp, KILL cr);
@ -9559,18 +9565,18 @@ instruct countLeadingZerosL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{
Register Rdst = $dst$$Register; Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register; Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register; Register Rtmp = $tmp$$Register;
__ srlx(Rsrc, 1, Rtmp); __ srlx(Rsrc, 1, Rtmp);
__ or3(Rsrc, Rtmp, Rdst); __ or3( Rsrc, Rtmp, Rdst);
__ srlx(Rdst, 2, Rtmp); __ srlx(Rdst, 2, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3( Rdst, Rtmp, Rdst);
__ srlx(Rdst, 4, Rtmp); __ srlx(Rdst, 4, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3( Rdst, Rtmp, Rdst);
__ srlx(Rdst, 8, Rtmp); __ srlx(Rdst, 8, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3( Rdst, Rtmp, Rdst);
__ srlx(Rdst, 16, Rtmp); __ srlx(Rdst, 16, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3( Rdst, Rtmp, Rdst);
__ srlx(Rdst, 32, Rtmp); __ srlx(Rdst, 32, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3( Rdst, Rtmp, Rdst);
__ popc(Rdst, Rdst); __ popc(Rdst, Rdst);
__ mov(BitsPerLong, Rtmp); __ mov(BitsPerLong, Rtmp);
__ sub(Rtmp, Rdst, Rdst); __ sub(Rtmp, Rdst, Rdst);

View file

@ -341,6 +341,26 @@ void TemplateTable::fast_aldc(bool wide) {
resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1)); resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1));
__ verify_oop(Otos_i); __ verify_oop(Otos_i);
Label L_done;
const Register Rcon_klass = G3_scratch; // same as Rcache
const Register Rarray_klass = G4_scratch; // same as Rscratch
__ load_klass(Otos_i, Rcon_klass);
AddressLiteral array_klass_addr((address)Universe::systemObjArrayKlassObj_addr());
__ load_contents(array_klass_addr, Rarray_klass);
__ cmp(Rarray_klass, Rcon_klass);
__ brx(Assembler::notEqual, false, Assembler::pt, L_done);
__ delayed()->nop();
__ ld(Address(Otos_i, arrayOopDesc::length_offset_in_bytes()), Rcon_klass);
__ tst(Rcon_klass);
__ brx(Assembler::zero, true, Assembler::pt, L_done);
__ delayed()->clr(Otos_i); // executed only if branch is taken
// Load the exception from the system-array which wraps it:
__ load_heap_oop(Otos_i, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i);
__ throw_if_not_x(Assembler::never, Interpreter::throw_exception_entry(), G3_scratch);
__ bind(L_done);
} }
void TemplateTable::ldc2_w() { void TemplateTable::ldc2_w() {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -80,7 +80,8 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); FLAG_SET_DEFAULT(InteriorEntryAlignment, 4);
} }
if (is_niagara1_plus()) { if (is_niagara1_plus()) {
if (AllocatePrefetchStyle > 0 && FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { if (has_blk_init() && AllocatePrefetchStyle > 0 &&
FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
// Use BIS instruction for allocation prefetch. // Use BIS instruction for allocation prefetch.
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
@ -118,16 +119,18 @@ void VM_Version::initialize() {
#endif #endif
char buf[512]; char buf[512];
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s", jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v8() ? ", has_v8" : ""), (has_v8() ? ", has_v8" : ""),
(has_v9() ? ", has_v9" : ""), (has_v9() ? ", has_v9" : ""),
(has_hardware_popc() ? ", popc" : ""), (has_hardware_popc() ? ", popc" : ""),
(has_vis1() ? ", has_vis1" : ""), (has_vis1() ? ", has_vis1" : ""),
(has_vis2() ? ", has_vis2" : ""), (has_vis2() ? ", has_vis2" : ""),
(has_blk_init() ? ", has_blk_init" : ""),
(is_ultra3() ? ", is_ultra3" : ""), (is_ultra3() ? ", is_ultra3" : ""),
(is_sun4v() ? ", is_sun4v" : ""), (is_sun4v() ? ", is_sun4v" : ""),
(is_niagara1() ? ", is_niagara1" : ""), (is_niagara1() ? ", is_niagara1" : ""),
(is_niagara1_plus() ? ", is_niagara1_plus" : ""), (is_niagara1_plus() ? ", is_niagara1_plus" : ""),
(is_sparc64() ? ", is_sparc64" : ""),
(!has_hardware_mul32() ? ", no-mul32" : ""), (!has_hardware_mul32() ? ", no-mul32" : ""),
(!has_hardware_div32() ? ", no-div32" : ""), (!has_hardware_div32() ? ", no-div32" : ""),
(!has_hardware_fsmuld() ? ", no-fsmuld" : "")); (!has_hardware_fsmuld() ? ", no-fsmuld" : ""));

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -33,7 +33,9 @@ protected:
v9_instructions = 5, v9_instructions = 5,
vis1_instructions = 6, vis1_instructions = 6,
vis2_instructions = 7, vis2_instructions = 7,
sun4v_instructions = 8 sun4v_instructions = 8,
blk_init_instructions = 9,
fmaf_instructions = 10
}; };
enum Feature_Flag_Set { enum Feature_Flag_Set {
@ -49,6 +51,8 @@ protected:
vis1_instructions_m = 1 << vis1_instructions, vis1_instructions_m = 1 << vis1_instructions,
vis2_instructions_m = 1 << vis2_instructions, vis2_instructions_m = 1 << vis2_instructions,
sun4v_m = 1 << sun4v_instructions, sun4v_m = 1 << sun4v_instructions,
blk_init_instructions_m = 1 << blk_init_instructions,
fmaf_instructions_m = 1 << fmaf_instructions,
generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m,
generic_v9_m = generic_v8_m | v9_instructions_m, generic_v9_m = generic_v8_m | v9_instructions_m,
@ -67,6 +71,7 @@ protected:
static int platform_features(int features); static int platform_features(int features);
static bool is_niagara1(int features) { return (features & sun4v_m) != 0; } static bool is_niagara1(int features) { return (features & sun4v_m) != 0; }
static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; }
static int maximum_niagara1_processor_count() { return 32; } static int maximum_niagara1_processor_count() { return 32; }
// Returns true if the platform is in the niagara line and // Returns true if the platform is in the niagara line and
@ -86,6 +91,7 @@ public:
static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; } static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; }
static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; }
static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; }
static bool has_blk_init() { return (_features & blk_init_instructions_m) != 0; }
static bool supports_compare_and_exchange() static bool supports_compare_and_exchange()
{ return has_v9(); } { return has_v9(); }
@ -93,8 +99,10 @@ public:
static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; } static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; }
static bool is_sun4v() { return (_features & sun4v_m) != 0; } static bool is_sun4v() { return (_features & sun4v_m) != 0; }
static bool is_niagara1() { return is_niagara1(_features); } static bool is_niagara1() { return is_niagara1(_features); }
static bool is_sparc64() { return is_sparc64(_features); }
static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); } static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); }
static bool has_fast_idiv() { return is_niagara1_plus() || is_sparc64(); }
static const char* cpu_features() { return _features_str; } static const char* cpu_features() { return _features_str; }

View file

@ -1275,6 +1275,12 @@ void Assembler::idivl(Register src) {
emit_byte(0xF8 | encode); emit_byte(0xF8 | encode);
} }
void Assembler::divl(Register src) { // Unsigned
int encode = prefix_and_encode(src->encoding());
emit_byte(0xF7);
emit_byte(0xF0 | encode);
}
void Assembler::imull(Register dst, Register src) { void Assembler::imull(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding()); int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F); emit_byte(0x0F);
@ -1288,7 +1294,7 @@ void Assembler::imull(Register dst, Register src, int value) {
if (is8bit(value)) { if (is8bit(value)) {
emit_byte(0x6B); emit_byte(0x6B);
emit_byte(0xC0 | encode); emit_byte(0xC0 | encode);
emit_byte(value); emit_byte(value & 0xFF);
} else { } else {
emit_byte(0x69); emit_byte(0x69);
emit_byte(0xC0 | encode); emit_byte(0xC0 | encode);
@ -3903,7 +3909,7 @@ void Assembler::imulq(Register dst, Register src, int value) {
if (is8bit(value)) { if (is8bit(value)) {
emit_byte(0x6B); emit_byte(0x6B);
emit_byte(0xC0 | encode); emit_byte(0xC0 | encode);
emit_byte(value); emit_byte(value & 0xFF);
} else { } else {
emit_byte(0x69); emit_byte(0x69);
emit_byte(0xC0 | encode); emit_byte(0xC0 | encode);

View file

@ -1011,6 +1011,7 @@ private:
void hlt(); void hlt();
void idivl(Register src); void idivl(Register src);
void divl(Register src); // Unsigned division
void idivq(Register src); void idivq(Register src);

View file

@ -399,6 +399,23 @@ void TemplateTable::fast_aldc(bool wide) {
if (VerifyOops) { if (VerifyOops) {
__ verify_oop(rax); __ verify_oop(rax);
} }
Label L_done, L_throw_exception;
const Register con_klass_temp = rcx; // same as Rcache
__ movptr(con_klass_temp, Address(rax, oopDesc::klass_offset_in_bytes()));
__ cmpptr(con_klass_temp, ExternalAddress((address)Universe::systemObjArrayKlassObj_addr()));
__ jcc(Assembler::notEqual, L_done);
__ cmpl(Address(rax, arrayOopDesc::length_offset_in_bytes()), 0);
__ jcc(Assembler::notEqual, L_throw_exception);
__ xorptr(rax, rax);
__ jmp(L_done);
// Load the exception from the system-array which wraps it:
__ bind(L_throw_exception);
__ movptr(rax, Address(rax, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
__ jump(ExternalAddress(Interpreter::throw_exception_entry()));
__ bind(L_done);
} }
void TemplateTable::ldc2_w() { void TemplateTable::ldc2_w() {

View file

@ -413,6 +413,25 @@ void TemplateTable::fast_aldc(bool wide) {
if (VerifyOops) { if (VerifyOops) {
__ verify_oop(rax); __ verify_oop(rax);
} }
Label L_done, L_throw_exception;
const Register con_klass_temp = rcx; // same as cache
const Register array_klass_temp = rdx; // same as index
__ movptr(con_klass_temp, Address(rax, oopDesc::klass_offset_in_bytes()));
__ lea(array_klass_temp, ExternalAddress((address)Universe::systemObjArrayKlassObj_addr()));
__ cmpptr(con_klass_temp, Address(array_klass_temp, 0));
__ jcc(Assembler::notEqual, L_done);
__ cmpl(Address(rax, arrayOopDesc::length_offset_in_bytes()), 0);
__ jcc(Assembler::notEqual, L_throw_exception);
__ xorptr(rax, rax);
__ jmp(L_done);
// Load the exception from the system-array which wraps it:
__ bind(L_throw_exception);
__ movptr(rax, Address(rax, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
__ jump(ExternalAddress(Interpreter::throw_exception_entry()));
__ bind(L_done);
} }
void TemplateTable::ldc2_w() { void TemplateTable::ldc2_w() {

View file

@ -446,6 +446,10 @@ public:
static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; } static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; }
static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; } static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; }
// Intel Core and newer cpus have fast IDIV instruction (excluding Atom).
static bool has_fast_idiv() { return is_intel() && cpu_family() == 6 &&
supports_sse3() && _model != 0x1C; }
static bool supports_compare_and_exchange() { return true; } static bool supports_compare_and_exchange() { return true; }
static const char* cpu_features() { return _features_str; } static const char* cpu_features() { return _features_str; }

View file

@ -1508,6 +1508,16 @@ bool Matcher::is_spillable_arg( int reg ) {
return can_be_java_arg(reg); return can_be_java_arg(reg);
} }
bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
// Use hardware integer DIV instruction when
// it is faster than a code which use multiply.
// Only when constant divisor fits into 32 bit
// (min_jint is excluded to get only correct
// positive 32 bit values from negative).
return VM_Version::has_fast_idiv() &&
(divisor == (int)divisor && divisor != min_jint);
}
// Register for DIVI projection of divmodI // Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() { RegMask Matcher::divI_proj_mask() {
return EAX_REG_mask; return EAX_REG_mask;
@ -1546,6 +1556,9 @@ bool is_operand_hi32_zero(Node* n) {
return true; return true;
} }
} }
if (opc == Op_ConL && (n->get_long() & 0xFFFFFFFF00000000LL) == 0LL) {
return true;
}
return false; return false;
} }
@ -2309,9 +2322,11 @@ encode %{
enc_class move_long_big_shift_sign( eRegL dst, immI_32_63 cnt ) %{ enc_class move_long_big_shift_sign( eRegL dst, immI_32_63 cnt ) %{
emit_opcode( cbuf, 0x8B ); // Move emit_opcode( cbuf, 0x8B ); // Move
emit_rm(cbuf, 0x3, $dst$$reg, HIGH_FROM_LOW($dst$$reg)); emit_rm(cbuf, 0x3, $dst$$reg, HIGH_FROM_LOW($dst$$reg));
emit_d8(cbuf,$primary); if( $cnt$$constant > 32 ) { // Shift, if not by zero
emit_rm(cbuf, 0x3, $secondary, $dst$$reg); emit_d8(cbuf,$primary);
emit_d8(cbuf,$cnt$$constant-32); emit_rm(cbuf, 0x3, $secondary, $dst$$reg);
emit_d8(cbuf,$cnt$$constant-32);
}
emit_d8(cbuf,$primary); emit_d8(cbuf,$primary);
emit_rm(cbuf, 0x3, $secondary, HIGH_FROM_LOW($dst$$reg)); emit_rm(cbuf, 0x3, $secondary, HIGH_FROM_LOW($dst$$reg));
emit_d8(cbuf,31); emit_d8(cbuf,31);
@ -8842,6 +8857,144 @@ instruct modL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI
ins_pipe( pipe_slow ); ins_pipe( pipe_slow );
%} %}
// Divide Register Long (no special case since divisor != -1)
instruct divL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlagsReg cr ) %{
match(Set dst (DivL dst imm));
effect( TEMP tmp, TEMP tmp2, KILL cr );
ins_cost(1000);
format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t"
"XOR $tmp2,$tmp2\n\t"
"CMP $tmp,EDX\n\t"
"JA,s fast\n\t"
"MOV $tmp2,EAX\n\t"
"MOV EAX,EDX\n\t"
"MOV EDX,0\n\t"
"JLE,s pos\n\t"
"LNEG EAX : $tmp2\n\t"
"DIV $tmp # unsigned division\n\t"
"XCHG EAX,$tmp2\n\t"
"DIV $tmp\n\t"
"LNEG $tmp2 : EAX\n\t"
"JMP,s done\n"
"pos:\n\t"
"DIV $tmp\n\t"
"XCHG EAX,$tmp2\n"
"fast:\n\t"
"DIV $tmp\n"
"done:\n\t"
"MOV EDX,$tmp2\n\t"
"NEG EDX:EAX # if $imm < 0" %}
ins_encode %{
int con = (int)$imm$$constant;
assert(con != 0 && con != -1 && con != min_jint, "wrong divisor");
int pcon = (con > 0) ? con : -con;
Label Lfast, Lpos, Ldone;
__ movl($tmp$$Register, pcon);
__ xorl($tmp2$$Register,$tmp2$$Register);
__ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register));
__ jccb(Assembler::above, Lfast); // result fits into 32 bit
__ movl($tmp2$$Register, $dst$$Register); // save
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags
__ jccb(Assembler::lessEqual, Lpos); // result is positive
// Negative dividend.
// convert value to positive to use unsigned division
__ lneg($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
__ xchgl($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
// revert result back to negative
__ lneg($tmp2$$Register, $dst$$Register);
__ jmpb(Ldone);
__ bind(Lpos);
__ divl($tmp$$Register); // Use unsigned division
__ xchgl($dst$$Register, $tmp2$$Register);
// Fallthrow for final divide, tmp2 has 32 bit hi result
__ bind(Lfast);
// fast path: src is positive
__ divl($tmp$$Register); // Use unsigned division
__ bind(Ldone);
__ movl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register);
if (con < 0) {
__ lneg(HIGH_FROM_LOW($dst$$Register), $dst$$Register);
}
%}
ins_pipe( pipe_slow );
%}
// Remainder Register Long (remainder fit into 32 bits)
instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlagsReg cr ) %{
match(Set dst (ModL dst imm));
effect( TEMP tmp, TEMP tmp2, KILL cr );
ins_cost(1000);
format %{ "MOV $tmp,abs($imm) # lrem EDX:EAX,$imm\n\t"
"CMP $tmp,EDX\n\t"
"JA,s fast\n\t"
"MOV $tmp2,EAX\n\t"
"MOV EAX,EDX\n\t"
"MOV EDX,0\n\t"
"JLE,s pos\n\t"
"LNEG EAX : $tmp2\n\t"
"DIV $tmp # unsigned division\n\t"
"MOV EAX,$tmp2\n\t"
"DIV $tmp\n\t"
"NEG EDX\n\t"
"JMP,s done\n"
"pos:\n\t"
"DIV $tmp\n\t"
"MOV EAX,$tmp2\n"
"fast:\n\t"
"DIV $tmp\n"
"done:\n\t"
"MOV EAX,EDX\n\t"
"SAR EDX,31\n\t" %}
ins_encode %{
int con = (int)$imm$$constant;
assert(con != 0 && con != -1 && con != min_jint, "wrong divisor");
int pcon = (con > 0) ? con : -con;
Label Lfast, Lpos, Ldone;
__ movl($tmp$$Register, pcon);
__ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register));
__ jccb(Assembler::above, Lfast); // src is positive and result fits into 32 bit
__ movl($tmp2$$Register, $dst$$Register); // save
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags
__ jccb(Assembler::lessEqual, Lpos); // result is positive
// Negative dividend.
// convert value to positive to use unsigned division
__ lneg($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
__ movl($dst$$Register, $tmp2$$Register);
__ divl($tmp$$Register);
// revert remainder back to negative
__ negl(HIGH_FROM_LOW($dst$$Register));
__ jmpb(Ldone);
__ bind(Lpos);
__ divl($tmp$$Register);
__ movl($dst$$Register, $tmp2$$Register);
__ bind(Lfast);
// fast path: src is positive
__ divl($tmp$$Register);
__ bind(Ldone);
__ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register));
__ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign
%}
ins_pipe( pipe_slow );
%}
// Integer Shift Instructions // Integer Shift Instructions
// Shift Left by one // Shift Left by one
instruct shlI_eReg_1(eRegI dst, immI1 shift, eFlagsReg cr) %{ instruct shlI_eReg_1(eRegI dst, immI1 shift, eFlagsReg cr) %{

View file

@ -2065,6 +2065,13 @@ bool Matcher::is_spillable_arg(int reg)
return can_be_java_arg(reg); return can_be_java_arg(reg);
} }
bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
// In 64 bit mode a code which use multiply when
// devisor is constant is faster than hardware
// DIV instruction (it uses MulHiL).
return false;
}
// Register for DIVI projection of divmodI // Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() { RegMask Matcher::divI_proj_mask() {
return INT_RAX_REG_mask; return INT_RAX_REG_mask;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -200,6 +200,18 @@ void os::print_context(outputStream *st, void *context) {
sigcontext* sc = (sigcontext*)context; sigcontext* sc = (sigcontext*)context;
st->print_cr("Registers:"); st->print_cr("Registers:");
st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
" G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_G1],
SIG_REGS(sc).u_regs[CON_G2],
SIG_REGS(sc).u_regs[CON_G3],
SIG_REGS(sc).u_regs[CON_G4]);
st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT
" G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_G5],
SIG_REGS(sc).u_regs[CON_G6],
SIG_REGS(sc).u_regs[CON_G7],
SIG_REGS(sc).y);
st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT
" O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_O0], SIG_REGS(sc).u_regs[CON_O0],
@ -213,18 +225,32 @@ void os::print_context(outputStream *st, void *context) {
SIG_REGS(sc).u_regs[CON_O6], SIG_REGS(sc).u_regs[CON_O6],
SIG_REGS(sc).u_regs[CON_O7]); SIG_REGS(sc).u_regs[CON_O7]);
st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
" G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
SIG_REGS(sc).u_regs[CON_G1], st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
SIG_REGS(sc).u_regs[CON_G2], " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_G3], sp[L0->sp_offset_in_saved_window()],
SIG_REGS(sc).u_regs[CON_G4]); sp[L1->sp_offset_in_saved_window()],
st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT sp[L2->sp_offset_in_saved_window()],
" G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, sp[L3->sp_offset_in_saved_window()]);
SIG_REGS(sc).u_regs[CON_G5], st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
SIG_REGS(sc).u_regs[CON_G6], " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_G7], sp[L4->sp_offset_in_saved_window()],
SIG_REGS(sc).y); sp[L5->sp_offset_in_saved_window()],
sp[L6->sp_offset_in_saved_window()],
sp[L7->sp_offset_in_saved_window()]);
st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT
" I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT,
sp[I0->sp_offset_in_saved_window()],
sp[I1->sp_offset_in_saved_window()],
sp[I2->sp_offset_in_saved_window()],
sp[I3->sp_offset_in_saved_window()]);
st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT
" I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT,
sp[I4->sp_offset_in_saved_window()],
sp[I5->sp_offset_in_saved_window()],
sp[I6->sp_offset_in_saved_window()],
sp[I7->sp_offset_in_saved_window()]);
st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT,
SIG_PC(sc), SIG_PC(sc),
@ -232,7 +258,6 @@ void os::print_context(outputStream *st, void *context) {
st->cr(); st->cr();
st->cr(); st->cr();
intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp);
print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t));
st->cr(); st->cr();
@ -242,7 +267,58 @@ void os::print_context(outputStream *st, void *context) {
// this at the end, and hope for the best. // this at the end, and hope for the best.
address pc = os::Linux::ucontext_get_pc(uc); address pc = os::Linux::ucontext_get_pc(uc);
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
}
void os::print_register_info(outputStream *st, void *context) {
if (context == NULL) return;
ucontext_t *uc = (ucontext_t*)context;
intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print("G1="); print_location(st, SIG_REGS(sc).u_regs[CON__G1]);
st->print("G2="); print_location(st, SIG_REGS(sc).u_regs[CON__G2]);
st->print("G3="); print_location(st, SIG_REGS(sc).u_regs[CON__G3]);
st->print("G4="); print_location(st, SIG_REGS(sc).u_regs[CON__G4]);
st->print("G5="); print_location(st, SIG_REGS(sc).u_regs[CON__G5]);
st->print("G6="); print_location(st, SIG_REGS(sc).u_regs[CON__G6]);
st->print("G7="); print_location(st, SIG_REGS(sc).u_regs[CON__G7]);
st->cr();
st->print("O0="); print_location(st, SIG_REGS(sc).u_regs[CON__O0]);
st->print("O1="); print_location(st, SIG_REGS(sc).u_regs[CON__O1]);
st->print("O2="); print_location(st, SIG_REGS(sc).u_regs[CON__O2]);
st->print("O3="); print_location(st, SIG_REGS(sc).u_regs[CON__O3]);
st->print("O4="); print_location(st, SIG_REGS(sc).u_regs[CON__O4]);
st->print("O5="); print_location(st, SIG_REGS(sc).u_regs[CON__O5]);
st->print("O6="); print_location(st, SIG_REGS(sc).u_regs[CON__O6]);
st->print("O7="); print_location(st, SIG_REGS(sc).u_regs[CON__O7]);
st->cr();
st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]);
st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]);
st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]);
st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]);
st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]);
st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]);
st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]);
st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]);
st->cr();
st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]);
st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]);
st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]);
st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]);
st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]);
st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]);
st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]);
st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]);
st->cr();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -718,11 +718,6 @@ void os::print_context(outputStream *st, void *context) {
ucontext_t *uc = (ucontext_t*)context; ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Registers:"); st->print_cr("Registers:");
// this is horrendously verbose but the layout of the registers in the
// context does not match how we defined our abstract Register set, so
// we can't just iterate through the gregs area
#ifdef AMD64 #ifdef AMD64
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
@ -745,68 +740,11 @@ void os::print_context(outputStream *st, void *context) {
st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
st->cr(); st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
st->print(", EFL=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]); st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]);
st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]); st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]);
st->cr(); st->cr();
st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]); st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
print_location(st, uc->uc_mcontext.gregs[REG_RAX]);
st->cr();
st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
print_location(st, uc->uc_mcontext.gregs[REG_RBX]);
st->cr();
st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]);
print_location(st, uc->uc_mcontext.gregs[REG_RCX]);
st->cr();
st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]);
print_location(st, uc->uc_mcontext.gregs[REG_RDX]);
st->cr();
st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]);
print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
st->cr();
st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]);
print_location(st, uc->uc_mcontext.gregs[REG_RBP]);
st->cr();
st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
print_location(st, uc->uc_mcontext.gregs[REG_RSI]);
st->cr();
st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
print_location(st, uc->uc_mcontext.gregs[REG_RDI]);
st->cr();
st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
print_location(st, uc->uc_mcontext.gregs[REG_R8]);
st->cr();
st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
print_location(st, uc->uc_mcontext.gregs[REG_R9]);
st->cr();
st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
print_location(st, uc->uc_mcontext.gregs[REG_R10]);
st->cr();
st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
print_location(st, uc->uc_mcontext.gregs[REG_R11]);
st->cr();
st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
print_location(st, uc->uc_mcontext.gregs[REG_R12]);
st->cr();
st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
print_location(st, uc->uc_mcontext.gregs[REG_R13]);
st->cr();
st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
print_location(st, uc->uc_mcontext.gregs[REG_R14]);
st->cr();
st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
print_location(st, uc->uc_mcontext.gregs[REG_R15]);
#else #else
st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]);
st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]);
@ -819,41 +757,8 @@ void os::print_context(outputStream *st, void *context) {
st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]); st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]);
st->cr(); st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]);
st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]);
print_location(st, uc->uc_mcontext.gregs[REG_EAX]);
st->cr();
st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]);
print_location(st, uc->uc_mcontext.gregs[REG_EBX]);
st->cr();
st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]);
print_location(st, uc->uc_mcontext.gregs[REG_ECX]);
st->cr();
st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]);
print_location(st, uc->uc_mcontext.gregs[REG_EDX]);
st->cr();
st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESP]);
print_location(st, uc->uc_mcontext.gregs[REG_ESP]);
st->cr();
st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]);
print_location(st, uc->uc_mcontext.gregs[REG_EBP]);
st->cr();
st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]);
print_location(st, uc->uc_mcontext.gregs[REG_ESI]);
st->cr();
st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]);
print_location(st, uc->uc_mcontext.gregs[REG_EDI]);
#endif // AMD64 #endif // AMD64
st->cr(); st->cr();
st->cr(); st->cr();
@ -868,7 +773,52 @@ void os::print_context(outputStream *st, void *context) {
// this at the end, and hope for the best. // this at the end, and hope for the best.
address pc = os::Linux::ucontext_get_pc(uc); address pc = os::Linux::ucontext_get_pc(uc);
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
}
void os::print_register_info(outputStream *st, void *context) {
if (context == NULL) return;
ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Register to memory mapping:");
st->cr();
// this is horrendously verbose but the layout of the registers in the
// context does not match how we defined our abstract Register set, so
// we can't just iterate through the gregs area
// this is only for the "general purpose" registers
#ifdef AMD64
st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]);
st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]);
st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]);
st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]);
st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]);
st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]);
st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]);
st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]);
st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]);
st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]);
st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]);
st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]);
st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]);
st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]);
st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]);
#else
st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[REG_EAX]);
st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[REG_EBX]);
st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[REG_ECX]);
st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[REG_EDX]);
st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[REG_ESP]);
st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[REG_EBP]);
st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[REG_ESI]);
st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[REG_EDI]);
#endif // AMD64
st->cr();
} }
void os::setup_fpu() { void os::setup_fpu() {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -540,6 +540,11 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
pc = (address) uc->uc_mcontext.gregs[REG_PC]; pc = (address) uc->uc_mcontext.gregs[REG_PC];
} }
// Sometimes the register windows are not properly flushed.
if(uc->uc_mcontext.gwins != NULL) {
::handle_unflushed_register_windows(uc->uc_mcontext.gwins);
}
// unmask current signal // unmask current signal
sigset_t newset; sigset_t newset;
sigemptyset(&newset); sigemptyset(&newset);
@ -558,6 +563,18 @@ void os::print_context(outputStream *st, void *context) {
ucontext_t *uc = (ucontext_t*)context; ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Registers:"); st->print_cr("Registers:");
st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
" G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_G1],
uc->uc_mcontext.gregs[REG_G2],
uc->uc_mcontext.gregs[REG_G3],
uc->uc_mcontext.gregs[REG_G4]);
st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT
" G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_G5],
uc->uc_mcontext.gregs[REG_G6],
uc->uc_mcontext.gregs[REG_G7],
uc->uc_mcontext.gregs[REG_Y]);
st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT
" O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_O0], uc->uc_mcontext.gregs[REG_O0],
@ -571,81 +588,39 @@ void os::print_context(outputStream *st, void *context) {
uc->uc_mcontext.gregs[REG_O6], uc->uc_mcontext.gregs[REG_O6],
uc->uc_mcontext.gregs[REG_O7]); uc->uc_mcontext.gregs[REG_O7]);
st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
" G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
uc->uc_mcontext.gregs[REG_G1], st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
uc->uc_mcontext.gregs[REG_G2], " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_G3], sp[L0->sp_offset_in_saved_window()],
uc->uc_mcontext.gregs[REG_G4]); sp[L1->sp_offset_in_saved_window()],
st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT sp[L2->sp_offset_in_saved_window()],
" G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, sp[L3->sp_offset_in_saved_window()]);
uc->uc_mcontext.gregs[REG_G5], st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
uc->uc_mcontext.gregs[REG_G6], " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_G7], sp[L4->sp_offset_in_saved_window()],
uc->uc_mcontext.gregs[REG_Y]); sp[L5->sp_offset_in_saved_window()],
sp[L6->sp_offset_in_saved_window()],
sp[L7->sp_offset_in_saved_window()]);
st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT
" I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT,
sp[I0->sp_offset_in_saved_window()],
sp[I1->sp_offset_in_saved_window()],
sp[I2->sp_offset_in_saved_window()],
sp[I3->sp_offset_in_saved_window()]);
st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT
" I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT,
sp[I4->sp_offset_in_saved_window()],
sp[I5->sp_offset_in_saved_window()],
sp[I6->sp_offset_in_saved_window()],
sp[I7->sp_offset_in_saved_window()]);
st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_PC], uc->uc_mcontext.gregs[REG_PC],
uc->uc_mcontext.gregs[REG_nPC]); uc->uc_mcontext.gregs[REG_nPC]);
st->cr(); st->cr();
st->cr(); st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("O0=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O0]);
print_location(st, uc->uc_mcontext.gregs[REG_O0]);
st->cr();
st->print_cr("O1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O1]);
print_location(st, uc->uc_mcontext.gregs[REG_O1]);
st->cr();
st->print_cr("O2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O2]);
print_location(st, uc->uc_mcontext.gregs[REG_O2]);
st->cr();
st->print_cr("O3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O3]);
print_location(st, uc->uc_mcontext.gregs[REG_O3]);
st->cr();
st->print_cr("O4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O4]);
print_location(st, uc->uc_mcontext.gregs[REG_O4]);
st->cr();
st->print_cr("O5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O5]);
print_location(st, uc->uc_mcontext.gregs[REG_O5]);
st->cr();
st->print_cr("O6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O6]);
print_location(st, uc->uc_mcontext.gregs[REG_O6]);
st->cr();
st->print_cr("O7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O7]);
print_location(st, uc->uc_mcontext.gregs[REG_O7]);
st->cr();
st->print_cr("G1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G1]);
print_location(st, uc->uc_mcontext.gregs[REG_G1]);
st->cr();
st->print_cr("G2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G2]);
print_location(st, uc->uc_mcontext.gregs[REG_G2]);
st->cr();
st->print_cr("G3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G3]);
print_location(st, uc->uc_mcontext.gregs[REG_G3]);
st->cr();
st->print_cr("G4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G4]);
print_location(st, uc->uc_mcontext.gregs[REG_G4]);
st->cr();
st->print_cr("G5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G5]);
print_location(st, uc->uc_mcontext.gregs[REG_G5]);
st->cr();
st->print_cr("G6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G6]);
print_location(st, uc->uc_mcontext.gregs[REG_G6]);
st->cr();
st->print_cr("G7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G7]);
print_location(st, uc->uc_mcontext.gregs[REG_G7]);
st->cr();
st->cr();
intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp);
print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t));
st->cr(); st->cr();
@ -656,7 +631,57 @@ void os::print_context(outputStream *st, void *context) {
ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc);
address pc = epc.pc(); address pc = epc.pc();
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
}
void os::print_register_info(outputStream *st, void *context) {
if (context == NULL) return;
ucontext_t *uc = (ucontext_t*)context;
intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print("G1="); print_location(st, uc->uc_mcontext.gregs[REG_G1]);
st->print("G2="); print_location(st, uc->uc_mcontext.gregs[REG_G2]);
st->print("G3="); print_location(st, uc->uc_mcontext.gregs[REG_G3]);
st->print("G4="); print_location(st, uc->uc_mcontext.gregs[REG_G4]);
st->print("G5="); print_location(st, uc->uc_mcontext.gregs[REG_G5]);
st->print("G6="); print_location(st, uc->uc_mcontext.gregs[REG_G6]);
st->print("G7="); print_location(st, uc->uc_mcontext.gregs[REG_G7]);
st->cr();
st->print("O0="); print_location(st, uc->uc_mcontext.gregs[REG_O0]);
st->print("O1="); print_location(st, uc->uc_mcontext.gregs[REG_O1]);
st->print("O2="); print_location(st, uc->uc_mcontext.gregs[REG_O2]);
st->print("O3="); print_location(st, uc->uc_mcontext.gregs[REG_O3]);
st->print("O4="); print_location(st, uc->uc_mcontext.gregs[REG_O4]);
st->print("O5="); print_location(st, uc->uc_mcontext.gregs[REG_O5]);
st->print("O6="); print_location(st, uc->uc_mcontext.gregs[REG_O6]);
st->print("O7="); print_location(st, uc->uc_mcontext.gregs[REG_O7]);
st->cr();
st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]);
st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]);
st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]);
st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]);
st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]);
st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]);
st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]);
st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]);
st->cr();
st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]);
st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]);
st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]);
st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]);
st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]);
st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]);
st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]);
st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]);
st->cr();
} }
void os::Solaris::init_thread_fpu_state(void) { void os::Solaris::init_thread_fpu_state(void) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -65,10 +65,6 @@ int VM_Version::platform_features(int features) {
// getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are
// supported on Solaris 10 and later. // supported on Solaris 10 and later.
if (os::Solaris::supports_getisax()) { if (os::Solaris::supports_getisax()) {
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose)
tty->print_cr("getisax(2) supported.");
#endif
// Check 32-bit architecture. // Check 32-bit architecture.
do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m);
@ -81,6 +77,11 @@ int VM_Version::platform_features(int features) {
uint_t avn = os::Solaris::getisax(&av, 1); uint_t avn = os::Solaris::getisax(&av, 1);
assert(avn == 1, "should only return one av"); assert(avn == 1, "should only return one av");
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose)
tty->print_cr("getisax(2) returned: " PTR32_FORMAT, av);
#endif
if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; if (av & AV_SPARC_MUL32) features |= hardware_mul32_m;
if (av & AV_SPARC_DIV32) features |= hardware_div32_m; if (av & AV_SPARC_DIV32) features |= hardware_div32_m;
if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
@ -88,11 +89,22 @@ int VM_Version::platform_features(int features) {
if (av & AV_SPARC_POPC) features |= hardware_popc_m; if (av & AV_SPARC_POPC) features |= hardware_popc_m;
if (av & AV_SPARC_VIS) features |= vis1_instructions_m; if (av & AV_SPARC_VIS) features |= vis1_instructions_m;
if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; if (av & AV_SPARC_VIS2) features |= vis2_instructions_m;
// Next values are not defined before Solaris 10
// but Solaris 8 is used for jdk6 update builds.
#ifndef AV_SPARC_ASI_BLK_INIT
#define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */
#endif
#ifndef AV_SPARC_FMAF
#define AV_SPARC_FMAF 0x0100 /* Sparc64 Fused Multiply-Add */
#endif
if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m;
if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m;
} else { } else {
// getisax(2) failed, use the old legacy code. // getisax(2) failed, use the old legacy code.
#ifndef PRODUCT #ifndef PRODUCT
if (PrintMiscellaneous && Verbose) if (PrintMiscellaneous && Verbose)
tty->print_cr("getisax(2) not supported."); tty->print_cr("getisax(2) is not supported.");
#endif #endif
char tmp; char tmp;

View file

@ -719,11 +719,6 @@ void os::print_context(outputStream *st, void *context) {
ucontext_t *uc = (ucontext_t*)context; ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Registers:"); st->print_cr("Registers:");
// this is horrendously verbose but the layout of the registers in the
// context does not match how we defined our abstract Register set, so
// we can't just iterate through the gregs area
#ifdef AMD64 #ifdef AMD64
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
@ -735,8 +730,8 @@ void os::print_context(outputStream *st, void *context) {
st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
st->cr(); st->cr();
st->print( "R8=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
st->print(", R9=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
st->cr(); st->cr();
@ -747,63 +742,6 @@ void os::print_context(outputStream *st, void *context) {
st->cr(); st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
print_location(st, uc->uc_mcontext.gregs[REG_RAX]);
st->cr();
st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
print_location(st, uc->uc_mcontext.gregs[REG_RBX]);
st->cr();
st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]);
print_location(st, uc->uc_mcontext.gregs[REG_RCX]);
st->cr();
st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]);
print_location(st, uc->uc_mcontext.gregs[REG_RDX]);
st->cr();
st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]);
print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
st->cr();
st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]);
print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
st->cr();
st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
print_location(st, uc->uc_mcontext.gregs[REG_RSI]);
st->cr();
st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
print_location(st, uc->uc_mcontext.gregs[REG_RDI]);
st->cr();
st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
print_location(st, uc->uc_mcontext.gregs[REG_R8]);
st->cr();
st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
print_location(st, uc->uc_mcontext.gregs[REG_R9]);
st->cr();
st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
print_location(st, uc->uc_mcontext.gregs[REG_R10]);
st->cr();
st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
print_location(st, uc->uc_mcontext.gregs[REG_R11]);
st->cr();
st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
print_location(st, uc->uc_mcontext.gregs[REG_R12]);
st->cr();
st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
print_location(st, uc->uc_mcontext.gregs[REG_R13]);
st->cr();
st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
print_location(st, uc->uc_mcontext.gregs[REG_R14]);
st->cr();
st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
print_location(st, uc->uc_mcontext.gregs[REG_R15]);
#else #else
st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]);
st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]);
@ -817,39 +755,6 @@ void os::print_context(outputStream *st, void *context) {
st->cr(); st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]);
st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]);
print_location(st, uc->uc_mcontext.gregs[EAX]);
st->cr();
st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]);
print_location(st, uc->uc_mcontext.gregs[EBX]);
st->cr();
st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]);
print_location(st, uc->uc_mcontext.gregs[ECX]);
st->cr();
st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]);
print_location(st, uc->uc_mcontext.gregs[EDX]);
st->cr();
st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]);
print_location(st, uc->uc_mcontext.gregs[UESP]);
st->cr();
st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]);
print_location(st, uc->uc_mcontext.gregs[EBP]);
st->cr();
st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]);
print_location(st, uc->uc_mcontext.gregs[ESI]);
st->cr();
st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]);
print_location(st, uc->uc_mcontext.gregs[EDI]);
#endif // AMD64 #endif // AMD64
st->cr(); st->cr();
st->cr(); st->cr();
@ -865,7 +770,52 @@ void os::print_context(outputStream *st, void *context) {
ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc);
address pc = epc.pc(); address pc = epc.pc();
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
}
void os::print_register_info(outputStream *st, void *context) {
if (context == NULL) return;
ucontext_t *uc = (ucontext_t*)context;
st->print_cr("Register to memory mapping:");
st->cr();
// this is horrendously verbose but the layout of the registers in the
// context does not match how we defined our abstract Register set, so
// we can't just iterate through the gregs area
// this is only for the "general purpose" registers
#ifdef AMD64
st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]);
st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]);
st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]);
st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]);
st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]);
st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]);
st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]);
st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]);
st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]);
st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]);
st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]);
st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]);
st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]);
st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]);
st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]);
#else
st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[EAX]);
st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[EBX]);
st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[ECX]);
st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[EDX]);
st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[UESP]);
st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[EBP]);
st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[ESI]);
st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[EDI]);
#endif
st->cr();
} }

View file

@ -387,8 +387,8 @@ void os::print_context(outputStream *st, void *context) {
st->print(", RSI=" INTPTR_FORMAT, uc->Rsi); st->print(", RSI=" INTPTR_FORMAT, uc->Rsi);
st->print(", RDI=" INTPTR_FORMAT, uc->Rdi); st->print(", RDI=" INTPTR_FORMAT, uc->Rdi);
st->cr(); st->cr();
st->print( "R8=" INTPTR_FORMAT, uc->R8); st->print( "R8 =" INTPTR_FORMAT, uc->R8);
st->print(", R9=" INTPTR_FORMAT, uc->R9); st->print(", R9 =" INTPTR_FORMAT, uc->R9);
st->print(", R10=" INTPTR_FORMAT, uc->R10); st->print(", R10=" INTPTR_FORMAT, uc->R10);
st->print(", R11=" INTPTR_FORMAT, uc->R11); st->print(", R11=" INTPTR_FORMAT, uc->R11);
st->cr(); st->cr();
@ -399,62 +399,6 @@ void os::print_context(outputStream *st, void *context) {
st->cr(); st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->Rip); st->print( "RIP=" INTPTR_FORMAT, uc->Rip);
st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("RAX=" INTPTR_FORMAT, uc->Rax);
print_location(st, uc->Rax);
st->cr();
st->print_cr("RBX=" INTPTR_FORMAT, uc->Rbx);
print_location(st, uc->Rbx);
st->cr();
st->print_cr("RCX=" INTPTR_FORMAT, uc->Rcx);
print_location(st, uc->Rcx);
st->cr();
st->print_cr("RDX=" INTPTR_FORMAT, uc->Rdx);
print_location(st, uc->Rdx);
st->cr();
st->print_cr("RSP=" INTPTR_FORMAT, uc->Rsp);
print_location(st, uc->Rsp);
st->cr();
st->print_cr("RBP=" INTPTR_FORMAT, uc->Rbp);
print_location(st, uc->Rbp);
st->cr();
st->print_cr("RSI=" INTPTR_FORMAT, uc->Rsi);
print_location(st, uc->Rsi);
st->cr();
st->print_cr("RDI=" INTPTR_FORMAT, uc->Rdi);
print_location(st, uc->Rdi);
st->cr();
st->print_cr("R8 =" INTPTR_FORMAT, uc->R8);
print_location(st, uc->R8);
st->cr();
st->print_cr("R9 =" INTPTR_FORMAT, uc->R9);
print_location(st, uc->R9);
st->cr();
st->print_cr("R10=" INTPTR_FORMAT, uc->R10);
print_location(st, uc->R10);
st->cr();
st->print_cr("R11=" INTPTR_FORMAT, uc->R11);
print_location(st, uc->R11);
st->cr();
st->print_cr("R12=" INTPTR_FORMAT, uc->R12);
print_location(st, uc->R12);
st->cr();
st->print_cr("R13=" INTPTR_FORMAT, uc->R13);
print_location(st, uc->R13);
st->cr();
st->print_cr("R14=" INTPTR_FORMAT, uc->R14);
print_location(st, uc->R14);
st->cr();
st->print_cr("R15=" INTPTR_FORMAT, uc->R15);
print_location(st, uc->R15);
#else #else
st->print( "EAX=" INTPTR_FORMAT, uc->Eax); st->print( "EAX=" INTPTR_FORMAT, uc->Eax);
st->print(", EBX=" INTPTR_FORMAT, uc->Ebx); st->print(", EBX=" INTPTR_FORMAT, uc->Ebx);
@ -468,38 +412,6 @@ void os::print_context(outputStream *st, void *context) {
st->cr(); st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->Eip); st->print( "EIP=" INTPTR_FORMAT, uc->Eip);
st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);
st->cr();
st->cr();
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
st->print_cr("EAX=" INTPTR_FORMAT, uc->Eax);
print_location(st, uc->Eax);
st->cr();
st->print_cr("EBX=" INTPTR_FORMAT, uc->Ebx);
print_location(st, uc->Ebx);
st->cr();
st->print_cr("ECX=" INTPTR_FORMAT, uc->Ecx);
print_location(st, uc->Ecx);
st->cr();
st->print_cr("EDX=" INTPTR_FORMAT, uc->Edx);
print_location(st, uc->Edx);
st->cr();
st->print_cr("ESP=" INTPTR_FORMAT, uc->Esp);
print_location(st, uc->Esp);
st->cr();
st->print_cr("EBP=" INTPTR_FORMAT, uc->Ebp);
print_location(st, uc->Ebp);
st->cr();
st->print_cr("ESI=" INTPTR_FORMAT, uc->Esi);
print_location(st, uc->Esi);
st->cr();
st->print_cr("EDI=" INTPTR_FORMAT, uc->Edi);
print_location(st, uc->Edi);
#endif // AMD64 #endif // AMD64
st->cr(); st->cr();
st->cr(); st->cr();
@ -514,7 +426,49 @@ void os::print_context(outputStream *st, void *context) {
// this at the end, and hope for the best. // this at the end, and hope for the best.
address pc = (address)uc->REG_PC; address pc = (address)uc->REG_PC;
st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc);
print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
st->cr();
}
void os::print_register_info(outputStream *st, void *context) {
if (context == NULL) return;
CONTEXT* uc = (CONTEXT*)context;
st->print_cr("Register to memory mapping:");
st->cr();
// this is only for the "general purpose" registers
#ifdef AMD64
st->print("RAX="); print_location(st, uc->Rax);
st->print("RBX="); print_location(st, uc->Rbx);
st->print("RCX="); print_location(st, uc->Rcx);
st->print("RDX="); print_location(st, uc->Rdx);
st->print("RSP="); print_location(st, uc->Rsp);
st->print("RBP="); print_location(st, uc->Rbp);
st->print("RSI="); print_location(st, uc->Rsi);
st->print("RDI="); print_location(st, uc->Rdi);
st->print("R8 ="); print_location(st, uc->R8);
st->print("R9 ="); print_location(st, uc->R9);
st->print("R10="); print_location(st, uc->R10);
st->print("R11="); print_location(st, uc->R11);
st->print("R12="); print_location(st, uc->R12);
st->print("R13="); print_location(st, uc->R13);
st->print("R14="); print_location(st, uc->R14);
st->print("R15="); print_location(st, uc->R15);
#else
st->print("EAX="); print_location(st, uc->Eax);
st->print("EBX="); print_location(st, uc->Ebx);
st->print("ECX="); print_location(st, uc->Ecx);
st->print("EDX="); print_location(st, uc->Edx);
st->print("ESP="); print_location(st, uc->Esp);
st->print("EBP="); print_location(st, uc->Ebp);
st->print("ESI="); print_location(st, uc->Esi);
st->print("EDI="); print_location(st, uc->Edi);
#endif
st->cr(); st->cr();
} }

View file

@ -178,15 +178,11 @@ class Compilation: public StackObj {
return (int) NMethodSizeLimit; // default 256K or 512K return (int) NMethodSizeLimit; // default 256K or 512K
#else #else
// conditional branches on PPC are restricted to 16 bit signed // conditional branches on PPC are restricted to 16 bit signed
return MAX2((unsigned int)NMethodSizeLimit,32*K); return MIN2((unsigned int)NMethodSizeLimit,32*K);
#endif #endif
} }
static int desired_max_constant_size() { static int desired_max_constant_size() {
#ifndef PPC return desired_max_code_buffer_size() / 10;
return (int) NMethodSizeLimit / 10; // about 25K
#else
return (MAX2((unsigned int)NMethodSizeLimit, 32*K)) / 10;
#endif
} }
static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate); static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate);

View file

@ -321,7 +321,7 @@ class UseCountComputer: public ValueVisitor, BlockClosure {
void visit(Value* n) { void visit(Value* n) {
// Local instructions and Phis for expression stack values at the // Local instructions and Phis for expression stack values at the
// start of basic blocks are not added to the instruction list // start of basic blocks are not added to the instruction list
if (!(*n)->is_linked()&& (*n)->can_be_linked()) { if (!(*n)->is_linked() && (*n)->can_be_linked()) {
assert(false, "a node was not appended to the graph"); assert(false, "a node was not appended to the graph");
Compilation::current()->bailout("a node was not appended to the graph"); Compilation::current()->bailout("a node was not appended to the graph");
} }

View file

@ -415,28 +415,26 @@ bool Constant::is_equal(Value v) const {
return false; return false;
} }
Constant::CompareResult Constant::compare(Instruction::Condition cond, Value right) const {
BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
BlockBegin* true_sux, BlockBegin* false_sux) {
Constant* rc = right->as_Constant(); Constant* rc = right->as_Constant();
// other is not a constant // other is not a constant
if (rc == NULL) return NULL; if (rc == NULL) return not_comparable;
ValueType* lt = type(); ValueType* lt = type();
ValueType* rt = rc->type(); ValueType* rt = rc->type();
// different types // different types
if (lt->base() != rt->base()) return NULL; if (lt->base() != rt->base()) return not_comparable;
switch (lt->tag()) { switch (lt->tag()) {
case intTag: { case intTag: {
int x = lt->as_IntConstant()->value(); int x = lt->as_IntConstant()->value();
int y = rt->as_IntConstant()->value(); int y = rt->as_IntConstant()->value();
switch (cond) { switch (cond) {
case If::eql: return x == y ? true_sux : false_sux; case If::eql: return x == y ? cond_true : cond_false;
case If::neq: return x != y ? true_sux : false_sux; case If::neq: return x != y ? cond_true : cond_false;
case If::lss: return x < y ? true_sux : false_sux; case If::lss: return x < y ? cond_true : cond_false;
case If::leq: return x <= y ? true_sux : false_sux; case If::leq: return x <= y ? cond_true : cond_false;
case If::gtr: return x > y ? true_sux : false_sux; case If::gtr: return x > y ? cond_true : cond_false;
case If::geq: return x >= y ? true_sux : false_sux; case If::geq: return x >= y ? cond_true : cond_false;
} }
break; break;
} }
@ -444,12 +442,12 @@ BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
jlong x = lt->as_LongConstant()->value(); jlong x = lt->as_LongConstant()->value();
jlong y = rt->as_LongConstant()->value(); jlong y = rt->as_LongConstant()->value();
switch (cond) { switch (cond) {
case If::eql: return x == y ? true_sux : false_sux; case If::eql: return x == y ? cond_true : cond_false;
case If::neq: return x != y ? true_sux : false_sux; case If::neq: return x != y ? cond_true : cond_false;
case If::lss: return x < y ? true_sux : false_sux; case If::lss: return x < y ? cond_true : cond_false;
case If::leq: return x <= y ? true_sux : false_sux; case If::leq: return x <= y ? cond_true : cond_false;
case If::gtr: return x > y ? true_sux : false_sux; case If::gtr: return x > y ? cond_true : cond_false;
case If::geq: return x >= y ? true_sux : false_sux; case If::geq: return x >= y ? cond_true : cond_false;
} }
break; break;
} }
@ -459,14 +457,14 @@ BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
assert(xvalue != NULL && yvalue != NULL, "not constants"); assert(xvalue != NULL && yvalue != NULL, "not constants");
if (xvalue->is_loaded() && yvalue->is_loaded()) { if (xvalue->is_loaded() && yvalue->is_loaded()) {
switch (cond) { switch (cond) {
case If::eql: return xvalue == yvalue ? true_sux : false_sux; case If::eql: return xvalue == yvalue ? cond_true : cond_false;
case If::neq: return xvalue != yvalue ? true_sux : false_sux; case If::neq: return xvalue != yvalue ? cond_true : cond_false;
} }
} }
break; break;
} }
} }
return NULL; return not_comparable;
} }

View file

@ -443,7 +443,7 @@ class Instruction: public CompilationResourceObj {
// generic // generic
virtual Instruction* as_Instruction() { return this; } // to satisfy HASHING1 macro virtual Instruction* as_Instruction() { return this; } // to satisfy HASHING1 macro
virtual Phi* as_Phi() { return NULL; } virtual Phi* as_Phi() { return NULL; }
virtual Local* as_Local() { return NULL; } virtual Local* as_Local() { return NULL; }
virtual Constant* as_Constant() { return NULL; } virtual Constant* as_Constant() { return NULL; }
virtual AccessField* as_AccessField() { return NULL; } virtual AccessField* as_AccessField() { return NULL; }
@ -650,8 +650,24 @@ LEAF(Constant, Instruction)
virtual intx hash() const; virtual intx hash() const;
virtual bool is_equal(Value v) const; virtual bool is_equal(Value v) const;
virtual BlockBegin* compare(Instruction::Condition condition, Value right,
BlockBegin* true_sux, BlockBegin* false_sux); enum CompareResult { not_comparable = -1, cond_false, cond_true };
virtual CompareResult compare(Instruction::Condition condition, Value right) const;
BlockBegin* compare(Instruction::Condition cond, Value right,
BlockBegin* true_sux, BlockBegin* false_sux) const {
switch (compare(cond, right)) {
case not_comparable:
return NULL;
case cond_false:
return false_sux;
case cond_true:
return true_sux;
default:
ShouldNotReachHere();
return NULL;
}
}
}; };

View file

@ -38,18 +38,20 @@ class CE_Eliminator: public BlockClosure {
private: private:
IR* _hir; IR* _hir;
int _cee_count; // the number of CEs successfully eliminated int _cee_count; // the number of CEs successfully eliminated
int _ifop_count; // the number of IfOps successfully simplified
int _has_substitution; int _has_substitution;
public: public:
CE_Eliminator(IR* hir) : _cee_count(0), _hir(hir) { CE_Eliminator(IR* hir) : _cee_count(0), _ifop_count(0), _hir(hir) {
_has_substitution = false; _has_substitution = false;
_hir->iterate_preorder(this); _hir->iterate_preorder(this);
if (_has_substitution) { if (_has_substitution) {
// substituted some phis so resolve the substitution // substituted some ifops/phis, so resolve the substitution
SubstitutionResolver sr(_hir); SubstitutionResolver sr(_hir);
} }
} }
int cee_count() const { return _cee_count; } int cee_count() const { return _cee_count; }
int ifop_count() const { return _ifop_count; }
void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) { void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) {
int e = sux->number_of_exception_handlers(); int e = sux->number_of_exception_handlers();
@ -68,156 +70,214 @@ class CE_Eliminator: public BlockClosure {
} }
} }
virtual void block_do(BlockBegin* block) { virtual void block_do(BlockBegin* block);
// 1) find conditional expression
// check if block ends with an If
If* if_ = block->end()->as_If();
if (if_ == NULL) return;
// check if If works on int or object types private:
// (we cannot handle If's working on long, float or doubles yet, Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval);
// since IfOp doesn't support them - these If's show up if cmp
// operations followed by If's are eliminated)
ValueType* if_type = if_->x()->type();
if (!if_type->is_int() && !if_type->is_object()) return;
BlockBegin* t_block = if_->tsux();
BlockBegin* f_block = if_->fsux();
Instruction* t_cur = t_block->next();
Instruction* f_cur = f_block->next();
// one Constant may be present between BlockBegin and BlockEnd
Value t_const = NULL;
Value f_const = NULL;
if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) {
t_const = t_cur;
t_cur = t_cur->next();
}
if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) {
f_const = f_cur;
f_cur = f_cur->next();
}
// check if both branches end with a goto
Goto* t_goto = t_cur->as_Goto();
if (t_goto == NULL) return;
Goto* f_goto = f_cur->as_Goto();
if (f_goto == NULL) return;
// check if both gotos merge into the same block
BlockBegin* sux = t_goto->default_sux();
if (sux != f_goto->default_sux()) return;
// check if at least one word was pushed on sux_state
ValueStack* sux_state = sux->state();
if (sux_state->stack_size() <= if_->state()->stack_size()) return;
// check if phi function is present at end of successor stack and that
// only this phi was pushed on the stack
Value sux_phi = sux_state->stack_at(if_->state()->stack_size());
if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return;
if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return;
// get the values that were pushed in the true- and false-branch
Value t_value = t_goto->state()->stack_at(if_->state()->stack_size());
Value f_value = f_goto->state()->stack_at(if_->state()->stack_size());
// backend does not support floats
assert(t_value->type()->base() == f_value->type()->base(), "incompatible types");
if (t_value->type()->is_float_kind()) return;
// check that successor has no other phi functions but sux_phi
// this can happen when t_block or f_block contained additonal stores to local variables
// that are no longer represented by explicit instructions
for_each_phi_fun(sux, phi,
if (phi != sux_phi) return;
);
// true and false blocks can't have phis
for_each_phi_fun(t_block, phi, return; );
for_each_phi_fun(f_block, phi, return; );
// 2) substitute conditional expression
// with an IfOp followed by a Goto
// cut if_ away and get node before
Instruction* cur_end = if_->prev(block);
// append constants of true- and false-block if necessary
// clone constants because original block must not be destroyed
assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch");
if (t_value == t_const) {
t_value = new Constant(t_const->type());
NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(t_value);
}
if (f_value == f_const) {
f_value = new Constant(f_const->type());
NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(f_value);
}
// it is very unlikely that the condition can be statically decided
// (this was checked previously by the Canonicalizer), so always
// append IfOp
Value result = new IfOp(if_->x(), if_->cond(), if_->y(), t_value, f_value);
NOT_PRODUCT(result->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(result);
// append Goto to successor
ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL;
Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint());
// prepare state for Goto
ValueStack* goto_state = if_->state();
while (sux_state->scope() != goto_state->scope()) {
goto_state = goto_state->caller_state();
assert(goto_state != NULL, "states do not match up");
}
goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci());
goto_state->push(result->type(), result);
assert(goto_state->is_same(sux_state), "states must match now");
goto_->set_state(goto_state);
cur_end = cur_end->set_next(goto_, goto_state->bci());
// Adjust control flow graph
BlockBegin::disconnect_edge(block, t_block);
BlockBegin::disconnect_edge(block, f_block);
if (t_block->number_of_preds() == 0) {
BlockBegin::disconnect_edge(t_block, sux);
}
adjust_exception_edges(block, t_block);
if (f_block->number_of_preds() == 0) {
BlockBegin::disconnect_edge(f_block, sux);
}
adjust_exception_edges(block, f_block);
// update block end
block->set_end(goto_);
// substitute the phi if possible
if (sux_phi->as_Phi()->operand_count() == 1) {
assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi");
sux_phi->set_subst(result);
_has_substitution = true;
}
// 3) successfully eliminated a conditional expression
_cee_count++;
if (PrintCEE) {
tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id());
}
_hir->verify();
}
}; };
void CE_Eliminator::block_do(BlockBegin* block) {
// 1) find conditional expression
// check if block ends with an If
If* if_ = block->end()->as_If();
if (if_ == NULL) return;
// check if If works on int or object types
// (we cannot handle If's working on long, float or doubles yet,
// since IfOp doesn't support them - these If's show up if cmp
// operations followed by If's are eliminated)
ValueType* if_type = if_->x()->type();
if (!if_type->is_int() && !if_type->is_object()) return;
BlockBegin* t_block = if_->tsux();
BlockBegin* f_block = if_->fsux();
Instruction* t_cur = t_block->next();
Instruction* f_cur = f_block->next();
// one Constant may be present between BlockBegin and BlockEnd
Value t_const = NULL;
Value f_const = NULL;
if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) {
t_const = t_cur;
t_cur = t_cur->next();
}
if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) {
f_const = f_cur;
f_cur = f_cur->next();
}
// check if both branches end with a goto
Goto* t_goto = t_cur->as_Goto();
if (t_goto == NULL) return;
Goto* f_goto = f_cur->as_Goto();
if (f_goto == NULL) return;
// check if both gotos merge into the same block
BlockBegin* sux = t_goto->default_sux();
if (sux != f_goto->default_sux()) return;
// check if at least one word was pushed on sux_state
ValueStack* sux_state = sux->state();
if (sux_state->stack_size() <= if_->state()->stack_size()) return;
// check if phi function is present at end of successor stack and that
// only this phi was pushed on the stack
Value sux_phi = sux_state->stack_at(if_->state()->stack_size());
if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return;
if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return;
// get the values that were pushed in the true- and false-branch
Value t_value = t_goto->state()->stack_at(if_->state()->stack_size());
Value f_value = f_goto->state()->stack_at(if_->state()->stack_size());
// backend does not support floats
assert(t_value->type()->base() == f_value->type()->base(), "incompatible types");
if (t_value->type()->is_float_kind()) return;
// check that successor has no other phi functions but sux_phi
// this can happen when t_block or f_block contained additonal stores to local variables
// that are no longer represented by explicit instructions
for_each_phi_fun(sux, phi,
if (phi != sux_phi) return;
);
// true and false blocks can't have phis
for_each_phi_fun(t_block, phi, return; );
for_each_phi_fun(f_block, phi, return; );
// 2) substitute conditional expression
// with an IfOp followed by a Goto
// cut if_ away and get node before
Instruction* cur_end = if_->prev(block);
// append constants of true- and false-block if necessary
// clone constants because original block must not be destroyed
assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch");
if (t_value == t_const) {
t_value = new Constant(t_const->type());
NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(t_value);
}
if (f_value == f_const) {
f_value = new Constant(f_const->type());
NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(f_value);
}
Value result = make_ifop(if_->x(), if_->cond(), if_->y(), t_value, f_value);
assert(result != NULL, "make_ifop must return a non-null instruction");
if (!result->is_linked() && result->can_be_linked()) {
NOT_PRODUCT(result->set_printable_bci(if_->printable_bci()));
cur_end = cur_end->set_next(result);
}
// append Goto to successor
ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL;
Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint());
// prepare state for Goto
ValueStack* goto_state = if_->state();
while (sux_state->scope() != goto_state->scope()) {
goto_state = goto_state->caller_state();
assert(goto_state != NULL, "states do not match up");
}
goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci());
goto_state->push(result->type(), result);
assert(goto_state->is_same(sux_state), "states must match now");
goto_->set_state(goto_state);
cur_end = cur_end->set_next(goto_, goto_state->bci());
// Adjust control flow graph
BlockBegin::disconnect_edge(block, t_block);
BlockBegin::disconnect_edge(block, f_block);
if (t_block->number_of_preds() == 0) {
BlockBegin::disconnect_edge(t_block, sux);
}
adjust_exception_edges(block, t_block);
if (f_block->number_of_preds() == 0) {
BlockBegin::disconnect_edge(f_block, sux);
}
adjust_exception_edges(block, f_block);
// update block end
block->set_end(goto_);
// substitute the phi if possible
if (sux_phi->as_Phi()->operand_count() == 1) {
assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi");
sux_phi->set_subst(result);
_has_substitution = true;
}
// 3) successfully eliminated a conditional expression
_cee_count++;
if (PrintCEE) {
tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id());
tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id());
}
_hir->verify();
}
Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) {
if (!OptimizeIfOps) {
return new IfOp(x, cond, y, tval, fval);
}
tval = tval->subst();
fval = fval->subst();
if (tval == fval) {
_ifop_count++;
return tval;
}
x = x->subst();
y = y->subst();
Constant* y_const = y->as_Constant();
if (y_const != NULL) {
IfOp* x_ifop = x->as_IfOp();
if (x_ifop != NULL) { // x is an ifop, y is a constant
Constant* x_tval_const = x_ifop->tval()->subst()->as_Constant();
Constant* x_fval_const = x_ifop->fval()->subst()->as_Constant();
if (x_tval_const != NULL && x_fval_const != NULL) {
Instruction::Condition x_ifop_cond = x_ifop->cond();
Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const);
Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const);
guarantee(t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
Value new_tval = t_compare_res == Constant::cond_true ? tval : fval;
Value new_fval = f_compare_res == Constant::cond_true ? tval : fval;
_ifop_count++;
if (new_tval == new_fval) {
return new_tval;
} else {
return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval);
}
}
} else {
Constant* x_const = x->as_Constant();
if (x_const != NULL) { // x and y are constants
Constant::CompareResult x_compare_res = x_const->compare(cond, y_const);
guarantee(x_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
_ifop_count++;
return x_compare_res == Constant::cond_true ? tval : fval;
}
}
}
return new IfOp(x, cond, y, tval, fval);
}
void Optimizer::eliminate_conditional_expressions() { void Optimizer::eliminate_conditional_expressions() {
// find conditional expressions & replace them with IfOps // find conditional expressions & replace them with IfOps
CE_Eliminator ce(ir()); CE_Eliminator ce(ir());
} }
class BlockMerger: public BlockClosure { class BlockMerger: public BlockClosure {
private: private:
IR* _hir; IR* _hir;

View file

@ -107,7 +107,6 @@ static void deopt_caller() {
RegisterMap reg_map(thread, false); RegisterMap reg_map(thread, false);
frame runtime_frame = thread->last_frame(); frame runtime_frame = thread->last_frame();
frame caller_frame = runtime_frame.sender(&reg_map); frame caller_frame = runtime_frame.sender(&reg_map);
// bypass VM_DeoptimizeFrame and deoptimize the frame directly
Deoptimization::deoptimize_frame(thread, caller_frame.id()); Deoptimization::deoptimize_frame(thread, caller_frame.id());
assert(caller_is_deopted(), "Must be deoptimized"); assert(caller_is_deopted(), "Must be deoptimized");
} }
@ -368,8 +367,7 @@ JRT_BLOCK_ENTRY(address, Runtime1::counter_overflow(JavaThread* thread, int bci,
if (osr_nm != NULL) { if (osr_nm != NULL) {
RegisterMap map(thread, false); RegisterMap map(thread, false);
frame fr = thread->last_frame().sender(&map); frame fr = thread->last_frame().sender(&map);
VM_DeoptimizeFrame deopt(thread, fr.id()); Deoptimization::deoptimize_frame(thread, fr.id());
VMThread::execute(&deopt);
} }
JRT_BLOCK_END JRT_BLOCK_END
return NULL; return NULL;
@ -441,8 +439,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// We don't really want to deoptimize the nmethod itself since we // We don't really want to deoptimize the nmethod itself since we
// can actually continue in the exception handler ourselves but I // can actually continue in the exception handler ourselves but I
// don't see an easy way to have the desired effect. // don't see an easy way to have the desired effect.
VM_DeoptimizeFrame deopt(thread, caller_frame.id()); Deoptimization::deoptimize_frame(thread, caller_frame.id());
VMThread::execute(&deopt); assert(caller_is_deopted(), "Must be deoptimized");
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
} }
@ -835,8 +833,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
nm->make_not_entrant(); nm->make_not_entrant();
} }
VM_DeoptimizeFrame deopt(thread, caller_frame.id()); Deoptimization::deoptimize_frame(thread, caller_frame.id());
VMThread::execute(&deopt);
// Return to the now deoptimized frame. // Return to the now deoptimized frame.
} }

View file

@ -75,6 +75,9 @@
develop(bool, SelectivePhiFunctions, true, \ develop(bool, SelectivePhiFunctions, true, \
"create phi functions at loop headers only when necessary") \ "create phi functions at loop headers only when necessary") \
\ \
develop(bool, OptimizeIfOps, true, \
"Optimize multiple IfOps") \
\
develop(bool, DoCEE, true, \ develop(bool, DoCEE, true, \
"Do Conditional Expression Elimination to simplify CFG") \ "Do Conditional Expression Elimination to simplify CFG") \
\ \

View file

@ -564,7 +564,7 @@ bool ciInstanceKlass::is_leaf_type() {
// This is OK, since any dependencies we decide to assert // This is OK, since any dependencies we decide to assert
// will be checked later under the Compile_lock. // will be checked later under the Compile_lock.
ciInstanceKlass* ciInstanceKlass::implementor(int n) { ciInstanceKlass* ciInstanceKlass::implementor(int n) {
if (n > implementors_limit) { if (n >= implementors_limit) {
return NULL; return NULL;
} }
ciInstanceKlass* impl = _implementors[n]; ciInstanceKlass* impl = _implementors[n];

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -73,6 +73,12 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
unsigned int hashValues[SymbolTable::symbol_alloc_batch_size]; unsigned int hashValues[SymbolTable::symbol_alloc_batch_size];
int names_count = 0; int names_count = 0;
// Side buffer for operands of variable-sized (InvokeDynamic) entries.
GrowableArray<int>* operands = NULL;
#ifdef ASSERT
GrowableArray<int>* indy_instructions = new GrowableArray<int>(THREAD, 10);
#endif
// parsing Index 0 is unused // parsing Index 0 is unused
for (int index = 1; index < length; index++) { for (int index = 1; index < length; index++) {
// Each of the following case guarantees one more byte in the stream // Each of the following case guarantees one more byte in the stream
@ -141,6 +147,7 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
ShouldNotReachHere(); ShouldNotReachHere();
} }
break; break;
case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles
case JVM_CONSTANT_InvokeDynamic : case JVM_CONSTANT_InvokeDynamic :
{ {
if (!EnableInvokeDynamic || if (!EnableInvokeDynamic ||
@ -151,10 +158,36 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
"Class file version does not support constant tag %u in class file %s"), "Class file version does not support constant tag %u in class file %s"),
tag, CHECK); tag, CHECK);
} }
cfs->guarantee_more(5, CHECK); // bsm_index, name_and_type_index, tag/access_flags if (!AllowTransitionalJSR292 && tag == JVM_CONSTANT_InvokeDynamicTrans) {
classfile_parse_error(
"This JVM does not support transitional InvokeDynamic tag %u in class file %s",
tag, CHECK);
}
bool trans_no_argc = AllowTransitionalJSR292 && (tag == JVM_CONSTANT_InvokeDynamicTrans);
cfs->guarantee_more(7, CHECK); // bsm_index, nt, argc, ..., tag/access_flags
u2 bootstrap_method_index = cfs->get_u2_fast(); u2 bootstrap_method_index = cfs->get_u2_fast();
u2 name_and_type_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast();
cp->invoke_dynamic_at_put(index, bootstrap_method_index, name_and_type_index); int argument_count = trans_no_argc ? 0 : cfs->get_u2_fast();
cfs->guarantee_more(2*argument_count + 1, CHECK); // argv[argc]..., tag/access_flags
int argv_offset = constantPoolOopDesc::_indy_argv_offset;
int op_count = argv_offset + argument_count; // bsm, nt, argc, argv[]...
int op_base = start_operand_group(operands, op_count, CHECK);
assert(argv_offset == 3, "else adjust next 3 assignments");
operands->at_put(op_base + constantPoolOopDesc::_indy_bsm_offset, bootstrap_method_index);
operands->at_put(op_base + constantPoolOopDesc::_indy_nt_offset, name_and_type_index);
operands->at_put(op_base + constantPoolOopDesc::_indy_argc_offset, argument_count);
for (int arg_i = 0; arg_i < argument_count; arg_i++) {
int arg = cfs->get_u2_fast();
operands->at_put(op_base + constantPoolOopDesc::_indy_argv_offset + arg_i, arg);
}
cp->invoke_dynamic_at_put(index, op_base, op_count);
#ifdef ASSERT
// Record the steps just taken for later checking.
indy_instructions->append(index);
indy_instructions->append(bootstrap_method_index);
indy_instructions->append(name_and_type_index);
indy_instructions->append(argument_count);
#endif //ASSERT
} }
break; break;
case JVM_CONSTANT_Integer : case JVM_CONSTANT_Integer :
@ -257,6 +290,23 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
oopFactory::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); oopFactory::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK);
} }
if (operands != NULL && operands->length() > 0) {
store_operand_array(operands, cp, CHECK);
}
#ifdef ASSERT
// Re-assert the indy structures, now that assertion checking can work.
for (int indy_i = 0; indy_i < indy_instructions->length(); ) {
int index = indy_instructions->at(indy_i++);
int bootstrap_method_index = indy_instructions->at(indy_i++);
int name_and_type_index = indy_instructions->at(indy_i++);
int argument_count = indy_instructions->at(indy_i++);
assert(cp->check_invoke_dynamic_at(index,
bootstrap_method_index, name_and_type_index,
argument_count),
"indy structure is OK");
}
#endif //ASSERT
// Copy _current pointer of local copy back to stream(). // Copy _current pointer of local copy back to stream().
#ifdef ASSERT #ifdef ASSERT
assert(cfs0->current() == old_current, "non-exclusive use of stream()"); assert(cfs0->current() == old_current, "non-exclusive use of stream()");
@ -264,6 +314,41 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
cfs0->set_current(cfs1.current()); cfs0->set_current(cfs1.current());
} }
int ClassFileParser::start_operand_group(GrowableArray<int>* &operands, int op_count, TRAPS) {
if (operands == NULL) {
operands = new GrowableArray<int>(THREAD, 100);
int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset;
while (operands->length() <= fillp_offset)
operands->append(0); // force op_base > 0, for an error check
DEBUG_ONLY(operands->at_put(fillp_offset, (int)badHeapWordVal));
}
int cnt_pos = operands->append(op_count);
int arg_pos = operands->length();
operands->at_grow(arg_pos + op_count - 1); // grow to include the operands
assert(operands->length() == arg_pos + op_count, "");
int op_base = cnt_pos - constantPoolOopDesc::_multi_operand_count_offset;
return op_base;
}
void ClassFileParser::store_operand_array(GrowableArray<int>* operands, constantPoolHandle cp, TRAPS) {
// Collect the buffer of operands from variable-sized entries into a permanent array.
int arraylen = operands->length();
int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset;
assert(operands->at(fillp_offset) == (int)badHeapWordVal, "value unused so far");
operands->at_put(fillp_offset, arraylen);
cp->multi_operand_buffer_grow(arraylen, CHECK);
typeArrayOop operands_oop = cp->operands();
assert(operands_oop->length() == arraylen, "");
for (int i = 0; i < arraylen; i++) {
operands_oop->int_at_put(i, operands->at(i));
}
cp->set_operands(operands_oop);
// The fill_pointer is used only by constantPoolOop::copy_entry_to and friends,
// when constant pools need to be merged. Make sure it is sane now.
assert(cp->multi_operand_buffer_fill_pointer() == arraylen, "");
}
bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); }
constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
@ -431,6 +516,8 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
ref_index, CHECK_(nullHandle)); ref_index, CHECK_(nullHandle));
} }
break; break;
case JVM_CONSTANT_InvokeDynamicTrans :
ShouldNotReachHere(); // this tag does not appear in the heap
case JVM_CONSTANT_InvokeDynamic : case JVM_CONSTANT_InvokeDynamic :
{ {
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
@ -438,7 +525,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292) check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292)
|| ||
(valid_cp_range(bootstrap_method_ref_index, length) && (valid_cp_range(bootstrap_method_ref_index, length) &&
cp->tag_at(bootstrap_method_ref_index).is_method_handle()), (cp->tag_at(bootstrap_method_ref_index).is_method_handle())),
"Invalid constant pool index %u in class file %s", "Invalid constant pool index %u in class file %s",
bootstrap_method_ref_index, bootstrap_method_ref_index,
CHECK_(nullHandle)); CHECK_(nullHandle));
@ -447,6 +534,18 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
"Invalid constant pool index %u in class file %s", "Invalid constant pool index %u in class file %s",
name_and_type_ref_index, name_and_type_ref_index,
CHECK_(nullHandle)); CHECK_(nullHandle));
int argc = cp->invoke_dynamic_argument_count_at(index);
for (int arg_i = 0; arg_i < argc; arg_i++) {
int arg = cp->invoke_dynamic_argument_index_at(index, arg_i);
check_property(valid_cp_range(arg, length) &&
cp->tag_at(arg).is_loadable_constant() ||
// temporary early forms of string and class:
cp->tag_at(arg).is_klass_index() ||
cp->tag_at(arg).is_string_index(),
"Invalid constant pool index %u in class file %s",
arg,
CHECK_(nullHandle));
}
break; break;
} }
default: default:
@ -2505,18 +2604,6 @@ void ClassFileParser::java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_pt
// the check for the "discovered" field should issue a warning if // the check for the "discovered" field should issue a warning if
// the field is not found. For 1.6 this code should be issue a // the field is not found. For 1.6 this code should be issue a
// fatal error if the "discovered" field is not found. // fatal error if the "discovered" field is not found.
//
// Increment fac.nonstatic_oop_count so that the start of the
// next type of non-static oops leaves room for the fake oop.
// Do not increment next_nonstatic_oop_offset so that the
// fake oop is place after the java.lang.ref.Reference oop
// fields.
//
// Check the fields in java.lang.ref.Reference for the "discovered"
// field. If it is not present, artifically create a field for it.
// This allows this VM to run on early JDK where the field is not
// present.
// //
// Increment fac.nonstatic_oop_count so that the start of the // Increment fac.nonstatic_oop_count so that the start of the
// next type of non-static oops leaves room for the fake oop. // next type of non-static oops leaves room for the fake oop.
@ -2663,7 +2750,7 @@ void ClassFileParser::java_lang_Class_fix_post(int* next_nonstatic_oop_offset_pt
// Force MethodHandle.vmentry to be an unmanaged pointer. // Force MethodHandle.vmentry to be an unmanaged pointer.
// There is no way for a classfile to express this, so we must help it. // There is no way for a classfile to express this, so we must help it.
void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp, void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
typeArrayHandle* fields_ptr, typeArrayHandle fields,
FieldAllocationCount *fac_ptr, FieldAllocationCount *fac_ptr,
TRAPS) { TRAPS) {
// Add fake fields for java.dyn.MethodHandle instances // Add fake fields for java.dyn.MethodHandle instances
@ -2687,41 +2774,45 @@ void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing I or J signature (for vmentry) in java.dyn.MethodHandle"); "missing I or J signature (for vmentry) in java.dyn.MethodHandle");
// Find vmentry field and change the signature.
bool found_vmentry = false; bool found_vmentry = false;
for (int i = 0; i < fields->length(); i += instanceKlass::next_offset) {
const int n = (*fields_ptr)()->length(); int name_index = fields->ushort_at(i + instanceKlass::name_index_offset);
for (int i = 0; i < n; i += instanceKlass::next_offset) { int sig_index = fields->ushort_at(i + instanceKlass::signature_index_offset);
int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset); int acc_flags = fields->ushort_at(i + instanceKlass::access_flags_offset);
int sig_index = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset);
int acc_flags = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset);
symbolOop f_name = cp->symbol_at(name_index); symbolOop f_name = cp->symbol_at(name_index);
symbolOop f_sig = cp->symbol_at(sig_index); symbolOop f_sig = cp->symbol_at(sig_index);
if (f_sig == vmSymbols::byte_signature() &&
f_name == vmSymbols::vmentry_name() &&
(acc_flags & JVM_ACC_STATIC) == 0) {
// Adjust the field type from byte to an unmanaged pointer.
assert(fac_ptr->nonstatic_byte_count > 0, "");
fac_ptr->nonstatic_byte_count -= 1;
(*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index); if (f_name == vmSymbols::vmentry_name() && (acc_flags & JVM_ACC_STATIC) == 0) {
assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64"); if (f_sig == vmSymbols::machine_word_signature()) {
if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1; // If the signature of vmentry is already changed, we're done.
else fac_ptr->nonstatic_word_count += 1; found_vmentry = true;
break;
}
else if (f_sig == vmSymbols::byte_signature()) {
// Adjust the field type from byte to an unmanaged pointer.
assert(fac_ptr->nonstatic_byte_count > 0, "");
fac_ptr->nonstatic_byte_count -= 1;
FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i + instanceKlass::low_offset); fields->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index);
assert(atype == NONSTATIC_BYTE, ""); assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64");
FieldAllocationType new_atype = (wordSize == longSize) ? NONSTATIC_DOUBLE : NONSTATIC_WORD; if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1;
(*fields_ptr)->ushort_at_put(i + instanceKlass::low_offset, new_atype); else fac_ptr->nonstatic_word_count += 1;
found_vmentry = true; FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset);
break; assert(atype == NONSTATIC_BYTE, "");
FieldAllocationType new_atype = (wordSize == longSize) ? NONSTATIC_DOUBLE : NONSTATIC_WORD;
fields->ushort_at_put(i + instanceKlass::low_offset, new_atype);
found_vmentry = true;
break;
}
} }
} }
if (!found_vmentry) if (!found_vmentry)
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing vmentry byte field in java.dyn.MethodHandle"); "missing vmentry byte field in java.dyn.MethodHandle");
} }
@ -3082,7 +3173,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
// adjust the vmentry field declaration in java.dyn.MethodHandle // adjust the vmentry field declaration in java.dyn.MethodHandle
if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) {
java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle)); java_dyn_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
} }
// Add a fake "discovered" field if it is not present // Add a fake "discovered" field if it is not present

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -56,6 +56,9 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
constantPoolHandle parse_constant_pool(TRAPS); constantPoolHandle parse_constant_pool(TRAPS);
static int start_operand_group(GrowableArray<int>* &operands, int op_count, TRAPS);
static void store_operand_array(GrowableArray<int>* operands, constantPoolHandle cp, TRAPS);
// Interface parsing // Interface parsing
objArrayHandle parse_interfaces(constantPoolHandle cp, objArrayHandle parse_interfaces(constantPoolHandle cp,
int length, int length,
@ -151,7 +154,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
// Adjust the field allocation counts for java.dyn.MethodHandle to add // Adjust the field allocation counts for java.dyn.MethodHandle to add
// a fake address (void*) field. // a fake address (void*) field.
void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp, void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
typeArrayHandle* fields_ptr, typeArrayHandle fields,
FieldAllocationCount *fac_ptr, TRAPS); FieldAllocationCount *fac_ptr, TRAPS);
// Format checker methods // Format checker methods

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,12 +26,12 @@
# include "incls/_systemDictionary.cpp.incl" # include "incls/_systemDictionary.cpp.incl"
Dictionary* SystemDictionary::_dictionary = NULL; Dictionary* SystemDictionary::_dictionary = NULL;
PlaceholderTable* SystemDictionary::_placeholders = NULL; PlaceholderTable* SystemDictionary::_placeholders = NULL;
Dictionary* SystemDictionary::_shared_dictionary = NULL; Dictionary* SystemDictionary::_shared_dictionary = NULL;
LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL; LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL; ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL; SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
int SystemDictionary::_number_of_modifications = 0; int SystemDictionary::_number_of_modifications = 0;
@ -1727,8 +1727,7 @@ void SystemDictionary::always_strong_classes_do(OopClosure* blk) {
placeholders_do(blk); placeholders_do(blk);
// Visit extra methods // Visit extra methods
if (invoke_method_table() != NULL) invoke_method_table()->oops_do(blk);
invoke_method_table()->oops_do(blk);
// Loader constraints. We must keep the symbolOop used in the name alive. // Loader constraints. We must keep the symbolOop used in the name alive.
constraints()->always_strong_classes_do(blk); constraints()->always_strong_classes_do(blk);
@ -1766,8 +1765,7 @@ void SystemDictionary::oops_do(OopClosure* f) {
dictionary()->oops_do(f); dictionary()->oops_do(f);
// Visit extra methods // Visit extra methods
if (invoke_method_table() != NULL) invoke_method_table()->oops_do(f);
invoke_method_table()->oops_do(f);
// Partially loaded classes // Partially loaded classes
placeholders()->oops_do(f); placeholders()->oops_do(f);
@ -1841,8 +1839,7 @@ void SystemDictionary::placeholders_do(void f(symbolOop, oop)) {
void SystemDictionary::methods_do(void f(methodOop)) { void SystemDictionary::methods_do(void f(methodOop)) {
dictionary()->methods_do(f); dictionary()->methods_do(f);
if (invoke_method_table() != NULL) invoke_method_table()->methods_do(f);
invoke_method_table()->methods_do(f);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -1870,12 +1867,12 @@ void SystemDictionary::initialize(TRAPS) {
// Allocate arrays // Allocate arrays
assert(dictionary() == NULL, assert(dictionary() == NULL,
"SystemDictionary should only be initialized once"); "SystemDictionary should only be initialized once");
_dictionary = new Dictionary(_nof_buckets); _dictionary = new Dictionary(_nof_buckets);
_placeholders = new PlaceholderTable(_nof_buckets); _placeholders = new PlaceholderTable(_nof_buckets);
_number_of_modifications = 0; _number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size); _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size); _resolution_errors = new ResolutionErrorTable(_resolution_error_size);
// _invoke_method_table is allocated lazily in find_method_handle_invoke() _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
// Allocate private object used as system class loader lock // Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK); _system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
@ -2346,10 +2343,6 @@ methodOop SystemDictionary::find_method_handle_invoke(symbolHandle name,
KlassHandle accessing_klass, KlassHandle accessing_klass,
TRAPS) { TRAPS) {
if (!EnableMethodHandles) return NULL; if (!EnableMethodHandles) return NULL;
if (invoke_method_table() == NULL) {
// create this side table lazily
_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
}
vmSymbols::SID name_id = vmSymbols::find_sid(name()); vmSymbols::SID name_id = vmSymbols::find_sid(name());
assert(name_id != vmSymbols::NO_SID, "must be a known name"); assert(name_id != vmSymbols::NO_SID, "must be a known name");
unsigned int hash = invoke_method_table()->compute_hash(signature, name_id); unsigned int hash = invoke_method_table()->compute_hash(signature, name_id);
@ -2562,7 +2555,9 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method,
} }
Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci, Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci,
int cache_index, TRAPS) { int cache_index,
Handle& argument_info_result,
TRAPS) {
Handle empty; Handle empty;
constantPoolHandle pool; constantPoolHandle pool;
@ -2576,7 +2571,7 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
constantTag tag = pool->tag_at(constant_pool_index); constantTag tag = pool->tag_at(constant_pool_index);
if (tag.is_invoke_dynamic()) { if (tag.is_invoke_dynamic()) {
// JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type] // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments
// The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry. // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index); int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index);
if (bsm_index != 0) { if (bsm_index != 0) {
@ -2592,9 +2587,38 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":", tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":",
(intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop); (intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop);
} }
assert(bsm_oop->is_oop() assert(bsm_oop->is_oop(), "must be sane");
&& java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane"); // caller must verify that it is of type MethodHandle
return Handle(THREAD, bsm_oop); Handle bsm(THREAD, bsm_oop);
bsm_oop = NULL; // safety
// Extract the optional static arguments.
Handle argument_info; // either null, or one arg, or Object[]{arg...}
int argc = pool->invoke_dynamic_argument_count_at(constant_pool_index);
if (TraceInvokeDynamic) {
tty->print_cr("find_bootstrap_method: [%d/%d] CONSTANT_InvokeDynamic: %d[%d]",
constant_pool_index, cache_index, bsm_index, argc);
}
if (argc > 0) {
objArrayHandle arg_array;
if (argc > 1) {
objArrayOop arg_array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), argc, CHECK_(empty));
arg_array = objArrayHandle(THREAD, arg_array_oop);
argument_info = arg_array;
}
for (int arg_i = 0; arg_i < argc; arg_i++) {
int arg_index = pool->invoke_dynamic_argument_index_at(constant_pool_index, arg_i);
oop arg_oop = pool->resolve_possibly_cached_constant_at(arg_index, CHECK_(empty));
if (arg_array.is_null()) {
argument_info = Handle(THREAD, arg_oop);
} else {
arg_array->obj_at_put(arg_i, arg_oop);
}
}
}
argument_info_result = argument_info; // return argument_info to caller
return bsm;
} }
// else null BSM; fall through // else null BSM; fall through
} else if (tag.is_name_and_type()) { } else if (tag.is_name_and_type()) {
@ -2607,14 +2631,14 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
// Fall through to pick up the per-class bootstrap method. // Fall through to pick up the per-class bootstrap method.
// This mechanism may go away in the PFD. // This mechanism may go away in the PFD.
assert(AllowTransitionalJSR292, "else the verifier should have stopped us already"); assert(AllowTransitionalJSR292, "else the verifier should have stopped us already");
argument_info_result = empty; // return no argument_info to caller
oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method(); oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method();
if (bsm_oop != NULL) { if (bsm_oop != NULL) {
if (TraceMethodHandles) { if (TraceMethodHandles) {
tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":", tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":",
(intptr_t) caller_method(), (intptr_t) bsm_oop); (intptr_t) caller_method(), (intptr_t) bsm_oop);
} }
assert(bsm_oop->is_oop() assert(bsm_oop->is_oop(), "must be sane");
&& java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane");
return Handle(THREAD, bsm_oop); return Handle(THREAD, bsm_oop);
} }

View file

@ -496,6 +496,7 @@ public:
static Handle find_bootstrap_method(methodHandle caller_method, static Handle find_bootstrap_method(methodHandle caller_method,
int caller_bci, // N.B. must be an invokedynamic int caller_bci, // N.B. must be an invokedynamic
int cache_index, // must be corresponding main_entry int cache_index, // must be corresponding main_entry
Handle &argument_info_result, // static BSM arguments, if any
TRAPS); TRAPS);
// Utility for printing loader "name" as part of tracing constraints // Utility for printing loader "name" as part of tracing constraints

View file

@ -1908,7 +1908,7 @@ void ClassVerifier::verify_invoke_instructions(
unsigned int types = (opcode == Bytecodes::_invokeinterface unsigned int types = (opcode == Bytecodes::_invokeinterface
? 1 << JVM_CONSTANT_InterfaceMethodref ? 1 << JVM_CONSTANT_InterfaceMethodref
: opcode == Bytecodes::_invokedynamic : opcode == Bytecodes::_invokedynamic
? (1 << JVM_CONSTANT_NameAndType ? ((AllowTransitionalJSR292 ? 1 << JVM_CONSTANT_NameAndType : 0)
|1 << JVM_CONSTANT_InvokeDynamic) |1 << JVM_CONSTANT_InvokeDynamic)
: 1 << JVM_CONSTANT_Methodref); : 1 << JVM_CONSTANT_Methodref);
verify_cp_type(index, cp, types, CHECK_VERIFY(this)); verify_cp_type(index, cp, types, CHECK_VERIFY(this));

View file

@ -914,3 +914,14 @@ void CodeCache::print() {
} }
#endif // PRODUCT #endif // PRODUCT
void CodeCache::print_bounds(outputStream* st) {
st->print_cr("Code Cache [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")",
_heap->low_boundary(),
_heap->high(),
_heap->high_boundary());
st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT
" adapters=" UINT32_FORMAT " free_code_cache=" SIZE_FORMAT,
CodeCache::nof_blobs(), CodeCache::nof_nmethods(),
CodeCache::nof_adapters(), CodeCache::unallocated_capacity());
}

View file

@ -137,6 +137,7 @@ class CodeCache : AllStatic {
static void print_internals(); static void print_internals();
static void verify(); // verifies the code cache static void verify(); // verifies the code cache
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
static void print_bounds(outputStream* st); // Prints a summary of the bounds of the code cache
// The full limits of the codeCache // The full limits of the codeCache
static address low_bound() { return (address) _heap->low_boundary(); } static address low_bound() { return (address) _heap->low_boundary(); }

View file

@ -354,12 +354,8 @@ void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) {
double CMSStats::time_until_cms_gen_full() const { double CMSStats::time_until_cms_gen_full() const {
size_t cms_free = _cms_gen->cmsSpace()->free(); size_t cms_free = _cms_gen->cmsSpace()->free();
GenCollectedHeap* gch = GenCollectedHeap::heap(); GenCollectedHeap* gch = GenCollectedHeap::heap();
size_t expected_promotion = gch->get_gen(0)->capacity(); size_t expected_promotion = MIN2(gch->get_gen(0)->capacity(),
if (HandlePromotionFailure) { (size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average());
expected_promotion = MIN2(
(size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average(),
expected_promotion);
}
if (cms_free > expected_promotion) { if (cms_free > expected_promotion) {
// Start a cms collection if there isn't enough space to promote // Start a cms collection if there isn't enough space to promote
// for the next minor collection. Use the padded average as // for the next minor collection. Use the padded average as
@ -865,57 +861,18 @@ size_t ConcurrentMarkSweepGeneration::max_available() const {
return free() + _virtual_space.uncommitted_size(); return free() + _virtual_space.uncommitted_size();
} }
bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe( bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
size_t max_promotion_in_bytes, size_t available = max_available();
bool younger_handles_promotion_failure) const { size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average();
bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
// This is the most conservative test. Full promotion is if (PrintGC && Verbose) {
// guaranteed if this is used. The multiplicative factor is to gclog_or_tty->print_cr(
// account for the worst case "dilatation". "CMS: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
double adjusted_max_promo_bytes = _dilatation_factor * max_promotion_in_bytes; "max_promo("SIZE_FORMAT")",
if (adjusted_max_promo_bytes > (double)max_uintx) { // larger than size_t res? "":" not", available, res? ">=":"<",
adjusted_max_promo_bytes = (double)max_uintx; av_promo, max_promotion_in_bytes);
} }
bool result = (max_contiguous_available() >= (size_t)adjusted_max_promo_bytes); return res;
if (younger_handles_promotion_failure && !result) {
// Full promotion is not guaranteed because fragmentation
// of the cms generation can prevent the full promotion.
result = (max_available() >= (size_t)adjusted_max_promo_bytes);
if (!result) {
// With promotion failure handling the test for the ability
// to support the promotion does not have to be guaranteed.
// Use an average of the amount promoted.
result = max_available() >= (size_t)
gc_stats()->avg_promoted()->padded_average();
if (PrintGC && Verbose && result) {
gclog_or_tty->print_cr(
"\nConcurrentMarkSweepGeneration::promotion_attempt_is_safe"
" max_available: " SIZE_FORMAT
" avg_promoted: " SIZE_FORMAT,
max_available(), (size_t)
gc_stats()->avg_promoted()->padded_average());
}
} else {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr(
"\nConcurrentMarkSweepGeneration::promotion_attempt_is_safe"
" max_available: " SIZE_FORMAT
" adj_max_promo_bytes: " SIZE_FORMAT,
max_available(), (size_t)adjusted_max_promo_bytes);
}
}
} else {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr(
"\nConcurrentMarkSweepGeneration::promotion_attempt_is_safe"
" contiguous_available: " SIZE_FORMAT
" adj_max_promo_bytes: " SIZE_FORMAT,
max_contiguous_available(), (size_t)adjusted_max_promo_bytes);
}
}
return result;
} }
// At a promotion failure dump information on block layout in heap // At a promotion failure dump information on block layout in heap
@ -6091,23 +6048,14 @@ void CMSCollector::sweep(bool asynch) {
assert(_collectorState == Resizing, "Change of collector state to" assert(_collectorState == Resizing, "Change of collector state to"
" Resizing must be done under the freelistLocks (plural)"); " Resizing must be done under the freelistLocks (plural)");
// Now that sweeping has been completed, if the GCH's // Now that sweeping has been completed, we clear
// incremental_collection_will_fail flag is set, clear it, // the incremental_collection_failed flag,
// thus inviting a younger gen collection to promote into // thus inviting a younger gen collection to promote into
// this generation. If such a promotion may still fail, // this generation. If such a promotion may still fail,
// the flag will be set again when a young collection is // the flag will be set again when a young collection is
// attempted. // attempted.
// I think the incremental_collection_will_fail flag's use
// is specific to a 2 generation collection policy, so i'll
// assert that that's the configuration we are operating within.
// The use of the flag can and should be generalized appropriately
// in the future to deal with a general n-generation system.
GenCollectedHeap* gch = GenCollectedHeap::heap(); GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(gch->collector_policy()->is_two_generation_policy(), gch->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up
"Resetting of incremental_collection_will_fail flag"
" may be incorrect otherwise");
gch->clear_incremental_collection_will_fail();
gch->update_full_collections_completed(_collection_count_start); gch->update_full_collections_completed(_collection_count_start);
} }

View file

@ -1185,8 +1185,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
virtual void par_promote_alloc_done(int thread_num); virtual void par_promote_alloc_done(int thread_num);
virtual void par_oop_since_save_marks_iterate_done(int thread_num); virtual void par_oop_since_save_marks_iterate_done(int thread_num);
virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes, virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes) const;
bool younger_handles_promotion_failure) const;
// Inform this (non-young) generation that a promotion failure was // Inform this (non-young) generation that a promotion failure was
// encountered during a collection of a younger generation that // encountered during a collection of a younger generation that

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -272,12 +272,16 @@ void ConcurrentMarkSweepThread::desynchronize(bool is_cms_thread) {
} }
} }
// Wait until the next synchronous GC or a timeout, whichever is earlier. // Wait until the next synchronous GC, a concurrent full gc request,
void ConcurrentMarkSweepThread::wait_on_cms_lock(long t) { // or a timeout, whichever is earlier.
void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) {
MutexLockerEx x(CGC_lock, MutexLockerEx x(CGC_lock,
Mutex::_no_safepoint_check_flag); Mutex::_no_safepoint_check_flag);
if (_should_terminate || _collector->_full_gc_requested) {
return;
}
set_CMS_flag(CMS_cms_wants_token); // to provoke notifies set_CMS_flag(CMS_cms_wants_token); // to provoke notifies
CGC_lock->wait(Mutex::_no_safepoint_check_flag, t); CGC_lock->wait(Mutex::_no_safepoint_check_flag, t_millis);
clear_CMS_flag(CMS_cms_wants_token); clear_CMS_flag(CMS_cms_wants_token);
assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token), assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
"Should not be set"); "Should not be set");
@ -289,7 +293,8 @@ void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
icms_wait(); icms_wait();
return; return;
} else { } else {
// Wait until the next synchronous GC or a timeout, whichever is earlier // Wait until the next synchronous GC, a concurrent full gc
// request or a timeout, whichever is earlier.
wait_on_cms_lock(CMSWaitDuration); wait_on_cms_lock(CMSWaitDuration);
} }
// Check if we should start a CMS collection cycle // Check if we should start a CMS collection cycle

View file

@ -120,8 +120,10 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
} }
// Wait on CMS lock until the next synchronous GC // Wait on CMS lock until the next synchronous GC
// or given timeout, whichever is earlier. // or given timeout, whichever is earlier. A timeout value
void wait_on_cms_lock(long t); // milliseconds // of 0 indicates that there is no upper bound on the wait time.
// A concurrent full gc request terminates the wait.
void wait_on_cms_lock(long t_millis);
// The CMS thread will yield during the work portion of its cycle // The CMS thread will yield during the work portion of its cycle
// only when requested to. Both synchronous and asychronous requests // only when requested to. Both synchronous and asychronous requests

View file

@ -2418,6 +2418,8 @@ void ConcurrentMark::clear_marking_state() {
for (int i = 0; i < (int)_max_task_num; ++i) { for (int i = 0; i < (int)_max_task_num; ++i) {
OopTaskQueue* queue = _task_queues->queue(i); OopTaskQueue* queue = _task_queues->queue(i);
queue->set_empty(); queue->set_empty();
// Clear any partial regions from the CMTasks
_tasks[i]->clear_aborted_region();
} }
} }
@ -2706,7 +2708,6 @@ void ConcurrentMark::abort() {
clear_marking_state(); clear_marking_state();
for (int i = 0; i < (int)_max_task_num; ++i) { for (int i = 0; i < (int)_max_task_num; ++i) {
_tasks[i]->clear_region_fields(); _tasks[i]->clear_region_fields();
_tasks[i]->clear_aborted_region();
} }
_has_aborted = true; _has_aborted = true;
@ -2985,7 +2986,7 @@ void CMTask::reset(CMBitMap* nextMarkBitMap) {
_nextMarkBitMap = nextMarkBitMap; _nextMarkBitMap = nextMarkBitMap;
clear_region_fields(); clear_region_fields();
clear_aborted_region(); assert(_aborted_region.is_empty(), "should have been cleared");
_calls = 0; _calls = 0;
_elapsed_time_ms = 0.0; _elapsed_time_ms = 0.0;

View file

@ -175,7 +175,7 @@ G1BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size
} }
assert(start_card > _array->index_for(_bottom), "Cannot be first card"); assert(start_card > _array->index_for(_bottom), "Cannot be first card");
assert(_array->offset_array(start_card-1) <= N_words, assert(_array->offset_array(start_card-1) <= N_words,
"Offset card has an unexpected value"); "Offset card has an unexpected value");
size_t start_card_for_region = start_card; size_t start_card_for_region = start_card;
u_char offset = max_jubyte; u_char offset = max_jubyte;
for (int i = 0; i < BlockOffsetArray::N_powers; i++) { for (int i = 0; i < BlockOffsetArray::N_powers; i++) {
@ -577,6 +577,16 @@ void G1BlockOffsetArray::alloc_block_work2(HeapWord** threshold_, size_t* index_
#endif #endif
} }
void
G1BlockOffsetArray::set_for_starts_humongous(HeapWord* new_end) {
assert(_end == new_end, "_end should have already been updated");
// The first BOT entry should have offset 0.
_array->set_offset_array(_array->index_for(_bottom), 0);
// The rest should point to the first one.
set_remainder_to_point_to_start(_bottom + N_words, new_end);
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// G1BlockOffsetArrayContigSpace // G1BlockOffsetArrayContigSpace
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -626,3 +636,12 @@ void G1BlockOffsetArrayContigSpace::zero_bottom_entry() {
"Precondition of call"); "Precondition of call");
_array->set_offset_array(bottom_index, 0); _array->set_offset_array(bottom_index, 0);
} }
void
G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_end) {
G1BlockOffsetArray::set_for_starts_humongous(new_end);
// Make sure _next_offset_threshold and _next_offset_index point to new_end.
_next_offset_threshold = new_end;
_next_offset_index = _array->index_for(new_end);
}

View file

@ -436,6 +436,8 @@ public:
} }
void check_all_cards(size_t left_card, size_t right_card) const; void check_all_cards(size_t left_card, size_t right_card) const;
virtual void set_for_starts_humongous(HeapWord* new_end);
}; };
// A subtype of BlockOffsetArray that takes advantage of the fact // A subtype of BlockOffsetArray that takes advantage of the fact
@ -484,4 +486,6 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray {
HeapWord* block_start_unsafe(const void* addr); HeapWord* block_start_unsafe(const void* addr);
HeapWord* block_start_unsafe_const(const void* addr) const; HeapWord* block_start_unsafe_const(const void* addr) const;
virtual void set_for_starts_humongous(HeapWord* new_end);
}; };

View file

@ -4118,10 +4118,14 @@ void G1ParEvacuateFollowersClosure::do_void() {
while (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) { while (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) {
assert(pss->verify_task(stolen_task), "sanity"); assert(pss->verify_task(stolen_task), "sanity");
if (stolen_task.is_narrow()) { if (stolen_task.is_narrow()) {
pss->push_on_queue((narrowOop*) stolen_task); pss->deal_with_reference((narrowOop*) stolen_task);
} else { } else {
pss->push_on_queue((oop*) stolen_task); pss->deal_with_reference((oop*) stolen_task);
} }
// We've just processed a reference and we might have made
// available new entries on the queues. So we have to make sure
// we drain the queues as necessary.
pss->trim_queue(); pss->trim_queue();
} }
} while (!offer_termination()); } while (!offer_termination());

View file

@ -1772,7 +1772,6 @@ public:
} }
} }
private:
template <class T> void deal_with_reference(T* ref_to_scan) { template <class T> void deal_with_reference(T* ref_to_scan) {
if (has_partial_array_mask(ref_to_scan)) { if (has_partial_array_mask(ref_to_scan)) {
_partial_scan_cl->do_oop_nv(ref_to_scan); _partial_scan_cl->do_oop_nv(ref_to_scan);

View file

@ -377,10 +377,26 @@ void HeapRegion::calc_gc_efficiency() {
} }
// </PREDICTION> // </PREDICTION>
void HeapRegion::set_startsHumongous() { void HeapRegion::set_startsHumongous(HeapWord* new_end) {
assert(end() == _orig_end,
"Should be normal before the humongous object allocation");
assert(top() == bottom(), "should be empty");
_humongous_type = StartsHumongous; _humongous_type = StartsHumongous;
_humongous_start_region = this; _humongous_start_region = this;
assert(end() == _orig_end, "Should be normal before alloc.");
set_end(new_end);
_offsets.set_for_starts_humongous(new_end);
}
void HeapRegion::set_continuesHumongous(HeapRegion* start) {
assert(end() == _orig_end,
"Should be normal before the humongous object allocation");
assert(top() == bottom(), "should be empty");
assert(start->startsHumongous(), "pre-condition");
_humongous_type = ContinuesHumongous;
_humongous_start_region = start;
} }
bool HeapRegion::claimHeapRegion(jint claimValue) { bool HeapRegion::claimHeapRegion(jint claimValue) {
@ -500,23 +516,6 @@ CompactibleSpace* HeapRegion::next_compaction_space() const {
return blk.result(); return blk.result();
} }
void HeapRegion::set_continuesHumongous(HeapRegion* start) {
// The order is important here.
start->add_continuingHumongousRegion(this);
_humongous_type = ContinuesHumongous;
_humongous_start_region = start;
}
void HeapRegion::add_continuingHumongousRegion(HeapRegion* cont) {
// Must join the blocks of the current H region seq with the block of the
// added region.
offsets()->join_blocks(bottom(), cont->bottom());
arrayOop obj = (arrayOop)(bottom());
obj->set_length((int) (obj->length() + cont->capacity()/jintSize));
set_end(cont->end());
set_top(cont->end());
}
void HeapRegion::save_marks() { void HeapRegion::save_marks() {
set_saved_mark(); set_saved_mark();
} }

View file

@ -395,14 +395,12 @@ class HeapRegion: public G1OffsetTableContigSpace {
// Causes the current region to represent a humongous object spanning "n" // Causes the current region to represent a humongous object spanning "n"
// regions. // regions.
virtual void set_startsHumongous(); void set_startsHumongous(HeapWord* new_end);
// The regions that continue a humongous sequence should be added using // The regions that continue a humongous sequence should be added using
// this method, in increasing address order. // this method, in increasing address order.
void set_continuesHumongous(HeapRegion* start); void set_continuesHumongous(HeapRegion* start);
void add_continuingHumongousRegion(HeapRegion* cont);
// If the region has a remembered set, return a pointer to it. // If the region has a remembered set, return a pointer to it.
HeapRegionRemSet* rem_set() const { HeapRegionRemSet* rem_set() const {
return _rem_set; return _rem_set;
@ -733,13 +731,6 @@ class HeapRegion: public G1OffsetTableContigSpace {
FilterOutOfRegionClosure* cl, FilterOutOfRegionClosure* cl,
bool filter_young); bool filter_young);
// The region "mr" is entirely in "this", and starts and ends at block
// boundaries. The caller declares that all the contained blocks are
// coalesced into one.
void declare_filled_region_to_BOT(MemRegion mr) {
_offsets.single_block(mr.start(), mr.end());
}
// A version of block start that is guaranteed to find *some* block // A version of block start that is guaranteed to find *some* block
// boundary at or before "p", but does not object iteration, and may // boundary at or before "p", but does not object iteration, and may
// therefore be used safely when the heap is unparseable. // therefore be used safely when the heap is unparseable.

View file

@ -1159,9 +1159,7 @@ HeapRegionRemSetIterator() :
_hrrs(NULL), _hrrs(NULL),
_g1h(G1CollectedHeap::heap()), _g1h(G1CollectedHeap::heap()),
_bosa(NULL), _bosa(NULL),
_sparse_iter(size_t(G1CollectedHeap::heap()->reserved_region().start()) _sparse_iter() { }
>> CardTableModRefBS::card_shift)
{}
void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) { void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) {
_hrrs = hrrs; _hrrs = hrrs;

View file

@ -91,34 +91,118 @@ HeapRegionSeq::alloc_obj_from_region_index(int ind, size_t word_size) {
} }
if (sumSizes >= word_size) { if (sumSizes >= word_size) {
_alloc_search_start = cur; _alloc_search_start = cur;
// Mark the allocated regions as allocated.
// We need to initialize the region(s) we just discovered. This is
// a bit tricky given that it can happen concurrently with
// refinement threads refining cards on these regions and
// potentially wanting to refine the BOT as they are scanning
// those cards (this can happen shortly after a cleanup; see CR
// 6991377). So we have to set up the region(s) carefully and in
// a specific order.
// Currently, allocs_are_zero_filled() returns false. The zero
// filling infrastructure will be going away soon (see CR 6977804).
// So no need to do anything else here.
bool zf = G1CollectedHeap::heap()->allocs_are_zero_filled(); bool zf = G1CollectedHeap::heap()->allocs_are_zero_filled();
assert(!zf, "not supported");
// This will be the "starts humongous" region.
HeapRegion* first_hr = _regions.at(first); HeapRegion* first_hr = _regions.at(first);
for (int i = first; i < cur; i++) { {
HeapRegion* hr = _regions.at(i); MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag);
if (zf) first_hr->set_zero_fill_allocated();
hr->ensure_zero_filled(); }
// The header of the new object will be placed at the bottom of
// the first region.
HeapWord* new_obj = first_hr->bottom();
// This will be the new end of the first region in the series that
// should also match the end of the last region in the seriers.
// (Note: sumSizes = "region size" x "number of regions we found").
HeapWord* new_end = new_obj + sumSizes;
// This will be the new top of the first region that will reflect
// this allocation.
HeapWord* new_top = new_obj + word_size;
// First, we need to zero the header of the space that we will be
// allocating. When we update top further down, some refinement
// threads might try to scan the region. By zeroing the header we
// ensure that any thread that will try to scan the region will
// come across the zero klass word and bail out.
//
// NOTE: It would not have been correct to have used
// CollectedHeap::fill_with_object() and make the space look like
// an int array. The thread that is doing the allocation will
// later update the object header to a potentially different array
// type and, for a very short period of time, the klass and length
// fields will be inconsistent. This could cause a refinement
// thread to calculate the object size incorrectly.
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
// We will set up the first region as "starts humongous". This
// will also update the BOT covering all the regions to reflect
// that there is a single object that starts at the bottom of the
// first region.
first_hr->set_startsHumongous(new_end);
// Then, if there are any, we will set up the "continues
// humongous" regions.
HeapRegion* hr = NULL;
for (int i = first + 1; i < cur; ++i) {
hr = _regions.at(i);
{ {
MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag);
hr->set_zero_fill_allocated(); hr->set_zero_fill_allocated();
} }
size_t sz = hr->capacity() / HeapWordSize; hr->set_continuesHumongous(first_hr);
HeapWord* tmp = hr->allocate(sz); }
assert(tmp != NULL, "Humongous allocation failure"); // If we have "continues humongous" regions (hr != NULL), then the
MemRegion mr = MemRegion(tmp, sz); // end of the last one should match new_end.
CollectedHeap::fill_with_object(mr); assert(hr == NULL || hr->end() == new_end, "sanity");
hr->declare_filled_region_to_BOT(mr);
if (i == first) { // Up to this point no concurrent thread would have been able to
first_hr->set_startsHumongous(); // do any scanning on any region in this series. All the top
// fields still point to bottom, so the intersection between
// [bottom,top] and [card_start,card_end] will be empty. Before we
// update the top fields, we'll do a storestore to make sure that
// no thread sees the update to top before the zeroing of the
// object header and the BOT initialization.
OrderAccess::storestore();
// Now that the BOT and the object header have been initialized,
// we can update top of the "starts humongous" region.
assert(first_hr->bottom() < new_top && new_top <= first_hr->end(),
"new_top should be in this region");
first_hr->set_top(new_top);
// Now, we will update the top fields of the "continues humongous"
// regions. The reason we need to do this is that, otherwise,
// these regions would look empty and this will confuse parts of
// G1. For example, the code that looks for a consecutive number
// of empty regions will consider them empty and try to
// re-allocate them. We can extend is_empty() to also include
// !continuesHumongous(), but it is easier to just update the top
// fields here.
hr = NULL;
for (int i = first + 1; i < cur; ++i) {
hr = _regions.at(i);
if ((i + 1) == cur) {
// last continues humongous region
assert(hr->bottom() < new_top && new_top <= hr->end(),
"new_top should fall on this region");
hr->set_top(new_top);
} else { } else {
assert(i > first, "sanity"); // not last one
hr->set_continuesHumongous(first_hr); assert(new_top > hr->end(), "new_top should be above this region");
hr->set_top(hr->end());
} }
} }
HeapWord* first_hr_bot = first_hr->bottom(); // If we have continues humongous regions (hr != NULL), then the
HeapWord* obj_end = first_hr_bot + word_size; // end of the last one should match new_end and its top should
first_hr->set_top(obj_end); // match new_top.
return first_hr_bot; assert(hr == NULL ||
(hr->end() == new_end && hr->top() == new_top), "sanity");
return new_obj;
} else { } else {
// If we started from the beginning, we want to know why we can't alloc. // If we started from the beginning, we want to know why we can't alloc.
return NULL; return NULL;

View file

@ -308,7 +308,7 @@ void RSHashTable::add_entry(SparsePRTEntry* e) {
assert(e2->num_valid_cards() > 0, "Postcondition."); assert(e2->num_valid_cards() > 0, "Postcondition.");
} }
CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() { CardIdx_t RSHashTableIter::find_first_card_in_list() {
CardIdx_t res; CardIdx_t res;
while (_bl_ind != RSHashTable::NullEntry) { while (_bl_ind != RSHashTable::NullEntry) {
res = _rsht->entry(_bl_ind)->card(0); res = _rsht->entry(_bl_ind)->card(0);
@ -322,14 +322,11 @@ CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() {
return SparsePRTEntry::NullEntry; return SparsePRTEntry::NullEntry;
} }
size_t /* RSHashTable:: */ RSHashTableIter::compute_card_ind(CardIdx_t ci) { size_t RSHashTableIter::compute_card_ind(CardIdx_t ci) {
return return (_rsht->entry(_bl_ind)->r_ind() * HeapRegion::CardsPerRegion) + ci;
_heap_bot_card_ind
+ (_rsht->entry(_bl_ind)->r_ind() * HeapRegion::CardsPerRegion)
+ ci;
} }
bool /* RSHashTable:: */ RSHashTableIter::has_next(size_t& card_index) { bool RSHashTableIter::has_next(size_t& card_index) {
_card_ind++; _card_ind++;
CardIdx_t ci; CardIdx_t ci;
if (_card_ind < SparsePRTEntry::cards_num() && if (_card_ind < SparsePRTEntry::cards_num() &&

View file

@ -169,7 +169,6 @@ class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
int _bl_ind; // [-1, 0.._rsht->_capacity) int _bl_ind; // [-1, 0.._rsht->_capacity)
short _card_ind; // [0..SparsePRTEntry::cards_num()) short _card_ind; // [0..SparsePRTEntry::cards_num())
RSHashTable* _rsht; RSHashTable* _rsht;
size_t _heap_bot_card_ind;
// If the bucket list pointed to by _bl_ind contains a card, sets // If the bucket list pointed to by _bl_ind contains a card, sets
// _bl_ind to the index of that entry, and returns the card. // _bl_ind to the index of that entry, and returns the card.
@ -183,13 +182,11 @@ class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
size_t compute_card_ind(CardIdx_t ci); size_t compute_card_ind(CardIdx_t ci);
public: public:
RSHashTableIter(size_t heap_bot_card_ind) : RSHashTableIter() :
_tbl_ind(RSHashTable::NullEntry), _tbl_ind(RSHashTable::NullEntry),
_bl_ind(RSHashTable::NullEntry), _bl_ind(RSHashTable::NullEntry),
_card_ind((SparsePRTEntry::cards_num() - 1)), _card_ind((SparsePRTEntry::cards_num() - 1)),
_rsht(NULL), _rsht(NULL) {}
_heap_bot_card_ind(heap_bot_card_ind)
{}
void init(RSHashTable* rsht) { void init(RSHashTable* rsht) {
_rsht = rsht; _rsht = rsht;
@ -280,20 +277,11 @@ public:
bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const { bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
return _next->contains_card(region_id, card_index); return _next->contains_card(region_id, card_index);
} }
#if 0
void verify_is_cleared();
void print();
#endif
}; };
class SparsePRTIter: public /* RSHashTable:: */RSHashTableIter { class SparsePRTIter: public RSHashTableIter {
public: public:
SparsePRTIter(size_t heap_bot_card_ind) :
/* RSHashTable:: */RSHashTableIter(heap_bot_card_ind)
{}
void init(const SparsePRT* sprt) { void init(const SparsePRT* sprt) {
RSHashTableIter::init(sprt->cur()); RSHashTableIter::init(sprt->cur());
} }

View file

@ -133,6 +133,7 @@ parallelScavengeHeap.cpp psMarkSweep.hpp
parallelScavengeHeap.cpp psParallelCompact.hpp parallelScavengeHeap.cpp psParallelCompact.hpp
parallelScavengeHeap.cpp psPromotionManager.hpp parallelScavengeHeap.cpp psPromotionManager.hpp
parallelScavengeHeap.cpp psScavenge.hpp parallelScavengeHeap.cpp psScavenge.hpp
parallelScavengeHeap.cpp vmError.hpp
parallelScavengeHeap.cpp vmThread.hpp parallelScavengeHeap.cpp vmThread.hpp
parallelScavengeHeap.cpp vmPSOperations.hpp parallelScavengeHeap.cpp vmPSOperations.hpp

View file

@ -846,7 +846,7 @@ void ParNewGeneration::collect(bool full,
// from this generation, pass on collection; let the next generation // from this generation, pass on collection; let the next generation
// do it. // do it.
if (!collection_attempt_is_safe()) { if (!collection_attempt_is_safe()) {
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_failed(); // slight lie, in that we did not even attempt one
return; return;
} }
assert(to()->is_empty(), "Else not collection_attempt_is_safe"); assert(to()->is_empty(), "Else not collection_attempt_is_safe");
@ -935,8 +935,6 @@ void ParNewGeneration::collect(bool full,
assert(to()->is_empty(), "to space should be empty now"); assert(to()->is_empty(), "to space should be empty now");
} else { } else {
assert(HandlePromotionFailure,
"Should only be here if promotion failure handling is on");
assert(_promo_failure_scan_stack.is_empty(), "post condition"); assert(_promo_failure_scan_stack.is_empty(), "post condition");
_promo_failure_scan_stack.clear(true); // Clear cached segments. _promo_failure_scan_stack.clear(true); // Clear cached segments.
@ -947,7 +945,7 @@ void ParNewGeneration::collect(bool full,
// All the spaces are in play for mark-sweep. // All the spaces are in play for mark-sweep.
swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
from()->set_next_compaction_space(to()); from()->set_next_compaction_space(to());
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_failed();
// Inform the next generation that a promotion failure occurred. // Inform the next generation that a promotion failure occurred.
_next_gen->promotion_failure_occurred(); _next_gen->promotion_failure_occurred();
@ -1092,11 +1090,6 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
old, m, sz); old, m, sz);
if (new_obj == NULL) { if (new_obj == NULL) {
if (!HandlePromotionFailure) {
// A failed promotion likely means the MaxLiveObjectEvacuationRatio flag
// is incorrectly set. In any case, its seriously wrong to be here!
vm_exit_out_of_memory(sz*wordSize, "promotion");
}
// promotion failed, forward to self // promotion failed, forward to self
_promotion_failed = true; _promotion_failed = true;
new_obj = old; new_obj = old;
@ -1206,12 +1199,6 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo(
old, m, sz); old, m, sz);
if (new_obj == NULL) { if (new_obj == NULL) {
if (!HandlePromotionFailure) {
// A failed promotion likely means the MaxLiveObjectEvacuationRatio
// flag is incorrectly set. In any case, its seriously wrong to be
// here!
vm_exit_out_of_memory(sz*wordSize, "promotion");
}
// promotion failed, forward to self // promotion failed, forward to self
forward_ptr = old->forward_to_atomic(old); forward_ptr = old->forward_to_atomic(old);
new_obj = old; new_obj = old;

View file

@ -805,7 +805,8 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
if (young_gen()->is_in_reserved(addr)) { if (young_gen()->is_in_reserved(addr)) {
assert(young_gen()->is_in(addr), assert(young_gen()->is_in(addr),
"addr should be in allocated part of young gen"); "addr should be in allocated part of young gen");
if (Debugging) return NULL; // called from find() in debug.cpp // called from os::print_location by find or VMError
if (Debugging || VMError::fatal_error_in_progress()) return NULL;
Unimplemented(); Unimplemented();
} else if (old_gen()->is_in_reserved(addr)) { } else if (old_gen()->is_in_reserved(addr)) {
assert(old_gen()->is_in(addr), assert(old_gen()->is_in(addr),

View file

@ -1272,6 +1272,7 @@ constantPoolOop.cpp javaClasses.hpp
constantPoolOop.cpp linkResolver.hpp constantPoolOop.cpp linkResolver.hpp
constantPoolOop.cpp objArrayKlass.hpp constantPoolOop.cpp objArrayKlass.hpp
constantPoolOop.cpp oop.inline.hpp constantPoolOop.cpp oop.inline.hpp
constantPoolOop.cpp oopFactory.hpp
constantPoolOop.cpp signature.hpp constantPoolOop.cpp signature.hpp
constantPoolOop.cpp symbolTable.hpp constantPoolOop.cpp symbolTable.hpp
constantPoolOop.cpp systemDictionary.hpp constantPoolOop.cpp systemDictionary.hpp

View file

@ -154,6 +154,7 @@ jvmtiExtensions.hpp allocation.hpp
jvmtiExtensions.hpp jvmti.h jvmtiExtensions.hpp jvmti.h
jvmtiExtensions.hpp jvmtiEnv.hpp jvmtiExtensions.hpp jvmtiEnv.hpp
jvmtiImpl.cpp deoptimization.hpp
jvmtiImpl.cpp exceptions.hpp jvmtiImpl.cpp exceptions.hpp
jvmtiImpl.cpp handles.hpp jvmtiImpl.cpp handles.hpp
jvmtiImpl.cpp handles.inline.hpp jvmtiImpl.cpp handles.inline.hpp

View file

@ -89,6 +89,7 @@ jvmtiEnv.cpp vmThread.hpp
jvmtiEnv.hpp jvmtiEnvBase.hpp jvmtiEnv.hpp jvmtiEnvBase.hpp
jvmtiEnvBase.cpp biasedLocking.hpp jvmtiEnvBase.cpp biasedLocking.hpp
jvmtiEnvBase.cpp deoptimization.hpp
jvmtiEnvBase.cpp interfaceSupport.hpp jvmtiEnvBase.cpp interfaceSupport.hpp
jvmtiEnvBase.cpp jfieldIDWorkaround.hpp jvmtiEnvBase.cpp jfieldIDWorkaround.hpp
jvmtiEnvBase.cpp jvmtiEnv.hpp jvmtiEnvBase.cpp jvmtiEnv.hpp

View file

@ -716,12 +716,13 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
assert(constantPoolCacheOopDesc::is_secondary_index(site_index), "proper format"); assert(constantPoolCacheOopDesc::is_secondary_index(site_index), "proper format");
// there is a second CPC entries that is of interest; it caches signature info: // there is a second CPC entries that is of interest; it caches signature info:
int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index(); int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index();
int pool_index = pool->cache()->entry_at(main_index)->constant_pool_index();
// first resolve the signature to a MH.invoke methodOop // first resolve the signature to a MH.invoke methodOop
if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) { if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) {
JvmtiHideSingleStepping jhss(thread); JvmtiHideSingleStepping jhss(thread);
CallInfo info; CallInfo callinfo;
LinkResolver::resolve_invoke(info, Handle(), pool, LinkResolver::resolve_invoke(callinfo, Handle(), pool,
site_index, bytecode, CHECK); site_index, bytecode, CHECK);
// The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves // The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves
// as a common reference point for all invokedynamic call sites with // as a common reference point for all invokedynamic call sites with
@ -729,8 +730,8 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
// as if it were an invokevirtual of MethodHandle.invoke. // as if it were an invokevirtual of MethodHandle.invoke.
pool->cache()->entry_at(main_index)->set_method( pool->cache()->entry_at(main_index)->set_method(
bytecode, bytecode,
info.resolved_method(), callinfo.resolved_method(),
info.vtable_index()); callinfo.vtable_index());
} }
// The method (f2 entry) of the main entry is the MH.invoke for the // The method (f2 entry) of the main entry is the MH.invoke for the
@ -740,9 +741,10 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(), assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(),
"correct result from LinkResolver::resolve_invokedynamic"); "correct result from LinkResolver::resolve_invokedynamic");
Handle info; // optional argument(s) in JVM_CONSTANT_InvokeDynamic
Handle bootm = SystemDictionary::find_bootstrap_method(caller_method, caller_bci, Handle bootm = SystemDictionary::find_bootstrap_method(caller_method, caller_bci,
main_index, CHECK); main_index, info, CHECK);
if (bootm.is_null()) { if (!java_dyn_MethodHandle::is_instance(bootm())) {
THROW_MSG(vmSymbols::java_lang_IllegalStateException(), THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
"no bootstrap method found for invokedynamic"); "no bootstrap method found for invokedynamic");
} }
@ -753,8 +755,6 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index)); symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index));
Handle info; // NYI: Other metadata from a new kind of CP entry. (Annotations?)
Handle call_site Handle call_site
= SystemDictionary::make_dynamic_call_site(bootm, = SystemDictionary::make_dynamic_call_site(bootm,
// Callee information: // Callee information:

View file

@ -659,9 +659,6 @@ HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
} }
return result; // could be null if we are out of space return result; // could be null if we are out of space
} else if (!gch->incremental_collection_will_fail()) { } else if (!gch->incremental_collection_will_fail()) {
// The gc_prologues have not executed yet. The value
// for incremental_collection_will_fail() is the remanent
// of the last collection.
// Do an incremental collection. // Do an incremental collection.
gch->do_collection(false /* full */, gch->do_collection(false /* full */,
false /* clear_all_soft_refs */, false /* clear_all_soft_refs */,
@ -739,9 +736,8 @@ bool GenCollectorPolicy::should_try_older_generation_allocation(
GenCollectedHeap* gch = GenCollectedHeap::heap(); GenCollectedHeap* gch = GenCollectedHeap::heap();
size_t gen0_capacity = gch->get_gen(0)->capacity_before_gc(); size_t gen0_capacity = gch->get_gen(0)->capacity_before_gc();
return (word_size > heap_word_size(gen0_capacity)) return (word_size > heap_word_size(gen0_capacity))
|| (GC_locker::is_active_and_needs_gc()) || GC_locker::is_active_and_needs_gc()
|| ( gch->last_incremental_collection_failed() || gch->incremental_collection_failed();
&& gch->incremental_collection_will_fail());
} }

View file

@ -510,7 +510,7 @@ void DefNewGeneration::collect(bool full,
// from this generation, pass on collection; let the next generation // from this generation, pass on collection; let the next generation
// do it. // do it.
if (!collection_attempt_is_safe()) { if (!collection_attempt_is_safe()) {
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_failed(); // Slight lie: we did not even attempt one
return; return;
} }
assert(to()->is_empty(), "Else not collection_attempt_is_safe"); assert(to()->is_empty(), "Else not collection_attempt_is_safe");
@ -596,9 +596,8 @@ void DefNewGeneration::collect(bool full,
if (PrintGC && !PrintGCDetails) { if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used); gch->print_heap_change(gch_prev_used);
} }
assert(!gch->incremental_collection_failed(), "Should be clear");
} else { } else {
assert(HandlePromotionFailure,
"Should not be here unless promotion failure handling is on");
assert(_promo_failure_scan_stack.is_empty(), "post condition"); assert(_promo_failure_scan_stack.is_empty(), "post condition");
_promo_failure_scan_stack.clear(true); // Clear cached segments. _promo_failure_scan_stack.clear(true); // Clear cached segments.
@ -613,7 +612,7 @@ void DefNewGeneration::collect(bool full,
// and from-space. // and from-space.
swap_spaces(); // For uniformity wrt ParNewGeneration. swap_spaces(); // For uniformity wrt ParNewGeneration.
from()->set_next_compaction_space(to()); from()->set_next_compaction_space(to());
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_failed();
// Inform the next generation that a promotion failure occurred. // Inform the next generation that a promotion failure occurred.
_next_gen->promotion_failure_occurred(); _next_gen->promotion_failure_occurred();
@ -700,12 +699,6 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) {
if (obj == NULL) { if (obj == NULL) {
obj = _next_gen->promote(old, s); obj = _next_gen->promote(old, s);
if (obj == NULL) { if (obj == NULL) {
if (!HandlePromotionFailure) {
// A failed promotion likely means the MaxLiveObjectEvacuationRatio flag
// is incorrectly set. In any case, its seriously wrong to be here!
vm_exit_out_of_memory(s*wordSize, "promotion");
}
handle_promotion_failure(old); handle_promotion_failure(old);
return old; return old;
} }
@ -812,47 +805,43 @@ bool DefNewGeneration::collection_attempt_is_safe() {
assert(_next_gen != NULL, assert(_next_gen != NULL,
"This must be the youngest gen, and not the only gen"); "This must be the youngest gen, and not the only gen");
} }
return _next_gen->promotion_attempt_is_safe(used());
// Decide if there's enough room for a full promotion
// When using extremely large edens, we effectively lose a
// large amount of old space. Use the "MaxLiveObjectEvacuationRatio"
// flag to reduce the minimum evacuation space requirements. If
// there is not enough space to evacuate eden during a scavenge,
// the VM will immediately exit with an out of memory error.
// This flag has not been tested
// with collectors other than simple mark & sweep.
//
// Note that with the addition of promotion failure handling, the
// VM will not immediately exit but will undo the young generation
// collection. The parameter is left here for compatibility.
const double evacuation_ratio = MaxLiveObjectEvacuationRatio / 100.0;
// worst_case_evacuation is based on "used()". For the case where this
// method is called after a collection, this is still appropriate because
// the case that needs to be detected is one in which a full collection
// has been done and has overflowed into the young generation. In that
// case a minor collection will fail (the overflow of the full collection
// means there is no space in the old generation for any promotion).
size_t worst_case_evacuation = (size_t)(used() * evacuation_ratio);
return _next_gen->promotion_attempt_is_safe(worst_case_evacuation,
HandlePromotionFailure);
} }
void DefNewGeneration::gc_epilogue(bool full) { void DefNewGeneration::gc_epilogue(bool full) {
DEBUG_ONLY(static bool seen_incremental_collection_failed = false;)
assert(!GC_locker::is_active(), "We should not be executing here");
// Check if the heap is approaching full after a collection has // Check if the heap is approaching full after a collection has
// been done. Generally the young generation is empty at // been done. Generally the young generation is empty at
// a minimum at the end of a collection. If it is not, then // a minimum at the end of a collection. If it is not, then
// the heap is approaching full. // the heap is approaching full.
GenCollectedHeap* gch = GenCollectedHeap::heap(); GenCollectedHeap* gch = GenCollectedHeap::heap();
clear_should_allocate_from_space(); if (full) {
if (collection_attempt_is_safe()) { DEBUG_ONLY(seen_incremental_collection_failed = false;)
gch->clear_incremental_collection_will_fail(); if (!collection_attempt_is_safe()) {
} else { gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state
gch->set_incremental_collection_will_fail(); set_should_allocate_from_space(); // we seem to be running out of space
if (full) { // we seem to be running out of space } else {
set_should_allocate_from_space(); gch->clear_incremental_collection_failed(); // We just did a full collection
clear_should_allocate_from_space(); // if set
} }
} else {
#ifdef ASSERT
// It is possible that incremental_collection_failed() == true
// here, because an attempted scavenge did not succeed. The policy
// is normally expected to cause a full collection which should
// clear that condition, so we should not be here twice in a row
// with incremental_collection_failed() == true without having done
// a full collection in between.
if (!seen_incremental_collection_failed &&
gch->incremental_collection_failed()) {
seen_incremental_collection_failed = true;
} else if (seen_incremental_collection_failed) {
assert(!gch->incremental_collection_failed(), "Twice in a row");
seen_incremental_collection_failed = false;
}
#endif // ASSERT
} }
if (ZapUnusedHeapArea) { if (ZapUnusedHeapArea) {

View file

@ -82,12 +82,6 @@ protected:
Stack<oop> _objs_with_preserved_marks; Stack<oop> _objs_with_preserved_marks;
Stack<markOop> _preserved_marks_of_objs; Stack<markOop> _preserved_marks_of_objs;
// Returns true if the collection can be safely attempted.
// If this method returns false, a collection is not
// guaranteed to fail but the system may not be able
// to recover from the failure.
bool collection_attempt_is_safe();
// Promotion failure handling // Promotion failure handling
OopClosure *_promo_failure_scan_stack_closure; OopClosure *_promo_failure_scan_stack_closure;
void set_promo_failure_scan_stack_closure(OopClosure *scan_stack_closure) { void set_promo_failure_scan_stack_closure(OopClosure *scan_stack_closure) {
@ -304,6 +298,14 @@ protected:
// GC support // GC support
virtual void compute_new_size(); virtual void compute_new_size();
// Returns true if the collection is likely to be safely
// completed. Even if this method returns true, a collection
// may not be guaranteed to succeed, and the system should be
// able to safely unwind and recover from that failure, albeit
// at some additional cost. Override superclass's implementation.
virtual bool collection_attempt_is_safe();
virtual void collect(bool full, virtual void collect(bool full,
bool clear_all_soft_refs, bool clear_all_soft_refs,
size_t size, size_t size,

View file

@ -142,8 +142,7 @@ jint GenCollectedHeap::initialize() {
} }
_perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set()); _perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set());
clear_incremental_collection_will_fail(); clear_incremental_collection_failed();
clear_last_incremental_collection_failed();
#ifndef SERIALGC #ifndef SERIALGC
// If we are running CMS, create the collector responsible // If we are running CMS, create the collector responsible
@ -1347,17 +1346,6 @@ class GenGCEpilogueClosure: public GenCollectedHeap::GenClosure {
}; };
void GenCollectedHeap::gc_epilogue(bool full) { void GenCollectedHeap::gc_epilogue(bool full) {
// Remember if a partial collection of the heap failed, and
// we did a complete collection.
if (full && incremental_collection_will_fail()) {
set_last_incremental_collection_failed();
} else {
clear_last_incremental_collection_failed();
}
// Clear the flag, if set; the generation gc_epilogues will set the
// flag again if the condition persists despite the collection.
clear_incremental_collection_will_fail();
#ifdef COMPILER2 #ifdef COMPILER2
assert(DerivedPointerTable::is_empty(), "derived pointer present"); assert(DerivedPointerTable::is_empty(), "derived pointer present");
size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr()));

View file

@ -62,11 +62,10 @@ public:
// The generational collector policy. // The generational collector policy.
GenCollectorPolicy* _gen_policy; GenCollectorPolicy* _gen_policy;
// If a generation would bail out of an incremental collection, // Indicates that the most recent previous incremental collection failed.
// it sets this flag. If the flag is set, satisfy_failed_allocation // The flag is cleared when an action is taken that might clear the
// will attempt allocating in all generations before doing a full GC. // condition that caused that incremental collection to fail.
bool _incremental_collection_will_fail; bool _incremental_collection_failed;
bool _last_incremental_collection_failed;
// In support of ExplicitGCInvokesConcurrent functionality // In support of ExplicitGCInvokesConcurrent functionality
unsigned int _full_collections_completed; unsigned int _full_collections_completed;
@ -469,26 +468,26 @@ public:
// call to "save_marks". // call to "save_marks".
bool no_allocs_since_save_marks(int level); bool no_allocs_since_save_marks(int level);
// If a generation bails out of an incremental collection, // Returns true if an incremental collection is likely to fail.
// it sets this flag.
bool incremental_collection_will_fail() { bool incremental_collection_will_fail() {
return _incremental_collection_will_fail; // Assumes a 2-generation system; the first disjunct remembers if an
} // incremental collection failed, even when we thought (second disjunct)
void set_incremental_collection_will_fail() { // that it would not.
_incremental_collection_will_fail = true; assert(heap()->collector_policy()->is_two_generation_policy(),
} "the following definition may not be suitable for an n(>2)-generation system");
void clear_incremental_collection_will_fail() { return incremental_collection_failed() || !get_gen(0)->collection_attempt_is_safe();
_incremental_collection_will_fail = false;
} }
bool last_incremental_collection_failed() const { // If a generation bails out of an incremental collection,
return _last_incremental_collection_failed; // it sets this flag.
bool incremental_collection_failed() const {
return _incremental_collection_failed;
} }
void set_last_incremental_collection_failed() { void set_incremental_collection_failed() {
_last_incremental_collection_failed = true; _incremental_collection_failed = true;
} }
void clear_last_incremental_collection_failed() { void clear_incremental_collection_failed() {
_last_incremental_collection_failed = false; _incremental_collection_failed = false;
} }
// Promotion of obj into gen failed. Try to promote obj to higher non-perm // Promotion of obj into gen failed. Try to promote obj to higher non-perm

View file

@ -165,15 +165,16 @@ size_t Generation::max_contiguous_available() const {
return max; return max;
} }
bool Generation::promotion_attempt_is_safe(size_t promotion_in_bytes, bool Generation::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
bool not_used) const { size_t available = max_contiguous_available();
bool res = (available >= max_promotion_in_bytes);
if (PrintGC && Verbose) { if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Generation::promotion_attempt_is_safe" gclog_or_tty->print_cr(
" contiguous_available: " SIZE_FORMAT "Generation: promo attempt is%s safe: available("SIZE_FORMAT") %s max_promo("SIZE_FORMAT")",
" promotion_in_bytes: " SIZE_FORMAT, res? "":" not", available, res? ">=":"<",
max_contiguous_available(), promotion_in_bytes); max_promotion_in_bytes);
} }
return max_contiguous_available() >= promotion_in_bytes; return res;
} }
// Ignores "ref" and calls allocate(). // Ignores "ref" and calls allocate().

View file

@ -173,15 +173,11 @@ class Generation: public CHeapObj {
// The largest number of contiguous free bytes in this or any higher generation. // The largest number of contiguous free bytes in this or any higher generation.
virtual size_t max_contiguous_available() const; virtual size_t max_contiguous_available() const;
// Returns true if promotions of the specified amount can // Returns true if promotions of the specified amount are
// be attempted safely (without a vm failure). // likely to succeed without a promotion failure.
// Promotion of the full amount is not guaranteed but // Promotion of the full amount is not guaranteed but
// can be attempted. // might be attempted in the worst case.
// younger_handles_promotion_failure virtual bool promotion_attempt_is_safe(size_t max_promotion_in_bytes) const;
// is true if the younger generation handles a promotion
// failure.
virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes,
bool younger_handles_promotion_failure) const;
// For a non-young generation, this interface can be used to inform a // For a non-young generation, this interface can be used to inform a
// generation that a promotion attempt into that generation failed. // generation that a promotion attempt into that generation failed.
@ -358,6 +354,16 @@ class Generation: public CHeapObj {
return (full || should_allocate(word_size, is_tlab)); return (full || should_allocate(word_size, is_tlab));
} }
// Returns true if the collection is likely to be safely
// completed. Even if this method returns true, a collection
// may not be guaranteed to succeed, and the system should be
// able to safely unwind and recover from that failure, albeit
// at some additional cost.
virtual bool collection_attempt_is_safe() {
guarantee(false, "Are you sure you want to call this method?");
return true;
}
// Perform a garbage collection. // Perform a garbage collection.
// If full is true attempt a full garbage collection of this generation. // If full is true attempt a full garbage collection of this generation.
// Otherwise, attempting to (at least) free enough space to support an // Otherwise, attempting to (at least) free enough space to support an

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -140,6 +140,7 @@ class CodeHeap : public CHeapObj {
// Returns reserved area high and low addresses // Returns reserved area high and low addresses
char *low_boundary() const { return _memory.low_boundary (); } char *low_boundary() const { return _memory.low_boundary (); }
char *high() const { return _memory.high(); }
char *high_boundary() const { return _memory.high_boundary(); } char *high_boundary() const { return _memory.high_boundary(); }
// Iteration // Iteration

View file

@ -419,29 +419,16 @@ void TenuredGeneration::retire_alloc_buffers_before_full_gc() {}
void TenuredGeneration::verify_alloc_buffers_clean() {} void TenuredGeneration::verify_alloc_buffers_clean() {}
#endif // SERIALGC #endif // SERIALGC
bool TenuredGeneration::promotion_attempt_is_safe( bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
size_t max_promotion_in_bytes, size_t available = max_contiguous_available();
bool younger_handles_promotion_failure) const { size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average();
bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
bool result = max_contiguous_available() >= max_promotion_in_bytes; if (PrintGC && Verbose) {
gclog_or_tty->print_cr(
if (younger_handles_promotion_failure && !result) { "Tenured: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
result = max_contiguous_available() >= "max_promo("SIZE_FORMAT")",
(size_t) gc_stats()->avg_promoted()->padded_average(); res? "":" not", available, res? ">=":"<",
if (PrintGC && Verbose && result) { av_promo, max_promotion_in_bytes);
gclog_or_tty->print_cr("TenuredGeneration::promotion_attempt_is_safe"
" contiguous_available: " SIZE_FORMAT
" avg_promoted: " SIZE_FORMAT,
max_contiguous_available(),
gc_stats()->avg_promoted()->padded_average());
}
} else {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("TenuredGeneration::promotion_attempt_is_safe"
" contiguous_available: " SIZE_FORMAT
" promotion_in_bytes: " SIZE_FORMAT,
max_contiguous_available(), max_promotion_in_bytes);
}
} }
return result; return res;
} }

View file

@ -101,8 +101,7 @@ class TenuredGeneration: public OneContigSpaceCardGeneration {
virtual void update_gc_stats(int level, bool full); virtual void update_gc_stats(int level, bool full);
virtual bool promotion_attempt_is_safe(size_t max_promoted_in_bytes, virtual bool promotion_attempt_is_safe(size_t max_promoted_in_bytes) const;
bool younger_handles_promotion_failure) const;
void verify_alloc_buffers_clean(); void verify_alloc_buffers_clean();
}; };

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -340,6 +340,7 @@ class Universe: AllStatic {
static klassOop* longArrayKlassObj_addr() { return &_longArrayKlassObj; } static klassOop* longArrayKlassObj_addr() { return &_longArrayKlassObj; }
static klassOop* singleArrayKlassObj_addr() { return &_singleArrayKlassObj; } static klassOop* singleArrayKlassObj_addr() { return &_singleArrayKlassObj; }
static klassOop* doubleArrayKlassObj_addr() { return &_doubleArrayKlassObj; } static klassOop* doubleArrayKlassObj_addr() { return &_doubleArrayKlassObj; }
static klassOop* systemObjArrayKlassObj_addr() { return &_systemObjArrayKlassObj; }
// The particular choice of collected heap. // The particular choice of collected heap.
static CollectedHeap* heap() { return _collectedHeap; } static CollectedHeap* heap() { return _collectedHeap; }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@ constantPoolOop constantPoolKlass::allocate(int length, bool is_conc_safe, TRAPS
c->set_length(length); c->set_length(length);
c->set_tags(NULL); c->set_tags(NULL);
c->set_cache(NULL); c->set_cache(NULL);
c->set_operands(NULL);
c->set_pool_holder(NULL); c->set_pool_holder(NULL);
c->set_flags(0); c->set_flags(0);
// only set to non-zero if constant pool is merged by RedefineClasses // only set to non-zero if constant pool is merged by RedefineClasses
@ -92,6 +93,7 @@ void constantPoolKlass::oop_follow_contents(oop obj) {
// gc of constant pool instance variables // gc of constant pool instance variables
MarkSweep::mark_and_push(cp->tags_addr()); MarkSweep::mark_and_push(cp->tags_addr());
MarkSweep::mark_and_push(cp->cache_addr()); MarkSweep::mark_and_push(cp->cache_addr());
MarkSweep::mark_and_push(cp->operands_addr());
MarkSweep::mark_and_push(cp->pool_holder_addr()); MarkSweep::mark_and_push(cp->pool_holder_addr());
} }
} }
@ -118,6 +120,7 @@ void constantPoolKlass::oop_follow_contents(ParCompactionManager* cm,
// gc of constant pool instance variables // gc of constant pool instance variables
PSParallelCompact::mark_and_push(cm, cp->tags_addr()); PSParallelCompact::mark_and_push(cm, cp->tags_addr());
PSParallelCompact::mark_and_push(cm, cp->cache_addr()); PSParallelCompact::mark_and_push(cm, cp->cache_addr());
PSParallelCompact::mark_and_push(cm, cp->operands_addr());
PSParallelCompact::mark_and_push(cm, cp->pool_holder_addr()); PSParallelCompact::mark_and_push(cm, cp->pool_holder_addr());
} }
} }
@ -146,6 +149,7 @@ int constantPoolKlass::oop_adjust_pointers(oop obj) {
} }
MarkSweep::adjust_pointer(cp->tags_addr()); MarkSweep::adjust_pointer(cp->tags_addr());
MarkSweep::adjust_pointer(cp->cache_addr()); MarkSweep::adjust_pointer(cp->cache_addr());
MarkSweep::adjust_pointer(cp->operands_addr());
MarkSweep::adjust_pointer(cp->pool_holder_addr()); MarkSweep::adjust_pointer(cp->pool_holder_addr());
return size; return size;
} }
@ -173,6 +177,7 @@ int constantPoolKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
} }
blk->do_oop(cp->tags_addr()); blk->do_oop(cp->tags_addr());
blk->do_oop(cp->cache_addr()); blk->do_oop(cp->cache_addr());
blk->do_oop(cp->operands_addr());
blk->do_oop(cp->pool_holder_addr()); blk->do_oop(cp->pool_holder_addr());
return size; return size;
} }
@ -205,6 +210,8 @@ int constantPoolKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr)
blk->do_oop(addr); blk->do_oop(addr);
addr = cp->cache_addr(); addr = cp->cache_addr();
blk->do_oop(addr); blk->do_oop(addr);
addr = cp->operands_addr();
blk->do_oop(addr);
addr = cp->pool_holder_addr(); addr = cp->pool_holder_addr();
blk->do_oop(addr); blk->do_oop(addr);
return size; return size;
@ -232,6 +239,7 @@ int constantPoolKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
} }
PSParallelCompact::adjust_pointer(cp->tags_addr()); PSParallelCompact::adjust_pointer(cp->tags_addr());
PSParallelCompact::adjust_pointer(cp->cache_addr()); PSParallelCompact::adjust_pointer(cp->cache_addr());
PSParallelCompact::adjust_pointer(cp->operands_addr());
PSParallelCompact::adjust_pointer(cp->pool_holder_addr()); PSParallelCompact::adjust_pointer(cp->pool_holder_addr());
return cp->object_size(); return cp->object_size();
} }
@ -262,6 +270,8 @@ constantPoolKlass::oop_update_pointers(ParCompactionManager* cm, oop obj,
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
p = cp->cache_addr(); p = cp->cache_addr();
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
p = cp->operands_addr();
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
p = cp->pool_holder_addr(); p = cp->pool_holder_addr();
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
@ -363,8 +373,18 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
st->print("signature_index=%d", cp->method_type_index_at(index)); st->print("signature_index=%d", cp->method_type_index_at(index));
break; break;
case JVM_CONSTANT_InvokeDynamic : case JVM_CONSTANT_InvokeDynamic :
st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index)); {
st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index)); st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index));
st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index));
int argc = cp->invoke_dynamic_argument_count_at(index);
if (argc > 0) {
for (int arg_i = 0; arg_i < argc; arg_i++) {
int arg = cp->invoke_dynamic_argument_index_at(index, arg_i);
st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg);
}
st->print("}");
}
}
break; break;
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
@ -381,6 +401,7 @@ void constantPoolKlass::oop_print_value_on(oop obj, outputStream* st) {
st->print("constant pool [%d]", cp->length()); st->print("constant pool [%d]", cp->length());
if (cp->has_pseudo_string()) st->print("/pseudo_string"); if (cp->has_pseudo_string()) st->print("/pseudo_string");
if (cp->has_invokedynamic()) st->print("/invokedynamic"); if (cp->has_invokedynamic()) st->print("/invokedynamic");
if (cp->operands() != NULL) st->print("/operands[%d]", cp->operands()->length());
cp->print_address_on(st); cp->print_address_on(st);
st->print(" for "); st->print(" for ");
cp->pool_holder()->print_value_on(st); cp->pool_holder()->print_value_on(st);
@ -440,6 +461,10 @@ void constantPoolKlass::oop_verify_on(oop obj, outputStream* st) {
guarantee(cp->cache()->is_perm(), "should be in permspace"); guarantee(cp->cache()->is_perm(), "should be in permspace");
guarantee(cp->cache()->is_constantPoolCache(), "should be constant pool cache"); guarantee(cp->cache()->is_constantPoolCache(), "should be constant pool cache");
} }
if (cp->operands() != NULL) {
guarantee(cp->operands()->is_perm(), "should be in permspace");
guarantee(cp->operands()->is_typeArray(), "should be type array");
}
if (cp->pool_holder() != NULL) { if (cp->pool_holder() != NULL) {
// Note: pool_holder() can be NULL in temporary constant pools // Note: pool_holder() can be NULL in temporary constant pools
// used during constant pool merging // used during constant pool merging

View file

@ -265,10 +265,9 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
int i = which; int i = which;
if (!uncached && cache() != NULL) { if (!uncached && cache() != NULL) {
if (constantPoolCacheOopDesc::is_secondary_index(which)) { if (constantPoolCacheOopDesc::is_secondary_index(which)) {
// Invokedynamic indexes are always processed in native order // Invokedynamic index.
// so there is no question of reading a native u2 in Java order here.
int pool_index = cache()->main_entry_at(which)->constant_pool_index(); int pool_index = cache()->main_entry_at(which)->constant_pool_index();
if (tag_at(pool_index).is_invoke_dynamic()) if (!AllowTransitionalJSR292 || tag_at(pool_index).is_invoke_dynamic())
pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index); pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
assert(tag_at(pool_index).is_name_and_type(), ""); assert(tag_at(pool_index).is_name_and_type(), "");
return pool_index; return pool_index;
@ -276,11 +275,17 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
// change byte-ordering and go via cache // change byte-ordering and go via cache
i = remap_instruction_operand_from_cache(which); i = remap_instruction_operand_from_cache(which);
} else { } else {
if (tag_at(which).is_name_and_type()) if (AllowTransitionalJSR292 && tag_at(which).is_name_and_type())
// invokedynamic index is a simple name-and-type // invokedynamic index is a simple name-and-type
return which; return which;
if (tag_at(which).is_invoke_dynamic()) {
int pool_index = invoke_dynamic_name_and_type_ref_index_at(which);
assert(tag_at(pool_index).is_name_and_type(), "");
return pool_index;
}
} }
assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
jint ref_index = *int_at_addr(i); jint ref_index = *int_at_addr(i);
return extract_high_short_from_int(ref_index); return extract_high_short_from_int(ref_index);
} }
@ -394,18 +399,61 @@ void constantPoolOopDesc::resolve_string_constants_impl(constantPoolHandle this_
} }
} }
// A resolved constant value in the CP cache is represented as a non-null
// value. As a special case, this value can be a 'systemObjArray'
// which masks an exception object to throw.
// This allows a MethodHandle constant reference to throw a consistent
// exception every time, if it fails to resolve.
static oop decode_exception_from_f1(oop result_oop, TRAPS) {
if (result_oop->klass() != Universe::systemObjArrayKlassObj())
return result_oop;
// Special cases here: Masked null, saved exception.
objArrayOop sys_array = (objArrayOop) result_oop;
assert(sys_array->length() == 1, "bad system array");
if (sys_array->length() == 1) {
THROW_OOP_(sys_array->obj_at(0), NULL);
}
return NULL;
}
oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) { oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) {
oop result_oop = NULL; oop result_oop = NULL;
Handle throw_exception;
if (cache_index == _possible_index_sentinel) {
// It is possible that this constant is one which is cached in the CP cache.
// We'll do a linear search. This should be OK because this usage is rare.
assert(index > 0, "valid index");
constantPoolCacheOop cache = this_oop()->cache();
for (int i = 0, len = cache->length(); i < len; i++) {
ConstantPoolCacheEntry* cpc_entry = cache->entry_at(i);
if (!cpc_entry->is_secondary_entry() && cpc_entry->constant_pool_index() == index) {
// Switch the query to use this CPC entry.
cache_index = i;
index = _no_index_sentinel;
break;
}
}
if (cache_index == _possible_index_sentinel)
cache_index = _no_index_sentinel; // not found
}
assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
assert(index == _no_index_sentinel || index >= 0, "");
if (cache_index >= 0) { if (cache_index >= 0) {
assert(index < 0, "only one kind of index at a time"); assert(index == _no_index_sentinel, "only one kind of index at a time");
ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index);
result_oop = cpc_entry->f1(); result_oop = cpc_entry->f1();
if (result_oop != NULL) { if (result_oop != NULL) {
return result_oop; // that was easy... return decode_exception_from_f1(result_oop, THREAD);
// That was easy...
} }
index = cpc_entry->constant_pool_index(); index = cpc_entry->constant_pool_index();
} }
jvalue prim_value; // temp used only in a few cases below
int tag_value = this_oop->tag_at(index).value(); int tag_value = this_oop->tag_at(index).value();
switch (tag_value) { switch (tag_value) {
@ -449,9 +497,14 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
KlassHandle klass(THREAD, this_oop->pool_holder()); KlassHandle klass(THREAD, this_oop->pool_holder());
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
callee, name, signature, callee, name, signature,
CHECK_NULL); THREAD);
if (HAS_PENDING_EXCEPTION) {
throw_exception = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
break;
}
result_oop = value(); result_oop = value();
// FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. assert(result_oop != NULL, "");
break; break;
} }
@ -468,20 +521,36 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
klass, klass,
false, false,
ignore_is_on_bcp, ignore_is_on_bcp,
CHECK_NULL); THREAD);
if (HAS_PENDING_EXCEPTION) {
throw_exception = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
break;
}
result_oop = value(); result_oop = value();
// FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. assert(result_oop != NULL, "");
break; break;
} }
/* maybe some day
case JVM_CONSTANT_Integer: case JVM_CONSTANT_Integer:
case JVM_CONSTANT_Float: prim_value.i = this_oop->int_at(index);
case JVM_CONSTANT_Long: result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
case JVM_CONSTANT_Double: break;
result_oop = java_lang_boxing_object::create(...);
case JVM_CONSTANT_Float:
prim_value.f = this_oop->float_at(index);
result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
break;
case JVM_CONSTANT_Long:
prim_value.j = this_oop->long_at(index);
result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
break;
case JVM_CONSTANT_Double:
prim_value.d = this_oop->double_at(index);
result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
break; break;
*/
default: default:
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
@ -492,18 +561,31 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
if (cache_index >= 0) { if (cache_index >= 0) {
// Cache the oop here also. // Cache the oop here also.
Handle result(THREAD, result_oop); if (throw_exception.not_null()) {
objArrayOop sys_array = oopFactory::new_system_objArray(1, CHECK_NULL);
sys_array->obj_at_put(0, throw_exception());
result_oop = sys_array;
throw_exception = Handle(); // be tidy
}
Handle result_handle(THREAD, result_oop);
result_oop = NULL; // safety result_oop = NULL; // safety
ObjectLocker ol(this_oop, THREAD); ObjectLocker ol(this_oop, THREAD);
ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index);
oop result_oop2 = cpc_entry->f1(); result_oop = cpc_entry->f1();
if (result_oop2 != NULL) { // Benign race condition: f1 may already be filled in while we were trying to lock.
// Race condition: May already be filled in while we were trying to lock. // The important thing here is that all threads pick up the same result.
return result_oop2; // It doesn't matter which racing thread wins, as long as only one
// result is used by all threads, and all future queries.
// That result may be either a resolved constant or a failure exception.
if (result_oop == NULL) {
result_oop = result_handle();
cpc_entry->set_f1(result_oop);
} }
cpc_entry->set_f1(result()); return decode_exception_from_f1(result_oop, THREAD);
return result();
} else { } else {
if (throw_exception.not_null()) {
THROW_HANDLE_(throw_exception, NULL);
}
return result_oop; return result_oop;
} }
} }
@ -621,6 +703,7 @@ void constantPoolOopDesc::shared_symbols_iterate(OopClosure* closure) {
void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) { void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) {
closure->do_oop(tags_addr()); closure->do_oop(tags_addr());
closure->do_oop(operands_addr());
} }
@ -838,13 +921,19 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_InvokeDynamic:
{ {
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1); int op_count = multi_operand_count_at(index1);
int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2); if (op_count == cp2->multi_operand_count_at(index2)) {
if (k1 == k2) { bool all_equal = true;
int i1 = invoke_dynamic_name_and_type_ref_index_at(index1); for (int op_i = 0; op_i < op_count; op_i++) {
int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2); int k1 = multi_operand_ref_at(index1, op_i);
if (i1 == i2) { int k2 = cp2->multi_operand_ref_at(index2, op_i);
return true; if (k1 != k2) {
all_equal = false;
break;
}
}
if (all_equal) {
return true; // got through loop; all elements equal
} }
} }
} break; } break;
@ -881,6 +970,25 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
} // end compare_entry_to() } // end compare_entry_to()
// Grow this->operands() to the indicated length, unless it is already at least that long.
void constantPoolOopDesc::multi_operand_buffer_grow(int min_length, TRAPS) {
int old_length = multi_operand_buffer_fill_pointer();
if (old_length >= min_length) return;
int new_length = min_length;
assert(new_length > _multi_operand_buffer_fill_pointer_offset, "");
typeArrayHandle new_operands = oopFactory::new_permanent_intArray(new_length, CHECK);
if (operands() == NULL) {
new_operands->int_at_put(_multi_operand_buffer_fill_pointer_offset, old_length);
} else {
// copy fill pointer and everything else
for (int i = 0; i < old_length; i++) {
new_operands->int_at_put(i, operands()->int_at(i));
}
}
set_operands(new_operands());
}
// Copy this constant pool's entries at start_i to end_i (inclusive) // Copy this constant pool's entries at start_i to end_i (inclusive)
// to the constant pool to_cp's entries starting at to_i. A total of // to the constant pool to_cp's entries starting at to_i. A total of
// (end_i - start_i) + 1 entries are copied. // (end_i - start_i) + 1 entries are copied.
@ -889,6 +997,13 @@ void constantPoolOopDesc::copy_cp_to(int start_i, int end_i,
int dest_i = to_i; // leave original alone for debug purposes int dest_i = to_i; // leave original alone for debug purposes
if (operands() != NULL) {
// pre-grow the target CP's operand buffer
int nops = this->multi_operand_buffer_fill_pointer();
nops += to_cp->multi_operand_buffer_fill_pointer();
to_cp->multi_operand_buffer_grow(nops, CHECK);
}
for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) {
copy_entry_to(src_i, to_cp, dest_i, CHECK); copy_entry_to(src_i, to_cp, dest_i, CHECK);
@ -1037,9 +1152,26 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_InvokeDynamic:
{ {
int op_count = multi_operand_count_at(from_i);
int fillp = to_cp->multi_operand_buffer_fill_pointer();
int to_op_base = fillp - _multi_operand_count_offset; // fillp is count offset; get to base
to_cp->multi_operand_buffer_grow(to_op_base + op_count, CHECK);
to_cp->operands()->int_at_put(fillp++, op_count);
assert(fillp == to_op_base + _multi_operand_base_offset, "just wrote count, will now write args");
for (int op_i = 0; op_i < op_count; op_i++) {
int op = multi_operand_ref_at(from_i, op_i);
to_cp->operands()->int_at_put(fillp++, op);
}
assert(fillp <= to_cp->operands()->length(), "oob");
to_cp->set_multi_operand_buffer_fill_pointer(fillp);
to_cp->invoke_dynamic_at_put(to_i, to_op_base, op_count);
#ifdef ASSERT
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i); int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i);
int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i); int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i);
to_cp->invoke_dynamic_at_put(to_i, k1, k2); int k3 = invoke_dynamic_argument_count_at(from_i);
assert(to_cp->check_invoke_dynamic_at(to_i, k1, k2, k3),
"indy structure is OK");
#endif //ASSERT
} break; } break;
// Invalid is used as the tag for the second constant pool entry // Invalid is used as the tag for the second constant pool entry
@ -1257,9 +1389,12 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) {
case JVM_CONSTANT_Methodref: case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_NameAndType: case JVM_CONSTANT_NameAndType:
case JVM_CONSTANT_InvokeDynamic:
return 5; return 5;
case JVM_CONSTANT_InvokeDynamic:
// u1 tag, u2 bsm, u2 nt, u2 argc, u2 argv[argc]
return 7 + 2 * invoke_dynamic_argument_count_at(idx);
case JVM_CONSTANT_Long: case JVM_CONSTANT_Long:
case JVM_CONSTANT_Double: case JVM_CONSTANT_Double:
return 9; return 9;
@ -1475,9 +1610,15 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size,
*bytes = JVM_CONSTANT_InvokeDynamic; *bytes = JVM_CONSTANT_InvokeDynamic;
idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx); idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx);
idx2 = invoke_dynamic_name_and_type_ref_index_at(idx); idx2 = invoke_dynamic_name_and_type_ref_index_at(idx);
int argc = invoke_dynamic_argument_count_at(idx);
Bytes::put_Java_u2((address) (bytes+1), idx1); Bytes::put_Java_u2((address) (bytes+1), idx1);
Bytes::put_Java_u2((address) (bytes+3), idx2); Bytes::put_Java_u2((address) (bytes+3), idx2);
DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2)); Bytes::put_Java_u2((address) (bytes+5), argc);
for (int arg_i = 0; arg_i < argc; arg_i++) {
int arg = invoke_dynamic_argument_index_at(idx, arg_i);
Bytes::put_Java_u2((address) (bytes+7+2*arg_i), arg);
}
DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd [%d]", idx1, idx2, argc));
break; break;
} }
} }

View file

@ -41,6 +41,7 @@ class constantPoolOopDesc : public oopDesc {
typeArrayOop _tags; // the tag array describing the constant pool's contents typeArrayOop _tags; // the tag array describing the constant pool's contents
constantPoolCacheOop _cache; // the cache holding interpreter runtime information constantPoolCacheOop _cache; // the cache holding interpreter runtime information
klassOop _pool_holder; // the corresponding class klassOop _pool_holder; // the corresponding class
typeArrayOop _operands; // for variable-sized (InvokeDynamic) nodes, usually empty
int _flags; // a few header bits to describe contents for GC int _flags; // a few header bits to describe contents for GC
int _length; // number of elements in the array int _length; // number of elements in the array
volatile bool _is_conc_safe; // if true, safe for concurrent volatile bool _is_conc_safe; // if true, safe for concurrent
@ -52,6 +53,8 @@ class constantPoolOopDesc : public oopDesc {
void tag_at_put(int which, jbyte t) { tags()->byte_at_put(which, t); } void tag_at_put(int which, jbyte t) { tags()->byte_at_put(which, t); }
void release_tag_at_put(int which, jbyte t) { tags()->release_byte_at_put(which, t); } void release_tag_at_put(int which, jbyte t) { tags()->release_byte_at_put(which, t); }
void set_operands(typeArrayOop operands) { oop_store_without_check((oop*)&_operands, operands); }
enum FlagBit { enum FlagBit {
FB_has_invokedynamic = 1, FB_has_invokedynamic = 1,
FB_has_pseudo_string = 2 FB_has_pseudo_string = 2
@ -67,6 +70,7 @@ class constantPoolOopDesc : public oopDesc {
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); } intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); }
oop* tags_addr() { return (oop*)&_tags; } oop* tags_addr() { return (oop*)&_tags; }
oop* cache_addr() { return (oop*)&_cache; } oop* cache_addr() { return (oop*)&_cache; }
oop* operands_addr() { return (oop*)&_operands; }
oop* obj_at_addr(int which) const { oop* obj_at_addr(int which) const {
assert(is_within_bounds(which), "index out of bounds"); assert(is_within_bounds(which), "index out of bounds");
@ -95,6 +99,7 @@ class constantPoolOopDesc : public oopDesc {
public: public:
typeArrayOop tags() const { return _tags; } typeArrayOop tags() const { return _tags; }
typeArrayOop operands() const { return _operands; }
bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); }
bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); } bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); }
@ -113,6 +118,7 @@ class constantPoolOopDesc : public oopDesc {
// Assembly code support // Assembly code support
static int tags_offset_in_bytes() { return offset_of(constantPoolOopDesc, _tags); } static int tags_offset_in_bytes() { return offset_of(constantPoolOopDesc, _tags); }
static int cache_offset_in_bytes() { return offset_of(constantPoolOopDesc, _cache); } static int cache_offset_in_bytes() { return offset_of(constantPoolOopDesc, _cache); }
static int operands_offset_in_bytes() { return offset_of(constantPoolOopDesc, _operands); }
static int pool_holder_offset_in_bytes() { return offset_of(constantPoolOopDesc, _pool_holder); } static int pool_holder_offset_in_bytes() { return offset_of(constantPoolOopDesc, _pool_holder); }
// Storing constants // Storing constants
@ -156,10 +162,28 @@ class constantPoolOopDesc : public oopDesc {
*int_at_addr(which) = ref_index; *int_at_addr(which) = ref_index;
} }
void invoke_dynamic_at_put(int which, int bootstrap_method_index, int name_and_type_index) { void invoke_dynamic_at_put(int which, int operand_base, int operand_count) {
tag_at_put(which, JVM_CONSTANT_InvokeDynamic); tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index; *int_at_addr(which) = operand_base; // this is the real information
} }
#ifdef ASSERT
bool check_invoke_dynamic_at(int which,
int bootstrap_method_index,
int name_and_type_index,
int argument_count) {
assert(invoke_dynamic_bootstrap_method_ref_index_at(which) == bootstrap_method_index,
"already stored by caller");
assert(invoke_dynamic_name_and_type_ref_index_at(which) == name_and_type_index,
"already stored by caller");
assert(invoke_dynamic_argument_count_at(which) == argument_count,
"consistent argument count");
if (argument_count != 0) {
invoke_dynamic_argument_index_at(which, 0);
invoke_dynamic_argument_index_at(which, argument_count - 1);
}
return true;
}
#endif //ASSERT
// Temporary until actual use // Temporary until actual use
void unresolved_string_at_put(int which, symbolOop s) { void unresolved_string_at_put(int which, symbolOop s) {
@ -401,27 +425,93 @@ class constantPoolOopDesc : public oopDesc {
int sym = method_type_index_at(which); int sym = method_type_index_at(which);
return symbol_at(sym); return symbol_at(sym);
} }
private:
// some nodes (InvokeDynamic) have a variable number of operands, each a u2 value
enum { _multi_operand_count_offset = -1,
_multi_operand_base_offset = 0,
_multi_operand_buffer_fill_pointer_offset = 0 // shared at front of operands array
};
int multi_operand_buffer_length() {
return operands() == NULL ? 0 : operands()->length();
}
int multi_operand_buffer_fill_pointer() {
return operands() == NULL
? _multi_operand_buffer_fill_pointer_offset + 1
: operands()->int_at(_multi_operand_buffer_fill_pointer_offset);
}
void multi_operand_buffer_grow(int min_length, TRAPS);
void set_multi_operand_buffer_fill_pointer(int fillp) {
assert(operands() != NULL, "");
operands()->int_at_put(_multi_operand_buffer_fill_pointer_offset, fillp);
}
int multi_operand_base_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
int op_base = *int_at_addr(which);
assert(op_base > _multi_operand_buffer_fill_pointer_offset, "Corrupted operand base");
return op_base;
}
int multi_operand_count_at(int which) {
int op_base = multi_operand_base_at(which);
assert((uint)(op_base + _multi_operand_count_offset) < (uint)operands()->length(), "oob");
int count = operands()->int_at(op_base + _multi_operand_count_offset);
return count;
}
int multi_operand_ref_at(int which, int i) {
int op_base = multi_operand_base_at(which);
assert((uint)i < (uint)multi_operand_count_at(which), "oob");
assert((uint)(op_base + _multi_operand_base_offset + i) < (uint)operands()->length(), "oob");
return operands()->int_at(op_base + _multi_operand_base_offset + i);
}
void set_multi_operand_ref_at(int which, int i, int ref) {
DEBUG_ONLY(multi_operand_ref_at(which, i)); // trigger asserts
int op_base = multi_operand_base_at(which);
operands()->int_at_put(op_base + _multi_operand_base_offset + i, ref);
}
public:
// layout of InvokeDynamic:
enum {
_indy_bsm_offset = 0, // CONSTANT_MethodHandle bsm
_indy_nt_offset = 1, // CONSTANT_NameAndType descr
_indy_argc_offset = 2, // u2 argc
_indy_argv_offset = 3 // u2 argv[argc]
};
int invoke_dynamic_bootstrap_method_ref_index_at(int which) { int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
jint ref_index = *int_at_addr(which); return multi_operand_ref_at(which, _indy_bsm_offset);
return extract_low_short_from_int(ref_index);
} }
int invoke_dynamic_name_and_type_ref_index_at(int which) { int invoke_dynamic_name_and_type_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
jint ref_index = *int_at_addr(which); return multi_operand_ref_at(which, _indy_nt_offset);
return extract_high_short_from_int(ref_index); }
int invoke_dynamic_argument_count_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
int argc = multi_operand_ref_at(which, _indy_argc_offset);
DEBUG_ONLY(int op_count = multi_operand_count_at(which));
assert(_indy_argv_offset + argc == op_count, "consistent inner and outer counts");
return argc;
}
int invoke_dynamic_argument_index_at(int which, int j) {
assert((uint)j < (uint)invoke_dynamic_argument_count_at(which), "oob");
return multi_operand_ref_at(which, _indy_argv_offset + j);
} }
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
// name_and_type_ref_index_at) all expect to be passed indices obtained // name_and_type_ref_index_at) all expect to be passed indices obtained
// directly from the bytecode, and extracted according to java byte order. // directly from the bytecode.
// If the indices are meant to refer to fields or methods, they are // If the indices are meant to refer to fields or methods, they are
// actually potentially byte-swapped, rewritten constant pool cache indices. // actually rewritten constant pool cache indices.
// The routine remap_instruction_operand_from_cache manages the adjustment // The routine remap_instruction_operand_from_cache manages the adjustment
// of these values back to constant pool indices. // of these values back to constant pool indices.
// There are also "uncached" versions which do not adjust the operand index; see below. // There are also "uncached" versions which do not adjust the operand index; see below.
// FIXME: Consider renaming these with a prefix "cached_" to make the distinction clear.
// In a few cases (the verifier) there are uses before a cpcache has been built,
// which are handled by a dynamic check in remap_instruction_operand_from_cache.
// FIXME: Remove the dynamic check, and adjust all callers to specify the correct mode.
// Lookup for entries consisting of (klass_index, name_and_type index) // Lookup for entries consisting of (klass_index, name_and_type index)
klassOop klass_ref_at(int which, TRAPS); klassOop klass_ref_at(int which, TRAPS);
symbolOop klass_ref_at_noresolve(int which); symbolOop klass_ref_at_noresolve(int which);
@ -443,15 +533,24 @@ class constantPoolOopDesc : public oopDesc {
resolve_string_constants_impl(h_this, CHECK); resolve_string_constants_impl(h_this, CHECK);
} }
private:
enum { _no_index_sentinel = -1, _possible_index_sentinel = -2 };
public:
// Resolve late bound constants. // Resolve late bound constants.
oop resolve_constant_at(int index, TRAPS) { oop resolve_constant_at(int index, TRAPS) {
constantPoolHandle h_this(THREAD, this); constantPoolHandle h_this(THREAD, this);
return resolve_constant_at_impl(h_this, index, -1, THREAD); return resolve_constant_at_impl(h_this, index, _no_index_sentinel, THREAD);
} }
oop resolve_cached_constant_at(int cache_index, TRAPS) { oop resolve_cached_constant_at(int cache_index, TRAPS) {
constantPoolHandle h_this(THREAD, this); constantPoolHandle h_this(THREAD, this);
return resolve_constant_at_impl(h_this, -1, cache_index, THREAD); return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, THREAD);
}
oop resolve_possibly_cached_constant_at(int pool_index, TRAPS) {
constantPoolHandle h_this(THREAD, this);
return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, THREAD);
} }
// Klass name matches name at offset // Klass name matches name at offset
@ -484,7 +583,7 @@ class constantPoolOopDesc : public oopDesc {
static klassOop klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int which, TRAPS); static klassOop klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int which, TRAPS);
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
// future by other Java code. These take constant pool indices rather than possibly-byte-swapped // future by other Java code. These take constant pool indices rather than
// constant pool cache indices as do the peer methods above. // constant pool cache indices as do the peer methods above.
symbolOop uncached_klass_ref_at_noresolve(int which); symbolOop uncached_klass_ref_at_noresolve(int which);
symbolOop uncached_name_ref_at(int which) { return impl_name_ref_at(which, true); } symbolOop uncached_name_ref_at(int which) { return impl_name_ref_at(which, true); }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -87,6 +87,19 @@ void ConstantPoolCacheEntry::set_bytecode_2(Bytecodes::Code code) {
OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << 24)); OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << 24));
} }
// Atomically sets f1 if it is still NULL, otherwise it keeps the
// current value.
void ConstantPoolCacheEntry::set_f1_if_null_atomic(oop f1) {
// Use barriers as in oop_store
HeapWord* f1_addr = (HeapWord*) &_f1;
update_barrier_set_pre(f1_addr, f1);
void* result = Atomic::cmpxchg_ptr(f1, f1_addr, NULL);
bool success = (result == NULL);
if (success) {
update_barrier_set((void*) f1_addr, f1);
}
}
#ifdef ASSERT #ifdef ASSERT
// It is possible to have two different dummy methodOops created // It is possible to have two different dummy methodOops created
// when the resolve code for invoke interface executes concurrently // when the resolve code for invoke interface executes concurrently
@ -165,7 +178,12 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
} }
assert(method->can_be_statically_bound(), "must be a MH invoker method"); assert(method->can_be_statically_bound(), "must be a MH invoker method");
assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized"); assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized");
set_f1(method()); // SystemDictionary::find_method_handle_invoke only caches
// methods which signature classes are on the boot classpath,
// otherwise the newly created method is returned. To avoid
// races in that case we store the first one coming in into the
// cp-cache atomically if it's still unset.
set_f1_if_null_atomic(method());
needs_vfinal_flag = false; // _f2 is not an oop needs_vfinal_flag = false; // _f2 is not an oop
assert(!is_vfinal(), "f2 not an oop"); assert(!is_vfinal(), "f2 not an oop");
byte_no = 1; // coordinate this with bytecode_number & is_resolved byte_no = 1; // coordinate this with bytecode_number & is_resolved

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -130,6 +130,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change"); assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change");
oop_store(&_f1, f1); oop_store(&_f1, f1);
} }
void set_f1_if_null_atomic(oop f1);
void set_f2(intx f2) { assert(_f2 == 0 || _f2 == f2, "illegal field change"); _f2 = f2; } void set_f2(intx f2) { assert(_f2 == 0 || _f2 == f2, "illegal field change"); _f2 = f2; }
int as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile, int as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile,
bool is_method_interface, bool is_method); bool is_method_interface, bool is_method);
@ -318,7 +319,9 @@ class constantPoolCacheOopDesc: public oopDesc {
// Sizing // Sizing
debug_only(friend class ClassVerifier;) debug_only(friend class ClassVerifier;)
public:
int length() const { return _length; } int length() const { return _length; }
private:
void set_length(int length) { _length = length; } void set_length(int length) { _length = length; }
static int header_size() { return sizeof(constantPoolCacheOopDesc) / HeapWordSize; } static int header_size() { return sizeof(constantPoolCacheOopDesc) / HeapWordSize; }

View file

@ -1254,7 +1254,7 @@ void GenerateOopMap::print_current_state(outputStream *os,
case Bytecodes::_invokestatic: case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic: case Bytecodes::_invokedynamic:
case Bytecodes::_invokeinterface: case Bytecodes::_invokeinterface:
int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2(); int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache();
constantPoolOop cp = method()->constants(); constantPoolOop cp = method()->constants();
int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
@ -1286,7 +1286,7 @@ void GenerateOopMap::print_current_state(outputStream *os,
case Bytecodes::_invokestatic: case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic: case Bytecodes::_invokedynamic:
case Bytecodes::_invokeinterface: case Bytecodes::_invokeinterface:
int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2(); int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache();
constantPoolOop cp = method()->constants(); constantPoolOop cp = method()->constants();
int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
@ -1356,8 +1356,8 @@ void GenerateOopMap::interp1(BytecodeStream *itr) {
case Bytecodes::_ldc2_w: ppush(vvCTS); break; case Bytecodes::_ldc2_w: ppush(vvCTS); break;
case Bytecodes::_ldc: do_ldc(itr->get_index(), itr->bci()); break; case Bytecodes::_ldc: // fall through:
case Bytecodes::_ldc_w: do_ldc(itr->get_index_u2(), itr->bci()); break; case Bytecodes::_ldc_w: do_ldc(itr->bci()); break;
case Bytecodes::_iload: case Bytecodes::_iload:
case Bytecodes::_fload: ppload(vCTS, itr->get_index()); break; case Bytecodes::_fload: ppload(vCTS, itr->get_index()); break;
@ -1829,9 +1829,16 @@ void GenerateOopMap::do_jsr(int targ_bci) {
void GenerateOopMap::do_ldc(int idx, int bci) { void GenerateOopMap::do_ldc(int bci) {
Bytecode_loadconstant* ldc = Bytecode_loadconstant_at(method(), bci);
constantPoolOop cp = method()->constants(); constantPoolOop cp = method()->constants();
CellTypeState cts = cp->is_pointer_entry(idx) ? CellTypeState::make_line_ref(bci) : valCTS; BasicType bt = ldc->result_type();
CellTypeState cts = (bt == T_OBJECT) ? CellTypeState::make_line_ref(bci) : valCTS;
// Make sure bt==T_OBJECT is the same as old code (is_pointer_entry).
// Note that CONSTANT_MethodHandle entries are u2 index pairs, not pointer-entries,
// and they are processed by _fast_aldc and the CP cache.
assert((ldc->has_cache_index() || cp->is_pointer_entry(ldc->pool_index()))
? (bt == T_OBJECT) : true, "expected object type");
ppush1(cts); ppush1(cts);
} }

View file

@ -389,7 +389,7 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPEC {
void pp (CellTypeState *in, CellTypeState *out); void pp (CellTypeState *in, CellTypeState *out);
void pp_new_ref (CellTypeState *in, int bci); void pp_new_ref (CellTypeState *in, int bci);
void ppdupswap (int poplen, const char *out); void ppdupswap (int poplen, const char *out);
void do_ldc (int idx, int bci); void do_ldc (int bci);
void do_astore (int idx); void do_astore (int idx);
void do_jsr (int delta); void do_jsr (int delta);
void do_field (int is_get, int is_static, int idx, int bci); void do_field (int is_get, int is_static, int idx, int bci);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -388,7 +388,8 @@ static Node *transform_long_divide( PhaseGVN *phase, Node *dividend, jlong divis
if (!d_pos) { if (!d_pos) {
q = new (phase->C, 3) SubLNode(phase->longcon(0), phase->transform(q)); q = new (phase->C, 3) SubLNode(phase->longcon(0), phase->transform(q));
} }
} else { } else if ( !Matcher::use_asm_for_ldiv_by_con(d) ) { // Use hardware DIV instruction when
// it is faster than code generated below.
// Attempt the jlong constant divide -> multiply transform found in // Attempt the jlong constant divide -> multiply transform found in
// "Division by Invariant Integers using Multiplication" // "Division by Invariant Integers using Multiplication"
// by Granlund and Montgomery // by Granlund and Montgomery
@ -558,7 +559,7 @@ Node *DivLNode::Ideal( PhaseGVN *phase, bool can_reshape) {
set_req(0,NULL); // Dividing by a not-zero constant; no faulting set_req(0,NULL); // Dividing by a not-zero constant; no faulting
// Dividing by MININT does not optimize as a power-of-2 shift. // Dividing by MINLONG does not optimize as a power-of-2 shift.
if( l == min_jlong ) return NULL; if( l == min_jlong ) return NULL;
return transform_long_divide( phase, in(1), l ); return transform_long_divide( phase, in(1), l );
@ -1062,7 +1063,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Fell thru, the unroll case is not appropriate. Transform the modulo // Fell thru, the unroll case is not appropriate. Transform the modulo
// into a long multiply/int multiply/subtract case // into a long multiply/int multiply/subtract case
// Cannot handle mod 0, and min_jint isn't handled by the transform // Cannot handle mod 0, and min_jlong isn't handled by the transform
if( con == 0 || con == min_jlong ) return NULL; if( con == 0 || con == min_jlong ) return NULL;
// Get the absolute value of the constant; at this point, we can use this // Get the absolute value of the constant; at this point, we can use this
@ -1075,7 +1076,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// If this is a power of two, then maybe we can mask it // If this is a power of two, then maybe we can mask it
if( is_power_of_2_long(pos_con) ) { if( is_power_of_2_long(pos_con) ) {
log2_con = log2_long(pos_con); log2_con = exact_log2_long(pos_con);
const Type *dt = phase->type(in(1)); const Type *dt = phase->type(in(1));
const TypeLong *dtl = dt->isa_long(); const TypeLong *dtl = dt->isa_long();
@ -1088,7 +1089,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Save in(1) so that it cannot be changed or deleted // Save in(1) so that it cannot be changed or deleted
hook->init_req(0, in(1)); hook->init_req(0, in(1));
// Divide using the transform from DivI to MulL // Divide using the transform from DivL to MulL
Node *result = transform_long_divide( phase, in(1), pos_con ); Node *result = transform_long_divide( phase, in(1), pos_con );
if (result != NULL) { if (result != NULL) {
Node *divide = phase->transform(result); Node *divide = phase->transform(result);

View file

@ -85,6 +85,7 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()), _processed(C->comp_arena()),
_collecting(true), _collecting(true),
_progress(false),
_compile(C), _compile(C),
_igvn(igvn), _igvn(igvn),
_node_map(C->comp_arena()) { _node_map(C->comp_arena()) {
@ -113,7 +114,7 @@ void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set");
assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge");
assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge");
f->add_edge(to_i, PointsToNode::PointsToEdge); add_edge(f, to_i, PointsToNode::PointsToEdge);
} }
void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
@ -126,7 +127,7 @@ void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
// don't add a self-referential edge, this can occur during removal of // don't add a self-referential edge, this can occur during removal of
// deferred edges // deferred edges
if (from_i != to_i) if (from_i != to_i)
f->add_edge(to_i, PointsToNode::DeferredEdge); add_edge(f, to_i, PointsToNode::DeferredEdge);
} }
int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) { int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) {
@ -157,7 +158,7 @@ void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) {
assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets"); assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets");
t->set_offset(offset); t->set_offset(offset);
f->add_edge(to_i, PointsToNode::FieldEdge); add_edge(f, to_i, PointsToNode::FieldEdge);
} }
void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) {
@ -995,7 +996,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
GrowableArray<Node *> memnode_worklist; GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis; GrowableArray<PhiNode *> orig_phis;
PhaseGVN *igvn = _igvn; PhaseIterGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types(); uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area(); Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena); VectorSet visited(arena);
@ -1531,14 +1532,9 @@ bool ConnectionGraph::compute_escape() {
has_allocations = true; has_allocations = true;
} }
if(n->is_AddP()) { if(n->is_AddP()) {
// Collect address nodes which directly reference an allocation. // Collect address nodes. Use them during stage 3 below
// Use them during stage 3 below to build initial connection graph // to build initial connection graph field edges.
// field edges. Other field edges could be added after StoreP/LoadP cg_worklist.append(n->_idx);
// nodes are processed during stage 4 below.
Node* base = get_addp_base(n);
if(base->is_Proj() && base->in(0)->is_Allocate()) {
cg_worklist.append(n->_idx);
}
} else if (n->is_MergeMem()) { } else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for // Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types(). // scalar replaceable objects in split_unique_types().
@ -1562,18 +1558,28 @@ bool ConnectionGraph::compute_escape() {
build_connection_graph(n, igvn); build_connection_graph(n, igvn);
} }
// 3. Pass to create fields edges (Allocate -F-> AddP). // 3. Pass to create initial fields edges (JavaObject -F-> AddP)
// to reduce number of iterations during stage 4 below.
uint cg_length = cg_worklist.length(); uint cg_length = cg_worklist.length();
for( uint next = 0; next < cg_length; ++next ) { for( uint next = 0; next < cg_length; ++next ) {
int ni = cg_worklist.at(next); int ni = cg_worklist.at(next);
build_connection_graph(ptnode_adr(ni)->_node, igvn); Node* n = ptnode_adr(ni)->_node;
Node* base = get_addp_base(n);
if (base->is_Proj())
base = base->in(0);
PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type();
if (nt == PointsToNode::JavaObject) {
build_connection_graph(n, igvn);
}
} }
cg_worklist.clear(); cg_worklist.clear();
cg_worklist.append(_phantom_object); cg_worklist.append(_phantom_object);
GrowableArray<uint> worklist;
// 4. Build Connection Graph which need // 4. Build Connection Graph which need
// to walk the connection graph. // to walk the connection graph.
_progress = false;
for (uint ni = 0; ni < nodes_size(); ni++) { for (uint ni = 0; ni < nodes_size(); ni++) {
PointsToNode* ptn = ptnode_adr(ni); PointsToNode* ptn = ptnode_adr(ni);
Node *n = ptn->_node; Node *n = ptn->_node;
@ -1581,13 +1587,52 @@ bool ConnectionGraph::compute_escape() {
build_connection_graph(n, igvn); build_connection_graph(n, igvn);
if (ptn->node_type() != PointsToNode::UnknownType) if (ptn->node_type() != PointsToNode::UnknownType)
cg_worklist.append(n->_idx); // Collect CG nodes cg_worklist.append(n->_idx); // Collect CG nodes
if (!_processed.test(n->_idx))
worklist.append(n->_idx); // Collect C/A/L/S nodes
} }
} }
// After IGVN user nodes may have smaller _idx than
// their inputs so they will be processed first in
// previous loop. Because of that not all Graph
// edges will be created. Walk over interesting
// nodes again until no new edges are created.
//
// Normally only 1-3 passes needed to build
// Connection Graph depending on graph complexity.
// Set limit to 10 to catch situation when something
// did go wrong and recompile the method without EA.
#define CG_BUILD_ITER_LIMIT 10
uint length = worklist.length();
int iterations = 0;
while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) {
_progress = false;
for( uint next = 0; next < length; ++next ) {
int ni = worklist.at(next);
PointsToNode* ptn = ptnode_adr(ni);
Node* n = ptn->_node;
assert(n != NULL, "should be known node");
build_connection_graph(n, igvn);
}
}
if (iterations >= CG_BUILD_ITER_LIMIT) {
assert(iterations < CG_BUILD_ITER_LIMIT,
err_msg("infinite EA connection graph build with %d nodes and worklist size %d",
nodes_size(), length));
// Possible infinite build_connection_graph loop,
// retry compilation without escape analysis.
C->record_failure(C2Compiler::retry_no_escape_analysis());
_collecting = false;
return false;
}
#undef CG_BUILD_ITER_LIMIT
Arena* arena = Thread::current()->resource_area(); Arena* arena = Thread::current()->resource_area();
VectorSet ptset(arena); VectorSet ptset(arena);
GrowableArray<uint> deferred_edges;
VectorSet visited(arena); VectorSet visited(arena);
worklist.clear();
// 5. Remove deferred edges from the graph and adjust // 5. Remove deferred edges from the graph and adjust
// escape state of nonescaping objects. // escape state of nonescaping objects.
@ -1597,7 +1642,7 @@ bool ConnectionGraph::compute_escape() {
PointsToNode* ptn = ptnode_adr(ni); PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type(); PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni, &deferred_edges, &visited); remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node; Node *n = ptn->_node;
if (n->is_AddP()) { if (n->is_AddP()) {
// Search for objects which are not scalar replaceable // Search for objects which are not scalar replaceable
@ -1608,7 +1653,7 @@ bool ConnectionGraph::compute_escape() {
} }
// 6. Propagate escape states. // 6. Propagate escape states.
GrowableArray<int> worklist; worklist.clear();
bool has_non_escaping_obj = false; bool has_non_escaping_obj = false;
// push all GlobalEscape nodes on the worklist // push all GlobalEscape nodes on the worklist
@ -2444,13 +2489,14 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// Don't set processed bit for AddP, LoadP, StoreP since // Don't set processed bit for AddP, LoadP, StoreP since
// they may need more then one pass to process. // they may need more then one pass to process.
// Also don't mark as processed Call nodes since their
// arguments may need more then one pass to process.
if (_processed.test(n_idx)) if (_processed.test(n_idx))
return; // No need to redefine node's state. return; // No need to redefine node's state.
if (n->is_Call()) { if (n->is_Call()) {
CallNode *call = n->as_Call(); CallNode *call = n->as_Call();
process_call_arguments(call, phase); process_call_arguments(call, phase);
_processed.set(n_idx);
return; return;
} }

View file

@ -219,6 +219,9 @@ private:
// is still being collected. If false, // is still being collected. If false,
// no new nodes will be processed. // no new nodes will be processed.
bool _progress; // Indicates whether new Graph's edges
// were created.
uint _phantom_object; // Index of globally escaping object uint _phantom_object; // Index of globally escaping object
// that pointer values loaded from // that pointer values loaded from
// a field which has not been set // a field which has not been set
@ -266,6 +269,13 @@ private:
void add_deferred_edge(uint from_i, uint to_i); void add_deferred_edge(uint from_i, uint to_i);
void add_field_edge(uint from_i, uint to_i, int offs); void add_field_edge(uint from_i, uint to_i, int offs);
// Add an edge of the specified type pointing to the specified target.
// Set _progress if new edge is added.
void add_edge(PointsToNode *f, uint to_i, PointsToNode::EdgeType et) {
uint e_cnt = f->edge_count();
f->add_edge(to_i, et);
_progress |= (f->edge_count() != e_cnt);
}
// Add an edge to node given by "to_i" from any field of adr_i whose offset // Add an edge to node given by "to_i" from any field of adr_i whose offset
// matches "offset" A deferred edge is added if to_i is a LocalVar, and // matches "offset" A deferred edge is added if to_i is a LocalVar, and

Some files were not shown because too many files have changed in this diff Show more