--- a/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
750c1ccb2f2d1ddfa95ab6c7f897fdab2f87f7e9 jdk7-b114
9cb24917216bc68997154f6e9566c3de62acb2f4 jdk7-b115
a4e6aa1f45ad23a6f083ed98d970b5006ea4d292 jdk7-b116
+228e73f288c543a8c34e2a54227103ae5649e6af jdk7-b117
+2e876e59938a853934aa738c811b26c452bd9fe8 jdk7-b118
--- a/.hgtags-top-repo Fri Nov 12 08:41:03 2010 -0500
+++ b/.hgtags-top-repo Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
27985a5c6e5268014d25d55886e0ecb96af4763d jdk7-b114
e8ebdf41b9c01a26642848f4134f5504e8fb3233 jdk7-b115
94e9a1bfba8b8d1fe0bfd43b88629b1f27b02a76 jdk7-b116
+7220e60b097fa027e922f1aeecdd330f3e37409f jdk7-b117
+a12a9e78df8a9d534da0b4a244ed68f0de0bd58e jdk7-b118
--- a/corba/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
88fddb73c5c4a4b50c319cbae9380caf5172ab45 jdk7-b114
da7561d479e0ddaa4650d8023ac0fc7294e014e3 jdk7-b115
98c028de4301106f2285ac0e128a1bb9b4c24f5c jdk7-b116
+fa502e4834dac2176499cc1f44794d5dc32a11b9 jdk7-b117
+42e77836fded7c2a3080d27316b96634ea9e33c6 jdk7-b118
--- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_io.jmk Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_io.jmk Sat Nov 13 18:56:50 2010 -0800
@@ -34,7 +34,7 @@
com/sun/corba/se/impl/io/ObjectStreamField.java \
com/sun/corba/se/impl/io/OptionalDataException.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/TypeMismatchException.java \
com/sun/corba/se/impl/io/InputStreamHook.java \
--- a/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java Sat Nov 13 18:56:50 2010 -0800
@@ -2553,8 +2553,8 @@
bridge.putObject( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetObjectField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
- ObjectUtility.compactObjectToString( v )) ;
+ o.toString(),
+ v.toString() ) ;
}
}
@@ -2566,7 +2566,7 @@
bridge.putBoolean( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetBooleanField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Boolean(v) ) ;
}
}
@@ -2579,7 +2579,7 @@
bridge.putByte( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetByteField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Byte(v) ) ;
}
}
@@ -2592,7 +2592,7 @@
bridge.putChar( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetCharField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Character(v) ) ;
}
}
@@ -2605,7 +2605,7 @@
bridge.putShort( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetShortField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Short(v) ) ;
}
}
@@ -2618,7 +2618,7 @@
bridge.putInt( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetIntField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Integer(v) ) ;
}
}
@@ -2631,7 +2631,7 @@
bridge.putLong( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetLongField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Long(v) ) ;
}
}
@@ -2644,7 +2644,7 @@
bridge.putFloat( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetFloatField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Float(v) ) ;
}
}
@@ -2657,7 +2657,7 @@
bridge.putDouble( o, key, v ) ;
} catch (Exception e) {
throw utilWrapper.errorSetDoubleField( e, fieldName,
- ObjectUtility.compactObjectToString( o ),
+ o.toString(),
new Double(v) ) ;
}
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,32 +32,22 @@
package com.sun.corba.se.impl.io;
import javax.rmi.CORBA.Util;
-import javax.rmi.PortableRemoteObject;
import java.util.Hashtable;
-import java.util.Stack;
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.Utility;
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 com.sun.org.omg.SendingContext.CodeBase;
import com.sun.org.omg.SendingContext.CodeBaseHelper;
import java.security.AccessController;
import java.security.PrivilegedAction;
-
-import com.sun.corba.se.impl.io.IIOPInputStream.ActiveRecursionManager;
+import java.security.PrivilegedExceptionAction;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.impl.logging.OMGSystemException;
@@ -809,65 +799,163 @@
return "com.sun.corba.se.impl.io.IIOPOutputStream";
}
- private com.sun.corba.se.impl.io.IIOPOutputStream createOutputStream() {
- return (com.sun.corba.se.impl.io.IIOPOutputStream)AccessController.doPrivileged(
- new StreamFactory(getOutputStreamClassName()));
+ private IIOPOutputStream createOutputStream() {
+ final String name = 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() {
return "com.sun.corba.se.impl.io.IIOPInputStream";
}
- private com.sun.corba.se.impl.io.IIOPInputStream createInputStream() {
- return (com.sun.corba.se.impl.io.IIOPInputStream)AccessController.doPrivileged(
- new StreamFactory(getInputStreamClassName()));
+ private IIOPInputStream createInputStream() {
+ final String name = 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
- * as part of a PrivilegedAction.
- *
- * 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.
+ * Construct a built in implementation with priveleges.
+ * Returning null indicates a non-built is specified.
*/
- private static final class StreamFactory implements PrivilegedAction {
- private String className;
-
- public StreamFactory (String _className) {
- className = _className;
- }
+ private IIOPInputStream createInputStreamBuiltIn(
+ 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 Object run() {
- try {
- // Note: We must use the system ClassLoader here
- // since we want to load classes outside of the
- // core JDK when running J2EE Pure ORB and
- // talking to Kestrel.
+ /**
+ * Returning null indicates a non-built is specified.
+ */
+ private IIOPInputStream createInputStreamBuiltInNoPriv(
+ final String name
+ ) throws IOException {
+ return
+ name.equals(
+ IIOPInputStream
+ .class.getName()
+ ) ?
+ new IIOPInputStream() :
+
+ name.equals(
+ com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3
+ .class.getName()
+ ) ?
+ new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3() :
+
+ 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();
if (cl == null)
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
// as expensive as it looks.
return streamClass.newInstance();
- } catch(Throwable t) {
- InternalError ie = new InternalError( "Error loading " + className ) ;
- ie.initCause( t ) ;
- throw ie ;
- }
- }
}
/**
--- a/corba/src/share/classes/com/sun/corba/se/impl/orb/PrefixParserAction.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/impl/orb/PrefixParserAction.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -110,7 +110,7 @@
throw wrapper.couldNotSetArray( thr,
getPropertyName(), new Integer(ctr),
componentType, new Integer(size),
- ObjectUtility.compactObjectToString( obj )) ;
+ obj.toString() ) ;
}
ctr++ ;
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectUtility.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectUtility.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,103 +50,8 @@
import java.math.BigDecimal ;
public final class ObjectUtility {
- private boolean useToString ;
- 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 ;
- }
+ private ObjectUtility() {}
- /** 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,
* return an array of that component type that consists of the
@@ -179,544 +84,4 @@
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());
- }
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,14 +33,7 @@
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Collection;
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.encoding.InputObject;
@@ -61,18 +54,12 @@
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.AlternateIIOPAddressComponent;
-import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
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.orbutil.threadpool.Work;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.transport.CorbaAcceptor;
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.SocketOrChannelAcceptor;
@@ -82,7 +69,6 @@
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.ORBUtility;
-import com.sun.corba.se.impl.ior.iiop.JavaSerializationComponent;
// BEGIN Legacy support.
import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
@@ -442,12 +428,7 @@
dprint(".doWork->: " + this);
}
if (selectionKey.isAcceptable()) {
- AccessController.doPrivileged(new PrivilegedAction() {
- public java.lang.Object run() {
accept();
- return null;
- }
- });
} else {
if (orb.transportDebugFlag) {
dprint(".doWork: ! selectionKey.isAcceptable: " + this);
--- a/corba/src/share/classes/com/sun/corba/se/spi/orb/OperationFactory.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/OperationFactory.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
package com.sun.corba.se.spi.orb ;
import java.util.StringTokenizer ;
+import java.util.Arrays ;
import java.lang.reflect.Array ;
@@ -446,7 +447,7 @@
public String toString() {
return "sequenceAction(separator=\"" + sep +
"\",actions=" +
- ObjectUtility.compactObjectToString(actions) + ")" ;
+ Arrays.toString(actions) + ")" ;
}
}
@@ -533,7 +534,7 @@
public String toString() {
return "mapSequenceAction(" +
- ObjectUtility.compactObjectToString(op) + ")" ;
+ Arrays.toString(op) + ")" ;
}
}
--- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ParserImplBase.java Fri Nov 12 08:41:03 2010 -0500
+++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ParserImplBase.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,7 @@
// Since exc wraps the actual exception, use exc.getCause()
// instead of exc.
throw wrapper.errorSettingField( exc.getCause(), name,
- ObjectUtility.compactObjectToString(value) ) ;
+ value.toString() ) ;
}
}
--- a/hotspot/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -127,3 +127,7 @@
5511edd5d719f3fc9fdd04879482026a3d2c8652 hs20-b01
bdbc48857210a509b3c50a3291ecb9dd6a72e016 jdk7-b115
96b3f2a7add0b445b8aa421f6823cff5a2e2fe03 jdk7-b116
+52f19c724d9634af79044a2e0defbe4a5f1adbda hs20-b02
+806d0c037e6bbb88dac0699673f4ba55ee8c02da jdk7-b117
+698b7b727e12de44139d8cca6ab9a494ead13253 jdk7-b118
+3ef7426b4deac5dcfd4afb35cabe9ab3d666df91 hs20-b02
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -188,7 +188,7 @@
} else {
throw new RuntimeException("should not reach here");
}
- } else if (ctag.isMethodHandle() || ctag.isMethodType()) {
+ } else if (ctag.isMethodHandle()) {
Oop x = getCachedConstant();
int refidx = cpool.getMethodHandleIndexAt(cpIndex);
int refkind = cpool.getMethodHandleRefKindAt(cpIndex);
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Sat Nov 13 18:56:50 2010 -0800
@@ -53,11 +53,19 @@
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("constantPoolOopDesc");
tags = new OopField(type.getOopField("_tags"), 0);
+ operands = new OopField(type.getOopField("_operands"), 0);
cache = new OopField(type.getOopField("_cache"), 0);
poolHolder = new OopField(type.getOopField("_pool_holder"), 0);
length = new CIntField(type.getCIntegerField("_length"), 0);
headerSize = type.getSize();
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) {
@@ -67,6 +75,7 @@
public boolean isConstantPool() { return true; }
private static OopField tags;
+ private static OopField operands;
private static OopField cache;
private static OopField poolHolder;
private static CIntField length; // number of elements in oop
@@ -74,7 +83,15 @@
private static long headerSize;
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 getOperands() { return (TypeArray) operands.getValue(this); }
public ConstantPoolCache getCache() { return (ConstantPoolCache) cache.getValue(this); }
public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); }
public int getLength() { return (int)length.getValue(this); }
@@ -278,6 +295,25 @@
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[] {
};
@@ -522,15 +558,20 @@
case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType);
- int value = getIntAt(ci);
- short bootstrapMethodIndex = (short) extractLowShortFromInt(value);
- short nameAndTypeIndex = (short) extractHighShortFromInt(value);
- dos.writeShort(bootstrapMethodIndex);
- dos.writeShort(nameAndTypeIndex);
+ int[] values = getMultiOperandsAt(ci);
+ for (int vn = 0; vn < values.length; vn++) {
+ dos.writeShort(values[vn]);
+ }
+ 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
- + ", N&T = " + nameAndTypeIndex);
+ + ", N&T = " + nameAndTypeIndex
+ + ", argc = " + argumentCount);
break;
}
+
default:
throw new InternalError("unknown tag: " + cpConstType);
} // switch
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Sat Nov 13 18:56:50 2010 -0800
@@ -42,7 +42,8 @@
public static final int JVM_CONSTANT_NameAndType = 12;
public static final int JVM_CONSTANT_MethodHandle = 15;
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
public static final int JVM_REF_getField = 1;
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Sat Nov 13 18:56:50 2010 -0800
@@ -303,12 +303,12 @@
case JVM_CONSTANT_MethodHandle: {
dos.writeByte(cpConstType);
int value = cpool.getIntAt(ci);
- short bootstrapMethodIndex = (short) extractLowShortFromInt(value);
- short nameAndTypeIndex = (short) extractHighShortFromInt(value);
- dos.writeShort(bootstrapMethodIndex);
- dos.writeShort(nameAndTypeIndex);
- if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " +
- bootstrapMethodIndex + ", N&T = " + nameAndTypeIndex);
+ byte refKind = (byte) extractLowShortFromInt(value);
+ short memberIndex = (short) extractHighShortFromInt(value);
+ dos.writeByte(refKind);
+ dos.writeShort(memberIndex);
+ if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " +
+ refKind + ", mem = " + memberIndex);
break;
}
@@ -323,10 +323,11 @@
case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType);
- int value = cpool.getIntAt(ci);
- short refIndex = (short) value;
- dos.writeShort(refIndex);
- if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex);
+ int[] values = cpool.getMultiOperandsAt(ci);
+ for (int vn = 0; vn < values.length; vn++) {
+ dos.writeShort(values[vn]);
+ }
+ if (DEBUG) debugMessage("CP[" + ci + "] = INDY indexes = " + Arrays.toString(values));
break;
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Sat Nov 13 18:56:50 2010 -0800
@@ -460,6 +460,18 @@
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) {
Formatter buf = new Formatter(genHTML);
buf.beginTable(1);
@@ -584,7 +596,7 @@
case JVM_CONSTANT_InvokeDynamic:
buf.cell("JVM_CONSTANT_InvokeDynamic");
- buf.cell(genLowHighShort(cpool.getIntAt(index)));
+ buf.cell(genListOfShort(cpool.getMultiOperandsAt(index)));
break;
default:
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,8 @@
private static int JVM_CONSTANT_NameAndType = 12;
private static int JVM_CONSTANT_MethodHandle = 15; // 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_UnresolvedClass = 100; // Temporary tag until actual use
private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool
--- a/hotspot/make/hotspot_version Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/make/hotspot_version Sat Nov 13 18:56:50 2010 -0800
@@ -35,7 +35,7 @@
HS_MAJOR_VER=20
HS_MINOR_VER=0
-HS_BUILD_NUMBER=02
+HS_BUILD_NUMBER=03
JDK_MAJOR_VER=1
JDK_MINOR_VER=7
--- a/hotspot/make/linux/Makefile Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/make/linux/Makefile Sat Nov 13 18:56:50 2010 -0800
@@ -62,7 +62,9 @@
include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make
ifndef CC_INTERP
-FORCE_TIERED=1
+ ifndef FORCE_TIERED
+ FORCE_TIERED=1
+ endif
endif
ifdef LP64
@@ -254,7 +256,7 @@
$(BUILDTREE) VARIANT=tiered
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
-ifdef FORCE_TIERED
+ifeq ($(FORCE_TIERED),1)
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
else
--- a/hotspot/make/solaris/Makefile Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/make/solaris/Makefile Sat Nov 13 18:56:50 2010 -0800
@@ -53,7 +53,9 @@
include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make
ifndef CC_INTERP
-FORCE_TIERED=1
+ ifndef FORCE_TIERED
+ FORCE_TIERED=1
+ endif
endif
ifdef LP64
@@ -210,7 +212,7 @@
$(BUILDTREE) VARIANT=tiered
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
-ifdef FORCE_TIERED
+ifeq ($(FORCE_TIERED),1)
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
else
--- a/hotspot/make/windows/build.make Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/make/windows/build.make Sat Nov 13 18:56:50 2010 -0800
@@ -74,9 +74,11 @@
!if "$(BUILDARCH)" != "ia64"
!ifndef CC_INTERP
+!ifndef FORCE_TIERED
FORCE_TIERED=1
!endif
!endif
+!endif
!if "$(BUILDARCH)" == "amd64"
Platform_arch=x86
@@ -100,7 +102,7 @@
!if "$(Variant)" == "compiler1"
VARIANT_TEXT=Client
!elseif "$(Variant)" == "compiler2"
-!ifdef FORCE_TIERED
+!if "$(FORCE_TIERED)" == "1"
VARIANT_TEXT=Server
realVariant=tiered
!else
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1126,7 +1126,7 @@
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, 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, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -206,6 +206,11 @@
inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); }
// 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) {
if (s2.is_register()) add(s1, s2.as_register(), d);
else { add(s1, s2.as_constant() + offset, d); offset = 0; }
--- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -664,7 +664,7 @@
// Use temps to avoid kills
LIR_Opr t1 = FrameMap::G1_opr;
LIR_Opr t2 = FrameMap::G3_opr;
- LIR_Opr addr = (type == objectType) ? new_register(T_OBJECT) : new_pointer_register();
+ LIR_Opr addr = new_pointer_register();
// get address of field
obj.load_item();
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -62,3 +62,5 @@
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
+
+define_pd_global(bool, UseMembar, false);
--- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -70,17 +70,29 @@
// Code generation
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)
- // G5_method: invoke methodOop; becomes method type.
+ // G5_method: invoke methodOop
// G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots])
- // O0, O1: garbage temps, blown away
- Register O0_argslot = O0;
+ // O0, O1, O2, O3, O4: garbage temps, blown away
+ Register O0_mtype = O0;
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
Label 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);
__ delayed()->nop();
@@ -88,23 +100,74 @@
__ align(CodeEntryAlignment);
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;
- assert(tem == G5_method_type, "yes, it's the same register");
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
- __ load_heap_oop(Address(G5_method_type, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot);
- __ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot);
- __ ld_ptr(__ argument_address(O0_argslot), G3_method_handle);
+ __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O4_argslot);
+ __ ldsw( Address(O4_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O4_argslot);
+ __ 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);
+
+ 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);
+
+ // 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
- __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
+ // 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;
}
@@ -630,9 +693,15 @@
switch (ek) {
case _adapter_opt_i2i:
+ value = vmarg;
+ break;
case _adapter_opt_l2i:
- __ unimplemented(entry_name(ek));
- value = vmarg;
+ {
+ // 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:
{
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Sat Nov 13 18:56:50 2010 -0800
@@ -1843,6 +1843,12 @@
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
RegMask Matcher::divI_proj_mask() {
ShouldNotReachHere();
@@ -9510,16 +9516,16 @@
Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
- __ srl(Rsrc, 1, Rtmp);
- __ srl(Rsrc, 0, Rdst);
+ __ srl(Rsrc, 1, Rtmp);
+ __ srl(Rsrc, 0, Rdst);
__ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 2, Rtmp);
+ __ srl(Rdst, 2, Rtmp);
__ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 4, Rtmp);
+ __ srl(Rdst, 4, Rtmp);
__ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 8, Rtmp);
+ __ srl(Rdst, 8, Rtmp);
__ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 16, Rtmp);
+ __ srl(Rdst, 16, Rtmp);
__ or3(Rdst, Rtmp, Rdst);
__ popc(Rdst, Rdst);
__ mov(BitsPerInt, Rtmp);
@@ -9528,7 +9534,7 @@
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
match(Set dst (CountLeadingZerosL src));
effect(TEMP dst, TEMP tmp, KILL cr);
@@ -9559,18 +9565,18 @@
Register Rdst = $dst$$Register;
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
- __ srlx(Rsrc, 1, Rtmp);
- __ or3(Rsrc, Rtmp, Rdst);
- __ srlx(Rdst, 2, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 4, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 8, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 16, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 32, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
+ __ srlx(Rsrc, 1, Rtmp);
+ __ or3( Rsrc, Rtmp, Rdst);
+ __ srlx(Rdst, 2, Rtmp);
+ __ or3( Rdst, Rtmp, Rdst);
+ __ srlx(Rdst, 4, Rtmp);
+ __ or3( Rdst, Rtmp, Rdst);
+ __ srlx(Rdst, 8, Rtmp);
+ __ or3( Rdst, Rtmp, Rdst);
+ __ srlx(Rdst, 16, Rtmp);
+ __ or3( Rdst, Rtmp, Rdst);
+ __ srlx(Rdst, 32, Rtmp);
+ __ or3( Rdst, Rtmp, Rdst);
__ popc(Rdst, Rdst);
__ mov(BitsPerLong, Rtmp);
__ sub(Rtmp, Rdst, Rdst);
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -341,6 +341,26 @@
resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1));
__ 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() {
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -80,7 +80,8 @@
FLAG_SET_DEFAULT(InteriorEntryAlignment, 4);
}
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.
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
@@ -118,16 +119,18 @@
#endif
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_v9() ? ", has_v9" : ""),
(has_hardware_popc() ? ", popc" : ""),
(has_vis1() ? ", has_vis1" : ""),
(has_vis2() ? ", has_vis2" : ""),
+ (has_blk_init() ? ", has_blk_init" : ""),
(is_ultra3() ? ", is_ultra3" : ""),
(is_sun4v() ? ", is_sun4v" : ""),
(is_niagara1() ? ", is_niagara1" : ""),
(is_niagara1_plus() ? ", is_niagara1_plus" : ""),
+ (is_sparc64() ? ", is_sparc64" : ""),
(!has_hardware_mul32() ? ", no-mul32" : ""),
(!has_hardware_div32() ? ", no-div32" : ""),
(!has_hardware_fsmuld() ? ", no-fsmuld" : ""));
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,9 @@
v9_instructions = 5,
vis1_instructions = 6,
vis2_instructions = 7,
- sun4v_instructions = 8
+ sun4v_instructions = 8,
+ blk_init_instructions = 9,
+ fmaf_instructions = 10
};
enum Feature_Flag_Set {
@@ -49,6 +51,8 @@
vis1_instructions_m = 1 << vis1_instructions,
vis2_instructions_m = 1 << vis2_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_v9_m = generic_v8_m | v9_instructions_m,
@@ -67,6 +71,7 @@
static int platform_features(int features);
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; }
// Returns true if the platform is in the niagara line and
@@ -86,6 +91,7 @@
static bool has_hardware_popc() { return (_features & hardware_popc_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_blk_init() { return (_features & blk_init_instructions_m) != 0; }
static bool supports_compare_and_exchange()
{ return has_v9(); }
@@ -93,8 +99,10 @@
static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; }
static bool is_sun4v() { return (_features & sun4v_m) != 0; }
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_idiv() { return is_niagara1_plus() || is_sparc64(); }
static const char* cpu_features() { return _features_str; }
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1275,6 +1275,12 @@
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) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
@@ -1288,7 +1294,7 @@
if (is8bit(value)) {
emit_byte(0x6B);
emit_byte(0xC0 | encode);
- emit_byte(value);
+ emit_byte(value & 0xFF);
} else {
emit_byte(0x69);
emit_byte(0xC0 | encode);
@@ -3903,7 +3909,7 @@
if (is8bit(value)) {
emit_byte(0x6B);
emit_byte(0xC0 | encode);
- emit_byte(value);
+ emit_byte(value & 0xFF);
} else {
emit_byte(0x69);
emit_byte(0xC0 | encode);
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1011,6 +1011,7 @@
void hlt();
void idivl(Register src);
+ void divl(Register src); // Unsigned division
void idivq(Register src);
--- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -499,7 +499,7 @@
Register new_val_reg = new_val()->as_register();
__ cmpptr(new_val_reg, (int32_t) NULL_WORD);
__ jcc(Assembler::equal, _continuation);
- ce->store_parameter(addr()->as_register(), 0);
+ ce->store_parameter(addr()->as_pointer_register(), 0);
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id)));
__ jmp(_continuation);
}
--- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -765,7 +765,7 @@
ShouldNotReachHere();
}
- LIR_Opr addr = (type == objectType) ? new_register(T_OBJECT) : new_pointer_register();
+ LIR_Opr addr = new_pointer_register();
LIR_Address* a;
if(offset.result()->is_constant()) {
a = new LIR_Address(obj.result(),
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -63,3 +63,5 @@
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
+
+define_pd_global(bool, UseMembar, false);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -399,6 +399,23 @@
if (VerifyOops) {
__ 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() {
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -413,6 +413,25 @@
if (VerifyOops) {
__ 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() {
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -446,6 +446,10 @@
static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 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 const char* cpu_features() { return _features_str; }
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Sat Nov 13 18:56:50 2010 -0800
@@ -1508,6 +1508,16 @@
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
RegMask Matcher::divI_proj_mask() {
return EAX_REG_mask;
@@ -1546,6 +1556,9 @@
return true;
}
}
+ if (opc == Op_ConL && (n->get_long() & 0xFFFFFFFF00000000LL) == 0LL) {
+ return true;
+ }
return false;
}
@@ -2309,9 +2322,11 @@
enc_class move_long_big_shift_sign( eRegL dst, immI_32_63 cnt ) %{
emit_opcode( cbuf, 0x8B ); // Move
emit_rm(cbuf, 0x3, $dst$$reg, HIGH_FROM_LOW($dst$$reg));
- emit_d8(cbuf,$primary);
- emit_rm(cbuf, 0x3, $secondary, $dst$$reg);
- emit_d8(cbuf,$cnt$$constant-32);
+ if( $cnt$$constant > 32 ) { // Shift, if not by zero
+ emit_d8(cbuf,$primary);
+ emit_rm(cbuf, 0x3, $secondary, $dst$$reg);
+ emit_d8(cbuf,$cnt$$constant-32);
+ }
emit_d8(cbuf,$primary);
emit_rm(cbuf, 0x3, $secondary, HIGH_FROM_LOW($dst$$reg));
emit_d8(cbuf,31);
@@ -8842,6 +8857,144 @@
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
// Shift Left by one
instruct shlI_eReg_1(eRegI dst, immI1 shift, eFlagsReg cr) %{
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Sat Nov 13 18:56:50 2010 -0800
@@ -2065,6 +2065,13 @@
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
RegMask Matcher::divI_proj_mask() {
return INT_RAX_REG_mask;
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -45,3 +45,5 @@
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
+
+define_pd_global(bool, UseMembar, false);
--- a/hotspot/src/os/linux/vm/attachListener_linux.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os/linux/vm/attachListener_linux.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -176,10 +176,10 @@
int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
os::get_temp_directory(), os::current_process_id());
- if (n <= (int)UNIX_PATH_MAX) {
+ if (n < (int)UNIX_PATH_MAX) {
n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path);
}
- if (n > (int)UNIX_PATH_MAX) {
+ if (n >= (int)UNIX_PATH_MAX) {
return -1;
}
--- a/hotspot/src/os/linux/vm/objectMonitor_linux.cpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-
-/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
--- a/hotspot/src/os/linux/vm/objectMonitor_linux.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
- private:
--- a/hotspot/src/os/linux/vm/objectMonitor_linux.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
--- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -827,8 +827,10 @@
switch (thr_type) {
case os::java_thread:
- // Java threads use ThreadStackSize which default value can be changed with the flag -Xss
- if (JavaThread::stack_size_at_create() > 0) stack_size = JavaThread::stack_size_at_create();
+ // Java threads use ThreadStackSize which default value can be
+ // changed with the flag -Xss
+ assert (JavaThread::stack_size_at_create() > 0, "this should be set");
+ stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
@@ -3922,12 +3924,21 @@
Linux::signal_sets_init();
Linux::install_signal_handlers();
+ // Check minimum allowable stack size for thread creation and to initialize
+ // the java system classes, including StackOverflowError - depends on page
+ // size. Add a page for compiler2 recursion in main thread.
+ // Add in 2*BytesPerWord times page size to account for VM stack during
+ // class initialization depending on 32 or 64 bit VM.
+ os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed,
+ (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
+ 2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::page_size());
+
size_t threadStackSizeInBytes = ThreadStackSize * K;
if (threadStackSizeInBytes != 0 &&
- threadStackSizeInBytes < Linux::min_stack_allowed) {
+ threadStackSizeInBytes < os::Linux::min_stack_allowed) {
tty->print_cr("\nThe stack size specified is too small, "
"Specify at least %dk",
- Linux::min_stack_allowed / K);
+ os::Linux::min_stack_allowed/ K);
return JNI_ERR;
}
@@ -4839,7 +4850,7 @@
// Next, demultiplex/decode time arguments
timespec absTime;
- if (time < 0) { // don't wait at all
+ if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
if (time > 0) {
--- a/hotspot/src/os/solaris/vm/objectMonitor_solaris.cpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
--- a/hotspot/src/os/solaris/vm/objectMonitor_solaris.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
- private:
--- a/hotspot/src/os/solaris/vm/objectMonitor_solaris.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -4878,18 +4878,17 @@
// Check minimum allowable stack size for thread creation and to initialize
// the java system classes, including StackOverflowError - depends on page
// size. Add a page for compiler2 recursion in main thread.
- // Add in BytesPerWord times page size to account for VM stack during
+ // Add in 2*BytesPerWord times page size to account for VM stack during
// class initialization depending on 32 or 64 bit VM.
- guarantee((Solaris::min_stack_allowed >=
- (StackYellowPages+StackRedPages+StackShadowPages+BytesPerWord
- COMPILER2_PRESENT(+1)) * page_size),
- "need to increase Solaris::min_stack_allowed on this platform");
+ os::Solaris::min_stack_allowed = MAX2(os::Solaris::min_stack_allowed,
+ (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
+ 2*BytesPerWord COMPILER2_PRESENT(+1)) * page_size);
size_t threadStackSizeInBytes = ThreadStackSize * K;
if (threadStackSizeInBytes != 0 &&
- threadStackSizeInBytes < Solaris::min_stack_allowed) {
+ threadStackSizeInBytes < os::Solaris::min_stack_allowed) {
tty->print_cr("\nThe stack size specified is too small, Specify at least %dk",
- Solaris::min_stack_allowed/K);
+ os::Solaris::min_stack_allowed/K);
return JNI_ERR;
}
@@ -5837,7 +5836,7 @@
// First, demultiplex/decode time arguments
timespec absTime;
- if (time < 0) { // don't wait at all
+ if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
if (time > 0) {
--- a/hotspot/src/os/windows/vm/objectMonitor_windows.cpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "incls/_precompiled.incl"
--- a/hotspot/src/os/windows/vm/objectMonitor_windows.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
- private:
--- a/hotspot/src/os/windows/vm/objectMonitor_windows.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
--- a/hotspot/src/os/windows/vm/os_windows.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -3311,7 +3311,6 @@
}
}
-
// this is called _after_ the global arguments have been parsed
jint os::init_2(void) {
// Allocate a single page and mark it as readable for safepoint polling
@@ -3390,6 +3389,21 @@
actual_reserve_size = default_reserve_size;
}
+ // Check minimum allowable stack size for thread creation and to initialize
+ // the java system classes, including StackOverflowError - depends on page
+ // size. Add a page for compiler2 recursion in main thread.
+ // Add in 2*BytesPerWord times page size to account for VM stack during
+ // class initialization depending on 32 or 64 bit VM.
+ size_t min_stack_allowed =
+ (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
+ 2*BytesPerWord COMPILER2_PRESENT(+1)) * os::vm_page_size();
+ if (actual_reserve_size < min_stack_allowed) {
+ tty->print_cr("\nThe stack size specified is too small, "
+ "Specify at least %dk",
+ min_stack_allowed / K);
+ return JNI_ERR;
+ }
+
JavaThread::set_stack_size_at_create(stack_commit_size);
// Calculate theoretical max. size of Threads to guard gainst artifical
@@ -3992,7 +4006,7 @@
if (time < 0) { // don't wait
return;
}
- else if (time == 0) {
+ else if (time == 0 && !isAbsolute) {
time = INFINITE;
}
else if (isAbsolute) {
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -200,6 +200,18 @@
sigcontext* sc = (sigcontext*)context;
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
" O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
SIG_REGS(sc).u_regs[CON_O0],
@@ -213,18 +225,32 @@
SIG_REGS(sc).u_regs[CON_O6],
SIG_REGS(sc).u_regs[CON_O7]);
- 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);
+
+ intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
+ st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
+ " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
+ sp[L0->sp_offset_in_saved_window()],
+ sp[L1->sp_offset_in_saved_window()],
+ sp[L2->sp_offset_in_saved_window()],
+ sp[L3->sp_offset_in_saved_window()]);
+ st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
+ " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
+ sp[L4->sp_offset_in_saved_window()],
+ 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,
SIG_PC(sc),
@@ -232,7 +258,6 @@
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);
print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t));
st->cr();
@@ -242,7 +267,58 @@
// this at the end, and hope for the best.
address pc = os::Linux::ucontext_get_pc(uc);
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();
}
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -718,11 +718,6 @@
ucontext_t *uc = (ucontext_t*)context;
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
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
@@ -745,68 +740,11 @@
st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
st->cr();
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(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]);
st->cr();
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
st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]);
st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]);
@@ -819,41 +757,8 @@
st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]);
st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]);
+ st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]);
st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
- st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_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[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
st->cr();
st->cr();
@@ -868,7 +773,52 @@
// this at the end, and hope for the best.
address pc = os::Linux::ucontext_get_pc(uc);
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() {
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -540,6 +540,11 @@
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
sigset_t newset;
sigemptyset(&newset);
@@ -558,6 +563,18 @@
ucontext_t *uc = (ucontext_t*)context;
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
" O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
uc->uc_mcontext.gregs[REG_O0],
@@ -571,81 +588,39 @@
uc->uc_mcontext.gregs[REG_O6],
uc->uc_mcontext.gregs[REG_O7]);
- 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]);
+
+ intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
+ st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
+ " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
+ sp[L0->sp_offset_in_saved_window()],
+ sp[L1->sp_offset_in_saved_window()],
+ sp[L2->sp_offset_in_saved_window()],
+ sp[L3->sp_offset_in_saved_window()]);
+ st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
+ " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
+ sp[L4->sp_offset_in_saved_window()],
+ 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,
uc->uc_mcontext.gregs[REG_PC],
uc->uc_mcontext.gregs[REG_nPC]);
-
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);
print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t));
st->cr();
@@ -656,7 +631,57 @@
ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc);
address pc = epc.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) {
--- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,10 +65,6 @@
// getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are
// supported on Solaris 10 and later.
if (os::Solaris::supports_getisax()) {
-#ifndef PRODUCT
- if (PrintMiscellaneous && Verbose)
- tty->print_cr("getisax(2) supported.");
-#endif
// Check 32-bit architecture.
do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m);
@@ -81,6 +77,11 @@
uint_t avn = os::Solaris::getisax(&av, 1);
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_DIV32) features |= hardware_div32_m;
if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
@@ -88,11 +89,22 @@
if (av & AV_SPARC_POPC) features |= hardware_popc_m;
if (av & AV_SPARC_VIS) features |= vis1_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 {
// getisax(2) failed, use the old legacy code.
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose)
- tty->print_cr("getisax(2) not supported.");
+ tty->print_cr("getisax(2) is not supported.");
#endif
char tmp;
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -719,11 +719,6 @@
ucontext_t *uc = (ucontext_t*)context;
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
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
@@ -735,8 +730,8 @@
st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
st->cr();
- st->print( "R8=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
- st->print(", R9=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
+ st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
+ st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
st->cr();
@@ -747,63 +742,6 @@
st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
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
st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]);
st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]);
@@ -817,39 +755,6 @@
st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]);
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
st->cr();
st->cr();
@@ -865,7 +770,52 @@
ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc);
address pc = epc.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();
}
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -387,8 +387,8 @@
st->print(", RSI=" INTPTR_FORMAT, uc->Rsi);
st->print(", RDI=" INTPTR_FORMAT, uc->Rdi);
st->cr();
- st->print( "R8=" INTPTR_FORMAT, uc->R8);
- st->print(", R9=" INTPTR_FORMAT, uc->R9);
+ st->print( "R8 =" INTPTR_FORMAT, uc->R8);
+ st->print(", R9 =" INTPTR_FORMAT, uc->R9);
st->print(", R10=" INTPTR_FORMAT, uc->R10);
st->print(", R11=" INTPTR_FORMAT, uc->R11);
st->cr();
@@ -399,62 +399,6 @@
st->cr();
st->print( "RIP=" INTPTR_FORMAT, uc->Rip);
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
st->print( "EAX=" INTPTR_FORMAT, uc->Eax);
st->print(", EBX=" INTPTR_FORMAT, uc->Ebx);
@@ -468,38 +412,6 @@
st->cr();
st->print( "EIP=" INTPTR_FORMAT, uc->Eip);
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
st->cr();
st->cr();
@@ -514,7 +426,49 @@
// this at the end, and hope for the best.
address pc = (address)uc->REG_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();
}
--- a/hotspot/src/share/vm/c1/c1_Compilation.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -178,15 +178,11 @@
return (int) NMethodSizeLimit; // default 256K or 512K
#else
// 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
}
static int desired_max_constant_size() {
-#ifndef PPC
- return (int) NMethodSizeLimit / 10; // about 25K
-#else
- return (MAX2((unsigned int)NMethodSizeLimit, 32*K)) / 10;
-#endif
+ return desired_max_code_buffer_size() / 10;
}
static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate);
--- a/hotspot/src/share/vm/c1/c1_IR.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_IR.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -321,7 +321,7 @@
void visit(Value* n) {
// Local instructions and Phis for expression stack values at the
// 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");
Compilation::current()->bailout("a node was not appended to the graph");
}
--- a/hotspot/src/share/vm/c1/c1_Instruction.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -415,28 +415,26 @@
return false;
}
-
-BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
- BlockBegin* true_sux, BlockBegin* false_sux) {
+Constant::CompareResult Constant::compare(Instruction::Condition cond, Value right) const {
Constant* rc = right->as_Constant();
// other is not a constant
- if (rc == NULL) return NULL;
+ if (rc == NULL) return not_comparable;
ValueType* lt = type();
ValueType* rt = rc->type();
// different types
- if (lt->base() != rt->base()) return NULL;
+ if (lt->base() != rt->base()) return not_comparable;
switch (lt->tag()) {
case intTag: {
int x = lt->as_IntConstant()->value();
int y = rt->as_IntConstant()->value();
switch (cond) {
- case If::eql: return x == y ? true_sux : false_sux;
- case If::neq: return x != y ? true_sux : false_sux;
- case If::lss: return x < y ? true_sux : false_sux;
- case If::leq: return x <= y ? true_sux : false_sux;
- case If::gtr: return x > y ? true_sux : false_sux;
- case If::geq: return x >= y ? true_sux : false_sux;
+ case If::eql: return x == y ? cond_true : cond_false;
+ case If::neq: return x != y ? cond_true : cond_false;
+ case If::lss: return x < y ? cond_true : cond_false;
+ case If::leq: return x <= y ? cond_true : cond_false;
+ case If::gtr: return x > y ? cond_true : cond_false;
+ case If::geq: return x >= y ? cond_true : cond_false;
}
break;
}
@@ -444,12 +442,12 @@
jlong x = lt->as_LongConstant()->value();
jlong y = rt->as_LongConstant()->value();
switch (cond) {
- case If::eql: return x == y ? true_sux : false_sux;
- case If::neq: return x != y ? true_sux : false_sux;
- case If::lss: return x < y ? true_sux : false_sux;
- case If::leq: return x <= y ? true_sux : false_sux;
- case If::gtr: return x > y ? true_sux : false_sux;
- case If::geq: return x >= y ? true_sux : false_sux;
+ case If::eql: return x == y ? cond_true : cond_false;
+ case If::neq: return x != y ? cond_true : cond_false;
+ case If::lss: return x < y ? cond_true : cond_false;
+ case If::leq: return x <= y ? cond_true : cond_false;
+ case If::gtr: return x > y ? cond_true : cond_false;
+ case If::geq: return x >= y ? cond_true : cond_false;
}
break;
}
@@ -459,14 +457,14 @@
assert(xvalue != NULL && yvalue != NULL, "not constants");
if (xvalue->is_loaded() && yvalue->is_loaded()) {
switch (cond) {
- case If::eql: return xvalue == yvalue ? true_sux : false_sux;
- case If::neq: return xvalue != yvalue ? true_sux : false_sux;
+ case If::eql: return xvalue == yvalue ? cond_true : cond_false;
+ case If::neq: return xvalue != yvalue ? cond_true : cond_false;
}
}
break;
}
}
- return NULL;
+ return not_comparable;
}
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -443,7 +443,7 @@
// generic
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 Constant* as_Constant() { return NULL; }
virtual AccessField* as_AccessField() { return NULL; }
@@ -650,8 +650,24 @@
virtual intx hash() 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;
+ }
+ }
};
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1350,7 +1350,6 @@
addr = ptr;
}
assert(addr->is_register(), "must be a register at this point");
- assert(addr->type() == T_OBJECT, "addr should point to an object");
LIR_Opr xor_res = new_pointer_register();
LIR_Opr xor_shift_res = new_pointer_register();
--- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -38,18 +38,20 @@
private:
IR* _hir;
int _cee_count; // the number of CEs successfully eliminated
+ int _ifop_count; // the number of IfOps successfully simplified
int _has_substitution;
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;
_hir->iterate_preorder(this);
if (_has_substitution) {
- // substituted some phis so resolve the substitution
+ // substituted some ifops/phis, so resolve the substitution
SubstitutionResolver sr(_hir);
}
}
int cee_count() const { return _cee_count; }
+ int ifop_count() const { return _ifop_count; }
void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) {
int e = sux->number_of_exception_handlers();
@@ -68,156 +70,214 @@
}
}
- 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;
+ virtual void block_do(BlockBegin* block);
+
+ private:
+ Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval);
+};
- // 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;
+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;
- BlockBegin* t_block = if_->tsux();
- BlockBegin* f_block = if_->fsux();
- Instruction* t_cur = t_block->next();
- Instruction* f_cur = f_block->next();
+ // 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;
- // 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();
- }
+ BlockBegin* t_block = if_->tsux();
+ BlockBegin* f_block = if_->fsux();
+ Instruction* t_cur = t_block->next();
+ Instruction* f_cur = f_block->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;
+ // 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 gotos merge into the same block
- BlockBegin* sux = t_goto->default_sux();
- if (sux != f_goto->default_sux()) return;
+ // 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 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 both gotos merge into the same block
+ BlockBegin* sux = t_goto->default_sux();
+ if (sux != f_goto->default_sux()) 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());
+ // 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;
- // 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 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;
- // 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; );
+ // 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;
- // 2) substitute conditional expression
- // with an IfOp followed by a Goto
- // cut if_ away and get node before
- Instruction* cur_end = if_->prev(block);
+ // 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);
- }
+ // 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);
+ 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());
+ // 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());
+ }
- // 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);
+ _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();
- cur_end = cur_end->set_next(goto_, goto_state->bci());
+ 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;
- // 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);
+ _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;
+ }
}
- 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();
}
-};
-
+ return new IfOp(x, cond, y, tval, fval);
+}
void Optimizer::eliminate_conditional_expressions() {
// find conditional expressions & replace them with IfOps
CE_Eliminator ce(ir());
}
-
class BlockMerger: public BlockClosure {
private:
IR* _hir;
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -107,7 +107,6 @@
RegisterMap reg_map(thread, false);
frame runtime_frame = thread->last_frame();
frame caller_frame = runtime_frame.sender(®_map);
- // bypass VM_DeoptimizeFrame and deoptimize the frame directly
Deoptimization::deoptimize_frame(thread, caller_frame.id());
assert(caller_is_deopted(), "Must be deoptimized");
}
@@ -368,8 +367,7 @@
if (osr_nm != NULL) {
RegisterMap map(thread, false);
frame fr = thread->last_frame().sender(&map);
- VM_DeoptimizeFrame deopt(thread, fr.id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(thread, fr.id());
}
JRT_BLOCK_END
return NULL;
@@ -441,8 +439,8 @@
// We don't really want to deoptimize the nmethod itself since we
// can actually continue in the exception handler ourselves but I
// don't see an easy way to have the desired effect.
- VM_DeoptimizeFrame deopt(thread, caller_frame.id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(thread, caller_frame.id());
+ assert(caller_is_deopted(), "Must be deoptimized");
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
}
@@ -835,8 +833,7 @@
nm->make_not_entrant();
}
- VM_DeoptimizeFrame deopt(thread, caller_frame.id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(thread, caller_frame.id());
// Return to the now deoptimized frame.
}
--- a/hotspot/src/share/vm/c1/c1_globals.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/c1/c1_globals.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -75,6 +75,9 @@
develop(bool, SelectivePhiFunctions, true, \
"create phi functions at loop headers only when necessary") \
\
+ develop(bool, OptimizeIfOps, true, \
+ "Optimize multiple IfOps") \
+ \
develop(bool, DoCEE, true, \
"Do Conditional Expression Elimination to simplify CFG") \
\
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -564,7 +564,7 @@
// This is OK, since any dependencies we decide to assert
// will be checked later under the Compile_lock.
ciInstanceKlass* ciInstanceKlass::implementor(int n) {
- if (n > implementors_limit) {
+ if (n >= implementors_limit) {
return NULL;
}
ciInstanceKlass* impl = _implementors[n];
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -73,6 +73,12 @@
unsigned int hashValues[SymbolTable::symbol_alloc_batch_size];
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
for (int index = 1; index < length; index++) {
// Each of the following case guarantees one more byte in the stream
@@ -141,6 +147,7 @@
ShouldNotReachHere();
}
break;
+ case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles
case JVM_CONSTANT_InvokeDynamic :
{
if (!EnableInvokeDynamic ||
@@ -151,10 +158,36 @@
"Class file version does not support constant tag %u in class file %s"),
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 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;
case JVM_CONSTANT_Integer :
@@ -257,6 +290,23 @@
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().
#ifdef ASSERT
assert(cfs0->current() == old_current, "non-exclusive use of stream()");
@@ -264,6 +314,41 @@
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); }
constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
@@ -431,6 +516,8 @@
ref_index, CHECK_(nullHandle));
}
break;
+ case JVM_CONSTANT_InvokeDynamicTrans :
+ ShouldNotReachHere(); // this tag does not appear in the heap
case JVM_CONSTANT_InvokeDynamic :
{
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
@@ -438,7 +525,7 @@
check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292)
||
(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",
bootstrap_method_ref_index,
CHECK_(nullHandle));
@@ -447,6 +534,18 @@
"Invalid constant pool index %u in class file %s",
name_and_type_ref_index,
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;
}
default:
@@ -2516,18 +2615,6 @@
// 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
- // 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.
int reference_sig_index = 0;
int reference_name_index = 0;
int reference_index = 0;
@@ -2663,7 +2750,7 @@
// Force MethodHandle.vmentry to be an unmanaged pointer.
// There is no way for a classfile to express this, so we must help it.
void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
- typeArrayHandle* fields_ptr,
+ typeArrayHandle fields,
FieldAllocationCount *fac_ptr,
TRAPS) {
// Add fake fields for java.dyn.MethodHandle instances
@@ -2687,41 +2774,45 @@
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing I or J signature (for vmentry) in java.dyn.MethodHandle");
+ // Find vmentry field and change the signature.
bool found_vmentry = false;
-
- const int n = (*fields_ptr)()->length();
- for (int i = 0; i < n; i += instanceKlass::next_offset) {
- int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_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);
+ for (int i = 0; i < fields->length(); i += instanceKlass::next_offset) {
+ int name_index = fields->ushort_at(i + instanceKlass::name_index_offset);
+ int sig_index = fields->ushort_at(i + instanceKlass::signature_index_offset);
+ int acc_flags = fields->ushort_at(i + instanceKlass::access_flags_offset);
symbolOop f_name = cp->symbol_at(name_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);
- assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64");
- if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1;
- else fac_ptr->nonstatic_word_count += 1;
-
- FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i + instanceKlass::low_offset);
- assert(atype == NONSTATIC_BYTE, "");
- FieldAllocationType new_atype = (wordSize == longSize) ? NONSTATIC_DOUBLE : NONSTATIC_WORD;
- (*fields_ptr)->ushort_at_put(i + instanceKlass::low_offset, new_atype);
-
- found_vmentry = true;
- break;
+
+ if (f_name == vmSymbols::vmentry_name() && (acc_flags & JVM_ACC_STATIC) == 0) {
+ if (f_sig == vmSymbols::machine_word_signature()) {
+ // If the signature of vmentry is already changed, we're done.
+ 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;
+
+ fields->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index);
+ assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64");
+ if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1;
+ else fac_ptr->nonstatic_word_count += 1;
+
+ FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset);
+ 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)
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing vmentry byte field in java.dyn.MethodHandle");
-
}
@@ -3082,7 +3173,7 @@
// adjust the vmentry field declaration in java.dyn.MethodHandle
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
@@ -4309,20 +4400,21 @@
}
-// Unqualified names may not contain the characters '.', ';', or '/'.
-// Method names also may not contain the characters '<' or '>', unless <init> or <clinit>.
-// Note that method names may not be <init> or <clinit> in this method.
-// Because these names have been checked as special cases before calling this method
-// in verify_legal_method_name.
-bool ClassFileParser::verify_unqualified_name(char* name, unsigned int length, int type) {
+// Unqualified names may not contain the characters '.', ';', '[', or '/'.
+// Method names also may not contain the characters '<' or '>', unless <init>
+// or <clinit>. Note that method names may not be <init> or <clinit> in this
+// method. Because these names have been checked as special cases before
+// calling this method in verify_legal_method_name.
+bool ClassFileParser::verify_unqualified_name(
+ char* name, unsigned int length, int type) {
jchar ch;
for (char* p = name; p != name + length; ) {
ch = *p;
if (ch < 128) {
p++;
- if (ch == '.' || ch == ';') {
- return false; // do not permit '.' or ';'
+ if (ch == '.' || ch == ';' || ch == '[' ) {
+ return false; // do not permit '.', ';', or '['
}
if (type != LegalClass && ch == '/') {
return false; // do not permit '/' unless it's class name
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,6 +56,9 @@
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
objArrayHandle parse_interfaces(constantPoolHandle cp,
int length,
@@ -151,7 +154,7 @@
// Adjust the field allocation counts for java.dyn.MethodHandle to add
// a fake address (void*) field.
void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
- typeArrayHandle* fields_ptr,
+ typeArrayHandle fields,
FieldAllocationCount *fac_ptr, TRAPS);
// Format checker methods
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/stackMapTableFormat.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// These classes represent the stack-map substructures described in the JVMS
+// (hence the non-conforming naming scheme).
+
+// These classes work with the types in their compressed form in-place (as they
+// would appear in the classfile). No virtual methods or fields allowed.
+
+class verification_type_info {
+ private:
+ // u1 tag
+ // u2 cpool_index || u2 bci (for ITEM_Object & ITEM_Uninitailized only)
+
+ address tag_addr() const { return (address)this; }
+ address cpool_index_addr() const { return tag_addr() + sizeof(u1); }
+ address bci_addr() const { return cpool_index_addr(); }
+
+ protected:
+ // No constructors - should be 'private', but GCC issues a warning if it is
+ verification_type_info() {}
+ verification_type_info(const verification_type_info&) {}
+
+ public:
+
+ static verification_type_info* at(address addr) {
+ return (verification_type_info*)addr;
+ }
+
+ static verification_type_info* create_at(address addr, u1 tag) {
+ verification_type_info* vti = (verification_type_info*)addr;
+ vti->set_tag(tag);
+ return vti;
+ }
+
+ static verification_type_info* create_object_at(address addr, u2 cp_idx) {
+ verification_type_info* vti = (verification_type_info*)addr;
+ vti->set_tag(ITEM_Object);
+ vti->set_cpool_index(cp_idx);
+ return vti;
+ }
+
+ static verification_type_info* create_uninit_at(address addr, u2 bci) {
+ verification_type_info* vti = (verification_type_info*)addr;
+ vti->set_tag(ITEM_Uninitialized);
+ vti->set_bci(bci);
+ return vti;
+ }
+
+ static size_t calculate_size(u1 tag) {
+ if (tag == ITEM_Object || tag == ITEM_Uninitialized) {
+ return sizeof(u1) + sizeof(u2);
+ } else {
+ return sizeof(u1);
+ }
+ }
+
+ static size_t max_size() { return sizeof(u1) + sizeof(u2); }
+
+ u1 tag() const { return *(u1*)tag_addr(); }
+ void set_tag(u1 tag) { *((u1*)tag_addr()) = tag; }
+
+ bool is_object() const { return tag() == ITEM_Object; }
+ bool is_uninitialized() const { return tag() == ITEM_Uninitialized; }
+
+ u2 cpool_index() const {
+ assert(is_object(), "This type has no cp_index");
+ return Bytes::get_Java_u2(cpool_index_addr());
+ }
+ void set_cpool_index(u2 idx) {
+ assert(is_object(), "This type has no cp_index");
+ Bytes::put_Java_u2(cpool_index_addr(), idx);
+ }
+
+ u2 bci() const {
+ assert(is_uninitialized(), "This type has no bci");
+ return Bytes::get_Java_u2(bci_addr());
+ }
+
+ void set_bci(u2 bci) {
+ assert(is_uninitialized(), "This type has no bci");
+ Bytes::put_Java_u2(bci_addr(), bci);
+ }
+
+ void copy_from(verification_type_info* from) {
+ set_tag(from->tag());
+ if (from->is_object()) {
+ set_cpool_index(from->cpool_index());
+ } else if (from->is_uninitialized()) {
+ set_bci(from->bci());
+ }
+ }
+
+ size_t size() const {
+ return calculate_size(tag());
+ }
+
+ verification_type_info* next() {
+ return (verification_type_info*)((address)this + size());
+ }
+
+ // This method is used when reading unverified data in order to ensure
+ // that we don't read past a particular memory limit. It returns false
+ // if any part of the data structure is outside the specified memory bounds.
+ bool verify(address start, address end) {
+ return ((address)this >= start &&
+ (address)this < end &&
+ (bci_addr() + sizeof(u2) <= end ||
+ !is_object() && !is_uninitialized()));
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) {
+ switch (tag()) {
+ case ITEM_Top: st->print("Top"); break;
+ case ITEM_Integer: st->print("Integer"); break;
+ case ITEM_Float: st->print("Float"); break;
+ case ITEM_Double: st->print("Double"); break;
+ case ITEM_Long: st->print("Long"); break;
+ case ITEM_Null: st->print("Null"); break;
+ case ITEM_UninitializedThis:
+ st->print("UninitializedThis"); break;
+ case ITEM_Uninitialized:
+ st->print("Uninitialized[#%d]", bci()); break;
+ case ITEM_Object:
+ st->print("Object[#%d]", cpool_index()); break;
+ default:
+ assert(false, "Bad verification_type_info");
+ }
+ }
+#endif
+};
+
+#define FOR_EACH_STACKMAP_FRAME_TYPE(macro, arg1, arg2) \
+ macro(same_frame, arg1, arg2) \
+ macro(same_frame_extended, arg1, arg2) \
+ macro(same_frame_1_stack_item_frame, arg1, arg2) \
+ macro(same_frame_1_stack_item_extended, arg1, arg2) \
+ macro(chop_frame, arg1, arg2) \
+ macro(append_frame, arg1, arg2) \
+ macro(full_frame, arg1, arg2)
+
+#define SM_FORWARD_DECL(type, arg1, arg2) class type;
+FOR_EACH_STACKMAP_FRAME_TYPE(SM_FORWARD_DECL, x, x)
+#undef SM_FORWARD_DECL
+
+class stack_map_frame {
+ protected:
+ address frame_type_addr() const { return (address)this; }
+
+ // No constructors - should be 'private', but GCC issues a warning if it is
+ stack_map_frame() {}
+ stack_map_frame(const stack_map_frame&) {}
+
+ public:
+
+ static stack_map_frame* at(address addr) {
+ return (stack_map_frame*)addr;
+ }
+
+ stack_map_frame* next() const {
+ return at((address)this + size());
+ }
+
+ u1 frame_type() const { return *(u1*)frame_type_addr(); }
+ void set_frame_type(u1 type) { *((u1*)frame_type_addr()) = type; }
+
+ // pseudo-virtual methods
+ inline size_t size() const;
+ inline int offset_delta() const;
+ inline void set_offset_delta(int offset_delta);
+ inline int number_of_types() const; // number of types contained in the frame
+ inline verification_type_info* types() const; // pointer to first type
+ inline bool is_valid_offset(int offset_delta) const;
+
+ // This method must be used when reading unverified data in order to ensure
+ // that we don't read past a particular memory limit. It returns false
+ // if any part of the data structure is outside the specified memory bounds.
+ inline bool verify(address start, address end) const;
+#ifdef ASSERT
+ inline void print_on(outputStream* st) const;
+#endif
+
+ // Create as_xxx and is_xxx methods for the subtypes
+#define FRAME_TYPE_DECL(stackmap_frame_type, arg1, arg2) \
+ inline stackmap_frame_type* as_##stackmap_frame_type() const; \
+ bool is_##stackmap_frame_type() { \
+ return as_##stackmap_frame_type() != NULL; \
+ }
+
+ FOR_EACH_STACKMAP_FRAME_TYPE(FRAME_TYPE_DECL, x, x)
+#undef FRAME_TYPE_DECL
+};
+
+class same_frame : public stack_map_frame {
+ private:
+ static int frame_type_to_offset_delta(u1 frame_type) {
+ return frame_type + 1; }
+ static u1 offset_delta_to_frame_type(int offset_delta) {
+ return (u1)(offset_delta - 1); }
+
+ public:
+
+ static bool is_frame_type(u1 tag) {
+ return tag < 64;
+ }
+
+ static same_frame* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (same_frame*)addr;
+ }
+
+ static same_frame* create_at(address addr, int offset_delta) {
+ same_frame* sm = (same_frame*)addr;
+ sm->set_offset_delta(offset_delta);
+ return sm;
+ }
+
+ static size_t calculate_size() { return sizeof(u1); }
+
+ size_t size() const { return calculate_size(); }
+ int offset_delta() const { return frame_type_to_offset_delta(frame_type()); }
+
+ void set_offset_delta(int offset_delta) {
+ assert(offset_delta <= 64, "Offset too large for same_frame");
+ set_frame_type(offset_delta_to_frame_type(offset_delta));
+ }
+
+ int number_of_types() const { return 0; }
+ verification_type_info* types() const { return NULL; }
+
+ bool is_valid_offset(int offset_delta) const {
+ return is_frame_type(offset_delta_to_frame_type(offset_delta));
+ }
+
+ bool verify_subtype(address start, address end) const {
+ return true;
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("same_frame(%d)", offset_delta());
+ }
+#endif
+};
+
+class same_frame_extended : public stack_map_frame {
+ private:
+ enum { _frame_id = 251 };
+ address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return tag == _frame_id;
+ }
+
+ static same_frame_extended* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame type");
+ return (same_frame_extended*)addr;
+ }
+
+ static same_frame_extended* create_at(address addr, u2 offset_delta) {
+ same_frame_extended* sm = (same_frame_extended*)addr;
+ sm->set_frame_type(_frame_id);
+ sm->set_offset_delta(offset_delta);
+ return sm;
+ }
+
+ static size_t calculate_size() { return sizeof(u1) + sizeof(u2); }
+
+ size_t size() const { return calculate_size(); }
+ int offset_delta() const {
+ return Bytes::get_Java_u2(offset_delta_addr()) + 1;
+ }
+
+ void set_offset_delta(int offset_delta) {
+ Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1);
+ }
+
+ int number_of_types() const { return 0; }
+ verification_type_info* types() const { return NULL; }
+ bool is_valid_offset(int offset) const { return true; }
+
+ bool verify_subtype(address start, address end) const {
+ return frame_type_addr() + size() <= end;
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("same_frame_extended(%d)", offset_delta());
+ }
+#endif
+};
+
+class same_frame_1_stack_item_frame : public stack_map_frame {
+ private:
+ address type_addr() const { return frame_type_addr() + sizeof(u1); }
+
+ static int frame_type_to_offset_delta(u1 frame_type) {
+ return frame_type - 63; }
+ static u1 offset_delta_to_frame_type(int offset_delta) {
+ return (u1)(offset_delta + 63); }
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return tag >= 64 && tag < 128;
+ }
+
+ static same_frame_1_stack_item_frame* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (same_frame_1_stack_item_frame*)addr;
+ }
+
+ static same_frame_1_stack_item_frame* create_at(
+ address addr, int offset_delta, verification_type_info* vti) {
+ same_frame_1_stack_item_frame* sm = (same_frame_1_stack_item_frame*)addr;
+ sm->set_offset_delta(offset_delta);
+ if (vti != NULL) {
+ sm->set_type(vti);
+ }
+ return sm;
+ }
+
+ static size_t calculate_size(verification_type_info* vti) {
+ return sizeof(u1) + vti->size();
+ }
+
+ static size_t max_size() {
+ return sizeof(u1) + verification_type_info::max_size();
+ }
+
+ size_t size() const { return calculate_size(types()); }
+ int offset_delta() const { return frame_type_to_offset_delta(frame_type()); }
+
+ void set_offset_delta(int offset_delta) {
+ assert(offset_delta > 0 && offset_delta <= 64,
+ "Offset too large for this frame type");
+ set_frame_type(offset_delta_to_frame_type(offset_delta));
+ }
+
+ void set_type(verification_type_info* vti) {
+ verification_type_info* cur = types();
+ cur->copy_from(vti);
+ }
+
+ int number_of_types() const { return 1; }
+ verification_type_info* types() const {
+ return verification_type_info::at(type_addr());
+ }
+
+ bool is_valid_offset(int offset_delta) const {
+ return is_frame_type(offset_delta_to_frame_type(offset_delta));
+ }
+
+ bool verify_subtype(address start, address end) const {
+ return types()->verify(start, end);
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("same_frame_1_stack_item_frame(%d,", offset_delta());
+ types()->print_on(st);
+ st->print(")");
+ }
+#endif
+};
+
+class same_frame_1_stack_item_extended : public stack_map_frame {
+ private:
+ address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
+ address type_addr() const { return offset_delta_addr() + sizeof(u2); }
+
+ enum { _frame_id = 247 };
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return tag == _frame_id;
+ }
+
+ static same_frame_1_stack_item_extended* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (same_frame_1_stack_item_extended*)addr;
+ }
+
+ static same_frame_1_stack_item_extended* create_at(
+ address addr, int offset_delta, verification_type_info* vti) {
+ same_frame_1_stack_item_extended* sm =
+ (same_frame_1_stack_item_extended*)addr;
+ sm->set_frame_type(_frame_id);
+ sm->set_offset_delta(offset_delta);
+ if (vti != NULL) {
+ sm->set_type(vti);
+ }
+ return sm;
+ }
+
+ static size_t calculate_size(verification_type_info* vti) {
+ return sizeof(u1) + sizeof(u2) + vti->size();
+ }
+
+ size_t size() const { return calculate_size(types()); }
+ int offset_delta() const {
+ return Bytes::get_Java_u2(offset_delta_addr()) + 1;
+ }
+
+ void set_offset_delta(int offset_delta) {
+ Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1);
+ }
+
+ void set_type(verification_type_info* vti) {
+ verification_type_info* cur = types();
+ cur->copy_from(vti);
+ }
+
+ int number_of_types() const { return 1; }
+ verification_type_info* types() const {
+ return verification_type_info::at(type_addr());
+ }
+ bool is_valid_offset(int offset) { return true; }
+
+ bool verify_subtype(address start, address end) const {
+ return type_addr() < end && types()->verify(start, end);
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("same_frame_1_stack_item_extended(%d,", offset_delta());
+ types()->print_on(st);
+ st->print(")");
+ }
+#endif
+};
+
+class chop_frame : public stack_map_frame {
+ private:
+ address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
+
+ static int frame_type_to_chops(u1 frame_type) {
+ int chop = 251 - frame_type;
+ return chop;
+ }
+
+ static u1 chops_to_frame_type(int chop) {
+ return 251 - chop;
+ }
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return frame_type_to_chops(tag) > 0 && frame_type_to_chops(tag) < 4;
+ }
+
+ static chop_frame* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (chop_frame*)addr;
+ }
+
+ static chop_frame* create_at(address addr, int offset_delta, int chops) {
+ chop_frame* sm = (chop_frame*)addr;
+ sm->set_chops(chops);
+ sm->set_offset_delta(offset_delta);
+ return sm;
+ }
+
+ static size_t calculate_size() {
+ return sizeof(u1) + sizeof(u2);
+ }
+
+ size_t size() const { return calculate_size(); }
+ int offset_delta() const {
+ return Bytes::get_Java_u2(offset_delta_addr()) + 1;
+ }
+ void set_offset_delta(int offset_delta) {
+ Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1);
+ }
+
+ int chops() const {
+ int chops = frame_type_to_chops(frame_type());
+ assert(chops > 0 && chops < 4, "Invalid number of chops in frame");
+ return chops;
+ }
+ void set_chops(int chops) {
+ assert(chops > 0 && chops <= 3, "Bad number of chops");
+ set_frame_type(chops_to_frame_type(chops));
+ }
+
+ int number_of_types() const { return 0; }
+ verification_type_info* types() const { return NULL; }
+ bool is_valid_offset(int offset) { return true; }
+
+ bool verify_subtype(address start, address end) const {
+ return frame_type_addr() + size() <= end;
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("chop_frame(%d,%d)", offset_delta(), chops());
+ }
+#endif
+};
+
+class append_frame : public stack_map_frame {
+ private:
+ address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
+ address types_addr() const { return offset_delta_addr() + sizeof(u2); }
+
+ static int frame_type_to_appends(u1 frame_type) {
+ int append = frame_type - 251;
+ return append;
+ }
+
+ static u1 appends_to_frame_type(int appends) {
+ assert(appends > 0 && appends < 4, "Invalid append amount");
+ return 251 + appends;
+ }
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return frame_type_to_appends(tag) > 0 && frame_type_to_appends(tag) < 4;
+ }
+
+ static append_frame* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (append_frame*)addr;
+ }
+
+ static append_frame* create_at(
+ address addr, int offset_delta, int appends,
+ verification_type_info* types) {
+ append_frame* sm = (append_frame*)addr;
+ sm->set_appends(appends);
+ sm->set_offset_delta(offset_delta);
+ if (types != NULL) {
+ verification_type_info* cur = sm->types();
+ for (int i = 0; i < appends; ++i) {
+ cur->copy_from(types);
+ cur = cur->next();
+ types = types->next();
+ }
+ }
+ return sm;
+ }
+
+ static size_t calculate_size(int appends, verification_type_info* types) {
+ size_t sz = sizeof(u1) + sizeof(u2);
+ for (int i = 0; i < appends; ++i) {
+ sz += types->size();
+ types = types->next();
+ }
+ return sz;
+ }
+
+ static size_t max_size() {
+ return sizeof(u1) + sizeof(u2) + 3 * verification_type_info::max_size();
+ }
+
+ size_t size() const { return calculate_size(number_of_types(), types()); }
+ int offset_delta() const {
+ return Bytes::get_Java_u2(offset_delta_addr()) + 1;
+ }
+
+ void set_offset_delta(int offset_delta) {
+ Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1);
+ }
+
+ void set_appends(int appends) {
+ assert(appends > 0 && appends < 4, "Bad number of appends");
+ set_frame_type(appends_to_frame_type(appends));
+ }
+
+ int number_of_types() const {
+ int appends = frame_type_to_appends(frame_type());
+ assert(appends > 0 && appends < 4, "Invalid number of appends in frame");
+ return appends;
+ }
+ verification_type_info* types() const {
+ return verification_type_info::at(types_addr());
+ }
+ bool is_valid_offset(int offset) const { return true; }
+
+ bool verify_subtype(address start, address end) const {
+ verification_type_info* vti = types();
+ if ((address)vti < end && vti->verify(start, end)) {
+ int nof = number_of_types();
+ vti = vti->next();
+ if (nof < 2 || vti->verify(start, end)) {
+ vti = vti->next();
+ if (nof < 3 || vti->verify(start, end)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("append_frame(%d,", offset_delta());
+ verification_type_info* vti = types();
+ for (int i = 0; i < number_of_types(); ++i) {
+ vti->print_on(st);
+ if (i != number_of_types() - 1) {
+ st->print(",");
+ }
+ vti = vti->next();
+ }
+ st->print(")");
+ }
+#endif
+};
+
+class full_frame : public stack_map_frame {
+ private:
+ address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); }
+ address num_locals_addr() const { return offset_delta_addr() + sizeof(u2); }
+ address locals_addr() const { return num_locals_addr() + sizeof(u2); }
+ address stack_slots_addr(address end_of_locals) const {
+ return end_of_locals; }
+ address stack_addr(address end_of_locals) const {
+ return stack_slots_addr(end_of_locals) + sizeof(u2); }
+
+ enum { _frame_id = 255 };
+
+ public:
+ static bool is_frame_type(u1 tag) {
+ return tag == _frame_id;
+ }
+
+ static full_frame* at(address addr) {
+ assert(is_frame_type(*addr), "Wrong frame id");
+ return (full_frame*)addr;
+ }
+
+ static full_frame* create_at(
+ address addr, int offset_delta, int num_locals,
+ verification_type_info* locals,
+ int stack_slots, verification_type_info* stack) {
+ full_frame* sm = (full_frame*)addr;
+ sm->set_frame_type(_frame_id);
+ sm->set_offset_delta(offset_delta);
+ sm->set_num_locals(num_locals);
+ if (locals != NULL) {
+ verification_type_info* cur = sm->locals();
+ for (int i = 0; i < num_locals; ++i) {
+ cur->copy_from(locals);
+ cur = cur->next();
+ locals = locals->next();
+ }
+ address end_of_locals = (address)cur;
+ sm->set_stack_slots(end_of_locals, stack_slots);
+ cur = sm->stack(end_of_locals);
+ for (int i = 0; i < stack_slots; ++i) {
+ cur->copy_from(stack);
+ cur = cur->next();
+ stack = stack->next();
+ }
+ }
+ return sm;
+ }
+
+ static size_t calculate_size(
+ int num_locals, verification_type_info* locals,
+ int stack_slots, verification_type_info* stack) {
+ size_t sz = sizeof(u1) + sizeof(u2) + sizeof(u2) + sizeof(u2);
+ verification_type_info* vti = locals;
+ for (int i = 0; i < num_locals; ++i) {
+ sz += vti->size();
+ vti = vti->next();
+ }
+ vti = stack;
+ for (int i = 0; i < stack_slots; ++i) {
+ sz += vti->size();
+ vti = vti->next();
+ }
+ return sz;
+ }
+
+ static size_t max_size(int locals, int stack) {
+ return sizeof(u1) + 3 * sizeof(u2) +
+ (locals + stack) * verification_type_info::max_size();
+ }
+
+ size_t size() const {
+ address eol = end_of_locals();
+ return calculate_size(num_locals(), locals(), stack_slots(eol), stack(eol));
+ }
+
+ int offset_delta() const {
+ return Bytes::get_Java_u2(offset_delta_addr()) + 1;
+ }
+ int num_locals() const { return Bytes::get_Java_u2(num_locals_addr()); }
+ verification_type_info* locals() const {
+ return verification_type_info::at(locals_addr());
+ }
+ address end_of_locals() const {
+ verification_type_info* vti = locals();
+ for (int i = 0; i < num_locals(); ++i) {
+ vti = vti->next();
+ }
+ return (address)vti;
+ }
+ int stack_slots(address end_of_locals) const {
+ return Bytes::get_Java_u2(stack_slots_addr(end_of_locals));
+ }
+ verification_type_info* stack(address end_of_locals) const {
+ return verification_type_info::at(stack_addr(end_of_locals));
+ }
+
+ void set_offset_delta(int offset_delta) {
+ Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1);
+ }
+ void set_num_locals(int num_locals) {
+ Bytes::put_Java_u2(num_locals_addr(), num_locals);
+ }
+ void set_stack_slots(address end_of_locals, int stack_slots) {
+ Bytes::put_Java_u2(stack_slots_addr(end_of_locals), stack_slots);
+ }
+
+ // These return only the locals. Extra processing is required for stack
+ // types of full frames.
+ int number_of_types() const { return num_locals(); }
+ verification_type_info* types() const { return locals(); }
+ bool is_valid_offset(int offset) { return true; }
+
+ bool verify_subtype(address start, address end) const {
+ verification_type_info* vti = types();
+ if ((address)vti >= end) {
+ return false;
+ }
+ int count = number_of_types();
+ for (int i = 0; i < count; ++i) {
+ if (!vti->verify(start, end)) {
+ return false;
+ }
+ vti = vti->next();
+ }
+ address eol = (address)vti;
+ if (eol + sizeof(u2) > end) {
+ return false;
+ }
+ count = stack_slots(eol);
+ vti = stack(eol);
+ for (int i = 0; i < stack_slots(eol); ++i) {
+ if (!vti->verify(start, end)) {
+ return false;
+ }
+ vti = vti->next();
+ }
+ return true;
+ }
+
+#ifdef ASSERT
+ void print_on(outputStream* st) const {
+ st->print("full_frame(%d,{", offset_delta());
+ verification_type_info* vti = locals();
+ for (int i = 0; i < num_locals(); ++i) {
+ vti->print_on(st);
+ if (i != num_locals() - 1) {
+ st->print(",");
+ }
+ vti = vti->next();
+ }
+ st->print("},{");
+ address end_of_locals = (address)vti;
+ vti = stack(end_of_locals);
+ int ss = stack_slots(end_of_locals);
+ for (int i = 0; i < ss; ++i) {
+ vti->print_on(st);
+ if (i != ss - 1) {
+ st->print(",");
+ }
+ vti = vti->next();
+ }
+ st->print("})");
+ }
+#endif
+};
+
+#define VIRTUAL_DISPATCH(stack_frame_type, func_name, args) \
+ stack_frame_type* item_##stack_frame_type = as_##stack_frame_type(); \
+ if (item_##stack_frame_type != NULL) { \
+ return item_##stack_frame_type->func_name args; \
+ }
+
+#define VOID_VIRTUAL_DISPATCH(stack_frame_type, func_name, args) \
+ stack_frame_type* item_##stack_frame_type = as_##stack_frame_type(); \
+ if (item_##stack_frame_type != NULL) { \
+ item_##stack_frame_type->func_name args; \
+ return; \
+ }
+
+size_t stack_map_frame::size() const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, size, ());
+ return 0;
+}
+
+int stack_map_frame::offset_delta() const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, offset_delta, ());
+ return 0;
+}
+
+void stack_map_frame::set_offset_delta(int offset_delta) {
+ FOR_EACH_STACKMAP_FRAME_TYPE(
+ VOID_VIRTUAL_DISPATCH, set_offset_delta, (offset_delta));
+}
+
+int stack_map_frame::number_of_types() const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, number_of_types, ());
+ return 0;
+}
+
+verification_type_info* stack_map_frame::types() const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, types, ());
+ return NULL;
+}
+
+bool stack_map_frame::is_valid_offset(int offset) const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, is_valid_offset, (offset));
+ return true;
+}
+
+bool stack_map_frame::verify(address start, address end) const {
+ if (frame_type_addr() >= start && frame_type_addr() < end) {
+ FOR_EACH_STACKMAP_FRAME_TYPE(
+ VIRTUAL_DISPATCH, verify_subtype, (start, end));
+ }
+ return false;
+}
+
+#ifdef ASSERT
+void stack_map_frame::print_on(outputStream* st) const {
+ FOR_EACH_STACKMAP_FRAME_TYPE(VOID_VIRTUAL_DISPATCH, print_on, (st));
+}
+#endif
+
+#undef VIRTUAL_DISPATCH
+#undef VOID_VIRTUAL_DISPATCH
+
+#define AS_SUBTYPE_DEF(stack_frame_type, arg1, arg2) \
+stack_frame_type* stack_map_frame::as_##stack_frame_type() const { \
+ if (stack_frame_type::is_frame_type(frame_type())) { \
+ return (stack_frame_type*)this; \
+ } else { \
+ return NULL; \
+ } \
+}
+
+FOR_EACH_STACKMAP_FRAME_TYPE(AS_SUBTYPE_DEF, x, x)
+#undef AS_SUBTYPE_DEF
+
+class stack_map_table_attribute {
+ private:
+ address name_index_addr() const {
+ return (address)this; }
+ address attribute_length_addr() const {
+ return name_index_addr() + sizeof(u2); }
+ address number_of_entries_addr() const {
+ return attribute_length_addr() + sizeof(u4); }
+ address entries_addr() const {
+ return number_of_entries_addr() + sizeof(u2); }
+
+ protected:
+ // No constructors - should be 'private', but GCC issues a warning if it is
+ stack_map_table_attribute() {}
+ stack_map_table_attribute(const stack_map_table_attribute&) {}
+
+ public:
+
+ static stack_map_table_attribute* at(address addr) {
+ return (stack_map_table_attribute*)addr;
+ }
+
+ u2 name_index() const {
+ return Bytes::get_Java_u2(name_index_addr()); }
+ u4 attribute_length() const {
+ return Bytes::get_Java_u4(attribute_length_addr()); }
+ u2 number_of_entries() const {
+ return Bytes::get_Java_u2(number_of_entries_addr()); }
+ stack_map_frame* entries() const {
+ return stack_map_frame::at(entries_addr());
+ }
+
+ static size_t header_size() {
+ return sizeof(u2) + sizeof(u4);
+ }
+
+ void set_name_index(u2 idx) {
+ Bytes::put_Java_u2(name_index_addr(), idx);
+ }
+ void set_attribute_length(u4 len) {
+ Bytes::put_Java_u4(attribute_length_addr(), len);
+ }
+ void set_number_of_entries(u2 num) {
+ Bytes::put_Java_u2(number_of_entries_addr(), num);
+ }
+};
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,12 @@
# include "incls/_systemDictionary.cpp.incl"
-Dictionary* SystemDictionary::_dictionary = NULL;
-PlaceholderTable* SystemDictionary::_placeholders = NULL;
-Dictionary* SystemDictionary::_shared_dictionary = NULL;
-LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
-ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
-SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
+Dictionary* SystemDictionary::_dictionary = NULL;
+PlaceholderTable* SystemDictionary::_placeholders = NULL;
+Dictionary* SystemDictionary::_shared_dictionary = NULL;
+LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
+ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
+SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
int SystemDictionary::_number_of_modifications = 0;
@@ -1727,8 +1727,7 @@
placeholders_do(blk);
// 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.
constraints()->always_strong_classes_do(blk);
@@ -1766,8 +1765,7 @@
dictionary()->oops_do(f);
// Visit extra methods
- if (invoke_method_table() != NULL)
- invoke_method_table()->oops_do(f);
+ invoke_method_table()->oops_do(f);
// Partially loaded classes
placeholders()->oops_do(f);
@@ -1841,8 +1839,7 @@
void SystemDictionary::methods_do(void f(methodOop)) {
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 @@
// Allocate arrays
assert(dictionary() == NULL,
"SystemDictionary should only be initialized once");
- _dictionary = new Dictionary(_nof_buckets);
- _placeholders = new PlaceholderTable(_nof_buckets);
+ _dictionary = new Dictionary(_nof_buckets);
+ _placeholders = new PlaceholderTable(_nof_buckets);
_number_of_modifications = 0;
- _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
- _resolution_errors = new ResolutionErrorTable(_resolution_error_size);
- // _invoke_method_table is allocated lazily in find_method_handle_invoke()
+ _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
+ _resolution_errors = new ResolutionErrorTable(_resolution_error_size);
+ _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
@@ -2346,10 +2343,6 @@
KlassHandle accessing_klass,
TRAPS) {
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());
assert(name_id != vmSymbols::NO_SID, "must be a known name");
unsigned int hash = invoke_method_table()->compute_hash(signature, name_id);
@@ -2562,7 +2555,9 @@
}
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;
constantPoolHandle pool;
@@ -2576,7 +2571,7 @@
constantTag tag = pool->tag_at(constant_pool_index);
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.
int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index);
if (bsm_index != 0) {
@@ -2592,9 +2587,38 @@
tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":",
(intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop);
}
- assert(bsm_oop->is_oop()
- && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane");
- return Handle(THREAD, bsm_oop);
+ assert(bsm_oop->is_oop(), "must be sane");
+ // caller must verify that it is of type MethodHandle
+ 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 if (tag.is_name_and_type()) {
@@ -2607,14 +2631,14 @@
// Fall through to pick up the per-class bootstrap method.
// This mechanism may go away in the PFD.
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();
if (bsm_oop != NULL) {
if (TraceMethodHandles) {
tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":",
(intptr_t) caller_method(), (intptr_t) bsm_oop);
}
- assert(bsm_oop->is_oop()
- && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane");
+ assert(bsm_oop->is_oop(), "must be sane");
return Handle(THREAD, bsm_oop);
}
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -496,6 +496,7 @@
static Handle find_bootstrap_method(methodHandle caller_method,
int caller_bci, // N.B. must be an invokedynamic
int cache_index, // must be corresponding main_entry
+ Handle &argument_info_result, // static BSM arguments, if any
TRAPS);
// Utility for printing loader "name" as part of tracing constraints
--- a/hotspot/src/share/vm/classfile/verifier.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1909,7 +1909,7 @@
unsigned int types = (opcode == Bytecodes::_invokeinterface
? 1 << JVM_CONSTANT_InterfaceMethodref
: opcode == Bytecodes::_invokedynamic
- ? (1 << JVM_CONSTANT_NameAndType
+ ? ((AllowTransitionalJSR292 ? 1 << JVM_CONSTANT_NameAndType : 0)
|1 << JVM_CONSTANT_InvokeDynamic)
: 1 << JVM_CONSTANT_Methodref);
verify_cp_type(index, cp, types, CHECK_VERIFY(this));
--- a/hotspot/src/share/vm/code/codeCache.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/code/codeCache.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -914,3 +914,14 @@
}
#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());
+}
--- a/hotspot/src/share/vm/code/codeCache.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/code/codeCache.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -137,6 +137,7 @@
static void print_internals();
static void verify(); // verifies the code cache
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
static address low_bound() { return (address) _heap->low_boundary(); }
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -354,12 +354,8 @@
double CMSStats::time_until_cms_gen_full() const {
size_t cms_free = _cms_gen->cmsSpace()->free();
GenCollectedHeap* gch = GenCollectedHeap::heap();
- size_t expected_promotion = gch->get_gen(0)->capacity();
- if (HandlePromotionFailure) {
- expected_promotion = MIN2(
- (size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average(),
- expected_promotion);
- }
+ size_t expected_promotion = MIN2(gch->get_gen(0)->capacity(),
+ (size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average());
if (cms_free > expected_promotion) {
// Start a cms collection if there isn't enough space to promote
// for the next minor collection. Use the padded average as
@@ -865,57 +861,18 @@
return free() + _virtual_space.uncommitted_size();
}
-bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(
- size_t max_promotion_in_bytes,
- bool younger_handles_promotion_failure) const {
-
- // This is the most conservative test. Full promotion is
- // guaranteed if this is used. The multiplicative factor is to
- // account for the worst case "dilatation".
- double adjusted_max_promo_bytes = _dilatation_factor * max_promotion_in_bytes;
- if (adjusted_max_promo_bytes > (double)max_uintx) { // larger than size_t
- adjusted_max_promo_bytes = (double)max_uintx;
- }
- bool result = (max_contiguous_available() >= (size_t)adjusted_max_promo_bytes);
-
- 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;
+bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
+ size_t available = max_available();
+ size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average();
+ bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(
+ "CMS: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
+ "max_promo("SIZE_FORMAT")",
+ res? "":" not", available, res? ">=":"<",
+ av_promo, max_promotion_in_bytes);
+ }
+ return res;
}
// At a promotion failure dump information on block layout in heap
@@ -6091,23 +6048,14 @@
assert(_collectorState == Resizing, "Change of collector state to"
" Resizing must be done under the freelistLocks (plural)");
- // Now that sweeping has been completed, if the GCH's
- // incremental_collection_will_fail flag is set, clear it,
+ // Now that sweeping has been completed, we clear
+ // the incremental_collection_failed flag,
// thus inviting a younger gen collection to promote into
// this generation. If such a promotion may still fail,
// the flag will be set again when a young collection is
// 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();
- assert(gch->collector_policy()->is_two_generation_policy(),
- "Resetting of incremental_collection_will_fail flag"
- " may be incorrect otherwise");
- gch->clear_incremental_collection_will_fail();
+ gch->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up
gch->update_full_collections_completed(_collection_count_start);
}
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1185,8 +1185,7 @@
virtual void par_promote_alloc_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,
- bool younger_handles_promotion_failure) const;
+ virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes) const;
// Inform this (non-young) generation that a promotion failure was
// encountered during a collection of a younger generation that
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -272,12 +272,16 @@
}
}
-// Wait until the next synchronous GC or a timeout, whichever is earlier.
-void ConcurrentMarkSweepThread::wait_on_cms_lock(long t) {
+// Wait until the next synchronous GC, a concurrent full gc request,
+// or a timeout, whichever is earlier.
+void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) {
MutexLockerEx x(CGC_lock,
Mutex::_no_safepoint_check_flag);
+ if (_should_terminate || _collector->_full_gc_requested) {
+ return;
+ }
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);
assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
"Should not be set");
@@ -289,7 +293,8 @@
icms_wait();
return;
} 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);
}
// Check if we should start a CMS collection cycle
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -120,8 +120,10 @@
}
// Wait on CMS lock until the next synchronous GC
- // or given timeout, whichever is earlier.
- void wait_on_cms_lock(long t); // milliseconds
+ // or given timeout, whichever is earlier. A timeout value
+ // 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
// only when requested to. Both synchronous and asychronous requests
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -2418,6 +2418,8 @@
for (int i = 0; i < (int)_max_task_num; ++i) {
OopTaskQueue* queue = _task_queues->queue(i);
queue->set_empty();
+ // Clear any partial regions from the CMTasks
+ _tasks[i]->clear_aborted_region();
}
}
@@ -2706,7 +2708,6 @@
clear_marking_state();
for (int i = 0; i < (int)_max_task_num; ++i) {
_tasks[i]->clear_region_fields();
- _tasks[i]->clear_aborted_region();
}
_has_aborted = true;
@@ -2985,7 +2986,7 @@
_nextMarkBitMap = nextMarkBitMap;
clear_region_fields();
- clear_aborted_region();
+ assert(_aborted_region.is_empty(), "should have been cleared");
_calls = 0;
_elapsed_time_ms = 0.0;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -175,7 +175,7 @@
}
assert(start_card > _array->index_for(_bottom), "Cannot be first card");
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;
u_char offset = max_jubyte;
for (int i = 0; i < BlockOffsetArray::N_powers; i++) {
@@ -577,6 +577,16 @@
#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
//////////////////////////////////////////////////////////////////////
@@ -626,3 +636,12 @@
"Precondition of call");
_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);
+}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -436,6 +436,8 @@
}
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
@@ -484,4 +486,6 @@
HeapWord* block_start_unsafe(const void* addr);
HeapWord* block_start_unsafe_const(const void* addr) const;
+
+ virtual void set_for_starts_humongous(HeapWord* new_end);
};
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -791,7 +791,7 @@
int _worker_i;
public:
RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, int worker_i = 0) :
- _cl(g1->g1_rem_set()->as_HRInto_G1RemSet(), worker_i),
+ _cl(g1->g1_rem_set(), worker_i),
_worker_i(worker_i),
_g1h(g1)
{ }
@@ -890,7 +890,7 @@
abandon_cur_alloc_region();
abandon_gc_alloc_regions();
assert(_cur_alloc_region == NULL, "Invariant.");
- g1_rem_set()->as_HRInto_G1RemSet()->cleanupHRRS();
+ g1_rem_set()->cleanupHRRS();
tear_down_region_lists();
set_used_regions_to_need_zero_fill();
@@ -1506,15 +1506,11 @@
}
// Also create a G1 rem set.
- if (G1UseHRIntoRS) {
- if (mr_bs()->is_a(BarrierSet::CardTableModRef)) {
- _g1_rem_set = new HRInto_G1RemSet(this, (CardTableModRefBS*)mr_bs());
- } else {
- vm_exit_during_initialization("G1 requires a cardtable mod ref bs.");
- return JNI_ENOMEM;
- }
+ if (mr_bs()->is_a(BarrierSet::CardTableModRef)) {
+ _g1_rem_set = new G1RemSet(this, (CardTableModRefBS*)mr_bs());
} else {
- _g1_rem_set = new StupidG1RemSet(this);
+ vm_exit_during_initialization("G1 requires a cardtable mod ref bs.");
+ return JNI_ENOMEM;
}
// Carve out the G1 part of the heap.
@@ -2706,8 +2702,7 @@
}
size_t G1CollectedHeap::cards_scanned() {
- HRInto_G1RemSet* g1_rset = (HRInto_G1RemSet*) g1_rem_set();
- return g1_rset->cardsScanned();
+ return g1_rem_set()->cardsScanned();
}
void
@@ -3850,6 +3845,54 @@
undo_waste() * HeapWordSize / K);
}
+#ifdef ASSERT
+bool G1ParScanThreadState::verify_ref(narrowOop* ref) const {
+ assert(ref != NULL, "invariant");
+ assert(UseCompressedOops, "sanity");
+ assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, ref));
+ oop p = oopDesc::load_decode_heap_oop(ref);
+ assert(_g1h->is_in_g1_reserved(p),
+ err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p)));
+ return true;
+}
+
+bool G1ParScanThreadState::verify_ref(oop* ref) const {
+ assert(ref != NULL, "invariant");
+ if (has_partial_array_mask(ref)) {
+ // Must be in the collection set--it's already been copied.
+ oop p = clear_partial_array_mask(ref);
+ assert(_g1h->obj_in_cs(p),
+ err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p)));
+ } else {
+ oop p = oopDesc::load_decode_heap_oop(ref);
+ assert(_g1h->is_in_g1_reserved(p),
+ err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, ref, intptr_t(p)));
+ }
+ return true;
+}
+
+bool G1ParScanThreadState::verify_task(StarTask ref) const {
+ if (ref.is_narrow()) {
+ return verify_ref((narrowOop*) ref);
+ } else {
+ return verify_ref((oop*) ref);
+ }
+}
+#endif // ASSERT
+
+void G1ParScanThreadState::trim_queue() {
+ StarTask ref;
+ do {
+ // Drain the overflow stack first, so other threads can steal.
+ while (refs()->pop_overflow(ref)) {
+ deal_with_reference(ref);
+ }
+ while (refs()->pop_local(ref)) {
+ deal_with_reference(ref);
+ }
+ } while (!refs()->is_empty());
+}
+
G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
_g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()),
_par_scan_state(par_scan_state) { }
@@ -4052,38 +4095,43 @@
: _g1h(g1h), _par_scan_state(par_scan_state),
_queues(queues), _terminator(terminator) {}
- void do_void() {
- G1ParScanThreadState* pss = par_scan_state();
- while (true) {
+ void do_void();
+
+private:
+ inline bool offer_termination();
+};
+
+bool G1ParEvacuateFollowersClosure::offer_termination() {
+ G1ParScanThreadState* const pss = par_scan_state();
+ pss->start_term_time();
+ const bool res = terminator()->offer_termination();
+ pss->end_term_time();
+ return res;
+}
+
+void G1ParEvacuateFollowersClosure::do_void() {
+ StarTask stolen_task;
+ G1ParScanThreadState* const pss = par_scan_state();
+ pss->trim_queue();
+
+ do {
+ while (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) {
+ assert(pss->verify_task(stolen_task), "sanity");
+ if (stolen_task.is_narrow()) {
+ pss->deal_with_reference((narrowOop*) stolen_task);
+ } else {
+ 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();
-
- StarTask stolen_task;
- if (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) {
- // slightly paranoid tests; I'm trying to catch potential
- // problems before we go into push_on_queue to know where the
- // problem is coming from
- assert((oop*)stolen_task != NULL, "Error");
- if (stolen_task.is_narrow()) {
- assert(UseCompressedOops, "Error");
- narrowOop* p = (narrowOop*) stolen_task;
- assert(has_partial_array_mask(p) ||
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "Error");
- pss->push_on_queue(p);
- } else {
- oop* p = (oop*) stolen_task;
- assert(has_partial_array_mask(p) || _g1h->is_in_g1_reserved(*p), "Error");
- pss->push_on_queue(p);
- }
- continue;
- }
- pss->start_term_time();
- if (terminator()->offer_termination()) break;
- pss->end_term_time();
}
- pss->end_term_time();
- pss->retire_alloc_buffers();
- }
-};
+ } while (!offer_termination());
+
+ pss->retire_alloc_buffers();
+}
class G1ParTask : public AbstractGangTask {
protected:
@@ -4182,8 +4230,7 @@
pss.print_termination_stats(i);
}
- assert(pss.refs_to_scan() == 0, "Task queue should be empty");
- assert(pss.overflowed_refs_to_scan() == 0, "Overflow queue should be empty");
+ assert(pss.refs()->is_empty(), "should be empty");
double end_time_ms = os::elapsedTime() * 1000.0;
_g1h->g1_policy()->record_gc_worker_end_time(i, end_time_ms);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1651,49 +1651,17 @@
size_t alloc_buffer_waste() const { return _alloc_buffer_waste; }
size_t undo_waste() const { return _undo_waste; }
+#ifdef ASSERT
+ bool verify_ref(narrowOop* ref) const;
+ bool verify_ref(oop* ref) const;
+ bool verify_task(StarTask ref) const;
+#endif // ASSERT
+
template <class T> void push_on_queue(T* ref) {
- assert(ref != NULL, "invariant");
- assert(has_partial_array_mask(ref) ||
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(ref)), "invariant");
-#ifdef ASSERT
- if (has_partial_array_mask(ref)) {
- oop p = clear_partial_array_mask(ref);
- // Verify that we point into the CS
- assert(_g1h->obj_in_cs(p), "Should be in CS");
- }
-#endif
+ assert(verify_ref(ref), "sanity");
refs()->push(ref);
}
- void pop_from_queue(StarTask& ref) {
- if (refs()->pop_local(ref)) {
- assert((oop*)ref != NULL, "pop_local() returned true");
- assert(UseCompressedOops || !ref.is_narrow(), "Error");
- assert(has_partial_array_mask((oop*)ref) ||
- _g1h->is_in_g1_reserved(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref)
- : oopDesc::load_decode_heap_oop((oop*)ref)),
- "invariant");
- } else {
- StarTask null_task;
- ref = null_task;
- }
- }
-
- void pop_from_overflow_queue(StarTask& ref) {
- StarTask new_ref;
- refs()->pop_overflow(new_ref);
- assert((oop*)new_ref != NULL, "pop() from a local non-empty stack");
- assert(UseCompressedOops || !new_ref.is_narrow(), "Error");
- assert(has_partial_array_mask((oop*)new_ref) ||
- _g1h->is_in_g1_reserved(new_ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)new_ref)
- : oopDesc::load_decode_heap_oop((oop*)new_ref)),
- "invariant");
- ref = new_ref;
- }
-
- int refs_to_scan() { return (int)refs()->size(); }
- int overflowed_refs_to_scan() { return (int)refs()->overflow_stack()->size(); }
-
template <class T> void update_rs(HeapRegion* from, T* p, int tid) {
if (G1DeferredRSUpdate) {
deferred_rs_update(from, p, tid);
@@ -1804,7 +1772,6 @@
}
}
-private:
template <class T> void deal_with_reference(T* ref_to_scan) {
if (has_partial_array_mask(ref_to_scan)) {
_partial_scan_cl->do_oop_nv(ref_to_scan);
@@ -1818,59 +1785,15 @@
}
}
-public:
- void trim_queue() {
- // I've replicated the loop twice, first to drain the overflow
- // queue, second to drain the task queue. This is better than
- // having a single loop, which checks both conditions and, inside
- // it, either pops the overflow queue or the task queue, as each
- // loop is tighter. Also, the decision to drain the overflow queue
- // first is not arbitrary, as the overflow queue is not visible
- // to the other workers, whereas the task queue is. So, we want to
- // drain the "invisible" entries first, while allowing the other
- // workers to potentially steal the "visible" entries.
-
- while (refs_to_scan() > 0 || overflowed_refs_to_scan() > 0) {
- while (overflowed_refs_to_scan() > 0) {
- StarTask ref_to_scan;
- assert((oop*)ref_to_scan == NULL, "Constructed above");
- pop_from_overflow_queue(ref_to_scan);
- // We shouldn't have pushed it on the queue if it was not
- // pointing into the CSet.
- assert((oop*)ref_to_scan != NULL, "Follows from inner loop invariant");
- if (ref_to_scan.is_narrow()) {
- assert(UseCompressedOops, "Error");
- narrowOop* p = (narrowOop*)ref_to_scan;
- assert(!has_partial_array_mask(p) &&
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
- deal_with_reference(p);
- } else {
- oop* p = (oop*)ref_to_scan;
- assert((has_partial_array_mask(p) && _g1h->is_in_g1_reserved(clear_partial_array_mask(p))) ||
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
- deal_with_reference(p);
- }
- }
-
- while (refs_to_scan() > 0) {
- StarTask ref_to_scan;
- assert((oop*)ref_to_scan == NULL, "Constructed above");
- pop_from_queue(ref_to_scan);
- if ((oop*)ref_to_scan != NULL) {
- if (ref_to_scan.is_narrow()) {
- assert(UseCompressedOops, "Error");
- narrowOop* p = (narrowOop*)ref_to_scan;
- assert(!has_partial_array_mask(p) &&
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
- deal_with_reference(p);
- } else {
- oop* p = (oop*)ref_to_scan;
- assert((has_partial_array_mask(p) && _g1h->obj_in_cs(clear_partial_array_mask(p))) ||
- _g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
- deal_with_reference(p);
- }
- }
- }
+ void deal_with_reference(StarTask ref) {
+ assert(verify_task(ref), "sanity");
+ if (ref.is_narrow()) {
+ deal_with_reference((narrowOop*)ref);
+ } else {
+ deal_with_reference((oop*)ref);
}
}
+
+public:
+ void trim_queue();
};
--- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -25,8 +25,6 @@
class HeapRegion;
class G1CollectedHeap;
class G1RemSet;
-class HRInto_G1RemSet;
-class G1RemSet;
class ConcurrentMark;
class DirtyCardToOopClosure;
class CMBitMap;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -97,13 +97,6 @@
}
};
-void
-StupidG1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
- int worker_i) {
- IntoCSRegionClosure rc(_g1, oc);
- _g1->heap_region_iterate(&rc);
-}
-
class VerifyRSCleanCardOopClosure: public OopClosure {
G1CollectedHeap* _g1;
public:
@@ -119,8 +112,9 @@
}
};
-HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
- : G1RemSet(g1), _ct_bs(ct_bs), _g1p(_g1->g1_policy()),
+G1RemSet::G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
+ : _g1(g1), _conc_refine_cards(0),
+ _ct_bs(ct_bs), _g1p(_g1->g1_policy()),
_cg1r(g1->concurrent_g1_refine()),
_traversal_in_progress(false),
_cset_rs_update_cl(NULL),
@@ -134,7 +128,7 @@
}
}
-HRInto_G1RemSet::~HRInto_G1RemSet() {
+G1RemSet::~G1RemSet() {
delete _seq_task;
for (uint i = 0; i < n_workers(); i++) {
assert(_cset_rs_update_cl[i] == NULL, "it should be");
@@ -277,7 +271,7 @@
// p threads
// Then thread t will start at region t * floor (n/p)
-HeapRegion* HRInto_G1RemSet::calculateStartRegion(int worker_i) {
+HeapRegion* G1RemSet::calculateStartRegion(int worker_i) {
HeapRegion* result = _g1p->collection_set();
if (ParallelGCThreads > 0) {
size_t cs_size = _g1p->collection_set_size();
@@ -290,7 +284,7 @@
return result;
}
-void HRInto_G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) {
+void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) {
double rs_time_start = os::elapsedTime();
HeapRegion *startRegion = calculateStartRegion(worker_i);
@@ -340,7 +334,7 @@
}
};
-void HRInto_G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) {
+void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) {
double start = os::elapsedTime();
// Apply the given closure to all remaining log entries.
RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq);
@@ -439,12 +433,11 @@
}
};
-void HRInto_G1RemSet::cleanupHRRS() {
+void G1RemSet::cleanupHRRS() {
HeapRegionRemSet::cleanup();
}
-void
-HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
+void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
int worker_i) {
#if CARD_REPEAT_HISTO
ct_freq_update_histo_and_reset();
@@ -508,8 +501,7 @@
_cset_rs_update_cl[worker_i] = NULL;
}
-void HRInto_G1RemSet::
-prepare_for_oops_into_collection_set_do() {
+void G1RemSet::prepare_for_oops_into_collection_set_do() {
#if G1_REM_SET_LOGGING
PrintRSClosure cl;
_g1->collection_set_iterate(&cl);
@@ -581,7 +573,7 @@
// RSet updating,
// * the post-write barrier shouldn't be logging updates to young
// regions (but there is a situation where this can happen - see
- // the comment in HRInto_G1RemSet::concurrentRefineOneCard below -
+ // the comment in G1RemSet::concurrentRefineOneCard below -
// that should not be applicable here), and
// * during actual RSet updating, the filtering of cards in young
// regions in HeapRegion::oops_on_card_seq_iterate_careful is
@@ -601,7 +593,7 @@
}
};
-void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() {
+void G1RemSet::cleanup_after_oops_into_collection_set_do() {
guarantee( _cards_scanned != NULL, "invariant" );
_total_cards_scanned = 0;
for (uint i = 0; i < n_workers(); ++i)
@@ -692,12 +684,12 @@
}
};
-void HRInto_G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm) {
+void G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm) {
ScrubRSClosure scrub_cl(region_bm, card_bm);
_g1->heap_region_iterate(&scrub_cl);
}
-void HRInto_G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm,
+void G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm,
int worker_num, int claim_val) {
ScrubRSClosure scrub_cl(region_bm, card_bm);
_g1->heap_region_par_iterate_chunked(&scrub_cl, worker_num, claim_val);
@@ -741,7 +733,7 @@
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
-bool HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
+bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
bool check_for_refs_into_cset) {
// Construct the region representing the card.
HeapWord* start = _ct_bs->addr_for(card_ptr);
@@ -820,7 +812,7 @@
return trigger_cl.value();
}
-bool HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
+bool G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
bool check_for_refs_into_cset) {
// If the card is no longer dirty, nothing to do.
if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
@@ -995,7 +987,7 @@
}
};
-void HRInto_G1RemSet::print_summary_info() {
+void G1RemSet::print_summary_info() {
G1CollectedHeap* g1 = G1CollectedHeap::heap();
#if CARD_REPEAT_HISTO
@@ -1029,30 +1021,26 @@
g1->concurrent_g1_refine()->threads_do(&p);
gclog_or_tty->print_cr("");
- if (G1UseHRIntoRS) {
- HRRSStatsIter blk;
- g1->heap_region_iterate(&blk);
- gclog_or_tty->print_cr(" Total heap region rem set sizes = " SIZE_FORMAT "K."
- " Max = " SIZE_FORMAT "K.",
- blk.total_mem_sz()/K, blk.max_mem_sz()/K);
- gclog_or_tty->print_cr(" Static structures = " SIZE_FORMAT "K,"
- " free_lists = " SIZE_FORMAT "K.",
- HeapRegionRemSet::static_mem_size()/K,
- HeapRegionRemSet::fl_mem_size()/K);
- gclog_or_tty->print_cr(" %d occupied cards represented.",
- blk.occupied());
- gclog_or_tty->print_cr(" Max sz region = [" PTR_FORMAT ", " PTR_FORMAT " )"
- ", cap = " SIZE_FORMAT "K, occ = " SIZE_FORMAT "K.",
- blk.max_mem_sz_region()->bottom(), blk.max_mem_sz_region()->end(),
- (blk.max_mem_sz_region()->rem_set()->mem_size() + K - 1)/K,
- (blk.max_mem_sz_region()->rem_set()->occupied() + K - 1)/K);
- gclog_or_tty->print_cr(" Did %d coarsenings.",
- HeapRegionRemSet::n_coarsenings());
-
- }
+ HRRSStatsIter blk;
+ g1->heap_region_iterate(&blk);
+ gclog_or_tty->print_cr(" Total heap region rem set sizes = " SIZE_FORMAT "K."
+ " Max = " SIZE_FORMAT "K.",
+ blk.total_mem_sz()/K, blk.max_mem_sz()/K);
+ gclog_or_tty->print_cr(" Static structures = " SIZE_FORMAT "K,"
+ " free_lists = " SIZE_FORMAT "K.",
+ HeapRegionRemSet::static_mem_size()/K,
+ HeapRegionRemSet::fl_mem_size()/K);
+ gclog_or_tty->print_cr(" %d occupied cards represented.",
+ blk.occupied());
+ gclog_or_tty->print_cr(" Max sz region = [" PTR_FORMAT ", " PTR_FORMAT " )"
+ ", cap = " SIZE_FORMAT "K, occ = " SIZE_FORMAT "K.",
+ blk.max_mem_sz_region()->bottom(), blk.max_mem_sz_region()->end(),
+ (blk.max_mem_sz_region()->rem_set()->mem_size() + K - 1)/K,
+ (blk.max_mem_sz_region()->rem_set()->occupied() + K - 1)/K);
+ gclog_or_tty->print_cr(" Did %d coarsenings.", HeapRegionRemSet::n_coarsenings());
}
-void HRInto_G1RemSet::prepare_for_verify() {
+void G1RemSet::prepare_for_verify() {
if (G1HRRSFlushLogBuffersOnVerify &&
(VerifyBeforeGC || VerifyAfterGC)
&& !_g1->full_collection()) {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -27,107 +27,18 @@
class G1CollectedHeap;
class CardTableModRefBarrierSet;
-class HRInto_G1RemSet;
class ConcurrentG1Refine;
+// A G1RemSet in which each heap region has a rem set that records the
+// external heap references into it. Uses a mod ref bs to track updates,
+// so that they can be used to update the individual region remsets.
+
class G1RemSet: public CHeapObj {
protected:
G1CollectedHeap* _g1;
unsigned _conc_refine_cards;
size_t n_workers();
-public:
- G1RemSet(G1CollectedHeap* g1) :
- _g1(g1), _conc_refine_cards(0)
- {}
-
- // Invoke "blk->do_oop" on all pointers into the CS in object in regions
- // outside the CS (having invoked "blk->set_region" to set the "from"
- // region correctly beforehand.) The "worker_i" param is for the
- // parallel case where the number of the worker thread calling this
- // function can be helpful in partitioning the work to be done. It
- // should be the same as the "i" passed to the calling thread's
- // work(i) function. In the sequential case this param will be ingored.
- virtual void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
- int worker_i) = 0;
-
- // Prepare for and cleanup after an oops_into_collection_set_do
- // call. Must call each of these once before and after (in sequential
- // code) any threads call oops into collection set do. (This offers an
- // opportunity to sequential setup and teardown of structures needed by a
- // parallel iteration over the CS's RS.)
- virtual void prepare_for_oops_into_collection_set_do() = 0;
- virtual void cleanup_after_oops_into_collection_set_do() = 0;
-
- // If "this" is of the given subtype, return "this", else "NULL".
- virtual HRInto_G1RemSet* as_HRInto_G1RemSet() { return NULL; }
-
- // Record, if necessary, the fact that *p (where "p" is in region "from",
- // and is, a fortiori, required to be non-NULL) has changed to its new value.
- virtual void write_ref(HeapRegion* from, oop* p) = 0;
- virtual void write_ref(HeapRegion* from, narrowOop* p) = 0;
- virtual void par_write_ref(HeapRegion* from, oop* p, int tid) = 0;
- virtual void par_write_ref(HeapRegion* from, narrowOop* p, int tid) = 0;
-
- // Requires "region_bm" and "card_bm" to be bitmaps with 1 bit per region
- // or card, respectively, such that a region or card with a corresponding
- // 0 bit contains no part of any live object. Eliminates any remembered
- // set entries that correspond to dead heap ranges.
- virtual void scrub(BitMap* region_bm, BitMap* card_bm) = 0;
- // Like the above, but assumes is called in parallel: "worker_num" is the
- // parallel thread id of the current thread, and "claim_val" is the
- // value that should be used to claim heap regions.
- virtual void scrub_par(BitMap* region_bm, BitMap* card_bm,
- int worker_num, int claim_val) = 0;
-
- // Refine the card corresponding to "card_ptr". If "sts" is non-NULL,
- // join and leave around parts that must be atomic wrt GC. (NULL means
- // being done at a safepoint.)
- // With some implementations of this routine, when check_for_refs_into_cset
- // is true, a true result may be returned if the given card contains oops
- // that have references into the current collection set.
- virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
- bool check_for_refs_into_cset) {
- return false;
- }
-
- // Print any relevant summary info.
- virtual void print_summary_info() {}
-
- // Prepare remebered set for verification.
- virtual void prepare_for_verify() {};
-};
-
-
-// The simplest possible G1RemSet: iterates over all objects in non-CS
-// regions, searching for pointers into the CS.
-class StupidG1RemSet: public G1RemSet {
-public:
- StupidG1RemSet(G1CollectedHeap* g1) : G1RemSet(g1) {}
-
- void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
- int worker_i);
-
- void prepare_for_oops_into_collection_set_do() {}
- void cleanup_after_oops_into_collection_set_do() {}
-
- // Nothing is necessary in the version below.
- void write_ref(HeapRegion* from, oop* p) {}
- void write_ref(HeapRegion* from, narrowOop* p) {}
- void par_write_ref(HeapRegion* from, oop* p, int tid) {}
- void par_write_ref(HeapRegion* from, narrowOop* p, int tid) {}
-
- void scrub(BitMap* region_bm, BitMap* card_bm) {}
- void scrub_par(BitMap* region_bm, BitMap* card_bm,
- int worker_num, int claim_val) {}
-
-};
-
-// A G1RemSet in which each heap region has a rem set that records the
-// external heap references into it. Uses a mod ref bs to track updates,
-// so that they can be used to update the individual region remsets.
-
-class HRInto_G1RemSet: public G1RemSet {
protected:
enum SomePrivateConstants {
UpdateRStoMergeSync = 0,
@@ -175,28 +86,32 @@
// scanned.
void cleanupHRRS();
- HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs);
- ~HRInto_G1RemSet();
+ G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs);
+ ~G1RemSet();
+ // Invoke "blk->do_oop" on all pointers into the CS in objects in regions
+ // outside the CS (having invoked "blk->set_region" to set the "from"
+ // region correctly beforehand.) The "worker_i" param is for the
+ // parallel case where the number of the worker thread calling this
+ // function can be helpful in partitioning the work to be done. It
+ // should be the same as the "i" passed to the calling thread's
+ // work(i) function. In the sequential case this param will be ingored.
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
int worker_i);
+ // Prepare for and cleanup after an oops_into_collection_set_do
+ // call. Must call each of these once before and after (in sequential
+ // code) any threads call oops_into_collection_set_do. (This offers an
+ // opportunity to sequential setup and teardown of structures needed by a
+ // parallel iteration over the CS's RS.)
void prepare_for_oops_into_collection_set_do();
void cleanup_after_oops_into_collection_set_do();
+
void scanRS(OopsInHeapRegionClosure* oc, int worker_i);
- template <class T> void scanNewRefsRS_work(OopsInHeapRegionClosure* oc, int worker_i);
- void scanNewRefsRS(OopsInHeapRegionClosure* oc, int worker_i) {
- if (UseCompressedOops) {
- scanNewRefsRS_work<narrowOop>(oc, worker_i);
- } else {
- scanNewRefsRS_work<oop>(oc, worker_i);
- }
- }
void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i);
+
HeapRegion* calculateStartRegion(int i);
- HRInto_G1RemSet* as_HRInto_G1RemSet() { return this; }
-
CardTableModRefBS* ct_bs() { return _ct_bs; }
size_t cardsScanned() { return _total_cards_scanned; }
@@ -219,17 +134,31 @@
bool self_forwarded(oop obj);
+ // Requires "region_bm" and "card_bm" to be bitmaps with 1 bit per region
+ // or card, respectively, such that a region or card with a corresponding
+ // 0 bit contains no part of any live object. Eliminates any remembered
+ // set entries that correspond to dead heap ranges.
void scrub(BitMap* region_bm, BitMap* card_bm);
+
+ // Like the above, but assumes is called in parallel: "worker_num" is the
+ // parallel thread id of the current thread, and "claim_val" is the
+ // value that should be used to claim heap regions.
void scrub_par(BitMap* region_bm, BitMap* card_bm,
int worker_num, int claim_val);
- // If check_for_refs_into_cset is true then a true result is returned
- // if the card contains oops that have references into the current
- // collection set.
+ // Refine the card corresponding to "card_ptr". If "sts" is non-NULL,
+ // join and leave around parts that must be atomic wrt GC. (NULL means
+ // being done at a safepoint.)
+ // If check_for_refs_into_cset is true, a true result is returned
+ // if the given card contains oops that have references into the
+ // current collection set.
virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
bool check_for_refs_into_cset);
+ // Print any relevant summary info.
virtual void print_summary_info();
+
+ // Prepare remembered set for verification.
virtual void prepare_for_verify();
};
@@ -250,13 +179,13 @@
class UpdateRSOopClosure: public OopClosure {
HeapRegion* _from;
- HRInto_G1RemSet* _rs;
+ G1RemSet* _rs;
int _worker_i;
template <class T> void do_oop_work(T* p);
public:
- UpdateRSOopClosure(HRInto_G1RemSet* rs, int worker_i = 0) :
+ UpdateRSOopClosure(G1RemSet* rs, int worker_i = 0) :
_from(NULL), _rs(rs), _worker_i(worker_i) {
guarantee(_rs != NULL, "Requires an HRIntoG1RemSet");
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -30,16 +30,18 @@
}
}
-template <class T> inline void HRInto_G1RemSet::write_ref_nv(HeapRegion* from, T* p) {
+template <class T>
+inline void G1RemSet::write_ref_nv(HeapRegion* from, T* p) {
par_write_ref_nv(from, p, 0);
}
-inline bool HRInto_G1RemSet::self_forwarded(oop obj) {
+inline bool G1RemSet::self_forwarded(oop obj) {
bool result = (obj->is_forwarded() && (obj->forwardee()== obj));
return result;
}
-template <class T> inline void HRInto_G1RemSet::par_write_ref_nv(HeapRegion* from, T* p, int tid) {
+template <class T>
+inline void G1RemSet::par_write_ref_nv(HeapRegion* from, T* p, int tid) {
oop obj = oopDesc::load_decode_heap_oop(p);
#ifdef ASSERT
// can't do because of races
@@ -77,7 +79,7 @@
// Deferred updates to the CSet are either discarded (in the normal case),
// or processed (if an evacuation failure occurs) at the end
// of the collection.
- // See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do().
+ // See G1RemSet::cleanup_after_oops_into_collection_set_do().
} else {
#if G1_REM_SET_LOGGING
gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS"
@@ -91,12 +93,14 @@
}
}
-template <class T> inline void UpdateRSOopClosure::do_oop_work(T* p) {
+template <class T>
+inline void UpdateRSOopClosure::do_oop_work(T* p) {
assert(_from != NULL, "from region must be non-NULL");
_rs->par_write_ref(_from, p, _worker_i);
}
-template <class T> inline void UpdateRSetImmediate::do_oop_work(T* p) {
+template <class T>
+inline void UpdateRSetImmediate::do_oop_work(T* p) {
assert(_from->is_in_reserved(p), "paranoia");
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -40,9 +40,6 @@
develop(intx, G1PolicyVerbose, 0, \
"The verbosity level on G1 policy decisions") \
\
- develop(bool, G1UseHRIntoRS, true, \
- "Determines whether the 'advanced' HR Into rem set is used.") \
- \
develop(intx, G1MarkingVerboseLevel, 0, \
"Level (0-4) of verboseness of the marking code") \
\
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -377,10 +377,26 @@
}
// </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_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) {
@@ -500,23 +516,6 @@
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() {
set_saved_mark();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -395,14 +395,12 @@
// Causes the current region to represent a humongous object spanning "n"
// regions.
- virtual void set_startsHumongous();
+ void set_startsHumongous(HeapWord* new_end);
// The regions that continue a humongous sequence should be added using
// this method, in increasing address order.
void set_continuesHumongous(HeapRegion* start);
- void add_continuingHumongousRegion(HeapRegion* cont);
-
// If the region has a remembered set, return a pointer to it.
HeapRegionRemSet* rem_set() const {
return _rem_set;
@@ -733,13 +731,6 @@
FilterOutOfRegionClosure* cl,
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
// boundary at or before "p", but does not object iteration, and may
// therefore be used safely when the heap is unparseable.
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1159,9 +1159,7 @@
_hrrs(NULL),
_g1h(G1CollectedHeap::heap()),
_bosa(NULL),
- _sparse_iter(size_t(G1CollectedHeap::heap()->reserved_region().start())
- >> CardTableModRefBS::card_shift)
-{}
+ _sparse_iter() { }
void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) {
_hrrs = hrrs;
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -91,34 +91,118 @@
}
if (sumSizes >= word_size) {
_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();
+ assert(!zf, "not supported");
+
+ // This will be the "starts humongous" region.
HeapRegion* first_hr = _regions.at(first);
- for (int i = first; i < cur; i++) {
- HeapRegion* hr = _regions.at(i);
- if (zf)
- hr->ensure_zero_filled();
+ {
+ MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag);
+ first_hr->set_zero_fill_allocated();
+ }
+ // 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);
hr->set_zero_fill_allocated();
}
- size_t sz = hr->capacity() / HeapWordSize;
- HeapWord* tmp = hr->allocate(sz);
- assert(tmp != NULL, "Humongous allocation failure");
- MemRegion mr = MemRegion(tmp, sz);
- CollectedHeap::fill_with_object(mr);
- hr->declare_filled_region_to_BOT(mr);
- if (i == first) {
- first_hr->set_startsHumongous();
+ hr->set_continuesHumongous(first_hr);
+ }
+ // If we have "continues humongous" regions (hr != NULL), then the
+ // end of the last one should match new_end.
+ assert(hr == NULL || hr->end() == new_end, "sanity");
+
+ // Up to this point no concurrent thread would have been able to
+ // 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 {
- assert(i > first, "sanity");
- hr->set_continuesHumongous(first_hr);
+ // not last one
+ assert(new_top > hr->end(), "new_top should be above this region");
+ hr->set_top(hr->end());
}
}
- HeapWord* first_hr_bot = first_hr->bottom();
- HeapWord* obj_end = first_hr_bot + word_size;
- first_hr->set_top(obj_end);
- return first_hr_bot;
+ // If we have continues humongous regions (hr != NULL), then the
+ // end of the last one should match new_end and its top should
+ // match new_top.
+ assert(hr == NULL ||
+ (hr->end() == new_end && hr->top() == new_top), "sanity");
+
+ return new_obj;
} else {
// If we started from the beginning, we want to know why we can't alloc.
return NULL;
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -308,7 +308,7 @@
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;
while (_bl_ind != RSHashTable::NullEntry) {
res = _rsht->entry(_bl_ind)->card(0);
@@ -322,14 +322,11 @@
return SparsePRTEntry::NullEntry;
}
-size_t /* RSHashTable:: */ RSHashTableIter::compute_card_ind(CardIdx_t ci) {
- return
- _heap_bot_card_ind
- + (_rsht->entry(_bl_ind)->r_ind() * HeapRegion::CardsPerRegion)
- + ci;
+size_t RSHashTableIter::compute_card_ind(CardIdx_t ci) {
+ return (_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++;
CardIdx_t ci;
if (_card_ind < SparsePRTEntry::cards_num() &&
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -169,7 +169,6 @@
int _bl_ind; // [-1, 0.._rsht->_capacity)
short _card_ind; // [0..SparsePRTEntry::cards_num())
RSHashTable* _rsht;
- size_t _heap_bot_card_ind;
// 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.
@@ -183,13 +182,11 @@
size_t compute_card_ind(CardIdx_t ci);
public:
- RSHashTableIter(size_t heap_bot_card_ind) :
+ RSHashTableIter() :
_tbl_ind(RSHashTable::NullEntry),
_bl_ind(RSHashTable::NullEntry),
_card_ind((SparsePRTEntry::cards_num() - 1)),
- _rsht(NULL),
- _heap_bot_card_ind(heap_bot_card_ind)
- {}
+ _rsht(NULL) {}
void init(RSHashTable* rsht) {
_rsht = rsht;
@@ -280,20 +277,11 @@
bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
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:
- SparsePRTIter(size_t heap_bot_card_ind) :
- /* RSHashTable:: */RSHashTableIter(heap_bot_card_ind)
- {}
-
void init(const SparsePRT* sprt) {
RSHashTableIter::init(sprt->cur());
}
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Sat Nov 13 18:56:50 2010 -0800
@@ -310,10 +310,16 @@
heapRegionSeq.inline.hpp heapRegionSeq.hpp
+instanceKlass.cpp g1RemSet.inline.hpp
+
+instanceRefKlass.cpp g1RemSet.inline.hpp
+
klass.hpp g1OopClosures.hpp
memoryService.cpp g1MemoryPool.hpp
+objArrayKlass.cpp g1RemSet.inline.hpp
+
ptrQueue.cpp allocation.hpp
ptrQueue.cpp allocation.inline.hpp
ptrQueue.cpp mutex.hpp
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Sat Nov 13 18:56:50 2010 -0800
@@ -133,6 +133,7 @@
parallelScavengeHeap.cpp psParallelCompact.hpp
parallelScavengeHeap.cpp psPromotionManager.hpp
parallelScavengeHeap.cpp psScavenge.hpp
+parallelScavengeHeap.cpp vmError.hpp
parallelScavengeHeap.cpp vmThread.hpp
parallelScavengeHeap.cpp vmPSOperations.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -846,7 +846,7 @@
// from this generation, pass on collection; let the next generation
// do it.
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;
}
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
@@ -935,8 +935,6 @@
assert(to()->is_empty(), "to space should be empty now");
} else {
- assert(HandlePromotionFailure,
- "Should only be here if promotion failure handling is on");
assert(_promo_failure_scan_stack.is_empty(), "post condition");
_promo_failure_scan_stack.clear(true); // Clear cached segments.
@@ -947,7 +945,7 @@
// All the spaces are in play for mark-sweep.
swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
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.
_next_gen->promotion_failure_occurred();
@@ -1092,11 +1090,6 @@
old, m, sz);
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 = true;
new_obj = old;
@@ -1206,12 +1199,6 @@
old, m, sz);
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
forward_ptr = old->forward_to_atomic(old);
new_obj = old;
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -805,7 +805,8 @@
if (young_gen()->is_in_reserved(addr)) {
assert(young_gen()->is_in(addr),
"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();
} else if (old_gen()->is_in_reserved(addr)) {
assert(old_gen()->is_in(addr),
--- a/hotspot/src/share/vm/includeDB_compiler1 Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/includeDB_compiler1 Sat Nov 13 18:56:50 2010 -0800
@@ -301,6 +301,7 @@
c1_MacroAssembler.hpp assembler_<arch>.inline.hpp
c1_MacroAssembler_<arch>.cpp arrayOop.hpp
+c1_MacroAssembler_<arch>.cpp basicLock.hpp
c1_MacroAssembler_<arch>.cpp biasedLocking.hpp
c1_MacroAssembler_<arch>.cpp c1_MacroAssembler.hpp
c1_MacroAssembler_<arch>.cpp c1_Runtime1.hpp
@@ -309,7 +310,6 @@
c1_MacroAssembler_<arch>.cpp markOop.hpp
c1_MacroAssembler_<arch>.cpp os.hpp
c1_MacroAssembler_<arch>.cpp stubRoutines.hpp
-c1_MacroAssembler_<arch>.cpp synchronizer.hpp
c1_MacroAssembler_<arch>.cpp systemDictionary.hpp
c1_MacroAssembler_<arch>.hpp generate_platform_dependent_include
--- a/hotspot/src/share/vm/includeDB_core Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/includeDB_core Sat Nov 13 18:56:50 2010 -0800
@@ -300,10 +300,17 @@
barrierSet.inline.hpp barrierSet.hpp
barrierSet.inline.hpp cardTableModRefBS.hpp
+basicLock.cpp basicLock.hpp
+basicLock.cpp synchronizer.hpp
+
+basicLock.hpp handles.hpp
+basicLock.hpp markOop.hpp
+basicLock.hpp top.hpp
+
+biasedLocking.cpp basicLock.hpp
biasedLocking.cpp biasedLocking.hpp
biasedLocking.cpp klass.inline.hpp
biasedLocking.cpp markOop.hpp
-biasedLocking.cpp synchronizer.hpp
biasedLocking.cpp task.hpp
biasedLocking.cpp vframe.hpp
biasedLocking.cpp vmThread.hpp
@@ -404,13 +411,13 @@
bytecodeInterpreterWithChecks.cpp bytecodeInterpreter.cpp
bytecodeInterpreter.hpp allocation.hpp
+bytecodeInterpreter.hpp basicLock.hpp
bytecodeInterpreter.hpp bytes_<arch>.hpp
bytecodeInterpreter.hpp frame.hpp
bytecodeInterpreter.hpp globalDefinitions.hpp
bytecodeInterpreter.hpp globals.hpp
bytecodeInterpreter.hpp methodDataOop.hpp
bytecodeInterpreter.hpp methodOop.hpp
-bytecodeInterpreter.hpp synchronizer.hpp
bytecodeInterpreter.inline.hpp bytecodeInterpreter.hpp
bytecodeInterpreter.inline.hpp stubRoutines.hpp
@@ -1265,6 +1272,7 @@
constantPoolOop.cpp linkResolver.hpp
constantPoolOop.cpp objArrayKlass.hpp
constantPoolOop.cpp oop.inline.hpp
+constantPoolOop.cpp oopFactory.hpp
constantPoolOop.cpp signature.hpp
constantPoolOop.cpp symbolTable.hpp
constantPoolOop.cpp systemDictionary.hpp
@@ -1667,10 +1675,10 @@
frame.cpp universe.inline.hpp
frame.hpp assembler.hpp
+frame.hpp basicLock.hpp
frame.hpp methodOop.hpp
frame.hpp monitorChunk.hpp
frame.hpp registerMap.hpp
-frame.hpp synchronizer.hpp
frame.hpp top.hpp
frame.inline.hpp bytecodeInterpreter.hpp
@@ -2120,6 +2128,7 @@
interfaceSupport_<os_family>.hpp generate_platform_dependent_include
interp_masm_<arch_model>.cpp arrayOop.hpp
+interp_masm_<arch_model>.cpp basicLock.hpp
interp_masm_<arch_model>.cpp biasedLocking.hpp
interp_masm_<arch_model>.cpp interp_masm_<arch_model>.hpp
interp_masm_<arch_model>.cpp interpreterRuntime.hpp
@@ -2131,7 +2140,6 @@
interp_masm_<arch_model>.cpp methodDataOop.hpp
interp_masm_<arch_model>.cpp methodOop.hpp
interp_masm_<arch_model>.cpp sharedRuntime.hpp
-interp_masm_<arch_model>.cpp synchronizer.hpp
interp_masm_<arch_model>.cpp thread_<os_family>.inline.hpp
interp_masm_<arch_model>.hpp assembler_<arch>.inline.hpp
@@ -3094,25 +3102,26 @@
objArrayOop.hpp arrayOop.hpp
+objectMonitor.cpp dtrace.hpp
+objectMonitor.cpp handles.inline.hpp
+objectMonitor.cpp interfaceSupport.hpp
+objectMonitor.cpp markOop.hpp
+objectMonitor.cpp mutexLocker.hpp
+objectMonitor.cpp objectMonitor.hpp
+objectMonitor.cpp objectMonitor.inline.hpp
+objectMonitor.cpp oop.inline.hpp
+objectMonitor.cpp osThread.hpp
+objectMonitor.cpp os_<os_family>.inline.hpp
+objectMonitor.cpp preserveException.hpp
+objectMonitor.cpp resourceArea.hpp
+objectMonitor.cpp stubRoutines.hpp
+objectMonitor.cpp thread.hpp
+objectMonitor.cpp thread_<os_family>.inline.hpp
+objectMonitor.cpp threadService.hpp
+objectMonitor.cpp vmSymbols.hpp
+
objectMonitor.hpp os.hpp
-
-objectMonitor_<os_family>.cpp dtrace.hpp
-objectMonitor_<os_family>.cpp interfaceSupport.hpp
-objectMonitor_<os_family>.cpp objectMonitor.hpp
-objectMonitor_<os_family>.cpp objectMonitor.inline.hpp
-objectMonitor_<os_family>.cpp oop.inline.hpp
-objectMonitor_<os_family>.cpp osThread.hpp
-objectMonitor_<os_family>.cpp os_<os_family>.inline.hpp
-objectMonitor_<os_family>.cpp threadService.hpp
-objectMonitor_<os_family>.cpp thread_<os_family>.inline.hpp
-objectMonitor_<os_family>.cpp vmSymbols.hpp
-
-objectMonitor_<os_family>.hpp generate_platform_dependent_include
-objectMonitor_<os_family>.hpp os_<os_family>.inline.hpp
-objectMonitor_<os_family>.hpp thread_<os_family>.inline.hpp
-objectMonitor_<os_family>.hpp top.hpp
-
-objectMonitor_<os_family>.inline.hpp generate_platform_dependent_include
+objectMonitor.hpp perfData.hpp
oop.cpp copy.hpp
oop.cpp handles.inline.hpp
@@ -3231,6 +3240,7 @@
orderAccess.hpp os.hpp
orderAccess_<os_arch>.inline.hpp orderAccess.hpp
+orderAccess_<os_arch>.inline.hpp vm_version_<arch>.hpp
os.cpp allocation.inline.hpp
os.cpp arguments.hpp
@@ -3328,7 +3338,6 @@
os_<os_family>.cpp nativeInst_<arch>.hpp
os_<os_family>.cpp no_precompiled_headers
os_<os_family>.cpp objectMonitor.hpp
-os_<os_family>.cpp objectMonitor.inline.hpp
os_<os_family>.cpp oop.inline.hpp
os_<os_family>.cpp osThread.hpp
os_<os_family>.cpp os_share_<os_family>.hpp
@@ -3388,6 +3397,12 @@
ostream.hpp allocation.hpp
ostream.hpp timer.hpp
+// include thread.hpp to prevent cyclic includes
+park.cpp thread.hpp
+
+park.hpp debug.hpp
+park.hpp globalDefinitions.hpp
+
pcDesc.cpp debugInfoRec.hpp
pcDesc.cpp nmethod.hpp
pcDesc.cpp pcDesc.hpp
@@ -3600,7 +3615,9 @@
relocator.cpp bytecodes.hpp
relocator.cpp handles.inline.hpp
relocator.cpp oop.inline.hpp
+relocator.cpp oopFactory.hpp
relocator.cpp relocator.hpp
+relocator.cpp stackMapTableFormat.hpp
relocator.cpp universe.inline.hpp
relocator.hpp bytecodes.hpp
@@ -3907,6 +3924,8 @@
stackMapTable.hpp methodOop.hpp
stackMapTable.hpp stackMapFrame.hpp
+stackMapTableFormat.hpp verificationType.hpp
+
stackValue.cpp debugInfo.hpp
stackValue.cpp frame.inline.hpp
stackValue.cpp handles.inline.hpp
@@ -4062,10 +4081,10 @@
synchronizer.cpp resourceArea.hpp
synchronizer.cpp stubRoutines.hpp
synchronizer.cpp synchronizer.hpp
-synchronizer.cpp threadService.hpp
synchronizer.cpp thread_<os_family>.inline.hpp
synchronizer.cpp vmSymbols.hpp
+synchronizer.hpp basicLock.hpp
synchronizer.hpp handles.hpp
synchronizer.hpp markOop.hpp
synchronizer.hpp perfData.hpp
@@ -4237,7 +4256,6 @@
thread.cpp mutexLocker.hpp
thread.cpp objArrayOop.hpp
thread.cpp objectMonitor.hpp
-thread.cpp objectMonitor.inline.hpp
thread.cpp oop.inline.hpp
thread.cpp oopFactory.hpp
thread.cpp osThread.hpp
@@ -4275,6 +4293,7 @@
thread.hpp oop.hpp
thread.hpp os.hpp
thread.hpp osThread.hpp
+thread.hpp park.hpp
thread.hpp safepoint.hpp
thread.hpp stubRoutines.hpp
thread.hpp threadLocalAllocBuffer.hpp
@@ -4586,6 +4605,7 @@
vframeArray.hpp growableArray.hpp
vframeArray.hpp monitorChunk.hpp
+vframe_hp.cpp basicLock.hpp
vframe_hp.cpp codeCache.hpp
vframe_hp.cpp debugInfoRec.hpp
vframe_hp.cpp handles.inline.hpp
@@ -4599,7 +4619,6 @@
vframe_hp.cpp scopeDesc.hpp
vframe_hp.cpp signature.hpp
vframe_hp.cpp stubRoutines.hpp
-vframe_hp.cpp synchronizer.hpp
vframe_hp.cpp vframeArray.hpp
vframe_hp.cpp vframe_hp.hpp
@@ -4751,6 +4770,7 @@
workgroup.cpp workgroup.hpp
workgroup.hpp taskqueue.hpp
+
workgroup.hpp thread_<os_family>.inline.hpp
xmlstream.cpp allocation.hpp
--- a/hotspot/src/share/vm/includeDB_features Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/includeDB_features Sat Nov 13 18:56:50 2010 -0800
@@ -154,6 +154,7 @@
jvmtiExtensions.hpp jvmti.h
jvmtiExtensions.hpp jvmtiEnv.hpp
+jvmtiImpl.cpp deoptimization.hpp
jvmtiImpl.cpp exceptions.hpp
jvmtiImpl.cpp handles.hpp
jvmtiImpl.cpp handles.inline.hpp
@@ -184,6 +185,13 @@
jvmtiImpl.hpp systemDictionary.hpp
jvmtiImpl.hpp vm_operations.hpp
+jvmtiRawMonitor.cpp interfaceSupport.hpp
+jvmtiRawMonitor.cpp jvmtiRawMonitor.hpp
+jvmtiRawMonitor.cpp thread.hpp
+
+jvmtiRawMonitor.hpp growableArray.hpp
+jvmtiRawMonitor.hpp objectMonitor.hpp
+
jvmtiTagMap.cpp biasedLocking.hpp
jvmtiTagMap.cpp javaCalls.hpp
jvmtiTagMap.cpp jniHandles.hpp
--- a/hotspot/src/share/vm/includeDB_jvmti Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/includeDB_jvmti Sat Nov 13 18:56:50 2010 -0800
@@ -35,6 +35,7 @@
// jvmtiCodeBlobEvents is jck optional, please put deps in includeDB_features
jvmtiEnter.cpp jvmtiEnter.hpp
+jvmtiEnter.cpp jvmtiRawMonitor.hpp
jvmtiEnter.cpp jvmtiUtil.hpp
jvmtiEnter.hpp interfaceSupport.hpp
@@ -44,6 +45,7 @@
jvmtiEnter.hpp systemDictionary.hpp
jvmtiEnterTrace.cpp jvmtiEnter.hpp
+jvmtiEnterTrace.cpp jvmtiRawMonitor.hpp
jvmtiEnterTrace.cpp jvmtiUtil.hpp
jvmtiEnv.cpp arguments.hpp
@@ -66,11 +68,11 @@
jvmtiEnv.cpp jvmtiGetLoadedClasses.hpp
jvmtiEnv.cpp jvmtiImpl.hpp
jvmtiEnv.cpp jvmtiManageCapabilities.hpp
+jvmtiEnv.cpp jvmtiRawMonitor.hpp
jvmtiEnv.cpp jvmtiRedefineClasses.hpp
jvmtiEnv.cpp jvmtiTagMap.hpp
jvmtiEnv.cpp jvmtiThreadState.inline.hpp
jvmtiEnv.cpp jvmtiUtil.hpp
-jvmtiEnv.cpp objectMonitor.inline.hpp
jvmtiEnv.cpp osThread.hpp
jvmtiEnv.cpp preserveException.hpp
jvmtiEnv.cpp reflectionUtils.hpp
@@ -87,6 +89,7 @@
jvmtiEnv.hpp jvmtiEnvBase.hpp
jvmtiEnvBase.cpp biasedLocking.hpp
+jvmtiEnvBase.cpp deoptimization.hpp
jvmtiEnvBase.cpp interfaceSupport.hpp
jvmtiEnvBase.cpp jfieldIDWorkaround.hpp
jvmtiEnvBase.cpp jvmtiEnv.hpp
@@ -178,11 +181,13 @@
jvmtiExport.cpp jvmtiExport.hpp
jvmtiExport.cpp jvmtiImpl.hpp
jvmtiExport.cpp jvmtiManageCapabilities.hpp
+jvmtiExport.cpp jvmtiRawMonitor.hpp
jvmtiExport.cpp jvmtiTagMap.hpp
jvmtiExport.cpp jvmtiThreadState.inline.hpp
jvmtiExport.cpp nmethod.hpp
jvmtiExport.cpp objArrayKlass.hpp
jvmtiExport.cpp objArrayOop.hpp
+jvmtiExport.cpp objectMonitor.hpp
jvmtiExport.cpp objectMonitor.inline.hpp
jvmtiExport.cpp pcDesc.hpp
jvmtiExport.cpp resourceArea.hpp
@@ -210,6 +215,8 @@
jvmtiManageCapabilities.hpp allocation.hpp
jvmtiManageCapabilities.hpp jvmti.h
+// jvmtiRawMonitor is jck optional, please put deps in includeDB_features
+
jvmtiRedefineClasses.cpp bitMap.inline.hpp
jvmtiRedefineClasses.cpp codeCache.hpp
jvmtiRedefineClasses.cpp deoptimization.hpp
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -716,12 +716,13 @@
assert(constantPoolCacheOopDesc::is_secondary_index(site_index), "proper format");
// 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 pool_index = pool->cache()->entry_at(main_index)->constant_pool_index();
// first resolve the signature to a MH.invoke methodOop
if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) {
JvmtiHideSingleStepping jhss(thread);
- CallInfo info;
- LinkResolver::resolve_invoke(info, Handle(), pool,
+ CallInfo callinfo;
+ LinkResolver::resolve_invoke(callinfo, Handle(), pool,
site_index, bytecode, CHECK);
// The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves
// as a common reference point for all invokedynamic call sites with
@@ -729,8 +730,8 @@
// as if it were an invokevirtual of MethodHandle.invoke.
pool->cache()->entry_at(main_index)->set_method(
bytecode,
- info.resolved_method(),
- info.vtable_index());
+ callinfo.resolved_method(),
+ callinfo.vtable_index());
}
// The method (f2 entry) of the main entry is the MH.invoke for the
@@ -740,9 +741,10 @@
assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(),
"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,
- main_index, CHECK);
- if (bootm.is_null()) {
+ main_index, info, CHECK);
+ if (!java_dyn_MethodHandle::is_instance(bootm())) {
THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
"no bootstrap method found for invokedynamic");
}
@@ -753,8 +755,6 @@
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
= SystemDictionary::make_dynamic_call_site(bootm,
// Callee information:
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -659,9 +659,6 @@
}
return result; // could be null if we are out of space
} 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.
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
@@ -739,9 +736,8 @@
GenCollectedHeap* gch = GenCollectedHeap::heap();
size_t gen0_capacity = gch->get_gen(0)->capacity_before_gc();
return (word_size > heap_word_size(gen0_capacity))
- || (GC_locker::is_active_and_needs_gc())
- || ( gch->last_incremental_collection_failed()
- && gch->incremental_collection_will_fail());
+ || GC_locker::is_active_and_needs_gc()
+ || gch->incremental_collection_failed();
}
--- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -510,7 +510,7 @@
// from this generation, pass on collection; let the next generation
// do it.
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;
}
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
@@ -596,9 +596,8 @@
if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used);
}
+ assert(!gch->incremental_collection_failed(), "Should be clear");
} else {
- assert(HandlePromotionFailure,
- "Should not be here unless promotion failure handling is on");
assert(_promo_failure_scan_stack.is_empty(), "post condition");
_promo_failure_scan_stack.clear(true); // Clear cached segments.
@@ -613,7 +612,7 @@
// and from-space.
swap_spaces(); // For uniformity wrt ParNewGeneration.
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.
_next_gen->promotion_failure_occurred();
@@ -700,12 +699,6 @@
if (obj == NULL) {
obj = _next_gen->promote(old, s);
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);
return old;
}
@@ -812,47 +805,43 @@
assert(_next_gen != NULL,
"This must be the youngest gen, and not the only gen");
}
-
- // 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);
+ return _next_gen->promotion_attempt_is_safe(used());
}
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
// been done. Generally the young generation is empty at
// a minimum at the end of a collection. If it is not, then
// the heap is approaching full.
GenCollectedHeap* gch = GenCollectedHeap::heap();
- clear_should_allocate_from_space();
- if (collection_attempt_is_safe()) {
- gch->clear_incremental_collection_will_fail();
+ if (full) {
+ DEBUG_ONLY(seen_incremental_collection_failed = false;)
+ if (!collection_attempt_is_safe()) {
+ gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state
+ set_should_allocate_from_space(); // we seem to be running out of space
+ } else {
+ gch->clear_incremental_collection_failed(); // We just did a full collection
+ clear_should_allocate_from_space(); // if set
+ }
} else {
- gch->set_incremental_collection_will_fail();
- if (full) { // we seem to be running out of space
- set_should_allocate_from_space();
+#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) {
--- a/hotspot/src/share/vm/memory/defNewGeneration.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/defNewGeneration.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -82,12 +82,6 @@
Stack<oop> _objs_with_preserved_marks;
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
OopClosure *_promo_failure_scan_stack_closure;
void set_promo_failure_scan_stack_closure(OopClosure *scan_stack_closure) {
@@ -304,6 +298,14 @@
// GC support
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,
bool clear_all_soft_refs,
size_t size,
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -142,8 +142,7 @@
}
_perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set());
- clear_incremental_collection_will_fail();
- clear_last_incremental_collection_failed();
+ clear_incremental_collection_failed();
#ifndef SERIALGC
// If we are running CMS, create the collector responsible
@@ -1347,17 +1346,6 @@
};
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
assert(DerivedPointerTable::is_empty(), "derived pointer present");
size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr()));
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -62,11 +62,10 @@
// The generational collector policy.
GenCollectorPolicy* _gen_policy;
- // If a generation would bail out of an incremental collection,
- // it sets this flag. If the flag is set, satisfy_failed_allocation
- // will attempt allocating in all generations before doing a full GC.
- bool _incremental_collection_will_fail;
- bool _last_incremental_collection_failed;
+ // Indicates that the most recent previous incremental collection failed.
+ // The flag is cleared when an action is taken that might clear the
+ // condition that caused that incremental collection to fail.
+ bool _incremental_collection_failed;
// In support of ExplicitGCInvokesConcurrent functionality
unsigned int _full_collections_completed;
@@ -469,26 +468,26 @@
// call to "save_marks".
bool no_allocs_since_save_marks(int level);
+ // Returns true if an incremental collection is likely to fail.
+ bool incremental_collection_will_fail() {
+ // Assumes a 2-generation system; the first disjunct remembers if an
+ // incremental collection failed, even when we thought (second disjunct)
+ // that it would not.
+ assert(heap()->collector_policy()->is_two_generation_policy(),
+ "the following definition may not be suitable for an n(>2)-generation system");
+ return incremental_collection_failed() || !get_gen(0)->collection_attempt_is_safe();
+ }
+
// If a generation bails out of an incremental collection,
// it sets this flag.
- bool incremental_collection_will_fail() {
- return _incremental_collection_will_fail;
- }
- void set_incremental_collection_will_fail() {
- _incremental_collection_will_fail = true;
- }
- void clear_incremental_collection_will_fail() {
- _incremental_collection_will_fail = false;
+ bool incremental_collection_failed() const {
+ return _incremental_collection_failed;
}
-
- bool last_incremental_collection_failed() const {
- return _last_incremental_collection_failed;
+ void set_incremental_collection_failed() {
+ _incremental_collection_failed = true;
}
- void set_last_incremental_collection_failed() {
- _last_incremental_collection_failed = true;
- }
- void clear_last_incremental_collection_failed() {
- _last_incremental_collection_failed = false;
+ void clear_incremental_collection_failed() {
+ _incremental_collection_failed = false;
}
// Promotion of obj into gen failed. Try to promote obj to higher non-perm
--- a/hotspot/src/share/vm/memory/generation.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/generation.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -165,15 +165,16 @@
return max;
}
-bool Generation::promotion_attempt_is_safe(size_t promotion_in_bytes,
- bool not_used) const {
+bool Generation::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
+ size_t available = max_contiguous_available();
+ bool res = (available >= max_promotion_in_bytes);
if (PrintGC && Verbose) {
- gclog_or_tty->print_cr("Generation::promotion_attempt_is_safe"
- " contiguous_available: " SIZE_FORMAT
- " promotion_in_bytes: " SIZE_FORMAT,
- max_contiguous_available(), promotion_in_bytes);
+ gclog_or_tty->print_cr(
+ "Generation: promo attempt is%s safe: available("SIZE_FORMAT") %s max_promo("SIZE_FORMAT")",
+ res? "":" not", available, res? ">=":"<",
+ max_promotion_in_bytes);
}
- return max_contiguous_available() >= promotion_in_bytes;
+ return res;
}
// Ignores "ref" and calls allocate().
--- a/hotspot/src/share/vm/memory/generation.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/generation.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -173,15 +173,11 @@
// The largest number of contiguous free bytes in this or any higher generation.
virtual size_t max_contiguous_available() const;
- // Returns true if promotions of the specified amount can
- // be attempted safely (without a vm failure).
+ // Returns true if promotions of the specified amount are
+ // likely to succeed without a promotion failure.
// Promotion of the full amount is not guaranteed but
- // can be attempted.
- // younger_handles_promotion_failure
- // 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;
+ // might be attempted in the worst case.
+ virtual bool promotion_attempt_is_safe(size_t max_promotion_in_bytes) const;
// For a non-young generation, this interface can be used to inform a
// generation that a promotion attempt into that generation failed.
@@ -358,6 +354,16 @@
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.
// If full is true attempt a full garbage collection of this generation.
// Otherwise, attempting to (at least) free enough space to support an
--- a/hotspot/src/share/vm/memory/heap.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/heap.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -140,6 +140,7 @@
// Returns reserved area high and low addresses
char *low_boundary() const { return _memory.low_boundary (); }
+ char *high() const { return _memory.high(); }
char *high_boundary() const { return _memory.high_boundary(); }
// Iteration
--- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -419,29 +419,16 @@
void TenuredGeneration::verify_alloc_buffers_clean() {}
#endif // SERIALGC
-bool TenuredGeneration::promotion_attempt_is_safe(
- size_t max_promotion_in_bytes,
- bool younger_handles_promotion_failure) const {
-
- bool result = max_contiguous_available() >= max_promotion_in_bytes;
-
- if (younger_handles_promotion_failure && !result) {
- result = max_contiguous_available() >=
- (size_t) gc_stats()->avg_promoted()->padded_average();
- if (PrintGC && Verbose && result) {
- 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);
- }
+bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
+ size_t available = max_contiguous_available();
+ size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average();
+ bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(
+ "Tenured: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
+ "max_promo("SIZE_FORMAT")",
+ res? "":" not", available, res? ">=":"<",
+ av_promo, max_promotion_in_bytes);
}
- return result;
+ return res;
}
--- a/hotspot/src/share/vm/memory/tenuredGeneration.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -101,8 +101,7 @@
virtual void update_gc_stats(int level, bool full);
- virtual bool promotion_attempt_is_safe(size_t max_promoted_in_bytes,
- bool younger_handles_promotion_failure) const;
+ virtual bool promotion_attempt_is_safe(size_t max_promoted_in_bytes) const;
void verify_alloc_buffers_clean();
};
--- a/hotspot/src/share/vm/memory/universe.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/memory/universe.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -340,6 +340,7 @@
static klassOop* longArrayKlassObj_addr() { return &_longArrayKlassObj; }
static klassOop* singleArrayKlassObj_addr() { return &_singleArrayKlassObj; }
static klassOop* doubleArrayKlassObj_addr() { return &_doubleArrayKlassObj; }
+ static klassOop* systemObjArrayKlassObj_addr() { return &_systemObjArrayKlassObj; }
// The particular choice of collected heap.
static CollectedHeap* heap() { return _collectedHeap; }
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
c->set_length(length);
c->set_tags(NULL);
c->set_cache(NULL);
+ c->set_operands(NULL);
c->set_pool_holder(NULL);
c->set_flags(0);
// only set to non-zero if constant pool is merged by RedefineClasses
@@ -92,6 +93,7 @@
// gc of constant pool instance variables
MarkSweep::mark_and_push(cp->tags_addr());
MarkSweep::mark_and_push(cp->cache_addr());
+ MarkSweep::mark_and_push(cp->operands_addr());
MarkSweep::mark_and_push(cp->pool_holder_addr());
}
}
@@ -118,6 +120,7 @@
// gc of constant pool instance variables
PSParallelCompact::mark_and_push(cm, cp->tags_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());
}
}
@@ -146,6 +149,7 @@
}
MarkSweep::adjust_pointer(cp->tags_addr());
MarkSweep::adjust_pointer(cp->cache_addr());
+ MarkSweep::adjust_pointer(cp->operands_addr());
MarkSweep::adjust_pointer(cp->pool_holder_addr());
return size;
}
@@ -173,6 +177,7 @@
}
blk->do_oop(cp->tags_addr());
blk->do_oop(cp->cache_addr());
+ blk->do_oop(cp->operands_addr());
blk->do_oop(cp->pool_holder_addr());
return size;
}
@@ -205,6 +210,8 @@
blk->do_oop(addr);
addr = cp->cache_addr();
blk->do_oop(addr);
+ addr = cp->operands_addr();
+ blk->do_oop(addr);
addr = cp->pool_holder_addr();
blk->do_oop(addr);
return size;
@@ -232,6 +239,7 @@
}
PSParallelCompact::adjust_pointer(cp->tags_addr());
PSParallelCompact::adjust_pointer(cp->cache_addr());
+ PSParallelCompact::adjust_pointer(cp->operands_addr());
PSParallelCompact::adjust_pointer(cp->pool_holder_addr());
return cp->object_size();
}
@@ -262,6 +270,8 @@
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
p = cp->cache_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();
PSParallelCompact::adjust_pointer(p, beg_addr, end_addr);
@@ -363,8 +373,18 @@
st->print("signature_index=%d", cp->method_type_index_at(index));
break;
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;
default:
ShouldNotReachHere();
@@ -381,6 +401,7 @@
st->print("constant pool [%d]", cp->length());
if (cp->has_pseudo_string()) st->print("/pseudo_string");
if (cp->has_invokedynamic()) st->print("/invokedynamic");
+ if (cp->operands() != NULL) st->print("/operands[%d]", cp->operands()->length());
cp->print_address_on(st);
st->print(" for ");
cp->pool_holder()->print_value_on(st);
@@ -440,6 +461,10 @@
guarantee(cp->cache()->is_perm(), "should be in permspace");
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) {
// Note: pool_holder() can be NULL in temporary constant pools
// used during constant pool merging
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -265,10 +265,9 @@
int i = which;
if (!uncached && cache() != NULL) {
if (constantPoolCacheOopDesc::is_secondary_index(which)) {
- // Invokedynamic indexes are always processed in native order
- // so there is no question of reading a native u2 in Java order here.
+ // Invokedynamic 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);
assert(tag_at(pool_index).is_name_and_type(), "");
return pool_index;
@@ -276,11 +275,17 @@
// change byte-ordering and go via cache
i = remap_instruction_operand_from_cache(which);
} 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
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_invoke_dynamic(), "Must be handled above");
jint ref_index = *int_at_addr(i);
return extract_high_short_from_int(ref_index);
}
@@ -394,18 +399,61 @@
}
}
+// 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 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) {
- 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);
result_oop = cpc_entry->f1();
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();
}
+ jvalue prim_value; // temp used only in a few cases below
+
int tag_value = this_oop->tag_at(index).value();
switch (tag_value) {
@@ -449,9 +497,14 @@
KlassHandle klass(THREAD, this_oop->pool_holder());
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
callee, name, signature,
- CHECK_NULL);
+ THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ throw_exception = Handle(THREAD, PENDING_EXCEPTION);
+ CLEAR_PENDING_EXCEPTION;
+ break;
+ }
result_oop = value();
- // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error.
+ assert(result_oop != NULL, "");
break;
}
@@ -468,20 +521,36 @@
klass,
false,
ignore_is_on_bcp,
- CHECK_NULL);
+ THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ throw_exception = Handle(THREAD, PENDING_EXCEPTION);
+ CLEAR_PENDING_EXCEPTION;
+ break;
+ }
result_oop = value();
- // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error.
+ assert(result_oop != NULL, "");
break;
}
- /* maybe some day
case JVM_CONSTANT_Integer:
+ prim_value.i = this_oop->int_at(index);
+ result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
+ break;
+
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:
- result_oop = java_lang_boxing_object::create(...);
+ prim_value.d = this_oop->double_at(index);
+ result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
break;
- */
default:
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
@@ -492,18 +561,31 @@
if (cache_index >= 0) {
// 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
ObjectLocker ol(this_oop, THREAD);
ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index);
- oop result_oop2 = cpc_entry->f1();
- if (result_oop2 != NULL) {
- // Race condition: May already be filled in while we were trying to lock.
- return result_oop2;
+ result_oop = cpc_entry->f1();
+ // Benign race condition: f1 may already be filled in while we were trying to lock.
+ // The important thing here is that all threads pick up the same result.
+ // 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 result();
+ return decode_exception_from_f1(result_oop, THREAD);
} else {
+ if (throw_exception.not_null()) {
+ THROW_HANDLE_(throw_exception, NULL);
+ }
return result_oop;
}
}
@@ -621,6 +703,7 @@
void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) {
closure->do_oop(tags_addr());
+ closure->do_oop(operands_addr());
}
@@ -838,13 +921,19 @@
case JVM_CONSTANT_InvokeDynamic:
{
- int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
- int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
- if (k1 == k2) {
- int i1 = invoke_dynamic_name_and_type_ref_index_at(index1);
- int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
- if (i1 == i2) {
- return true;
+ int op_count = multi_operand_count_at(index1);
+ if (op_count == cp2->multi_operand_count_at(index2)) {
+ bool all_equal = true;
+ for (int op_i = 0; op_i < op_count; op_i++) {
+ int k1 = multi_operand_ref_at(index1, op_i);
+ int k2 = cp2->multi_operand_ref_at(index2, op_i);
+ if (k1 != k2) {
+ all_equal = false;
+ break;
+ }
+ }
+ if (all_equal) {
+ return true; // got through loop; all elements equal
}
}
} break;
@@ -881,6 +970,25 @@
} // 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)
// to the constant pool to_cp's entries starting at to_i. A total of
// (end_i - start_i) + 1 entries are copied.
@@ -889,6 +997,13 @@
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 */ ) {
copy_entry_to(src_i, to_cp, dest_i, CHECK);
@@ -1037,9 +1152,26 @@
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 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;
// Invalid is used as the tag for the second constant pool entry
@@ -1257,8 +1389,11 @@
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_NameAndType:
+ return 5;
+
case JVM_CONSTANT_InvokeDynamic:
- return 5;
+ // 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_Double:
@@ -1475,9 +1610,15 @@
*bytes = JVM_CONSTANT_InvokeDynamic;
idx1 = invoke_dynamic_bootstrap_method_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+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;
}
}
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -41,6 +41,7 @@
typeArrayOop _tags; // the tag array describing the constant pool's contents
constantPoolCacheOop _cache; // the cache holding interpreter runtime information
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 _length; // number of elements in the array
volatile bool _is_conc_safe; // if true, safe for concurrent
@@ -52,6 +53,8 @@
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 set_operands(typeArrayOop operands) { oop_store_without_check((oop*)&_operands, operands); }
+
enum FlagBit {
FB_has_invokedynamic = 1,
FB_has_pseudo_string = 2
@@ -67,6 +70,7 @@
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); }
oop* tags_addr() { return (oop*)&_tags; }
oop* cache_addr() { return (oop*)&_cache; }
+ oop* operands_addr() { return (oop*)&_operands; }
oop* obj_at_addr(int which) const {
assert(is_within_bounds(which), "index out of bounds");
@@ -95,6 +99,7 @@
public:
typeArrayOop tags() const { return _tags; }
+ typeArrayOop operands() const { return _operands; }
bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); }
bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); }
@@ -113,6 +118,7 @@
// Assembly code support
static int tags_offset_in_bytes() { return offset_of(constantPoolOopDesc, _tags); }
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); }
// Storing constants
@@ -156,10 +162,28 @@
*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);
- *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
void unresolved_string_at_put(int which, symbolOop s) {
@@ -401,27 +425,93 @@
int sym = method_type_index_at(which);
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) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
- jint ref_index = *int_at_addr(which);
- return extract_low_short_from_int(ref_index);
+ return multi_operand_ref_at(which, _indy_bsm_offset);
}
int invoke_dynamic_name_and_type_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
- jint ref_index = *int_at_addr(which);
- return extract_high_short_from_int(ref_index);
+ return multi_operand_ref_at(which, _indy_nt_offset);
+ }
+ 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,
// 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
- // 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
// of these values back to constant pool indices.
// 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)
klassOop klass_ref_at(int which, TRAPS);
symbolOop klass_ref_at_noresolve(int which);
@@ -443,15 +533,24 @@
resolve_string_constants_impl(h_this, CHECK);
}
+ private:
+ enum { _no_index_sentinel = -1, _possible_index_sentinel = -2 };
+ public:
+
// Resolve late bound constants.
oop resolve_constant_at(int index, TRAPS) {
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) {
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
@@ -484,7 +583,7 @@
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
- // 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.
symbolOop uncached_klass_ref_at_noresolve(int which);
symbolOop uncached_name_ref_at(int which) { return impl_name_ref_at(which, true); }
--- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -87,6 +87,19 @@
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
// It is possible to have two different dummy methodOops created
// when the resolve code for invoke interface executes concurrently
@@ -165,7 +178,12 @@
}
assert(method->can_be_statically_bound(), "must be a MH invoker method");
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
assert(!is_vfinal(), "f2 not an oop");
byte_no = 1; // coordinate this with bytecode_number & is_resolved
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -130,6 +130,7 @@
assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change");
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; }
int as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile,
bool is_method_interface, bool is_method);
@@ -318,7 +319,9 @@
// Sizing
debug_only(friend class ClassVerifier;)
+ public:
int length() const { return _length; }
+ private:
void set_length(int length) { _length = length; }
static int header_size() { return sizeof(constantPoolCacheOopDesc) / HeapWordSize; }
--- a/hotspot/src/share/vm/oops/generateOopMap.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/generateOopMap.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1254,7 +1254,7 @@
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
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();
int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
@@ -1286,7 +1286,7 @@
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
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();
int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
@@ -1356,8 +1356,8 @@
case Bytecodes::_ldc2_w: ppush(vvCTS); break;
- case Bytecodes::_ldc: do_ldc(itr->get_index(), itr->bci()); break;
- case Bytecodes::_ldc_w: do_ldc(itr->get_index_u2(), itr->bci()); break;
+ case Bytecodes::_ldc: // fall through:
+ case Bytecodes::_ldc_w: do_ldc(itr->bci()); break;
case Bytecodes::_iload:
case Bytecodes::_fload: ppload(vCTS, itr->get_index()); break;
@@ -1829,9 +1829,16 @@
-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();
- 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);
}
--- a/hotspot/src/share/vm/oops/generateOopMap.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/generateOopMap.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -389,7 +389,7 @@
void pp (CellTypeState *in, CellTypeState *out);
void pp_new_ref (CellTypeState *in, int bci);
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_jsr (int delta);
void do_field (int is_get, int is_static, int idx, int bci);
--- a/hotspot/src/share/vm/oops/methodOop.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/oops/methodOop.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -247,6 +247,10 @@
return constMethod()->stackmap_data();
}
+ void set_stackmap_data(typeArrayOop sd) {
+ constMethod()->set_stackmap_data(sd);
+ }
+
// exception handler table
typeArrayOop exception_table() const
{ return constMethod()->exception_table(); }
--- a/hotspot/src/share/vm/opto/divnode.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/opto/divnode.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -388,7 +388,8 @@
if (!d_pos) {
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
// "Division by Invariant Integers using Multiplication"
// by Granlund and Montgomery
@@ -558,7 +559,7 @@
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;
return transform_long_divide( phase, in(1), l );
@@ -1062,7 +1063,7 @@
// Fell thru, the unroll case is not appropriate. Transform the modulo
// 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;
// Get the absolute value of the constant; at this point, we can use this
@@ -1075,7 +1076,7 @@
// If this is a power of two, then maybe we can mask it
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 TypeLong *dtl = dt->isa_long();
@@ -1088,7 +1089,7 @@
// Save in(1) so that it cannot be changed or deleted
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 );
if (result != NULL) {
Node *divide = phase->transform(result);
--- a/hotspot/src/share/vm/opto/escape.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/opto/escape.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -85,6 +85,7 @@
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()),
_collecting(true),
+ _progress(false),
_compile(C),
_igvn(igvn),
_node_map(C->comp_arena()) {
@@ -113,7 +114,7 @@
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(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) {
@@ -126,7 +127,7 @@
// don't add a self-referential edge, this can occur during removal of
// deferred edges
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) {
@@ -157,7 +158,7 @@
assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets");
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) {
@@ -995,7 +996,7 @@
GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis;
- PhaseGVN *igvn = _igvn;
+ PhaseIterGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
@@ -1531,14 +1532,9 @@
has_allocations = true;
}
if(n->is_AddP()) {
- // Collect address nodes which directly reference an allocation.
- // Use them during stage 3 below to build initial connection graph
- // field edges. Other field edges could be added after StoreP/LoadP
- // 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);
- }
+ // Collect address nodes. Use them during stage 3 below
+ // to build initial connection graph field edges.
+ cg_worklist.append(n->_idx);
} else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
@@ -1562,18 +1558,28 @@
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();
for( uint next = 0; next < cg_length; ++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.append(_phantom_object);
+ GrowableArray<uint> worklist;
// 4. Build Connection Graph which need
// to walk the connection graph.
+ _progress = false;
for (uint ni = 0; ni < nodes_size(); ni++) {
PointsToNode* ptn = ptnode_adr(ni);
Node *n = ptn->_node;
@@ -1581,13 +1587,52 @@
build_connection_graph(n, igvn);
if (ptn->node_type() != PointsToNode::UnknownType)
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();
VectorSet ptset(arena);
- GrowableArray<uint> deferred_edges;
VectorSet visited(arena);
+ worklist.clear();
// 5. Remove deferred edges from the graph and adjust
// escape state of nonescaping objects.
@@ -1597,7 +1642,7 @@
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
- remove_deferred(ni, &deferred_edges, &visited);
+ remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node;
if (n->is_AddP()) {
// Search for objects which are not scalar replaceable
@@ -1608,7 +1653,7 @@
}
// 6. Propagate escape states.
- GrowableArray<int> worklist;
+ worklist.clear();
bool has_non_escaping_obj = false;
// push all GlobalEscape nodes on the worklist
@@ -2444,13 +2489,14 @@
// Don't set processed bit for AddP, LoadP, StoreP since
// 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))
return; // No need to redefine node's state.
if (n->is_Call()) {
CallNode *call = n->as_Call();
process_call_arguments(call, phase);
- _processed.set(n_idx);
return;
}
--- a/hotspot/src/share/vm/opto/escape.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/opto/escape.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -219,6 +219,9 @@
// is still being collected. If false,
// no new nodes will be processed.
+ bool _progress; // Indicates whether new Graph's edges
+ // were created.
+
uint _phantom_object; // Index of globally escaping object
// that pointer values loaded from
// a field which has not been set
@@ -266,6 +269,13 @@
void add_deferred_edge(uint from_i, uint to_i);
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
// matches "offset" A deferred edge is added if to_i is a LocalVar, and
--- a/hotspot/src/share/vm/opto/matcher.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/opto/matcher.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -298,6 +298,10 @@
// Register for MODL projection of divmodL
static RegMask modL_proj_mask();
+ // Use hardware DIV instruction when it is faster than
+ // a code which use multiply for division by constant.
+ static bool use_asm_for_ldiv_by_con( jlong divisor );
+
static const RegMask method_handle_invoke_SP_save_mask();
// Java-Interpreter calling convention
--- a/hotspot/src/share/vm/prims/jvm.h Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/jvm.h Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1047,7 +1047,8 @@
JVM_CONSTANT_NameAndType,
JVM_CONSTANT_MethodHandle = 15, // JSR 292
JVM_CONSTANT_MethodType = 16, // JSR 292
- JVM_CONSTANT_InvokeDynamic = 17 // JSR 292
+ JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files
+ JVM_CONSTANT_InvokeDynamic = 18 // JSR 292
};
/* JVM_CONSTANT_MethodHandle subtypes */
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1407,8 +1407,7 @@
// If any of the top 2 frames is a compiled one, need to deoptimize it
for (int i = 0; i < 2; i++) {
if (!is_interpreted[i]) {
- VM_DeoptimizeFrame op(java_thread, frame_sp[i]);
- VMThread::execute(&op);
+ Deoptimization::deoptimize_frame(java_thread, frame_sp[i]);
}
}
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1322,8 +1322,7 @@
if (!vf->fr().can_be_deoptimized()) {
return JVMTI_ERROR_OPAQUE_FRAME;
}
- VM_DeoptimizeFrame deopt(java_thread, jvf->fr().id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(java_thread, jvf->fr().id());
}
// Get information about method return type
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -25,26 +25,6 @@
# include "incls/_precompiled.incl"
# include "incls/_jvmtiImpl.cpp.incl"
-GrowableArray<JvmtiRawMonitor*> *JvmtiPendingMonitors::_monitors = new (ResourceObj::C_HEAP) GrowableArray<JvmtiRawMonitor*>(1,true);
-
-void JvmtiPendingMonitors::transition_raw_monitors() {
- assert((Threads::number_of_threads()==1),
- "Java thread has not created yet or more than one java thread \
-is running. Raw monitor transition will not work");
- JavaThread *current_java_thread = JavaThread::current();
- assert(current_java_thread->thread_state() == _thread_in_vm, "Must be in vm");
- {
- ThreadBlockInVM __tbivm(current_java_thread);
- for(int i=0; i< count(); i++) {
- JvmtiRawMonitor *rmonitor = monitors()->at(i);
- int r = rmonitor->raw_enter(current_java_thread);
- assert(r == ObjectMonitor::OM_OK, "raw_enter should have worked");
- }
- }
- // pending monitors are converted to real monitor so delete them all.
- dispose();
-}
-
//
// class JvmtiAgentThread
//
@@ -216,57 +196,6 @@
}
}
-
-//
-// class JvmtiRawMonitor
-//
-
-JvmtiRawMonitor::JvmtiRawMonitor(const char *name) {
-#ifdef ASSERT
- _name = strcpy(NEW_C_HEAP_ARRAY(char, strlen(name) + 1), name);
-#else
- _name = NULL;
-#endif
- _magic = JVMTI_RM_MAGIC;
-}
-
-JvmtiRawMonitor::~JvmtiRawMonitor() {
-#ifdef ASSERT
- FreeHeap(_name);
-#endif
- _magic = 0;
-}
-
-
-bool
-JvmtiRawMonitor::is_valid() {
- int value = 0;
-
- // This object might not be a JvmtiRawMonitor so we can't assume
- // the _magic field is properly aligned. Get the value in a safe
- // way and then check against JVMTI_RM_MAGIC.
-
- switch (sizeof(_magic)) {
- case 2:
- value = Bytes::get_native_u2((address)&_magic);
- break;
-
- case 4:
- value = Bytes::get_native_u4((address)&_magic);
- break;
-
- case 8:
- value = Bytes::get_native_u8((address)&_magic);
- break;
-
- default:
- guarantee(false, "_magic field is an unexpected size");
- }
-
- return value == JVMTI_RM_MAGIC;
-}
-
-
//
// class JvmtiBreakpoint
//
@@ -799,8 +728,7 @@
// Schedule deoptimization so that eventually the local
// update will be written to an interpreter frame.
- VM_DeoptimizeFrame deopt(_jvf->thread(), _jvf->fr().id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id());
// Now store a new value for the local which will be applied
// once deoptimization occurs. Note however that while this
--- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -26,7 +26,6 @@
// Forward Declarations
//
-class JvmtiRawMonitor;
class JvmtiBreakpoint;
class JvmtiBreakpoints;
@@ -327,76 +326,6 @@
return false;
}
-
-///////////////////////////////////////////////////////////////
-//
-// class JvmtiRawMonitor
-//
-// Used by JVMTI methods: All RawMonitor methods (CreateRawMonitor, EnterRawMonitor, etc.)
-//
-// Wrapper for ObjectMonitor class that saves the Monitor's name
-//
-
-class JvmtiRawMonitor : public ObjectMonitor {
-private:
- int _magic;
- char * _name;
- // JVMTI_RM_MAGIC is set in contructor and unset in destructor.
- enum { JVMTI_RM_MAGIC = (int)(('T' << 24) | ('I' << 16) | ('R' << 8) | 'M') };
-
-public:
- JvmtiRawMonitor(const char *name);
- ~JvmtiRawMonitor();
- int magic() { return _magic; }
- const char *get_name() { return _name; }
- bool is_valid();
-};
-
-// Onload pending raw monitors
-// Class is used to cache onload or onstart monitor enter
-// which will transition into real monitor when
-// VM is fully initialized.
-class JvmtiPendingMonitors : public AllStatic {
-
-private:
- static GrowableArray<JvmtiRawMonitor*> *_monitors; // Cache raw monitor enter
-
- inline static GrowableArray<JvmtiRawMonitor*>* monitors() { return _monitors; }
-
- static void dispose() {
- delete monitors();
- }
-
-public:
- static void enter(JvmtiRawMonitor *monitor) {
- monitors()->append(monitor);
- }
-
- static int count() {
- return monitors()->length();
- }
-
- static void destroy(JvmtiRawMonitor *monitor) {
- while (monitors()->contains(monitor)) {
- monitors()->remove(monitor);
- }
- }
-
- // Return false if monitor is not found in the list.
- static bool exit(JvmtiRawMonitor *monitor) {
- if (monitors()->contains(monitor)) {
- monitors()->remove(monitor);
- return true;
- } else {
- return false;
- }
- }
-
- static void transition_raw_monitors();
-};
-
-
-
///////////////////////////////////////////////////////////////
// The get/set local operations must only be done by the VM thread
// because the interpreter version needs to access oop maps, which can
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/jvmtiRawMonitor.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_jvmtiRawMonitor.cpp.incl"
+
+GrowableArray<JvmtiRawMonitor*> *JvmtiPendingMonitors::_monitors = new (ResourceObj::C_HEAP) GrowableArray<JvmtiRawMonitor*>(1,true);
+
+void JvmtiPendingMonitors::transition_raw_monitors() {
+ assert((Threads::number_of_threads()==1),
+ "Java thread has not created yet or more than one java thread \
+is running. Raw monitor transition will not work");
+ JavaThread *current_java_thread = JavaThread::current();
+ assert(current_java_thread->thread_state() == _thread_in_vm, "Must be in vm");
+ {
+ ThreadBlockInVM __tbivm(current_java_thread);
+ for(int i=0; i< count(); i++) {
+ JvmtiRawMonitor *rmonitor = monitors()->at(i);
+ int r = rmonitor->raw_enter(current_java_thread);
+ assert(r == ObjectMonitor::OM_OK, "raw_enter should have worked");
+ }
+ }
+ // pending monitors are converted to real monitor so delete them all.
+ dispose();
+}
+
+//
+// class JvmtiRawMonitor
+//
+
+JvmtiRawMonitor::JvmtiRawMonitor(const char *name) {
+#ifdef ASSERT
+ _name = strcpy(NEW_C_HEAP_ARRAY(char, strlen(name) + 1), name);
+#else
+ _name = NULL;
+#endif
+ _magic = JVMTI_RM_MAGIC;
+}
+
+JvmtiRawMonitor::~JvmtiRawMonitor() {
+#ifdef ASSERT
+ FreeHeap(_name);
+#endif
+ _magic = 0;
+}
+
+
+bool
+JvmtiRawMonitor::is_valid() {
+ int value = 0;
+
+ // This object might not be a JvmtiRawMonitor so we can't assume
+ // the _magic field is properly aligned. Get the value in a safe
+ // way and then check against JVMTI_RM_MAGIC.
+
+ switch (sizeof(_magic)) {
+ case 2:
+ value = Bytes::get_native_u2((address)&_magic);
+ break;
+
+ case 4:
+ value = Bytes::get_native_u4((address)&_magic);
+ break;
+
+ case 8:
+ value = Bytes::get_native_u8((address)&_magic);
+ break;
+
+ default:
+ guarantee(false, "_magic field is an unexpected size");
+ }
+
+ return value == JVMTI_RM_MAGIC;
+}
+
+// -------------------------------------------------------------------------
+// The raw monitor subsystem is entirely distinct from normal
+// java-synchronization or jni-synchronization. raw monitors are not
+// associated with objects. They can be implemented in any manner
+// that makes sense. The original implementors decided to piggy-back
+// the raw-monitor implementation on the existing Java objectMonitor mechanism.
+// This flaw needs to fixed. We should reimplement raw monitors as sui-generis.
+// Specifically, we should not implement raw monitors via java monitors.
+// Time permitting, we should disentangle and deconvolve the two implementations
+// and move the resulting raw monitor implementation over to the JVMTI directories.
+// Ideally, the raw monitor implementation would be built on top of
+// park-unpark and nothing else.
+//
+// raw monitors are used mainly by JVMTI
+// The raw monitor implementation borrows the ObjectMonitor structure,
+// but the operators are degenerate and extremely simple.
+//
+// Mixed use of a single objectMonitor instance -- as both a raw monitor
+// and a normal java monitor -- is not permissible.
+//
+// Note that we use the single RawMonitor_lock to protect queue operations for
+// _all_ raw monitors. This is a scalability impediment, but since raw monitor usage
+// is deprecated and rare, this is not of concern. The RawMonitor_lock can not
+// be held indefinitely. The critical sections must be short and bounded.
+//
+// -------------------------------------------------------------------------
+
+int JvmtiRawMonitor::SimpleEnter (Thread * Self) {
+ for (;;) {
+ if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
+ return OS_OK ;
+ }
+
+ ObjectWaiter Node (Self) ;
+ Self->_ParkEvent->reset() ; // strictly optional
+ Node.TState = ObjectWaiter::TS_ENTER ;
+
+ RawMonitor_lock->lock_without_safepoint_check() ;
+ Node._next = _EntryList ;
+ _EntryList = &Node ;
+ OrderAccess::fence() ;
+ if (_owner == NULL && Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
+ _EntryList = Node._next ;
+ RawMonitor_lock->unlock() ;
+ return OS_OK ;
+ }
+ RawMonitor_lock->unlock() ;
+ while (Node.TState == ObjectWaiter::TS_ENTER) {
+ Self->_ParkEvent->park() ;
+ }
+ }
+}
+
+int JvmtiRawMonitor::SimpleExit (Thread * Self) {
+ guarantee (_owner == Self, "invariant") ;
+ OrderAccess::release_store_ptr (&_owner, NULL) ;
+ OrderAccess::fence() ;
+ if (_EntryList == NULL) return OS_OK ;
+ ObjectWaiter * w ;
+
+ RawMonitor_lock->lock_without_safepoint_check() ;
+ w = _EntryList ;
+ if (w != NULL) {
+ _EntryList = w->_next ;
+ }
+ RawMonitor_lock->unlock() ;
+ if (w != NULL) {
+ guarantee (w ->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ ParkEvent * ev = w->_event ;
+ w->TState = ObjectWaiter::TS_RUN ;
+ OrderAccess::fence() ;
+ ev->unpark() ;
+ }
+ return OS_OK ;
+}
+
+int JvmtiRawMonitor::SimpleWait (Thread * Self, jlong millis) {
+ guarantee (_owner == Self , "invariant") ;
+ guarantee (_recursions == 0, "invariant") ;
+
+ ObjectWaiter Node (Self) ;
+ Node._notified = 0 ;
+ Node.TState = ObjectWaiter::TS_WAIT ;
+
+ RawMonitor_lock->lock_without_safepoint_check() ;
+ Node._next = _WaitSet ;
+ _WaitSet = &Node ;
+ RawMonitor_lock->unlock() ;
+
+ SimpleExit (Self) ;
+ guarantee (_owner != Self, "invariant") ;
+
+ int ret = OS_OK ;
+ if (millis <= 0) {
+ Self->_ParkEvent->park();
+ } else {
+ ret = Self->_ParkEvent->park(millis);
+ }
+
+ // If thread still resides on the waitset then unlink it.
+ // Double-checked locking -- the usage is safe in this context
+ // as we TState is volatile and the lock-unlock operators are
+ // serializing (barrier-equivalent).
+
+ if (Node.TState == ObjectWaiter::TS_WAIT) {
+ RawMonitor_lock->lock_without_safepoint_check() ;
+ if (Node.TState == ObjectWaiter::TS_WAIT) {
+ // Simple O(n) unlink, but performance isn't critical here.
+ ObjectWaiter * p ;
+ ObjectWaiter * q = NULL ;
+ for (p = _WaitSet ; p != &Node; p = p->_next) {
+ q = p ;
+ }
+ guarantee (p == &Node, "invariant") ;
+ if (q == NULL) {
+ guarantee (p == _WaitSet, "invariant") ;
+ _WaitSet = p->_next ;
+ } else {
+ guarantee (p == q->_next, "invariant") ;
+ q->_next = p->_next ;
+ }
+ Node.TState = ObjectWaiter::TS_RUN ;
+ }
+ RawMonitor_lock->unlock() ;
+ }
+
+ guarantee (Node.TState == ObjectWaiter::TS_RUN, "invariant") ;
+ SimpleEnter (Self) ;
+
+ guarantee (_owner == Self, "invariant") ;
+ guarantee (_recursions == 0, "invariant") ;
+ return ret ;
+}
+
+int JvmtiRawMonitor::SimpleNotify (Thread * Self, bool All) {
+ guarantee (_owner == Self, "invariant") ;
+ if (_WaitSet == NULL) return OS_OK ;
+
+ // We have two options:
+ // A. Transfer the threads from the WaitSet to the EntryList
+ // B. Remove the thread from the WaitSet and unpark() it.
+ //
+ // We use (B), which is crude and results in lots of futile
+ // context switching. In particular (B) induces lots of contention.
+
+ ParkEvent * ev = NULL ; // consider using a small auto array ...
+ RawMonitor_lock->lock_without_safepoint_check() ;
+ for (;;) {
+ ObjectWaiter * w = _WaitSet ;
+ if (w == NULL) break ;
+ _WaitSet = w->_next ;
+ if (ev != NULL) { ev->unpark(); ev = NULL; }
+ ev = w->_event ;
+ OrderAccess::loadstore() ;
+ w->TState = ObjectWaiter::TS_RUN ;
+ OrderAccess::storeload();
+ if (!All) break ;
+ }
+ RawMonitor_lock->unlock() ;
+ if (ev != NULL) ev->unpark();
+ return OS_OK ;
+}
+
+// Any JavaThread will enter here with state _thread_blocked
+int JvmtiRawMonitor::raw_enter(TRAPS) {
+ TEVENT (raw_enter) ;
+ void * Contended ;
+
+ // don't enter raw monitor if thread is being externally suspended, it will
+ // surprise the suspender if a "suspended" thread can still enter monitor
+ JavaThread * jt = (JavaThread *)THREAD;
+ if (THREAD->is_Java_thread()) {
+ jt->SR_lock()->lock_without_safepoint_check();
+ while (jt->is_external_suspend()) {
+ jt->SR_lock()->unlock();
+ jt->java_suspend_self();
+ jt->SR_lock()->lock_without_safepoint_check();
+ }
+ // guarded by SR_lock to avoid racing with new external suspend requests.
+ Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
+ jt->SR_lock()->unlock();
+ } else {
+ Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
+ }
+
+ if (Contended == THREAD) {
+ _recursions ++ ;
+ return OM_OK ;
+ }
+
+ if (Contended == NULL) {
+ guarantee (_owner == THREAD, "invariant") ;
+ guarantee (_recursions == 0, "invariant") ;
+ return OM_OK ;
+ }
+
+ THREAD->set_current_pending_monitor(this);
+
+ if (!THREAD->is_Java_thread()) {
+ // No other non-Java threads besides VM thread would acquire
+ // a raw monitor.
+ assert(THREAD->is_VM_thread(), "must be VM thread");
+ SimpleEnter (THREAD) ;
+ } else {
+ guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
+ for (;;) {
+ jt->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or
+ // java_suspend_self()
+ SimpleEnter (THREAD) ;
+
+ // were we externally suspended while we were waiting?
+ if (!jt->handle_special_suspend_equivalent_condition()) break ;
+
+ // This thread was externally suspended
+ //
+ // This logic isn't needed for JVMTI raw monitors,
+ // but doesn't hurt just in case the suspend rules change. This
+ // logic is needed for the JvmtiRawMonitor.wait() reentry phase.
+ // We have reentered the contended monitor, but while we were
+ // waiting another thread suspended us. We don't want to reenter
+ // the monitor while suspended because that would surprise the
+ // thread that suspended us.
+ //
+ // Drop the lock -
+ SimpleExit (THREAD) ;
+
+ jt->java_suspend_self();
+ }
+
+ assert(_owner == THREAD, "Fatal error with monitor owner!");
+ assert(_recursions == 0, "Fatal error with monitor recursions!");
+ }
+
+ THREAD->set_current_pending_monitor(NULL);
+ guarantee (_recursions == 0, "invariant") ;
+ return OM_OK;
+}
+
+// Used mainly for JVMTI raw monitor implementation
+// Also used for JvmtiRawMonitor::wait().
+int JvmtiRawMonitor::raw_exit(TRAPS) {
+ TEVENT (raw_exit) ;
+ if (THREAD != _owner) {
+ return OM_ILLEGAL_MONITOR_STATE;
+ }
+ if (_recursions > 0) {
+ --_recursions ;
+ return OM_OK ;
+ }
+
+ void * List = _EntryList ;
+ SimpleExit (THREAD) ;
+
+ return OM_OK;
+}
+
+// Used for JVMTI raw monitor implementation.
+// All JavaThreads will enter here with state _thread_blocked
+
+int JvmtiRawMonitor::raw_wait(jlong millis, bool interruptible, TRAPS) {
+ TEVENT (raw_wait) ;
+ if (THREAD != _owner) {
+ return OM_ILLEGAL_MONITOR_STATE;
+ }
+
+ // To avoid spurious wakeups we reset the parkevent -- This is strictly optional.
+ // The caller must be able to tolerate spurious returns from raw_wait().
+ THREAD->_ParkEvent->reset() ;
+ OrderAccess::fence() ;
+
+ // check interrupt event
+ if (interruptible && Thread::is_interrupted(THREAD, true)) {
+ return OM_INTERRUPTED;
+ }
+
+ intptr_t save = _recursions ;
+ _recursions = 0 ;
+ _waiters ++ ;
+ if (THREAD->is_Java_thread()) {
+ guarantee (((JavaThread *) THREAD)->thread_state() == _thread_blocked, "invariant") ;
+ ((JavaThread *)THREAD)->set_suspend_equivalent();
+ }
+ int rv = SimpleWait (THREAD, millis) ;
+ _recursions = save ;
+ _waiters -- ;
+
+ guarantee (THREAD == _owner, "invariant") ;
+ if (THREAD->is_Java_thread()) {
+ JavaThread * jSelf = (JavaThread *) THREAD ;
+ for (;;) {
+ if (!jSelf->handle_special_suspend_equivalent_condition()) break ;
+ SimpleExit (THREAD) ;
+ jSelf->java_suspend_self();
+ SimpleEnter (THREAD) ;
+ jSelf->set_suspend_equivalent() ;
+ }
+ }
+ guarantee (THREAD == _owner, "invariant") ;
+
+ if (interruptible && Thread::is_interrupted(THREAD, true)) {
+ return OM_INTERRUPTED;
+ }
+ return OM_OK ;
+}
+
+int JvmtiRawMonitor::raw_notify(TRAPS) {
+ TEVENT (raw_notify) ;
+ if (THREAD != _owner) {
+ return OM_ILLEGAL_MONITOR_STATE;
+ }
+ SimpleNotify (THREAD, false) ;
+ return OM_OK;
+}
+
+int JvmtiRawMonitor::raw_notifyAll(TRAPS) {
+ TEVENT (raw_notifyAll) ;
+ if (THREAD != _owner) {
+ return OM_ILLEGAL_MONITOR_STATE;
+ }
+ SimpleNotify (THREAD, true) ;
+ return OM_OK;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/jvmtiRawMonitor.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+//
+// class JvmtiRawMonitor
+//
+// Used by JVMTI methods: All RawMonitor methods (CreateRawMonitor, EnterRawMonitor, etc.)
+//
+// Wrapper for ObjectMonitor class that saves the Monitor's name
+//
+
+class JvmtiRawMonitor : public ObjectMonitor {
+private:
+ int _magic;
+ char * _name;
+ // JVMTI_RM_MAGIC is set in contructor and unset in destructor.
+ enum { JVMTI_RM_MAGIC = (int)(('T' << 24) | ('I' << 16) | ('R' << 8) | 'M') };
+
+ int SimpleEnter (Thread * Self) ;
+ int SimpleExit (Thread * Self) ;
+ int SimpleWait (Thread * Self, jlong millis) ;
+ int SimpleNotify (Thread * Self, bool All) ;
+
+public:
+ JvmtiRawMonitor(const char *name);
+ ~JvmtiRawMonitor();
+ int raw_enter(TRAPS);
+ int raw_exit(TRAPS);
+ int raw_wait(jlong millis, bool interruptable, TRAPS);
+ int raw_notify(TRAPS);
+ int raw_notifyAll(TRAPS);
+ int magic() { return _magic; }
+ const char *get_name() { return _name; }
+ bool is_valid();
+};
+
+// Onload pending raw monitors
+// Class is used to cache onload or onstart monitor enter
+// which will transition into real monitor when
+// VM is fully initialized.
+class JvmtiPendingMonitors : public AllStatic {
+
+private:
+ static GrowableArray<JvmtiRawMonitor*> *_monitors; // Cache raw monitor enter
+
+ inline static GrowableArray<JvmtiRawMonitor*>* monitors() { return _monitors; }
+
+ static void dispose() {
+ delete monitors();
+ }
+
+public:
+ static void enter(JvmtiRawMonitor *monitor) {
+ monitors()->append(monitor);
+ }
+
+ static int count() {
+ return monitors()->length();
+ }
+
+ static void destroy(JvmtiRawMonitor *monitor) {
+ while (monitors()->contains(monitor)) {
+ monitors()->remove(monitor);
+ }
+ }
+
+ // Return false if monitor is not found in the list.
+ static bool exit(JvmtiRawMonitor *monitor) {
+ if (monitors()->contains(monitor)) {
+ monitors()->remove(monitor);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static void transition_raw_monitors();
+};
--- a/hotspot/src/share/vm/prims/methodComparator.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/methodComparator.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -147,10 +147,9 @@
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
- case Bytecodes::_invokedynamic : // fall through
case Bytecodes::_invokeinterface : {
- int cpci_old = _s_old->has_index_u4() ? _s_old->get_index_u4() : _s_old->get_index_u2_cpcache();
- int cpci_new = _s_new->has_index_u4() ? _s_new->get_index_u4() : _s_new->get_index_u2_cpcache();
+ int cpci_old = _s_old->get_index_u2_cpcache();
+ int cpci_new = _s_new->get_index_u2_cpcache();
// Check if the names of classes, field/method names and signatures at these indexes
// are the same. Indices which are really into constantpool cache (rather than constant
// pool itself) are accepted by the constantpool query routines below.
@@ -160,6 +159,33 @@
return false;
break;
}
+ case Bytecodes::_invokedynamic: {
+ int cpci_old = _s_old->get_index_u4();
+ int cpci_new = _s_new->get_index_u4();
+ // Check if the names of classes, field/method names and signatures at these indexes
+ // are the same. Indices which are really into constantpool cache (rather than constant
+ // pool itself) are accepted by the constantpool query routines below.
+ if ((_old_cp->name_ref_at(cpci_old) != _new_cp->name_ref_at(cpci_new)) ||
+ (_old_cp->signature_ref_at(cpci_old) != _new_cp->signature_ref_at(cpci_new)))
+ return false;
+ int cpi_old = _old_cp->cache()->main_entry_at(cpci_old)->constant_pool_index();
+ int cpi_new = _new_cp->cache()->main_entry_at(cpci_new)->constant_pool_index();
+ int bsm_old = _old_cp->invoke_dynamic_bootstrap_method_ref_index_at(cpi_old);
+ int bsm_new = _new_cp->invoke_dynamic_bootstrap_method_ref_index_at(cpi_new);
+ if (!pool_constants_same(bsm_old, bsm_new))
+ return false;
+ int cnt_old = _old_cp->invoke_dynamic_argument_count_at(cpi_old);
+ int cnt_new = _new_cp->invoke_dynamic_argument_count_at(cpi_new);
+ if (cnt_old != cnt_new)
+ return false;
+ for (int arg_i = 0; arg_i < cnt_old; arg_i++) {
+ int idx_old = _old_cp->invoke_dynamic_argument_index_at(cpi_old, arg_i);
+ int idx_new = _new_cp->invoke_dynamic_argument_index_at(cpi_new, arg_i);
+ if (!pool_constants_same(idx_old, idx_new))
+ return false;
+ }
+ break;
+ }
case Bytecodes::_ldc : // fall through
case Bytecodes::_ldc_w : {
@@ -167,51 +193,8 @@
Bytecode_loadconstant* ldc_new = Bytecode_loadconstant_at(_s_new->method(), _s_new->bci());
int cpi_old = ldc_old->pool_index();
int cpi_new = ldc_new->pool_index();
- constantTag tag_old = _old_cp->tag_at(cpi_old);
- constantTag tag_new = _new_cp->tag_at(cpi_new);
- if (tag_old.is_int() || tag_old.is_float()) {
- if (tag_old.value() != tag_new.value())
- return false;
- if (tag_old.is_int()) {
- if (_old_cp->int_at(cpi_old) != _new_cp->int_at(cpi_new))
- return false;
- } else {
- // Use jint_cast to compare the bits rather than numerical values.
- // This makes a difference for NaN constants.
- if (jint_cast(_old_cp->float_at(cpi_old)) != jint_cast(_new_cp->float_at(cpi_new)))
- return false;
- }
- } else if (tag_old.is_string() || tag_old.is_unresolved_string()) {
- if (! (tag_new.is_unresolved_string() || tag_new.is_string()))
- return false;
- if (strcmp(_old_cp->string_at_noresolve(cpi_old),
- _new_cp->string_at_noresolve(cpi_new)) != 0)
- return false;
- } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) {
- // tag_old should be klass - 4881222
- if (! (tag_new.is_unresolved_klass() || tag_new.is_klass()))
- return false;
- if (_old_cp->klass_at_noresolve(cpi_old) !=
- _new_cp->klass_at_noresolve(cpi_new))
- return false;
- } else if (tag_old.is_method_type() && tag_new.is_method_type()) {
- int mti_old = _old_cp->method_type_index_at(cpi_old);
- int mti_new = _new_cp->method_type_index_at(cpi_new);
- if ((_old_cp->symbol_at(mti_old) != _new_cp->symbol_at(mti_new)))
- return false;
- } else if (tag_old.is_method_handle() && tag_new.is_method_handle()) {
- if (_old_cp->method_handle_ref_kind_at(cpi_old) !=
- _new_cp->method_handle_ref_kind_at(cpi_new))
- return false;
- int mhi_old = _old_cp->method_handle_index_at(cpi_old);
- int mhi_new = _new_cp->method_handle_index_at(cpi_new);
- if ((_old_cp->uncached_klass_ref_at_noresolve(mhi_old) != _new_cp->uncached_klass_ref_at_noresolve(mhi_new)) ||
- (_old_cp->uncached_name_ref_at(mhi_old) != _new_cp->uncached_name_ref_at(mhi_new)) ||
- (_old_cp->uncached_signature_ref_at(mhi_old) != _new_cp->uncached_signature_ref_at(mhi_new)))
- return false;
- } else {
- return false; // unknown tag
- }
+ if (!pool_constants_same(cpi_old, cpi_new))
+ return false;
break;
}
@@ -392,6 +375,55 @@
return true;
}
+bool MethodComparator::pool_constants_same(int cpi_old, int cpi_new) {
+ constantTag tag_old = _old_cp->tag_at(cpi_old);
+ constantTag tag_new = _new_cp->tag_at(cpi_new);
+ if (tag_old.is_int() || tag_old.is_float()) {
+ if (tag_old.value() != tag_new.value())
+ return false;
+ if (tag_old.is_int()) {
+ if (_old_cp->int_at(cpi_old) != _new_cp->int_at(cpi_new))
+ return false;
+ } else {
+ // Use jint_cast to compare the bits rather than numerical values.
+ // This makes a difference for NaN constants.
+ if (jint_cast(_old_cp->float_at(cpi_old)) != jint_cast(_new_cp->float_at(cpi_new)))
+ return false;
+ }
+ } else if (tag_old.is_string() || tag_old.is_unresolved_string()) {
+ if (! (tag_new.is_unresolved_string() || tag_new.is_string()))
+ return false;
+ if (strcmp(_old_cp->string_at_noresolve(cpi_old),
+ _new_cp->string_at_noresolve(cpi_new)) != 0)
+ return false;
+ } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) {
+ // tag_old should be klass - 4881222
+ if (! (tag_new.is_unresolved_klass() || tag_new.is_klass()))
+ return false;
+ if (_old_cp->klass_at_noresolve(cpi_old) !=
+ _new_cp->klass_at_noresolve(cpi_new))
+ return false;
+ } else if (tag_old.is_method_type() && tag_new.is_method_type()) {
+ int mti_old = _old_cp->method_type_index_at(cpi_old);
+ int mti_new = _new_cp->method_type_index_at(cpi_new);
+ if ((_old_cp->symbol_at(mti_old) != _new_cp->symbol_at(mti_new)))
+ return false;
+ } else if (tag_old.is_method_handle() && tag_new.is_method_handle()) {
+ if (_old_cp->method_handle_ref_kind_at(cpi_old) !=
+ _new_cp->method_handle_ref_kind_at(cpi_new))
+ return false;
+ int mhi_old = _old_cp->method_handle_index_at(cpi_old);
+ int mhi_new = _new_cp->method_handle_index_at(cpi_new);
+ if ((_old_cp->uncached_klass_ref_at_noresolve(mhi_old) != _new_cp->uncached_klass_ref_at_noresolve(mhi_new)) ||
+ (_old_cp->uncached_name_ref_at(mhi_old) != _new_cp->uncached_name_ref_at(mhi_new)) ||
+ (_old_cp->uncached_signature_ref_at(mhi_old) != _new_cp->uncached_signature_ref_at(mhi_new)))
+ return false;
+ } else {
+ return false; // unknown tag
+ }
+ return true;
+}
+
int MethodComparator::check_stack_and_locals_size(methodOop old_method, methodOop new_method) {
if (old_method->max_stack() != new_method->max_stack()) {
--- a/hotspot/src/share/vm/prims/methodComparator.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/methodComparator.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
static GrowableArray<int> *_fwd_jmps;
static bool args_same(Bytecodes::Code c_old, Bytecodes::Code c_new);
+ static bool pool_constants_same(int cpi_old, int cpi_new);
static int check_stack_and_locals_size(methodOop old_method, methodOop new_method);
public:
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -974,6 +974,8 @@
assert(src != T_VOID && dst != T_VOID, "should not be here");
if (src == dst) return true;
if (type2size[src] != type2size[dst]) return false;
+ if (src == T_OBJECT || dst == T_OBJECT) return false;
+ if (raw) return true; // bitwise reinterpretation; caller guarantees safety
// allow reinterpretation casts for integral widening
if (is_subword_type(src)) { // subwords can fit in int or other subwords
if (dst == T_INT) // any subword fits in an int
--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -119,11 +119,8 @@
PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.version", "1.0", false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name",
"Java Virtual Machine Specification", false));
- PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.vendor",
- JDK_Version::is_gte_jdk17x_version() ? "Oracle Corporation" : "Sun Microsystems Inc.", false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(), false));
- PropertyList_add(&_system_properties, new SystemProperty("java.vm.vendor", VM_Version::vm_vendor(), false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true));
// following are JVMTI agent writeable properties.
@@ -151,6 +148,14 @@
os::init_system_properties_values();
}
+
+ // Update/Initialize System properties after JDK version number is known
+void Arguments::init_version_specific_system_properties() {
+ PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.vendor",
+ JDK_Version::is_gte_jdk17x_version() ? "Oracle Corporation" : "Sun Microsystems Inc.", false));
+ PropertyList_add(&_system_properties, new SystemProperty("java.vm.vendor", VM_Version::vm_vendor(), false));
+}
+
/**
* Provide a slightly more user-friendly way of eliminating -XX flags.
* When a flag is eliminated, it can be added to this list in order to
@@ -185,6 +190,10 @@
JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) },
{ "UseDepthFirstScavengeOrder",
JDK_Version::jdk_update(6,22), JDK_Version::jdk(7) },
+ { "HandlePromotionFailure",
+ JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) },
+ { "MaxLiveObjectEvacuationRatio",
+ JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};
@@ -948,26 +957,54 @@
}
}
+void Arguments::check_compressed_oops_compat() {
+#ifdef _LP64
+ assert(UseCompressedOops, "Precondition");
+# if defined(COMPILER1) && !defined(TIERED)
+ // Until c1 supports compressed oops turn them off.
+ FLAG_SET_DEFAULT(UseCompressedOops, false);
+# else
+ // Is it on by default or set on ergonomically
+ bool is_on_by_default = FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops);
+
+ // Tiered currently doesn't work with compressed oops
+ if (TieredCompilation) {
+ if (is_on_by_default) {
+ FLAG_SET_DEFAULT(UseCompressedOops, false);
+ return;
+ } else {
+ vm_exit_during_initialization(
+ "Tiered compilation is not supported with compressed oops yet", NULL);
+ }
+ }
+
+ // If dumping an archive or forcing its use, disable compressed oops if possible
+ if (DumpSharedSpaces || RequireSharedSpaces) {
+ if (is_on_by_default) {
+ FLAG_SET_DEFAULT(UseCompressedOops, false);
+ return;
+ } else {
+ vm_exit_during_initialization(
+ "Class Data Sharing is not supported with compressed oops yet", NULL);
+ }
+ } else if (UseSharedSpaces) {
+ // UseSharedSpaces is on by default. With compressed oops, we turn it off.
+ FLAG_SET_DEFAULT(UseSharedSpaces, false);
+ }
+
+# endif // defined(COMPILER1) && !defined(TIERED)
+#endif // _LP64
+}
+
void Arguments::set_tiered_flags() {
if (FLAG_IS_DEFAULT(CompilationPolicyChoice)) {
FLAG_SET_DEFAULT(CompilationPolicyChoice, 2);
}
-
if (CompilationPolicyChoice < 2) {
vm_exit_during_initialization(
"Incompatible compilation policy selected", NULL);
}
-
-#ifdef _LP64
- if (FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops)) {
- UseCompressedOops = false;
- }
- if (UseCompressedOops) {
- vm_exit_during_initialization(
- "Tiered compilation is not supported with compressed oops yet", NULL);
- }
-#endif
- // Increase the code cache size - tiered compiles a lot more.
+ // Increase the code cache size - tiered compiles a lot more.
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 2);
}
@@ -1676,7 +1713,8 @@
bool status = true;
status = status && verify_min_value(StackYellowPages, 1, "StackYellowPages");
status = status && verify_min_value(StackRedPages, 1, "StackRedPages");
- status = status && verify_min_value(StackShadowPages, 1, "StackShadowPages");
+ // greater stack shadow pages can't generate instruction to bang stack
+ status = status && verify_interval(StackShadowPages, 1, 50, "StackShadowPages");
return status;
}
@@ -1722,8 +1760,6 @@
status = false;
}
- status = status && verify_percentage(MaxLiveObjectEvacuationRatio,
- "MaxLiveObjectEvacuationRatio");
status = status && verify_percentage(AdaptiveSizePolicyWeight,
"AdaptiveSizePolicyWeight");
status = status && verify_percentage(AdaptivePermSizeWeight, "AdaptivePermSizeWeight");
@@ -2827,6 +2863,7 @@
return JNI_OK;
}
+
// Parse entry point called from JNI_CreateJavaVM
jint Arguments::parse(const JavaVMInitArgs* args) {
@@ -2969,10 +3006,6 @@
PrintGC = true;
}
-#if defined(_LP64) && defined(COMPILER1) && !defined(TIERED)
- UseCompressedOops = false;
-#endif
-
// Set object alignment values.
set_object_alignment();
@@ -2987,13 +3020,10 @@
set_ergonomics_flags();
#ifdef _LP64
- // XXX JSR 292 currently does not support compressed oops.
- if (EnableMethodHandles && UseCompressedOops) {
- if (FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops)) {
- UseCompressedOops = false;
- }
+ if (UseCompressedOops) {
+ check_compressed_oops_compat();
}
-#endif // _LP64
+#endif
// Check the GC selections again.
if (!check_gc_consistency()) {
--- a/hotspot/src/share/vm/runtime/arguments.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -291,6 +291,8 @@
// Tiered
static void set_tiered_flags();
+ // Check compressed oops compatibility with other flags
+ static void check_compressed_oops_compat();
// CMS/ParNew garbage collectors
static void set_parnew_gc_flags();
static void set_cms_and_parnew_gc_flags();
@@ -484,6 +486,9 @@
// System properties
static void init_system_properties();
+ // Update/Initialize System properties after JDK version number is known
+ static void init_version_specific_system_properties();
+
// Property List manipulation
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/basicLock.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_basicLock.cpp.incl"
+
+void BasicLock::print_on(outputStream* st) const {
+ st->print("monitor");
+}
+
+void BasicLock::move_to(oop obj, BasicLock* dest) {
+ // Check to see if we need to inflate the lock. This is only needed
+ // if an object is locked using "this" lightweight monitor. In that
+ // case, the displaced_header() is unlocked, because the
+ // displaced_header() contains the header for the originally unlocked
+ // object. However the object could have already been inflated. But it
+ // does not matter, the inflation will just a no-op. For other cases,
+ // the displaced header will be either 0x0 or 0x3, which are location
+ // independent, therefore the BasicLock is free to move.
+ //
+ // During OSR we may need to relocate a BasicLock (which contains a
+ // displaced word) from a location in an interpreter frame to a
+ // new location in a compiled frame. "this" refers to the source
+ // basiclock in the interpreter frame. "dest" refers to the destination
+ // basiclock in the new compiled frame. We *always* inflate in move_to().
+ // The always-Inflate policy works properly, but in 1.5.0 it can sometimes
+ // cause performance problems in code that makes heavy use of a small # of
+ // uncontended locks. (We'd inflate during OSR, and then sync performance
+ // would subsequently plummet because the thread would be forced thru the slow-path).
+ // This problem has been made largely moot on IA32 by inlining the inflated fast-path
+ // operations in Fast_Lock and Fast_Unlock in i486.ad.
+ //
+ // Note that there is a way to safely swing the object's markword from
+ // one stack location to another. This avoids inflation. Obviously,
+ // we need to ensure that both locations refer to the current thread's stack.
+ // There are some subtle concurrency issues, however, and since the benefit is
+ // is small (given the support for inflated fast-path locking in the fast_lock, etc)
+ // we'll leave that optimization for another time.
+
+ if (displaced_header()->is_neutral()) {
+ ObjectSynchronizer::inflate_helper(obj);
+ // WARNING: We can not put check here, because the inflation
+ // will not update the displaced header. Once BasicLock is inflated,
+ // no one should ever look at its content.
+ } else {
+ // Typically the displaced header will be 0 (recursive stack lock) or
+ // unused_mark. Naively we'd like to assert that the displaced mark
+ // value is either 0, neutral, or 3. But with the advent of the
+ // store-before-CAS avoidance in fast_lock/compiler_lock_object
+ // we can find any flavor mark in the displaced mark.
+ }
+// [RGV] The next line appears to do nothing!
+ intptr_t dh = (intptr_t) displaced_header();
+ dest->set_displaced_header(displaced_header());
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/basicLock.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+class BasicLock VALUE_OBJ_CLASS_SPEC {
+ friend class VMStructs;
+ private:
+ volatile markOop _displaced_header;
+ public:
+ markOop displaced_header() const { return _displaced_header; }
+ void set_displaced_header(markOop header) { _displaced_header = header; }
+
+ void print_on(outputStream* st) const;
+
+ // move a basic lock (used during deoptimization
+ void move_to(oop obj, BasicLock* dest);
+
+ static int displaced_header_offset_in_bytes() { return offset_of(BasicLock, _displaced_header); }
+};
+
+// A BasicObjectLock associates a specific Java object with a BasicLock.
+// It is currently embedded in an interpreter frame.
+
+// Because some machines have alignment restrictions on the control stack,
+// the actual space allocated by the interpreter may include padding words
+// after the end of the BasicObjectLock. Also, in order to guarantee
+// alignment of the embedded BasicLock objects on such machines, we
+// put the embedded BasicLock at the beginning of the struct.
+
+class BasicObjectLock VALUE_OBJ_CLASS_SPEC {
+ friend class VMStructs;
+ private:
+ BasicLock _lock; // the lock, must be double word aligned
+ oop _obj; // object holds the lock;
+
+ public:
+ // Manipulation
+ oop obj() const { return _obj; }
+ void set_obj(oop obj) { _obj = obj; }
+ BasicLock* lock() { return &_lock; }
+
+ // Note: Use frame::interpreter_frame_monitor_size() for the size of BasicObjectLocks
+ // in interpreter activation frames since it includes machine-specific padding.
+ static int size() { return sizeof(BasicObjectLock)/wordSize; }
+
+ // GC support
+ void oops_do(OopClosure* f) { f->do_oop(&_obj); }
+
+ static int obj_offset_in_bytes() { return offset_of(BasicObjectLock, _obj); }
+ static int lock_offset_in_bytes() { return offset_of(BasicObjectLock, _lock); }
+};
+
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1065,7 +1065,9 @@
}
-void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
+void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) {
+ assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "can only deoptimize other thread at a safepoint");
// Compute frame and register map based on thread and sp.
RegisterMap reg_map(thread, UseBiasedLocking);
frame fr = thread->last_frame();
@@ -1076,6 +1078,16 @@
}
+void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
+ if (thread == Thread::current()) {
+ Deoptimization::deoptimize_frame_internal(thread, id);
+ } else {
+ VM_DeoptimizeFrame deopt(thread, id);
+ VMThread::execute(&deopt);
+ }
+}
+
+
// JVMTI PopFrame support
JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address))
{
--- a/hotspot/src/share/vm/runtime/deoptimization.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -216,6 +216,10 @@
// Only called from VMDeoptimizeFrame
// @argument thread. Thread where stub_frame resides.
// @argument id. id of frame that should be deoptimized.
+ static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id);
+
+ // If thread is not the current thread then execute
+ // VM_DeoptimizeFrame otherwise deoptimize directly.
static void deoptimize_frame(JavaThread* thread, intptr_t* id);
// Statistics
--- a/hotspot/src/share/vm/runtime/frame.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/frame.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -878,7 +878,7 @@
#endif /* CC_INTERP */
-#ifndef PPC
+#if !defined(PPC) || defined(ZERO)
if (m->is_native()) {
#ifdef CC_INTERP
f->do_oop((oop*)&istate->_oop_temp);
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/globals.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -327,10 +327,10 @@
/* UseMembar is theoretically a temp flag used for memory barrier \
* removal testing. It was supposed to be removed before FCS but has \
* been re-added (see 6401008) */ \
- product(bool, UseMembar, false, \
+ product_pd(bool, UseMembar, \
"(Unstable) Issues membars on thread state transitions") \
\
- /* Temporary: See 6948537 */ \
+ /* Temporary: See 6948537 */ \
experimental(bool, UseMemSetInBOT, true, \
"(Unstable) uses memset in BOT updates in GC code") \
\
@@ -822,6 +822,9 @@
develop(bool, PrintJVMWarnings, false, \
"Prints warnings for unimplemented JVM functions") \
\
+ product(bool, PrintWarnings, true, \
+ "Prints JVM warnings to output stream") \
+ \
notproduct(uintx, WarnOnStalledSpinLock, 0, \
"Prints warnings for stalled SpinLocks") \
\
@@ -1585,7 +1588,7 @@
"(Temporary, subject to experimentation)" \
"Nominal minimum work per abortable preclean iteration") \
\
- product(intx, CMSAbortablePrecleanWaitMillis, 100, \
+ manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \
"(Temporary, subject to experimentation)" \
" Time that we sleep between iterations when not given" \
" enough work per iteration") \
@@ -1677,7 +1680,7 @@
product(uintx, CMSWorkQueueDrainThreshold, 10, \
"Don't drain below this size per parallel worker/thief") \
\
- product(intx, CMSWaitDuration, 2000, \
+ manageable(intx, CMSWaitDuration, 2000, \
"Time in milliseconds that CMS thread waits for young GC") \
\
product(bool, CMSYield, true, \
@@ -1786,10 +1789,6 @@
notproduct(bool, GCALotAtAllSafepoints, false, \
"Enforce ScavengeALot/GCALot at all potential safepoints") \
\
- product(bool, HandlePromotionFailure, true, \
- "The youngest generation collection does not require " \
- "a guarantee of full promotion of all live objects.") \
- \
product(bool, PrintPromotionFailure, false, \
"Print additional diagnostic information following " \
" promotion failure") \
@@ -3003,9 +3002,6 @@
product(intx, NewRatio, 2, \
"Ratio of new/old generation sizes") \
\
- product(uintx, MaxLiveObjectEvacuationRatio, 100, \
- "Max percent of eden objects that will be live at scavenge") \
- \
product_pd(uintx, NewSizeThreadIncrease, \
"Additional size added to desired new generation size per " \
"non-daemon thread (in bytes)") \
@@ -3542,7 +3538,7 @@
product(uintx, SharedDummyBlockSize, 512*M, \
"Size of dummy block used to shift heap addresses (in bytes)") \
\
- product(uintx, SharedReadWriteSize, 12*M, \
+ product(uintx, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(13*M), \
"Size of read-write space in permanent generation (in bytes)") \
\
product(uintx, SharedReadOnlySize, 10*M, \
--- a/hotspot/src/share/vm/runtime/java.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/java.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -198,7 +198,7 @@
if (CountCompiledCalls) {
print_method_invocation_histogram();
}
- if (ProfileInterpreter || C1UpdateMethodData) {
+ if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) {
print_method_profiling_data();
}
if (TimeCompiler) {
--- a/hotspot/src/share/vm/runtime/mutex.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/mutex.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -265,48 +265,3 @@
}
};
-/*
- * Per-thread blocking support for JSR166. See the Java-level
- * Documentation for rationale. Basically, park acts like wait, unpark
- * like notify.
- *
- * 6271289 --
- * To avoid errors where an os thread expires but the JavaThread still
- * exists, Parkers are immortal (type-stable) and are recycled across
- * new threads. This parallels the ParkEvent implementation.
- * Because park-unpark allow spurious wakeups it is harmless if an
- * unpark call unparks a new thread using the old Parker reference.
- *
- * In the future we'll want to think about eliminating Parker and using
- * ParkEvent instead. There's considerable duplication between the two
- * services.
- *
- */
-
-class Parker : public os::PlatformParker {
-private:
- volatile int _counter ;
- Parker * FreeNext ;
- JavaThread * AssociatedWith ; // Current association
-
-public:
- Parker() : PlatformParker() {
- _counter = 0 ;
- FreeNext = NULL ;
- AssociatedWith = NULL ;
- }
-protected:
- ~Parker() { ShouldNotReachHere(); }
-public:
- // For simplicity of interface with Java, all forms of park (indefinite,
- // relative, and absolute) are multiplexed into one call.
- void park(bool isAbsolute, jlong time);
- void unpark();
-
- // Lifecycle operators
- static Parker * Allocate (JavaThread * t) ;
- static void Release (Parker * e) ;
-private:
- static Parker * volatile FreeList ;
- static volatile int ListLock ;
-};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,2421 @@
+/*
+ * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_objectMonitor.cpp.incl"
+
+#if defined(__GNUC__) && !defined(IA64)
+ // Need to inhibit inlining for older versions of GCC to avoid build-time failures
+ #define ATTR __attribute__((noinline))
+#else
+ #define ATTR
+#endif
+
+
+#ifdef DTRACE_ENABLED
+
+// Only bother with this argument setup if dtrace is available
+// TODO-FIXME: probes should not fire when caller is _blocked. assert() accordingly.
+
+HS_DTRACE_PROBE_DECL4(hotspot, monitor__notify,
+ jlong, uintptr_t, char*, int);
+HS_DTRACE_PROBE_DECL4(hotspot, monitor__notifyAll,
+ jlong, uintptr_t, char*, int);
+HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__enter,
+ jlong, uintptr_t, char*, int);
+HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__entered,
+ jlong, uintptr_t, char*, int);
+HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__exit,
+ jlong, uintptr_t, char*, int);
+
+#define DTRACE_MONITOR_PROBE_COMMON(klassOop, thread) \
+ char* bytes = NULL; \
+ int len = 0; \
+ jlong jtid = SharedRuntime::get_java_tid(thread); \
+ symbolOop klassname = ((oop)(klassOop))->klass()->klass_part()->name(); \
+ if (klassname != NULL) { \
+ bytes = (char*)klassname->bytes(); \
+ len = klassname->utf8_length(); \
+ }
+
+#define DTRACE_MONITOR_WAIT_PROBE(monitor, klassOop, thread, millis) \
+ { \
+ if (DTraceMonitorProbes) { \
+ DTRACE_MONITOR_PROBE_COMMON(klassOop, thread); \
+ HS_DTRACE_PROBE5(hotspot, monitor__wait, jtid, \
+ (monitor), bytes, len, (millis)); \
+ } \
+ }
+
+#define DTRACE_MONITOR_PROBE(probe, monitor, klassOop, thread) \
+ { \
+ if (DTraceMonitorProbes) { \
+ DTRACE_MONITOR_PROBE_COMMON(klassOop, thread); \
+ HS_DTRACE_PROBE4(hotspot, monitor__##probe, jtid, \
+ (uintptr_t)(monitor), bytes, len); \
+ } \
+ }
+
+#else // ndef DTRACE_ENABLED
+
+#define DTRACE_MONITOR_WAIT_PROBE(klassOop, thread, millis, mon) {;}
+#define DTRACE_MONITOR_PROBE(probe, klassOop, thread, mon) {;}
+
+#endif // ndef DTRACE_ENABLED
+
+// Tunables ...
+// The knob* variables are effectively final. Once set they should
+// never be modified hence. Consider using __read_mostly with GCC.
+
+int ObjectMonitor::Knob_Verbose = 0 ;
+int ObjectMonitor::Knob_SpinLimit = 5000 ; // derived by an external tool -
+static int Knob_LogSpins = 0 ; // enable jvmstat tally for spins
+static int Knob_HandOff = 0 ;
+static int Knob_ReportSettings = 0 ;
+
+static int Knob_SpinBase = 0 ; // Floor AKA SpinMin
+static int Knob_SpinBackOff = 0 ; // spin-loop backoff
+static int Knob_CASPenalty = -1 ; // Penalty for failed CAS
+static int Knob_OXPenalty = -1 ; // Penalty for observed _owner change
+static int Knob_SpinSetSucc = 1 ; // spinners set the _succ field
+static int Knob_SpinEarly = 1 ;
+static int Knob_SuccEnabled = 1 ; // futile wake throttling
+static int Knob_SuccRestrict = 0 ; // Limit successors + spinners to at-most-one
+static int Knob_MaxSpinners = -1 ; // Should be a function of # CPUs
+static int Knob_Bonus = 100 ; // spin success bonus
+static int Knob_BonusB = 100 ; // spin success bonus
+static int Knob_Penalty = 200 ; // spin failure penalty
+static int Knob_Poverty = 1000 ;
+static int Knob_SpinAfterFutile = 1 ; // Spin after returning from park()
+static int Knob_FixedSpin = 0 ;
+static int Knob_OState = 3 ; // Spinner checks thread state of _owner
+static int Knob_UsePause = 1 ;
+static int Knob_ExitPolicy = 0 ;
+static int Knob_PreSpin = 10 ; // 20-100 likely better
+static int Knob_ResetEvent = 0 ;
+static int BackOffMask = 0 ;
+
+static int Knob_FastHSSEC = 0 ;
+static int Knob_MoveNotifyee = 2 ; // notify() - disposition of notifyee
+static int Knob_QMode = 0 ; // EntryList-cxq policy - queue discipline
+static volatile int InitDone = 0 ;
+
+#define TrySpin TrySpin_VaryDuration
+
+// -----------------------------------------------------------------------------
+// Theory of operations -- Monitors lists, thread residency, etc:
+//
+// * A thread acquires ownership of a monitor by successfully
+// CAS()ing the _owner field from null to non-null.
+//
+// * Invariant: A thread appears on at most one monitor list --
+// cxq, EntryList or WaitSet -- at any one time.
+//
+// * Contending threads "push" themselves onto the cxq with CAS
+// and then spin/park.
+//
+// * After a contending thread eventually acquires the lock it must
+// dequeue itself from either the EntryList or the cxq.
+//
+// * The exiting thread identifies and unparks an "heir presumptive"
+// tentative successor thread on the EntryList. Critically, the
+// exiting thread doesn't unlink the successor thread from the EntryList.
+// After having been unparked, the wakee will recontend for ownership of
+// the monitor. The successor (wakee) will either acquire the lock or
+// re-park itself.
+//
+// Succession is provided for by a policy of competitive handoff.
+// The exiting thread does _not_ grant or pass ownership to the
+// successor thread. (This is also referred to as "handoff" succession").
+// Instead the exiting thread releases ownership and possibly wakes
+// a successor, so the successor can (re)compete for ownership of the lock.
+// If the EntryList is empty but the cxq is populated the exiting
+// thread will drain the cxq into the EntryList. It does so by
+// by detaching the cxq (installing null with CAS) and folding
+// the threads from the cxq into the EntryList. The EntryList is
+// doubly linked, while the cxq is singly linked because of the
+// CAS-based "push" used to enqueue recently arrived threads (RATs).
+//
+// * Concurrency invariants:
+//
+// -- only the monitor owner may access or mutate the EntryList.
+// The mutex property of the monitor itself protects the EntryList
+// from concurrent interference.
+// -- Only the monitor owner may detach the cxq.
+//
+// * The monitor entry list operations avoid locks, but strictly speaking
+// they're not lock-free. Enter is lock-free, exit is not.
+// See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html
+//
+// * The cxq can have multiple concurrent "pushers" but only one concurrent
+// detaching thread. This mechanism is immune from the ABA corruption.
+// More precisely, the CAS-based "push" onto cxq is ABA-oblivious.
+//
+// * Taken together, the cxq and the EntryList constitute or form a
+// single logical queue of threads stalled trying to acquire the lock.
+// We use two distinct lists to improve the odds of a constant-time
+// dequeue operation after acquisition (in the ::enter() epilog) and
+// to reduce heat on the list ends. (c.f. Michael Scott's "2Q" algorithm).
+// A key desideratum is to minimize queue & monitor metadata manipulation
+// that occurs while holding the monitor lock -- that is, we want to
+// minimize monitor lock holds times. Note that even a small amount of
+// fixed spinning will greatly reduce the # of enqueue-dequeue operations
+// on EntryList|cxq. That is, spinning relieves contention on the "inner"
+// locks and monitor metadata.
+//
+// Cxq points to the the set of Recently Arrived Threads attempting entry.
+// Because we push threads onto _cxq with CAS, the RATs must take the form of
+// a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when
+// the unlocking thread notices that EntryList is null but _cxq is != null.
+//
+// The EntryList is ordered by the prevailing queue discipline and
+// can be organized in any convenient fashion, such as a doubly-linked list or
+// a circular doubly-linked list. Critically, we want insert and delete operations
+// to operate in constant-time. If we need a priority queue then something akin
+// to Solaris' sleepq would work nicely. Viz.,
+// http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.
+// Queue discipline is enforced at ::exit() time, when the unlocking thread
+// drains the cxq into the EntryList, and orders or reorders the threads on the
+// EntryList accordingly.
+//
+// Barring "lock barging", this mechanism provides fair cyclic ordering,
+// somewhat similar to an elevator-scan.
+//
+// * The monitor synchronization subsystem avoids the use of native
+// synchronization primitives except for the narrow platform-specific
+// park-unpark abstraction. See the comments in os_solaris.cpp regarding
+// the semantics of park-unpark. Put another way, this monitor implementation
+// depends only on atomic operations and park-unpark. The monitor subsystem
+// manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the
+// underlying OS manages the READY<->RUN transitions.
+//
+// * Waiting threads reside on the WaitSet list -- wait() puts
+// the caller onto the WaitSet.
+//
+// * notify() or notifyAll() simply transfers threads from the WaitSet to
+// either the EntryList or cxq. Subsequent exit() operations will
+// unpark the notifyee. Unparking a notifee in notify() is inefficient -
+// it's likely the notifyee would simply impale itself on the lock held
+// by the notifier.
+//
+// * An interesting alternative is to encode cxq as (List,LockByte) where
+// the LockByte is 0 iff the monitor is owned. _owner is simply an auxiliary
+// variable, like _recursions, in the scheme. The threads or Events that form
+// the list would have to be aligned in 256-byte addresses. A thread would
+// try to acquire the lock or enqueue itself with CAS, but exiting threads
+// could use a 1-0 protocol and simply STB to set the LockByte to 0.
+// Note that is is *not* word-tearing, but it does presume that full-word
+// CAS operations are coherent with intermix with STB operations. That's true
+// on most common processors.
+//
+// * See also http://blogs.sun.com/dave
+
+
+// -----------------------------------------------------------------------------
+// Enter support
+
+bool ObjectMonitor::try_enter(Thread* THREAD) {
+ if (THREAD != _owner) {
+ if (THREAD->is_lock_owned ((address)_owner)) {
+ assert(_recursions == 0, "internal state error");
+ _owner = THREAD ;
+ _recursions = 1 ;
+ OwnerIsThread = 1 ;
+ return true;
+ }
+ if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
+ return false;
+ }
+ return true;
+ } else {
+ _recursions++;
+ return true;
+ }
+}
+
+void ATTR ObjectMonitor::enter(TRAPS) {
+ // The following code is ordered to check the most common cases first
+ // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
+ Thread * const Self = THREAD ;
+ void * cur ;
+
+ cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
+ if (cur == NULL) {
+ // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
+ assert (_recursions == 0 , "invariant") ;
+ assert (_owner == Self, "invariant") ;
+ // CONSIDER: set or assert OwnerIsThread == 1
+ return ;
+ }
+
+ if (cur == Self) {
+ // TODO-FIXME: check for integer overflow! BUGID 6557169.
+ _recursions ++ ;
+ return ;
+ }
+
+ if (Self->is_lock_owned ((address)cur)) {
+ assert (_recursions == 0, "internal state error");
+ _recursions = 1 ;
+ // Commute owner from a thread-specific on-stack BasicLockObject address to
+ // a full-fledged "Thread *".
+ _owner = Self ;
+ OwnerIsThread = 1 ;
+ return ;
+ }
+
+ // We've encountered genuine contention.
+ assert (Self->_Stalled == 0, "invariant") ;
+ Self->_Stalled = intptr_t(this) ;
+
+ // Try one round of spinning *before* enqueueing Self
+ // and before going through the awkward and expensive state
+ // transitions. The following spin is strictly optional ...
+ // Note that if we acquire the monitor from an initial spin
+ // we forgo posting JVMTI events and firing DTRACE probes.
+ if (Knob_SpinEarly && TrySpin (Self) > 0) {
+ assert (_owner == Self , "invariant") ;
+ assert (_recursions == 0 , "invariant") ;
+ assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
+ Self->_Stalled = 0 ;
+ return ;
+ }
+
+ assert (_owner != Self , "invariant") ;
+ assert (_succ != Self , "invariant") ;
+ assert (Self->is_Java_thread() , "invariant") ;
+ JavaThread * jt = (JavaThread *) Self ;
+ assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
+ assert (jt->thread_state() != _thread_blocked , "invariant") ;
+ assert (this->object() != NULL , "invariant") ;
+ assert (_count >= 0, "invariant") ;
+
+ // Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
+ // Ensure the object-monitor relationship remains stable while there's contention.
+ Atomic::inc_ptr(&_count);
+
+ { // Change java thread status to indicate blocked on monitor enter.
+ JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
+
+ DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
+ if (JvmtiExport::should_post_monitor_contended_enter()) {
+ JvmtiExport::post_monitor_contended_enter(jt, this);
+ }
+
+ OSThreadContendState osts(Self->osthread());
+ ThreadBlockInVM tbivm(jt);
+
+ Self->set_current_pending_monitor(this);
+
+ // TODO-FIXME: change the following for(;;) loop to straight-line code.
+ for (;;) {
+ jt->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition()
+ // or java_suspend_self()
+
+ EnterI (THREAD) ;
+
+ if (!ExitSuspendEquivalent(jt)) break ;
+
+ //
+ // We have acquired the contended monitor, but while we were
+ // waiting another thread suspended us. We don't want to enter
+ // the monitor while suspended because that would surprise the
+ // thread that suspended us.
+ //
+ _recursions = 0 ;
+ _succ = NULL ;
+ exit (Self) ;
+
+ jt->java_suspend_self();
+ }
+ Self->set_current_pending_monitor(NULL);
+ }
+
+ Atomic::dec_ptr(&_count);
+ assert (_count >= 0, "invariant") ;
+ Self->_Stalled = 0 ;
+
+ // Must either set _recursions = 0 or ASSERT _recursions == 0.
+ assert (_recursions == 0 , "invariant") ;
+ assert (_owner == Self , "invariant") ;
+ assert (_succ != Self , "invariant") ;
+ assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
+
+ // The thread -- now the owner -- is back in vm mode.
+ // Report the glorious news via TI,DTrace and jvmstat.
+ // The probe effect is non-trivial. All the reportage occurs
+ // while we hold the monitor, increasing the length of the critical
+ // section. Amdahl's parallel speedup law comes vividly into play.
+ //
+ // Another option might be to aggregate the events (thread local or
+ // per-monitor aggregation) and defer reporting until a more opportune
+ // time -- such as next time some thread encounters contention but has
+ // yet to acquire the lock. While spinning that thread could
+ // spinning we could increment JVMStat counters, etc.
+
+ DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
+ if (JvmtiExport::should_post_monitor_contended_entered()) {
+ JvmtiExport::post_monitor_contended_entered(jt, this);
+ }
+ if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
+ ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
+ }
+}
+
+
+// Caveat: TryLock() is not necessarily serializing if it returns failure.
+// Callers must compensate as needed.
+
+int ObjectMonitor::TryLock (Thread * Self) {
+ for (;;) {
+ void * own = _owner ;
+ if (own != NULL) return 0 ;
+ if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
+ // Either guarantee _recursions == 0 or set _recursions = 0.
+ assert (_recursions == 0, "invariant") ;
+ assert (_owner == Self, "invariant") ;
+ // CONSIDER: set or assert that OwnerIsThread == 1
+ return 1 ;
+ }
+ // The lock had been free momentarily, but we lost the race to the lock.
+ // Interference -- the CAS failed.
+ // We can either return -1 or retry.
+ // Retry doesn't make as much sense because the lock was just acquired.
+ if (true) return -1 ;
+ }
+}
+
+void ATTR ObjectMonitor::EnterI (TRAPS) {
+ Thread * Self = THREAD ;
+ assert (Self->is_Java_thread(), "invariant") ;
+ assert (((JavaThread *) Self)->thread_state() == _thread_blocked , "invariant") ;
+
+ // Try the lock - TATAS
+ if (TryLock (Self) > 0) {
+ assert (_succ != Self , "invariant") ;
+ assert (_owner == Self , "invariant") ;
+ assert (_Responsible != Self , "invariant") ;
+ return ;
+ }
+
+ DeferredInitialize () ;
+
+ // We try one round of spinning *before* enqueueing Self.
+ //
+ // If the _owner is ready but OFFPROC we could use a YieldTo()
+ // operation to donate the remainder of this thread's quantum
+ // to the owner. This has subtle but beneficial affinity
+ // effects.
+
+ if (TrySpin (Self) > 0) {
+ assert (_owner == Self , "invariant") ;
+ assert (_succ != Self , "invariant") ;
+ assert (_Responsible != Self , "invariant") ;
+ return ;
+ }
+
+ // The Spin failed -- Enqueue and park the thread ...
+ assert (_succ != Self , "invariant") ;
+ assert (_owner != Self , "invariant") ;
+ assert (_Responsible != Self , "invariant") ;
+
+ // Enqueue "Self" on ObjectMonitor's _cxq.
+ //
+ // Node acts as a proxy for Self.
+ // As an aside, if were to ever rewrite the synchronization code mostly
+ // in Java, WaitNodes, ObjectMonitors, and Events would become 1st-class
+ // Java objects. This would avoid awkward lifecycle and liveness issues,
+ // as well as eliminate a subset of ABA issues.
+ // TODO: eliminate ObjectWaiter and enqueue either Threads or Events.
+ //
+
+ ObjectWaiter node(Self) ;
+ Self->_ParkEvent->reset() ;
+ node._prev = (ObjectWaiter *) 0xBAD ;
+ node.TState = ObjectWaiter::TS_CXQ ;
+
+ // Push "Self" onto the front of the _cxq.
+ // Once on cxq/EntryList, Self stays on-queue until it acquires the lock.
+ // Note that spinning tends to reduce the rate at which threads
+ // enqueue and dequeue on EntryList|cxq.
+ ObjectWaiter * nxt ;
+ for (;;) {
+ node._next = nxt = _cxq ;
+ if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
+
+ // Interference - the CAS failed because _cxq changed. Just retry.
+ // As an optional optimization we retry the lock.
+ if (TryLock (Self) > 0) {
+ assert (_succ != Self , "invariant") ;
+ assert (_owner == Self , "invariant") ;
+ assert (_Responsible != Self , "invariant") ;
+ return ;
+ }
+ }
+
+ // Check for cxq|EntryList edge transition to non-null. This indicates
+ // the onset of contention. While contention persists exiting threads
+ // will use a ST:MEMBAR:LD 1-1 exit protocol. When contention abates exit
+ // operations revert to the faster 1-0 mode. This enter operation may interleave
+ // (race) a concurrent 1-0 exit operation, resulting in stranding, so we
+ // arrange for one of the contending thread to use a timed park() operations
+ // to detect and recover from the race. (Stranding is form of progress failure
+ // where the monitor is unlocked but all the contending threads remain parked).
+ // That is, at least one of the contended threads will periodically poll _owner.
+ // One of the contending threads will become the designated "Responsible" thread.
+ // The Responsible thread uses a timed park instead of a normal indefinite park
+ // operation -- it periodically wakes and checks for and recovers from potential
+ // strandings admitted by 1-0 exit operations. We need at most one Responsible
+ // thread per-monitor at any given moment. Only threads on cxq|EntryList may
+ // be responsible for a monitor.
+ //
+ // Currently, one of the contended threads takes on the added role of "Responsible".
+ // A viable alternative would be to use a dedicated "stranding checker" thread
+ // that periodically iterated over all the threads (or active monitors) and unparked
+ // successors where there was risk of stranding. This would help eliminate the
+ // timer scalability issues we see on some platforms as we'd only have one thread
+ // -- the checker -- parked on a timer.
+
+ if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
+ // Try to assume the role of responsible thread for the monitor.
+ // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=Self }
+ Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
+ }
+
+ // The lock have been released while this thread was occupied queueing
+ // itself onto _cxq. To close the race and avoid "stranding" and
+ // progress-liveness failure we must resample-retry _owner before parking.
+ // Note the Dekker/Lamport duality: ST cxq; MEMBAR; LD Owner.
+ // In this case the ST-MEMBAR is accomplished with CAS().
+ //
+ // TODO: Defer all thread state transitions until park-time.
+ // Since state transitions are heavy and inefficient we'd like
+ // to defer the state transitions until absolutely necessary,
+ // and in doing so avoid some transitions ...
+
+ TEVENT (Inflated enter - Contention) ;
+ int nWakeups = 0 ;
+ int RecheckInterval = 1 ;
+
+ for (;;) {
+
+ if (TryLock (Self) > 0) break ;
+ assert (_owner != Self, "invariant") ;
+
+ if ((SyncFlags & 2) && _Responsible == NULL) {
+ Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
+ }
+
+ // park self
+ if (_Responsible == Self || (SyncFlags & 1)) {
+ TEVENT (Inflated enter - park TIMED) ;
+ Self->_ParkEvent->park ((jlong) RecheckInterval) ;
+ // Increase the RecheckInterval, but clamp the value.
+ RecheckInterval *= 8 ;
+ if (RecheckInterval > 1000) RecheckInterval = 1000 ;
+ } else {
+ TEVENT (Inflated enter - park UNTIMED) ;
+ Self->_ParkEvent->park() ;
+ }
+
+ if (TryLock(Self) > 0) break ;
+
+ // The lock is still contested.
+ // Keep a tally of the # of futile wakeups.
+ // Note that the counter is not protected by a lock or updated by atomics.
+ // That is by design - we trade "lossy" counters which are exposed to
+ // races during updates for a lower probe effect.
+ TEVENT (Inflated enter - Futile wakeup) ;
+ if (ObjectMonitor::_sync_FutileWakeups != NULL) {
+ ObjectMonitor::_sync_FutileWakeups->inc() ;
+ }
+ ++ nWakeups ;
+
+ // Assuming this is not a spurious wakeup we'll normally find _succ == Self.
+ // We can defer clearing _succ until after the spin completes
+ // TrySpin() must tolerate being called with _succ == Self.
+ // Try yet another round of adaptive spinning.
+ if ((Knob_SpinAfterFutile & 1) && TrySpin (Self) > 0) break ;
+
+ // We can find that we were unpark()ed and redesignated _succ while
+ // we were spinning. That's harmless. If we iterate and call park(),
+ // park() will consume the event and return immediately and we'll
+ // just spin again. This pattern can repeat, leaving _succ to simply
+ // spin on a CPU. Enable Knob_ResetEvent to clear pending unparks().
+ // Alternately, we can sample fired() here, and if set, forgo spinning
+ // in the next iteration.
+
+ if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
+ Self->_ParkEvent->reset() ;
+ OrderAccess::fence() ;
+ }
+ if (_succ == Self) _succ = NULL ;
+
+ // Invariant: after clearing _succ a thread *must* retry _owner before parking.
+ OrderAccess::fence() ;
+ }
+
+ // Egress :
+ // Self has acquired the lock -- Unlink Self from the cxq or EntryList.
+ // Normally we'll find Self on the EntryList .
+ // From the perspective of the lock owner (this thread), the
+ // EntryList is stable and cxq is prepend-only.
+ // The head of cxq is volatile but the interior is stable.
+ // In addition, Self.TState is stable.
+
+ assert (_owner == Self , "invariant") ;
+ assert (object() != NULL , "invariant") ;
+ // I'd like to write:
+ // guarantee (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
+ // but as we're at a safepoint that's not safe.
+
+ UnlinkAfterAcquire (Self, &node) ;
+ if (_succ == Self) _succ = NULL ;
+
+ assert (_succ != Self, "invariant") ;
+ if (_Responsible == Self) {
+ _Responsible = NULL ;
+ // Dekker pivot-point.
+ // Consider OrderAccess::storeload() here
+
+ // We may leave threads on cxq|EntryList without a designated
+ // "Responsible" thread. This is benign. When this thread subsequently
+ // exits the monitor it can "see" such preexisting "old" threads --
+ // threads that arrived on the cxq|EntryList before the fence, above --
+ // by LDing cxq|EntryList. Newly arrived threads -- that is, threads
+ // that arrive on cxq after the ST:MEMBAR, above -- will set Responsible
+ // non-null and elect a new "Responsible" timer thread.
+ //
+ // This thread executes:
+ // ST Responsible=null; MEMBAR (in enter epilog - here)
+ // LD cxq|EntryList (in subsequent exit)
+ //
+ // Entering threads in the slow/contended path execute:
+ // ST cxq=nonnull; MEMBAR; LD Responsible (in enter prolog)
+ // The (ST cxq; MEMBAR) is accomplished with CAS().
+ //
+ // The MEMBAR, above, prevents the LD of cxq|EntryList in the subsequent
+ // exit operation from floating above the ST Responsible=null.
+ //
+ // In *practice* however, EnterI() is always followed by some atomic
+ // operation such as the decrement of _count in ::enter(). Those atomics
+ // obviate the need for the explicit MEMBAR, above.
+ }
+
+ // We've acquired ownership with CAS().
+ // CAS is serializing -- it has MEMBAR/FENCE-equivalent semantics.
+ // But since the CAS() this thread may have also stored into _succ,
+ // EntryList, cxq or Responsible. These meta-data updates must be
+ // visible __before this thread subsequently drops the lock.
+ // Consider what could occur if we didn't enforce this constraint --
+ // STs to monitor meta-data and user-data could reorder with (become
+ // visible after) the ST in exit that drops ownership of the lock.
+ // Some other thread could then acquire the lock, but observe inconsistent
+ // or old monitor meta-data and heap data. That violates the JMM.
+ // To that end, the 1-0 exit() operation must have at least STST|LDST
+ // "release" barrier semantics. Specifically, there must be at least a
+ // STST|LDST barrier in exit() before the ST of null into _owner that drops
+ // the lock. The barrier ensures that changes to monitor meta-data and data
+ // protected by the lock will be visible before we release the lock, and
+ // therefore before some other thread (CPU) has a chance to acquire the lock.
+ // See also: http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
+ //
+ // Critically, any prior STs to _succ or EntryList must be visible before
+ // the ST of null into _owner in the *subsequent* (following) corresponding
+ // monitorexit. Recall too, that in 1-0 mode monitorexit does not necessarily
+ // execute a serializing instruction.
+
+ if (SyncFlags & 8) {
+ OrderAccess::fence() ;
+ }
+ return ;
+}
+
+// ReenterI() is a specialized inline form of the latter half of the
+// contended slow-path from EnterI(). We use ReenterI() only for
+// monitor reentry in wait().
+//
+// In the future we should reconcile EnterI() and ReenterI(), adding
+// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
+// loop accordingly.
+
+void ATTR ObjectMonitor::ReenterI (Thread * Self, ObjectWaiter * SelfNode) {
+ assert (Self != NULL , "invariant") ;
+ assert (SelfNode != NULL , "invariant") ;
+ assert (SelfNode->_thread == Self , "invariant") ;
+ assert (_waiters > 0 , "invariant") ;
+ assert (((oop)(object()))->mark() == markOopDesc::encode(this) , "invariant") ;
+ assert (((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
+ JavaThread * jt = (JavaThread *) Self ;
+
+ int nWakeups = 0 ;
+ for (;;) {
+ ObjectWaiter::TStates v = SelfNode->TState ;
+ guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
+ assert (_owner != Self, "invariant") ;
+
+ if (TryLock (Self) > 0) break ;
+ if (TrySpin (Self) > 0) break ;
+
+ TEVENT (Wait Reentry - parking) ;
+
+ // State transition wrappers around park() ...
+ // ReenterI() wisely defers state transitions until
+ // it's clear we must park the thread.
+ {
+ OSThreadContendState osts(Self->osthread());
+ ThreadBlockInVM tbivm(jt);
+
+ // cleared by handle_special_suspend_equivalent_condition()
+ // or java_suspend_self()
+ jt->set_suspend_equivalent();
+ if (SyncFlags & 1) {
+ Self->_ParkEvent->park ((jlong)1000) ;
+ } else {
+ Self->_ParkEvent->park () ;
+ }
+
+ // were we externally suspended while we were waiting?
+ for (;;) {
+ if (!ExitSuspendEquivalent (jt)) break ;
+ if (_succ == Self) { _succ = NULL; OrderAccess::fence(); }
+ jt->java_suspend_self();
+ jt->set_suspend_equivalent();
+ }
+ }
+
+ // Try again, but just so we distinguish between futile wakeups and
+ // successful wakeups. The following test isn't algorithmically
+ // necessary, but it helps us maintain sensible statistics.
+ if (TryLock(Self) > 0) break ;
+
+ // The lock is still contested.
+ // Keep a tally of the # of futile wakeups.
+ // Note that the counter is not protected by a lock or updated by atomics.
+ // That is by design - we trade "lossy" counters which are exposed to
+ // races during updates for a lower probe effect.
+ TEVENT (Wait Reentry - futile wakeup) ;
+ ++ nWakeups ;
+
+ // Assuming this is not a spurious wakeup we'll normally
+ // find that _succ == Self.
+ if (_succ == Self) _succ = NULL ;
+
+ // Invariant: after clearing _succ a contending thread
+ // *must* retry _owner before parking.
+ OrderAccess::fence() ;
+
+ if (ObjectMonitor::_sync_FutileWakeups != NULL) {
+ ObjectMonitor::_sync_FutileWakeups->inc() ;
+ }
+ }
+
+ // Self has acquired the lock -- Unlink Self from the cxq or EntryList .
+ // Normally we'll find Self on the EntryList.
+ // Unlinking from the EntryList is constant-time and atomic-free.
+ // From the perspective of the lock owner (this thread), the
+ // EntryList is stable and cxq is prepend-only.
+ // The head of cxq is volatile but the interior is stable.
+ // In addition, Self.TState is stable.
+
+ assert (_owner == Self, "invariant") ;
+ assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
+ UnlinkAfterAcquire (Self, SelfNode) ;
+ if (_succ == Self) _succ = NULL ;
+ assert (_succ != Self, "invariant") ;
+ SelfNode->TState = ObjectWaiter::TS_RUN ;
+ OrderAccess::fence() ; // see comments at the end of EnterI()
+}
+
+// after the thread acquires the lock in ::enter(). Equally, we could defer
+// unlinking the thread until ::exit()-time.
+
+void ObjectMonitor::UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode)
+{
+ assert (_owner == Self, "invariant") ;
+ assert (SelfNode->_thread == Self, "invariant") ;
+
+ if (SelfNode->TState == ObjectWaiter::TS_ENTER) {
+ // Normal case: remove Self from the DLL EntryList .
+ // This is a constant-time operation.
+ ObjectWaiter * nxt = SelfNode->_next ;
+ ObjectWaiter * prv = SelfNode->_prev ;
+ if (nxt != NULL) nxt->_prev = prv ;
+ if (prv != NULL) prv->_next = nxt ;
+ if (SelfNode == _EntryList ) _EntryList = nxt ;
+ assert (nxt == NULL || nxt->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ assert (prv == NULL || prv->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ TEVENT (Unlink from EntryList) ;
+ } else {
+ guarantee (SelfNode->TState == ObjectWaiter::TS_CXQ, "invariant") ;
+ // Inopportune interleaving -- Self is still on the cxq.
+ // This usually means the enqueue of self raced an exiting thread.
+ // Normally we'll find Self near the front of the cxq, so
+ // dequeueing is typically fast. If needbe we can accelerate
+ // this with some MCS/CHL-like bidirectional list hints and advisory
+ // back-links so dequeueing from the interior will normally operate
+ // in constant-time.
+ // Dequeue Self from either the head (with CAS) or from the interior
+ // with a linear-time scan and normal non-atomic memory operations.
+ // CONSIDER: if Self is on the cxq then simply drain cxq into EntryList
+ // and then unlink Self from EntryList. We have to drain eventually,
+ // so it might as well be now.
+
+ ObjectWaiter * v = _cxq ;
+ assert (v != NULL, "invariant") ;
+ if (v != SelfNode || Atomic::cmpxchg_ptr (SelfNode->_next, &_cxq, v) != v) {
+ // The CAS above can fail from interference IFF a "RAT" arrived.
+ // In that case Self must be in the interior and can no longer be
+ // at the head of cxq.
+ if (v == SelfNode) {
+ assert (_cxq != v, "invariant") ;
+ v = _cxq ; // CAS above failed - start scan at head of list
+ }
+ ObjectWaiter * p ;
+ ObjectWaiter * q = NULL ;
+ for (p = v ; p != NULL && p != SelfNode; p = p->_next) {
+ q = p ;
+ assert (p->TState == ObjectWaiter::TS_CXQ, "invariant") ;
+ }
+ assert (v != SelfNode, "invariant") ;
+ assert (p == SelfNode, "Node not found on cxq") ;
+ assert (p != _cxq, "invariant") ;
+ assert (q != NULL, "invariant") ;
+ assert (q->_next == p, "invariant") ;
+ q->_next = p->_next ;
+ }
+ TEVENT (Unlink from cxq) ;
+ }
+
+ // Diagnostic hygiene ...
+ SelfNode->_prev = (ObjectWaiter *) 0xBAD ;
+ SelfNode->_next = (ObjectWaiter *) 0xBAD ;
+ SelfNode->TState = ObjectWaiter::TS_RUN ;
+}
+
+// -----------------------------------------------------------------------------
+// Exit support
+//
+// exit()
+// ~~~~~~
+// Note that the collector can't reclaim the objectMonitor or deflate
+// the object out from underneath the thread calling ::exit() as the
+// thread calling ::exit() never transitions to a stable state.
+// This inhibits GC, which in turn inhibits asynchronous (and
+// inopportune) reclamation of "this".
+//
+// We'd like to assert that: (THREAD->thread_state() != _thread_blocked) ;
+// There's one exception to the claim above, however. EnterI() can call
+// exit() to drop a lock if the acquirer has been externally suspended.
+// In that case exit() is called with _thread_state as _thread_blocked,
+// but the monitor's _count field is > 0, which inhibits reclamation.
+//
+// 1-0 exit
+// ~~~~~~~~
+// ::exit() uses a canonical 1-1 idiom with a MEMBAR although some of
+// the fast-path operators have been optimized so the common ::exit()
+// operation is 1-0. See i486.ad fast_unlock(), for instance.
+// The code emitted by fast_unlock() elides the usual MEMBAR. This
+// greatly improves latency -- MEMBAR and CAS having considerable local
+// latency on modern processors -- but at the cost of "stranding". Absent the
+// MEMBAR, a thread in fast_unlock() can race a thread in the slow
+// ::enter() path, resulting in the entering thread being stranding
+// and a progress-liveness failure. Stranding is extremely rare.
+// We use timers (timed park operations) & periodic polling to detect
+// and recover from stranding. Potentially stranded threads periodically
+// wake up and poll the lock. See the usage of the _Responsible variable.
+//
+// The CAS() in enter provides for safety and exclusion, while the CAS or
+// MEMBAR in exit provides for progress and avoids stranding. 1-0 locking
+// eliminates the CAS/MEMBAR from the exist path, but it admits stranding.
+// We detect and recover from stranding with timers.
+//
+// If a thread transiently strands it'll park until (a) another
+// thread acquires the lock and then drops the lock, at which time the
+// exiting thread will notice and unpark the stranded thread, or, (b)
+// the timer expires. If the lock is high traffic then the stranding latency
+// will be low due to (a). If the lock is low traffic then the odds of
+// stranding are lower, although the worst-case stranding latency
+// is longer. Critically, we don't want to put excessive load in the
+// platform's timer subsystem. We want to minimize both the timer injection
+// rate (timers created/sec) as well as the number of timers active at
+// any one time. (more precisely, we want to minimize timer-seconds, which is
+// the integral of the # of active timers at any instant over time).
+// Both impinge on OS scalability. Given that, at most one thread parked on
+// a monitor will use a timer.
+
+void ATTR ObjectMonitor::exit(TRAPS) {
+ Thread * Self = THREAD ;
+ if (THREAD != _owner) {
+ if (THREAD->is_lock_owned((address) _owner)) {
+ // Transmute _owner from a BasicLock pointer to a Thread address.
+ // We don't need to hold _mutex for this transition.
+ // Non-null to Non-null is safe as long as all readers can
+ // tolerate either flavor.
+ assert (_recursions == 0, "invariant") ;
+ _owner = THREAD ;
+ _recursions = 0 ;
+ OwnerIsThread = 1 ;
+ } else {
+ // NOTE: we need to handle unbalanced monitor enter/exit
+ // in native code by throwing an exception.
+ // TODO: Throw an IllegalMonitorStateException ?
+ TEVENT (Exit - Throw IMSX) ;
+ assert(false, "Non-balanced monitor enter/exit!");
+ if (false) {
+ THROW(vmSymbols::java_lang_IllegalMonitorStateException());
+ }
+ return;
+ }
+ }
+
+ if (_recursions != 0) {
+ _recursions--; // this is simple recursive enter
+ TEVENT (Inflated exit - recursive) ;
+ return ;
+ }
+
+ // Invariant: after setting Responsible=null an thread must execute
+ // a MEMBAR or other serializing instruction before fetching EntryList|cxq.
+ if ((SyncFlags & 4) == 0) {
+ _Responsible = NULL ;
+ }
+
+ for (;;) {
+ assert (THREAD == _owner, "invariant") ;
+
+
+ if (Knob_ExitPolicy == 0) {
+ // release semantics: prior loads and stores from within the critical section
+ // must not float (reorder) past the following store that drops the lock.
+ // On SPARC that requires MEMBAR #loadstore|#storestore.
+ // But of course in TSO #loadstore|#storestore is not required.
+ // I'd like to write one of the following:
+ // A. OrderAccess::release() ; _owner = NULL
+ // B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
+ // Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
+ // store into a _dummy variable. That store is not needed, but can result
+ // in massive wasteful coherency traffic on classic SMP systems.
+ // Instead, I use release_store(), which is implemented as just a simple
+ // ST on x64, x86 and SPARC.
+ OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
+ OrderAccess::storeload() ; // See if we need to wake a successor
+ if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
+ TEVENT (Inflated exit - simple egress) ;
+ return ;
+ }
+ TEVENT (Inflated exit - complex egress) ;
+
+ // Normally the exiting thread is responsible for ensuring succession,
+ // but if other successors are ready or other entering threads are spinning
+ // then this thread can simply store NULL into _owner and exit without
+ // waking a successor. The existence of spinners or ready successors
+ // guarantees proper succession (liveness). Responsibility passes to the
+ // ready or running successors. The exiting thread delegates the duty.
+ // More precisely, if a successor already exists this thread is absolved
+ // of the responsibility of waking (unparking) one.
+ //
+ // The _succ variable is critical to reducing futile wakeup frequency.
+ // _succ identifies the "heir presumptive" thread that has been made
+ // ready (unparked) but that has not yet run. We need only one such
+ // successor thread to guarantee progress.
+ // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
+ // section 3.3 "Futile Wakeup Throttling" for details.
+ //
+ // Note that spinners in Enter() also set _succ non-null.
+ // In the current implementation spinners opportunistically set
+ // _succ so that exiting threads might avoid waking a successor.
+ // Another less appealing alternative would be for the exiting thread
+ // to drop the lock and then spin briefly to see if a spinner managed
+ // to acquire the lock. If so, the exiting thread could exit
+ // immediately without waking a successor, otherwise the exiting
+ // thread would need to dequeue and wake a successor.
+ // (Note that we'd need to make the post-drop spin short, but no
+ // shorter than the worst-case round-trip cache-line migration time.
+ // The dropped lock needs to become visible to the spinner, and then
+ // the acquisition of the lock by the spinner must become visible to
+ // the exiting thread).
+ //
+
+ // It appears that an heir-presumptive (successor) must be made ready.
+ // Only the current lock owner can manipulate the EntryList or
+ // drain _cxq, so we need to reacquire the lock. If we fail
+ // to reacquire the lock the responsibility for ensuring succession
+ // falls to the new owner.
+ //
+ if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
+ return ;
+ }
+ TEVENT (Exit - Reacquired) ;
+ } else {
+ if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
+ OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
+ OrderAccess::storeload() ;
+ // Ratify the previously observed values.
+ if (_cxq == NULL || _succ != NULL) {
+ TEVENT (Inflated exit - simple egress) ;
+ return ;
+ }
+
+ // inopportune interleaving -- the exiting thread (this thread)
+ // in the fast-exit path raced an entering thread in the slow-enter
+ // path.
+ // We have two choices:
+ // A. Try to reacquire the lock.
+ // If the CAS() fails return immediately, otherwise
+ // we either restart/rerun the exit operation, or simply
+ // fall-through into the code below which wakes a successor.
+ // B. If the elements forming the EntryList|cxq are TSM
+ // we could simply unpark() the lead thread and return
+ // without having set _succ.
+ if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
+ TEVENT (Inflated exit - reacquired succeeded) ;
+ return ;
+ }
+ TEVENT (Inflated exit - reacquired failed) ;
+ } else {
+ TEVENT (Inflated exit - complex egress) ;
+ }
+ }
+
+ guarantee (_owner == THREAD, "invariant") ;
+
+ ObjectWaiter * w = NULL ;
+ int QMode = Knob_QMode ;
+
+ if (QMode == 2 && _cxq != NULL) {
+ // QMode == 2 : cxq has precedence over EntryList.
+ // Try to directly wake a successor from the cxq.
+ // If successful, the successor will need to unlink itself from cxq.
+ w = _cxq ;
+ assert (w != NULL, "invariant") ;
+ assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
+ ExitEpilog (Self, w) ;
+ return ;
+ }
+
+ if (QMode == 3 && _cxq != NULL) {
+ // Aggressively drain cxq into EntryList at the first opportunity.
+ // This policy ensure that recently-run threads live at the head of EntryList.
+ // Drain _cxq into EntryList - bulk transfer.
+ // First, detach _cxq.
+ // The following loop is tantamount to: w = swap (&cxq, NULL)
+ w = _cxq ;
+ for (;;) {
+ assert (w != NULL, "Invariant") ;
+ ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
+ if (u == w) break ;
+ w = u ;
+ }
+ assert (w != NULL , "invariant") ;
+
+ ObjectWaiter * q = NULL ;
+ ObjectWaiter * p ;
+ for (p = w ; p != NULL ; p = p->_next) {
+ guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
+ p->TState = ObjectWaiter::TS_ENTER ;
+ p->_prev = q ;
+ q = p ;
+ }
+
+ // Append the RATs to the EntryList
+ // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
+ ObjectWaiter * Tail ;
+ for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
+ if (Tail == NULL) {
+ _EntryList = w ;
+ } else {
+ Tail->_next = w ;
+ w->_prev = Tail ;
+ }
+
+ // Fall thru into code that tries to wake a successor from EntryList
+ }
+
+ if (QMode == 4 && _cxq != NULL) {
+ // Aggressively drain cxq into EntryList at the first opportunity.
+ // This policy ensure that recently-run threads live at the head of EntryList.
+
+ // Drain _cxq into EntryList - bulk transfer.
+ // First, detach _cxq.
+ // The following loop is tantamount to: w = swap (&cxq, NULL)
+ w = _cxq ;
+ for (;;) {
+ assert (w != NULL, "Invariant") ;
+ ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
+ if (u == w) break ;
+ w = u ;
+ }
+ assert (w != NULL , "invariant") ;
+
+ ObjectWaiter * q = NULL ;
+ ObjectWaiter * p ;
+ for (p = w ; p != NULL ; p = p->_next) {
+ guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
+ p->TState = ObjectWaiter::TS_ENTER ;
+ p->_prev = q ;
+ q = p ;
+ }
+
+ // Prepend the RATs to the EntryList
+ if (_EntryList != NULL) {
+ q->_next = _EntryList ;
+ _EntryList->_prev = q ;
+ }
+ _EntryList = w ;
+
+ // Fall thru into code that tries to wake a successor from EntryList
+ }
+
+ w = _EntryList ;
+ if (w != NULL) {
+ // I'd like to write: guarantee (w->_thread != Self).
+ // But in practice an exiting thread may find itself on the EntryList.
+ // Lets say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and
+ // then calls exit(). Exit release the lock by setting O._owner to NULL.
+ // Lets say T1 then stalls. T2 acquires O and calls O.notify(). The
+ // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
+ // release the lock "O". T2 resumes immediately after the ST of null into
+ // _owner, above. T2 notices that the EntryList is populated, so it
+ // reacquires the lock and then finds itself on the EntryList.
+ // Given all that, we have to tolerate the circumstance where "w" is
+ // associated with Self.
+ assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ ExitEpilog (Self, w) ;
+ return ;
+ }
+
+ // If we find that both _cxq and EntryList are null then just
+ // re-run the exit protocol from the top.
+ w = _cxq ;
+ if (w == NULL) continue ;
+
+ // Drain _cxq into EntryList - bulk transfer.
+ // First, detach _cxq.
+ // The following loop is tantamount to: w = swap (&cxq, NULL)
+ for (;;) {
+ assert (w != NULL, "Invariant") ;
+ ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
+ if (u == w) break ;
+ w = u ;
+ }
+ TEVENT (Inflated exit - drain cxq into EntryList) ;
+
+ assert (w != NULL , "invariant") ;
+ assert (_EntryList == NULL , "invariant") ;
+
+ // Convert the LIFO SLL anchored by _cxq into a DLL.
+ // The list reorganization step operates in O(LENGTH(w)) time.
+ // It's critical that this step operate quickly as
+ // "Self" still holds the outer-lock, restricting parallelism
+ // and effectively lengthening the critical section.
+ // Invariant: s chases t chases u.
+ // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
+ // we have faster access to the tail.
+
+ if (QMode == 1) {
+ // QMode == 1 : drain cxq to EntryList, reversing order
+ // We also reverse the order of the list.
+ ObjectWaiter * s = NULL ;
+ ObjectWaiter * t = w ;
+ ObjectWaiter * u = NULL ;
+ while (t != NULL) {
+ guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
+ t->TState = ObjectWaiter::TS_ENTER ;
+ u = t->_next ;
+ t->_prev = u ;
+ t->_next = s ;
+ s = t;
+ t = u ;
+ }
+ _EntryList = s ;
+ assert (s != NULL, "invariant") ;
+ } else {
+ // QMode == 0 or QMode == 2
+ _EntryList = w ;
+ ObjectWaiter * q = NULL ;
+ ObjectWaiter * p ;
+ for (p = w ; p != NULL ; p = p->_next) {
+ guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
+ p->TState = ObjectWaiter::TS_ENTER ;
+ p->_prev = q ;
+ q = p ;
+ }
+ }
+
+ // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
+ // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
+
+ // See if we can abdicate to a spinner instead of waking a thread.
+ // A primary goal of the implementation is to reduce the
+ // context-switch rate.
+ if (_succ != NULL) continue;
+
+ w = _EntryList ;
+ if (w != NULL) {
+ guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ ExitEpilog (Self, w) ;
+ return ;
+ }
+ }
+}
+
+// ExitSuspendEquivalent:
+// A faster alternate to handle_special_suspend_equivalent_condition()
+//
+// handle_special_suspend_equivalent_condition() unconditionally
+// acquires the SR_lock. On some platforms uncontended MutexLocker()
+// operations have high latency. Note that in ::enter() we call HSSEC
+// while holding the monitor, so we effectively lengthen the critical sections.
+//
+// There are a number of possible solutions:
+//
+// A. To ameliorate the problem we might also defer state transitions
+// to as late as possible -- just prior to parking.
+// Given that, we'd call HSSEC after having returned from park(),
+// but before attempting to acquire the monitor. This is only a
+// partial solution. It avoids calling HSSEC while holding the
+// monitor (good), but it still increases successor reacquisition latency --
+// the interval between unparking a successor and the time the successor
+// resumes and retries the lock. See ReenterI(), which defers state transitions.
+// If we use this technique we can also avoid EnterI()-exit() loop
+// in ::enter() where we iteratively drop the lock and then attempt
+// to reacquire it after suspending.
+//
+// B. In the future we might fold all the suspend bits into a
+// composite per-thread suspend flag and then update it with CAS().
+// Alternately, a Dekker-like mechanism with multiple variables
+// would suffice:
+// ST Self->_suspend_equivalent = false
+// MEMBAR
+// LD Self_>_suspend_flags
+//
+
+
+bool ObjectMonitor::ExitSuspendEquivalent (JavaThread * jSelf) {
+ int Mode = Knob_FastHSSEC ;
+ if (Mode && !jSelf->is_external_suspend()) {
+ assert (jSelf->is_suspend_equivalent(), "invariant") ;
+ jSelf->clear_suspend_equivalent() ;
+ if (2 == Mode) OrderAccess::storeload() ;
+ if (!jSelf->is_external_suspend()) return false ;
+ // We raced a suspension -- fall thru into the slow path
+ TEVENT (ExitSuspendEquivalent - raced) ;
+ jSelf->set_suspend_equivalent() ;
+ }
+ return jSelf->handle_special_suspend_equivalent_condition() ;
+}
+
+
+void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
+ assert (_owner == Self, "invariant") ;
+
+ // Exit protocol:
+ // 1. ST _succ = wakee
+ // 2. membar #loadstore|#storestore;
+ // 2. ST _owner = NULL
+ // 3. unpark(wakee)
+
+ _succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
+ ParkEvent * Trigger = Wakee->_event ;
+
+ // Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
+ // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
+ // out-of-scope (non-extant).
+ Wakee = NULL ;
+
+ // Drop the lock
+ OrderAccess::release_store_ptr (&_owner, NULL) ;
+ OrderAccess::fence() ; // ST _owner vs LD in unpark()
+
+ if (SafepointSynchronize::do_call_back()) {
+ TEVENT (unpark before SAFEPOINT) ;
+ }
+
+ DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
+ Trigger->unpark() ;
+
+ // Maintain stats and report events to JVMTI
+ if (ObjectMonitor::_sync_Parks != NULL) {
+ ObjectMonitor::_sync_Parks->inc() ;
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// Class Loader deadlock handling.
+//
+// complete_exit exits a lock returning recursion count
+// complete_exit/reenter operate as a wait without waiting
+// complete_exit requires an inflated monitor
+// The _owner field is not always the Thread addr even with an
+// inflated monitor, e.g. the monitor can be inflated by a non-owning
+// thread due to contention.
+intptr_t ObjectMonitor::complete_exit(TRAPS) {
+ Thread * const Self = THREAD;
+ assert(Self->is_Java_thread(), "Must be Java thread!");
+ JavaThread *jt = (JavaThread *)THREAD;
+
+ DeferredInitialize();
+
+ if (THREAD != _owner) {
+ if (THREAD->is_lock_owned ((address)_owner)) {
+ assert(_recursions == 0, "internal state error");
+ _owner = THREAD ; /* Convert from basiclock addr to Thread addr */
+ _recursions = 0 ;
+ OwnerIsThread = 1 ;
+ }
+ }
+
+ guarantee(Self == _owner, "complete_exit not owner");
+ intptr_t save = _recursions; // record the old recursion count
+ _recursions = 0; // set the recursion level to be 0
+ exit (Self) ; // exit the monitor
+ guarantee (_owner != Self, "invariant");
+ return save;
+}
+
+// reenter() enters a lock and sets recursion count
+// complete_exit/reenter operate as a wait without waiting
+void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
+ Thread * const Self = THREAD;
+ assert(Self->is_Java_thread(), "Must be Java thread!");
+ JavaThread *jt = (JavaThread *)THREAD;
+
+ guarantee(_owner != Self, "reenter already owner");
+ enter (THREAD); // enter the monitor
+ guarantee (_recursions == 0, "reenter recursion");
+ _recursions = recursions;
+ return;
+}
+
+
+// -----------------------------------------------------------------------------
+// A macro is used below because there may already be a pending
+// exception which should not abort the execution of the routines
+// which use this (which is why we don't put this into check_slow and
+// call it with a CHECK argument).
+
+#define CHECK_OWNER() \
+ do { \
+ if (THREAD != _owner) { \
+ if (THREAD->is_lock_owned((address) _owner)) { \
+ _owner = THREAD ; /* Convert from basiclock addr to Thread addr */ \
+ _recursions = 0; \
+ OwnerIsThread = 1 ; \
+ } else { \
+ TEVENT (Throw IMSX) ; \
+ THROW(vmSymbols::java_lang_IllegalMonitorStateException()); \
+ } \
+ } \
+ } while (false)
+
+// check_slow() is a misnomer. It's called to simply to throw an IMSX exception.
+// TODO-FIXME: remove check_slow() -- it's likely dead.
+
+void ObjectMonitor::check_slow(TRAPS) {
+ TEVENT (check_slow - throw IMSX) ;
+ assert(THREAD != _owner && !THREAD->is_lock_owned((address) _owner), "must not be owner");
+ THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
+}
+
+static int Adjust (volatile int * adr, int dx) {
+ int v ;
+ for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
+ return v ;
+}
+// -----------------------------------------------------------------------------
+// Wait/Notify/NotifyAll
+//
+// Note: a subset of changes to ObjectMonitor::wait()
+// will need to be replicated in complete_exit above
+void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
+ Thread * const Self = THREAD ;
+ assert(Self->is_Java_thread(), "Must be Java thread!");
+ JavaThread *jt = (JavaThread *)THREAD;
+
+ DeferredInitialize () ;
+
+ // Throw IMSX or IEX.
+ CHECK_OWNER();
+
+ // check for a pending interrupt
+ if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
+ // post monitor waited event. Note that this is past-tense, we are done waiting.
+ if (JvmtiExport::should_post_monitor_waited()) {
+ // Note: 'false' parameter is passed here because the
+ // wait was not timed out due to thread interrupt.
+ JvmtiExport::post_monitor_waited(jt, this, false);
+ }
+ TEVENT (Wait - Throw IEX) ;
+ THROW(vmSymbols::java_lang_InterruptedException());
+ return ;
+ }
+ TEVENT (Wait) ;
+
+ assert (Self->_Stalled == 0, "invariant") ;
+ Self->_Stalled = intptr_t(this) ;
+ jt->set_current_waiting_monitor(this);
+
+ // create a node to be put into the queue
+ // Critically, after we reset() the event but prior to park(), we must check
+ // for a pending interrupt.
+ ObjectWaiter node(Self);
+ node.TState = ObjectWaiter::TS_WAIT ;
+ Self->_ParkEvent->reset() ;
+ OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
+
+ // Enter the waiting queue, which is a circular doubly linked list in this case
+ // but it could be a priority queue or any data structure.
+ // _WaitSetLock protects the wait queue. Normally the wait queue is accessed only
+ // by the the owner of the monitor *except* in the case where park()
+ // returns because of a timeout of interrupt. Contention is exceptionally rare
+ // so we use a simple spin-lock instead of a heavier-weight blocking lock.
+
+ Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
+ AddWaiter (&node) ;
+ Thread::SpinRelease (&_WaitSetLock) ;
+
+ if ((SyncFlags & 4) == 0) {
+ _Responsible = NULL ;
+ }
+ intptr_t save = _recursions; // record the old recursion count
+ _waiters++; // increment the number of waiters
+ _recursions = 0; // set the recursion level to be 1
+ exit (Self) ; // exit the monitor
+ guarantee (_owner != Self, "invariant") ;
+
+ // As soon as the ObjectMonitor's ownership is dropped in the exit()
+ // call above, another thread can enter() the ObjectMonitor, do the
+ // notify(), and exit() the ObjectMonitor. If the other thread's
+ // exit() call chooses this thread as the successor and the unpark()
+ // call happens to occur while this thread is posting a
+ // MONITOR_CONTENDED_EXIT event, then we run the risk of the event
+ // handler using RawMonitors and consuming the unpark().
+ //
+ // To avoid the problem, we re-post the event. This does no harm
+ // even if the original unpark() was not consumed because we are the
+ // chosen successor for this monitor.
+ if (node._notified != 0 && _succ == Self) {
+ node._event->unpark();
+ }
+
+ // The thread is on the WaitSet list - now park() it.
+ // On MP systems it's conceivable that a brief spin before we park
+ // could be profitable.
+ //
+ // TODO-FIXME: change the following logic to a loop of the form
+ // while (!timeout && !interrupted && _notified == 0) park()
+
+ int ret = OS_OK ;
+ int WasNotified = 0 ;
+ { // State transition wrappers
+ OSThread* osthread = Self->osthread();
+ OSThreadWaitState osts(osthread, true);
+ {
+ ThreadBlockInVM tbivm(jt);
+ // Thread is in thread_blocked state and oop access is unsafe.
+ jt->set_suspend_equivalent();
+
+ if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
+ // Intentionally empty
+ } else
+ if (node._notified == 0) {
+ if (millis <= 0) {
+ Self->_ParkEvent->park () ;
+ } else {
+ ret = Self->_ParkEvent->park (millis) ;
+ }
+ }
+
+ // were we externally suspended while we were waiting?
+ if (ExitSuspendEquivalent (jt)) {
+ // TODO-FIXME: add -- if succ == Self then succ = null.
+ jt->java_suspend_self();
+ }
+
+ } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
+
+
+ // Node may be on the WaitSet, the EntryList (or cxq), or in transition
+ // from the WaitSet to the EntryList.
+ // See if we need to remove Node from the WaitSet.
+ // We use double-checked locking to avoid grabbing _WaitSetLock
+ // if the thread is not on the wait queue.
+ //
+ // Note that we don't need a fence before the fetch of TState.
+ // In the worst case we'll fetch a old-stale value of TS_WAIT previously
+ // written by the is thread. (perhaps the fetch might even be satisfied
+ // by a look-aside into the processor's own store buffer, although given
+ // the length of the code path between the prior ST and this load that's
+ // highly unlikely). If the following LD fetches a stale TS_WAIT value
+ // then we'll acquire the lock and then re-fetch a fresh TState value.
+ // That is, we fail toward safety.
+
+ if (node.TState == ObjectWaiter::TS_WAIT) {
+ Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
+ if (node.TState == ObjectWaiter::TS_WAIT) {
+ DequeueSpecificWaiter (&node) ; // unlink from WaitSet
+ assert(node._notified == 0, "invariant");
+ node.TState = ObjectWaiter::TS_RUN ;
+ }
+ Thread::SpinRelease (&_WaitSetLock) ;
+ }
+
+ // The thread is now either on off-list (TS_RUN),
+ // on the EntryList (TS_ENTER), or on the cxq (TS_CXQ).
+ // The Node's TState variable is stable from the perspective of this thread.
+ // No other threads will asynchronously modify TState.
+ guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ;
+ OrderAccess::loadload() ;
+ if (_succ == Self) _succ = NULL ;
+ WasNotified = node._notified ;
+
+ // Reentry phase -- reacquire the monitor.
+ // re-enter contended monitor after object.wait().
+ // retain OBJECT_WAIT state until re-enter successfully completes
+ // Thread state is thread_in_vm and oop access is again safe,
+ // although the raw address of the object may have changed.
+ // (Don't cache naked oops over safepoints, of course).
+
+ // post monitor waited event. Note that this is past-tense, we are done waiting.
+ if (JvmtiExport::should_post_monitor_waited()) {
+ JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
+ }
+ OrderAccess::fence() ;
+
+ assert (Self->_Stalled != 0, "invariant") ;
+ Self->_Stalled = 0 ;
+
+ assert (_owner != Self, "invariant") ;
+ ObjectWaiter::TStates v = node.TState ;
+ if (v == ObjectWaiter::TS_RUN) {
+ enter (Self) ;
+ } else {
+ guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
+ ReenterI (Self, &node) ;
+ node.wait_reenter_end(this);
+ }
+
+ // Self has reacquired the lock.
+ // Lifecycle - the node representing Self must not appear on any queues.
+ // Node is about to go out-of-scope, but even if it were immortal we wouldn't
+ // want residual elements associated with this thread left on any lists.
+ guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ;
+ assert (_owner == Self, "invariant") ;
+ assert (_succ != Self , "invariant") ;
+ } // OSThreadWaitState()
+
+ jt->set_current_waiting_monitor(NULL);
+
+ guarantee (_recursions == 0, "invariant") ;
+ _recursions = save; // restore the old recursion count
+ _waiters--; // decrement the number of waiters
+
+ // Verify a few postconditions
+ assert (_owner == Self , "invariant") ;
+ assert (_succ != Self , "invariant") ;
+ assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
+
+ if (SyncFlags & 32) {
+ OrderAccess::fence() ;
+ }
+
+ // check if the notification happened
+ if (!WasNotified) {
+ // no, it could be timeout or Thread.interrupt() or both
+ // check for interrupt event, otherwise it is timeout
+ if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
+ TEVENT (Wait - throw IEX from epilog) ;
+ THROW(vmSymbols::java_lang_InterruptedException());
+ }
+ }
+
+ // NOTE: Spurious wake up will be consider as timeout.
+ // Monitor notify has precedence over thread interrupt.
+}
+
+
+// Consider:
+// If the lock is cool (cxq == null && succ == null) and we're on an MP system
+// then instead of transferring a thread from the WaitSet to the EntryList
+// we might just dequeue a thread from the WaitSet and directly unpark() it.
+
+void ObjectMonitor::notify(TRAPS) {
+ CHECK_OWNER();
+ if (_WaitSet == NULL) {
+ TEVENT (Empty-Notify) ;
+ return ;
+ }
+ DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
+
+ int Policy = Knob_MoveNotifyee ;
+
+ Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
+ ObjectWaiter * iterator = DequeueWaiter() ;
+ if (iterator != NULL) {
+ TEVENT (Notify1 - Transfer) ;
+ guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
+ guarantee (iterator->_notified == 0, "invariant") ;
+ if (Policy != 4) {
+ iterator->TState = ObjectWaiter::TS_ENTER ;
+ }
+ iterator->_notified = 1 ;
+
+ ObjectWaiter * List = _EntryList ;
+ if (List != NULL) {
+ assert (List->_prev == NULL, "invariant") ;
+ assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ assert (List != iterator, "invariant") ;
+ }
+
+ if (Policy == 0) { // prepend to EntryList
+ if (List == NULL) {
+ iterator->_next = iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ } else {
+ List->_prev = iterator ;
+ iterator->_next = List ;
+ iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ }
+ } else
+ if (Policy == 1) { // append to EntryList
+ if (List == NULL) {
+ iterator->_next = iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ } else {
+ // CONSIDER: finding the tail currently requires a linear-time walk of
+ // the EntryList. We can make tail access constant-time by converting to
+ // a CDLL instead of using our current DLL.
+ ObjectWaiter * Tail ;
+ for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
+ assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
+ Tail->_next = iterator ;
+ iterator->_prev = Tail ;
+ iterator->_next = NULL ;
+ }
+ } else
+ if (Policy == 2) { // prepend to cxq
+ // prepend to cxq
+ if (List == NULL) {
+ iterator->_next = iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ } else {
+ iterator->TState = ObjectWaiter::TS_CXQ ;
+ for (;;) {
+ ObjectWaiter * Front = _cxq ;
+ iterator->_next = Front ;
+ if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
+ break ;
+ }
+ }
+ }
+ } else
+ if (Policy == 3) { // append to cxq
+ iterator->TState = ObjectWaiter::TS_CXQ ;
+ for (;;) {
+ ObjectWaiter * Tail ;
+ Tail = _cxq ;
+ if (Tail == NULL) {
+ iterator->_next = NULL ;
+ if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
+ break ;
+ }
+ } else {
+ while (Tail->_next != NULL) Tail = Tail->_next ;
+ Tail->_next = iterator ;
+ iterator->_prev = Tail ;
+ iterator->_next = NULL ;
+ break ;
+ }
+ }
+ } else {
+ ParkEvent * ev = iterator->_event ;
+ iterator->TState = ObjectWaiter::TS_RUN ;
+ OrderAccess::fence() ;
+ ev->unpark() ;
+ }
+
+ if (Policy < 4) {
+ iterator->wait_reenter_begin(this);
+ }
+
+ // _WaitSetLock protects the wait queue, not the EntryList. We could
+ // move the add-to-EntryList operation, above, outside the critical section
+ // protected by _WaitSetLock. In practice that's not useful. With the
+ // exception of wait() timeouts and interrupts the monitor owner
+ // is the only thread that grabs _WaitSetLock. There's almost no contention
+ // on _WaitSetLock so it's not profitable to reduce the length of the
+ // critical section.
+ }
+
+ Thread::SpinRelease (&_WaitSetLock) ;
+
+ if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
+ ObjectMonitor::_sync_Notifications->inc() ;
+ }
+}
+
+
+void ObjectMonitor::notifyAll(TRAPS) {
+ CHECK_OWNER();
+ ObjectWaiter* iterator;
+ if (_WaitSet == NULL) {
+ TEVENT (Empty-NotifyAll) ;
+ return ;
+ }
+ DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
+
+ int Policy = Knob_MoveNotifyee ;
+ int Tally = 0 ;
+ Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
+
+ for (;;) {
+ iterator = DequeueWaiter () ;
+ if (iterator == NULL) break ;
+ TEVENT (NotifyAll - Transfer1) ;
+ ++Tally ;
+
+ // Disposition - what might we do with iterator ?
+ // a. add it directly to the EntryList - either tail or head.
+ // b. push it onto the front of the _cxq.
+ // For now we use (a).
+
+ guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
+ guarantee (iterator->_notified == 0, "invariant") ;
+ iterator->_notified = 1 ;
+ if (Policy != 4) {
+ iterator->TState = ObjectWaiter::TS_ENTER ;
+ }
+
+ ObjectWaiter * List = _EntryList ;
+ if (List != NULL) {
+ assert (List->_prev == NULL, "invariant") ;
+ assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
+ assert (List != iterator, "invariant") ;
+ }
+
+ if (Policy == 0) { // prepend to EntryList
+ if (List == NULL) {
+ iterator->_next = iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ } else {
+ List->_prev = iterator ;
+ iterator->_next = List ;
+ iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ }
+ } else
+ if (Policy == 1) { // append to EntryList
+ if (List == NULL) {
+ iterator->_next = iterator->_prev = NULL ;
+ _EntryList = iterator ;
+ } else {
+ // CONSIDER: finding the tail currently requires a linear-time walk of
+ // the EntryList. We can make tail access constant-time by converting to
+ // a CDLL instead of using our current DLL.
+ ObjectWaiter * Tail ;
+ for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
+ assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
+ Tail->_next = iterator ;
+ iterator->_prev = Tail ;
+ iterator->_next = NULL ;
+ }
+ } else
+ if (Policy == 2) { // prepend to cxq
+ // prepend to cxq
+ iterator->TState = ObjectWaiter::TS_CXQ ;
+ for (;;) {
+ ObjectWaiter * Front = _cxq ;
+ iterator->_next = Front ;
+ if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
+ break ;
+ }
+ }
+ } else
+ if (Policy == 3) { // append to cxq
+ iterator->TState = ObjectWaiter::TS_CXQ ;
+ for (;;) {
+ ObjectWaiter * Tail ;
+ Tail = _cxq ;
+ if (Tail == NULL) {
+ iterator->_next = NULL ;
+ if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
+ break ;
+ }
+ } else {
+ while (Tail->_next != NULL) Tail = Tail->_next ;
+ Tail->_next = iterator ;
+ iterator->_prev = Tail ;
+ iterator->_next = NULL ;
+ break ;
+ }
+ }
+ } else {
+ ParkEvent * ev = iterator->_event ;
+ iterator->TState = ObjectWaiter::TS_RUN ;
+ OrderAccess::fence() ;
+ ev->unpark() ;
+ }
+
+ if (Policy < 4) {
+ iterator->wait_reenter_begin(this);
+ }
+
+ // _WaitSetLock protects the wait queue, not the EntryList. We could
+ // move the add-to-EntryList operation, above, outside the critical section
+ // protected by _WaitSetLock. In practice that's not useful. With the
+ // exception of wait() timeouts and interrupts the monitor owner
+ // is the only thread that grabs _WaitSetLock. There's almost no contention
+ // on _WaitSetLock so it's not profitable to reduce the length of the
+ // critical section.
+ }
+
+ Thread::SpinRelease (&_WaitSetLock) ;
+
+ if (Tally != 0 && ObjectMonitor::_sync_Notifications != NULL) {
+ ObjectMonitor::_sync_Notifications->inc(Tally) ;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Adaptive Spinning Support
+//
+// Adaptive spin-then-block - rational spinning
+//
+// Note that we spin "globally" on _owner with a classic SMP-polite TATAS
+// algorithm. On high order SMP systems it would be better to start with
+// a brief global spin and then revert to spinning locally. In the spirit of MCS/CLH,
+// a contending thread could enqueue itself on the cxq and then spin locally
+// on a thread-specific variable such as its ParkEvent._Event flag.
+// That's left as an exercise for the reader. Note that global spinning is
+// not problematic on Niagara, as the L2$ serves the interconnect and has both
+// low latency and massive bandwidth.
+//
+// Broadly, we can fix the spin frequency -- that is, the % of contended lock
+// acquisition attempts where we opt to spin -- at 100% and vary the spin count
+// (duration) or we can fix the count at approximately the duration of
+// a context switch and vary the frequency. Of course we could also
+// vary both satisfying K == Frequency * Duration, where K is adaptive by monitor.
+// See http://j2se.east/~dice/PERSIST/040824-AdaptiveSpinning.html.
+//
+// This implementation varies the duration "D", where D varies with
+// the success rate of recent spin attempts. (D is capped at approximately
+// length of a round-trip context switch). The success rate for recent
+// spin attempts is a good predictor of the success rate of future spin
+// attempts. The mechanism adapts automatically to varying critical
+// section length (lock modality), system load and degree of parallelism.
+// D is maintained per-monitor in _SpinDuration and is initialized
+// optimistically. Spin frequency is fixed at 100%.
+//
+// Note that _SpinDuration is volatile, but we update it without locks
+// or atomics. The code is designed so that _SpinDuration stays within
+// a reasonable range even in the presence of races. The arithmetic
+// operations on _SpinDuration are closed over the domain of legal values,
+// so at worst a race will install and older but still legal value.
+// At the very worst this introduces some apparent non-determinism.
+// We might spin when we shouldn't or vice-versa, but since the spin
+// count are relatively short, even in the worst case, the effect is harmless.
+//
+// Care must be taken that a low "D" value does not become an
+// an absorbing state. Transient spinning failures -- when spinning
+// is overall profitable -- should not cause the system to converge
+// on low "D" values. We want spinning to be stable and predictable
+// and fairly responsive to change and at the same time we don't want
+// it to oscillate, become metastable, be "too" non-deterministic,
+// or converge on or enter undesirable stable absorbing states.
+//
+// We implement a feedback-based control system -- using past behavior
+// to predict future behavior. We face two issues: (a) if the
+// input signal is random then the spin predictor won't provide optimal
+// results, and (b) if the signal frequency is too high then the control
+// system, which has some natural response lag, will "chase" the signal.
+// (b) can arise from multimodal lock hold times. Transient preemption
+// can also result in apparent bimodal lock hold times.
+// Although sub-optimal, neither condition is particularly harmful, as
+// in the worst-case we'll spin when we shouldn't or vice-versa.
+// The maximum spin duration is rather short so the failure modes aren't bad.
+// To be conservative, I've tuned the gain in system to bias toward
+// _not spinning. Relatedly, the system can sometimes enter a mode where it
+// "rings" or oscillates between spinning and not spinning. This happens
+// when spinning is just on the cusp of profitability, however, so the
+// situation is not dire. The state is benign -- there's no need to add
+// hysteresis control to damp the transition rate between spinning and
+// not spinning.
+//
+
+intptr_t ObjectMonitor::SpinCallbackArgument = 0 ;
+int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL ;
+
+// Spinning: Fixed frequency (100%), vary duration
+
+
+int ObjectMonitor::TrySpin_VaryDuration (Thread * Self) {
+
+ // Dumb, brutal spin. Good for comparative measurements against adaptive spinning.
+ int ctr = Knob_FixedSpin ;
+ if (ctr != 0) {
+ while (--ctr >= 0) {
+ if (TryLock (Self) > 0) return 1 ;
+ SpinPause () ;
+ }
+ return 0 ;
+ }
+
+ for (ctr = Knob_PreSpin + 1; --ctr >= 0 ; ) {
+ if (TryLock(Self) > 0) {
+ // Increase _SpinDuration ...
+ // Note that we don't clamp SpinDuration precisely at SpinLimit.
+ // Raising _SpurDuration to the poverty line is key.
+ int x = _SpinDuration ;
+ if (x < Knob_SpinLimit) {
+ if (x < Knob_Poverty) x = Knob_Poverty ;
+ _SpinDuration = x + Knob_BonusB ;
+ }
+ return 1 ;
+ }
+ SpinPause () ;
+ }
+
+ // Admission control - verify preconditions for spinning
+ //
+ // We always spin a little bit, just to prevent _SpinDuration == 0 from
+ // becoming an absorbing state. Put another way, we spin briefly to
+ // sample, just in case the system load, parallelism, contention, or lock
+ // modality changed.
+ //
+ // Consider the following alternative:
+ // Periodically set _SpinDuration = _SpinLimit and try a long/full
+ // spin attempt. "Periodically" might mean after a tally of
+ // the # of failed spin attempts (or iterations) reaches some threshold.
+ // This takes us into the realm of 1-out-of-N spinning, where we
+ // hold the duration constant but vary the frequency.
+
+ ctr = _SpinDuration ;
+ if (ctr < Knob_SpinBase) ctr = Knob_SpinBase ;
+ if (ctr <= 0) return 0 ;
+
+ if (Knob_SuccRestrict && _succ != NULL) return 0 ;
+ if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
+ TEVENT (Spin abort - notrunnable [TOP]);
+ return 0 ;
+ }
+
+ int MaxSpin = Knob_MaxSpinners ;
+ if (MaxSpin >= 0) {
+ if (_Spinner > MaxSpin) {
+ TEVENT (Spin abort -- too many spinners) ;
+ return 0 ;
+ }
+ // Slighty racy, but benign ...
+ Adjust (&_Spinner, 1) ;
+ }
+
+ // We're good to spin ... spin ingress.
+ // CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
+ // when preparing to LD...CAS _owner, etc and the CAS is likely
+ // to succeed.
+ int hits = 0 ;
+ int msk = 0 ;
+ int caspty = Knob_CASPenalty ;
+ int oxpty = Knob_OXPenalty ;
+ int sss = Knob_SpinSetSucc ;
+ if (sss && _succ == NULL ) _succ = Self ;
+ Thread * prv = NULL ;
+
+ // There are three ways to exit the following loop:
+ // 1. A successful spin where this thread has acquired the lock.
+ // 2. Spin failure with prejudice
+ // 3. Spin failure without prejudice
+
+ while (--ctr >= 0) {
+
+ // Periodic polling -- Check for pending GC
+ // Threads may spin while they're unsafe.
+ // We don't want spinning threads to delay the JVM from reaching
+ // a stop-the-world safepoint or to steal cycles from GC.
+ // If we detect a pending safepoint we abort in order that
+ // (a) this thread, if unsafe, doesn't delay the safepoint, and (b)
+ // this thread, if safe, doesn't steal cycles from GC.
+ // This is in keeping with the "no loitering in runtime" rule.
+ // We periodically check to see if there's a safepoint pending.
+ if ((ctr & 0xFF) == 0) {
+ if (SafepointSynchronize::do_call_back()) {
+ TEVENT (Spin: safepoint) ;
+ goto Abort ; // abrupt spin egress
+ }
+ if (Knob_UsePause & 1) SpinPause () ;
+
+ int (*scb)(intptr_t,int) = SpinCallbackFunction ;
+ if (hits > 50 && scb != NULL) {
+ int abend = (*scb)(SpinCallbackArgument, 0) ;
+ }
+ }
+
+ if (Knob_UsePause & 2) SpinPause() ;
+
+ // Exponential back-off ... Stay off the bus to reduce coherency traffic.
+ // This is useful on classic SMP systems, but is of less utility on
+ // N1-style CMT platforms.
+ //
+ // Trade-off: lock acquisition latency vs coherency bandwidth.
+ // Lock hold times are typically short. A histogram
+ // of successful spin attempts shows that we usually acquire
+ // the lock early in the spin. That suggests we want to
+ // sample _owner frequently in the early phase of the spin,
+ // but then back-off and sample less frequently as the spin
+ // progresses. The back-off makes a good citizen on SMP big
+ // SMP systems. Oversampling _owner can consume excessive
+ // coherency bandwidth. Relatedly, if we _oversample _owner we
+ // can inadvertently interfere with the the ST m->owner=null.
+ // executed by the lock owner.
+ if (ctr & msk) continue ;
+ ++hits ;
+ if ((hits & 0xF) == 0) {
+ // The 0xF, above, corresponds to the exponent.
+ // Consider: (msk+1)|msk
+ msk = ((msk << 2)|3) & BackOffMask ;
+ }
+
+ // Probe _owner with TATAS
+ // If this thread observes the monitor transition or flicker
+ // from locked to unlocked to locked, then the odds that this
+ // thread will acquire the lock in this spin attempt go down
+ // considerably. The same argument applies if the CAS fails
+ // or if we observe _owner change from one non-null value to
+ // another non-null value. In such cases we might abort
+ // the spin without prejudice or apply a "penalty" to the
+ // spin count-down variable "ctr", reducing it by 100, say.
+
+ Thread * ox = (Thread *) _owner ;
+ if (ox == NULL) {
+ ox = (Thread *) Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
+ if (ox == NULL) {
+ // The CAS succeeded -- this thread acquired ownership
+ // Take care of some bookkeeping to exit spin state.
+ if (sss && _succ == Self) {
+ _succ = NULL ;
+ }
+ if (MaxSpin > 0) Adjust (&_Spinner, -1) ;
+
+ // Increase _SpinDuration :
+ // The spin was successful (profitable) so we tend toward
+ // longer spin attempts in the future.
+ // CONSIDER: factor "ctr" into the _SpinDuration adjustment.
+ // If we acquired the lock early in the spin cycle it
+ // makes sense to increase _SpinDuration proportionally.
+ // Note that we don't clamp SpinDuration precisely at SpinLimit.
+ int x = _SpinDuration ;
+ if (x < Knob_SpinLimit) {
+ if (x < Knob_Poverty) x = Knob_Poverty ;
+ _SpinDuration = x + Knob_Bonus ;
+ }
+ return 1 ;
+ }
+
+ // The CAS failed ... we can take any of the following actions:
+ // * penalize: ctr -= Knob_CASPenalty
+ // * exit spin with prejudice -- goto Abort;
+ // * exit spin without prejudice.
+ // * Since CAS is high-latency, retry again immediately.
+ prv = ox ;
+ TEVENT (Spin: cas failed) ;
+ if (caspty == -2) break ;
+ if (caspty == -1) goto Abort ;
+ ctr -= caspty ;
+ continue ;
+ }
+
+ // Did lock ownership change hands ?
+ if (ox != prv && prv != NULL ) {
+ TEVENT (spin: Owner changed)
+ if (oxpty == -2) break ;
+ if (oxpty == -1) goto Abort ;
+ ctr -= oxpty ;
+ }
+ prv = ox ;
+
+ // Abort the spin if the owner is not executing.
+ // The owner must be executing in order to drop the lock.
+ // Spinning while the owner is OFFPROC is idiocy.
+ // Consider: ctr -= RunnablePenalty ;
+ if (Knob_OState && NotRunnable (Self, ox)) {
+ TEVENT (Spin abort - notrunnable);
+ goto Abort ;
+ }
+ if (sss && _succ == NULL ) _succ = Self ;
+ }
+
+ // Spin failed with prejudice -- reduce _SpinDuration.
+ // TODO: Use an AIMD-like policy to adjust _SpinDuration.
+ // AIMD is globally stable.
+ TEVENT (Spin failure) ;
+ {
+ int x = _SpinDuration ;
+ if (x > 0) {
+ // Consider an AIMD scheme like: x -= (x >> 3) + 100
+ // This is globally sample and tends to damp the response.
+ x -= Knob_Penalty ;
+ if (x < 0) x = 0 ;
+ _SpinDuration = x ;
+ }
+ }
+
+ Abort:
+ if (MaxSpin >= 0) Adjust (&_Spinner, -1) ;
+ if (sss && _succ == Self) {
+ _succ = NULL ;
+ // Invariant: after setting succ=null a contending thread
+ // must recheck-retry _owner before parking. This usually happens
+ // in the normal usage of TrySpin(), but it's safest
+ // to make TrySpin() as foolproof as possible.
+ OrderAccess::fence() ;
+ if (TryLock(Self) > 0) return 1 ;
+ }
+ return 0 ;
+}
+
+// NotRunnable() -- informed spinning
+//
+// Don't bother spinning if the owner is not eligible to drop the lock.
+// Peek at the owner's schedctl.sc_state and Thread._thread_values and
+// spin only if the owner thread is _thread_in_Java or _thread_in_vm.
+// The thread must be runnable in order to drop the lock in timely fashion.
+// If the _owner is not runnable then spinning will not likely be
+// successful (profitable).
+//
+// Beware -- the thread referenced by _owner could have died
+// so a simply fetch from _owner->_thread_state might trap.
+// Instead, we use SafeFetchXX() to safely LD _owner->_thread_state.
+// Because of the lifecycle issues the schedctl and _thread_state values
+// observed by NotRunnable() might be garbage. NotRunnable must
+// tolerate this and consider the observed _thread_state value
+// as advisory.
+//
+// Beware too, that _owner is sometimes a BasicLock address and sometimes
+// a thread pointer. We differentiate the two cases with OwnerIsThread.
+// Alternately, we might tag the type (thread pointer vs basiclock pointer)
+// with the LSB of _owner. Another option would be to probablistically probe
+// the putative _owner->TypeTag value.
+//
+// Checking _thread_state isn't perfect. Even if the thread is
+// in_java it might be blocked on a page-fault or have been preempted
+// and sitting on a ready/dispatch queue. _thread state in conjunction
+// with schedctl.sc_state gives us a good picture of what the
+// thread is doing, however.
+//
+// TODO: check schedctl.sc_state.
+// We'll need to use SafeFetch32() to read from the schedctl block.
+// See RFE #5004247 and http://sac.sfbay.sun.com/Archives/CaseLog/arc/PSARC/2005/351/
+//
+// The return value from NotRunnable() is *advisory* -- the
+// result is based on sampling and is not necessarily coherent.
+// The caller must tolerate false-negative and false-positive errors.
+// Spinning, in general, is probabilistic anyway.
+
+
+int ObjectMonitor::NotRunnable (Thread * Self, Thread * ox) {
+ // Check either OwnerIsThread or ox->TypeTag == 2BAD.
+ if (!OwnerIsThread) return 0 ;
+
+ if (ox == NULL) return 0 ;
+
+ // Avoid transitive spinning ...
+ // Say T1 spins or blocks trying to acquire L. T1._Stalled is set to L.
+ // Immediately after T1 acquires L it's possible that T2, also
+ // spinning on L, will see L.Owner=T1 and T1._Stalled=L.
+ // This occurs transiently after T1 acquired L but before
+ // T1 managed to clear T1.Stalled. T2 does not need to abort
+ // its spin in this circumstance.
+ intptr_t BlockedOn = SafeFetchN ((intptr_t *) &ox->_Stalled, intptr_t(1)) ;
+
+ if (BlockedOn == 1) return 1 ;
+ if (BlockedOn != 0) {
+ return BlockedOn != intptr_t(this) && _owner == ox ;
+ }
+
+ assert (sizeof(((JavaThread *)ox)->_thread_state == sizeof(int)), "invariant") ;
+ int jst = SafeFetch32 ((int *) &((JavaThread *) ox)->_thread_state, -1) ; ;
+ // consider also: jst != _thread_in_Java -- but that's overspecific.
+ return jst == _thread_blocked || jst == _thread_in_native ;
+}
+
+
+// -----------------------------------------------------------------------------
+// WaitSet management ...
+
+ObjectWaiter::ObjectWaiter(Thread* thread) {
+ _next = NULL;
+ _prev = NULL;
+ _notified = 0;
+ TState = TS_RUN ;
+ _thread = thread;
+ _event = thread->_ParkEvent ;
+ _active = false;
+ assert (_event != NULL, "invariant") ;
+}
+
+void ObjectWaiter::wait_reenter_begin(ObjectMonitor *mon) {
+ JavaThread *jt = (JavaThread *)this->_thread;
+ _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
+}
+
+void ObjectWaiter::wait_reenter_end(ObjectMonitor *mon) {
+ JavaThread *jt = (JavaThread *)this->_thread;
+ JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
+}
+
+inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
+ assert(node != NULL, "should not dequeue NULL node");
+ assert(node->_prev == NULL, "node already in list");
+ assert(node->_next == NULL, "node already in list");
+ // put node at end of queue (circular doubly linked list)
+ if (_WaitSet == NULL) {
+ _WaitSet = node;
+ node->_prev = node;
+ node->_next = node;
+ } else {
+ ObjectWaiter* head = _WaitSet ;
+ ObjectWaiter* tail = head->_prev;
+ assert(tail->_next == head, "invariant check");
+ tail->_next = node;
+ head->_prev = node;
+ node->_next = head;
+ node->_prev = tail;
+ }
+}
+
+inline ObjectWaiter* ObjectMonitor::DequeueWaiter() {
+ // dequeue the very first waiter
+ ObjectWaiter* waiter = _WaitSet;
+ if (waiter) {
+ DequeueSpecificWaiter(waiter);
+ }
+ return waiter;
+}
+
+inline void ObjectMonitor::DequeueSpecificWaiter(ObjectWaiter* node) {
+ assert(node != NULL, "should not dequeue NULL node");
+ assert(node->_prev != NULL, "node already removed from list");
+ assert(node->_next != NULL, "node already removed from list");
+ // when the waiter has woken up because of interrupt,
+ // timeout or other spurious wake-up, dequeue the
+ // waiter from waiting list
+ ObjectWaiter* next = node->_next;
+ if (next == node) {
+ assert(node->_prev == node, "invariant check");
+ _WaitSet = NULL;
+ } else {
+ ObjectWaiter* prev = node->_prev;
+ assert(prev->_next == node, "invariant check");
+ assert(next->_prev == node, "invariant check");
+ next->_prev = prev;
+ prev->_next = next;
+ if (_WaitSet == node) {
+ _WaitSet = next;
+ }
+ }
+ node->_next = NULL;
+ node->_prev = NULL;
+}
+
+// -----------------------------------------------------------------------------
+// PerfData support
+PerfCounter * ObjectMonitor::_sync_ContendedLockAttempts = NULL ;
+PerfCounter * ObjectMonitor::_sync_FutileWakeups = NULL ;
+PerfCounter * ObjectMonitor::_sync_Parks = NULL ;
+PerfCounter * ObjectMonitor::_sync_EmptyNotifications = NULL ;
+PerfCounter * ObjectMonitor::_sync_Notifications = NULL ;
+PerfCounter * ObjectMonitor::_sync_PrivateA = NULL ;
+PerfCounter * ObjectMonitor::_sync_PrivateB = NULL ;
+PerfCounter * ObjectMonitor::_sync_SlowExit = NULL ;
+PerfCounter * ObjectMonitor::_sync_SlowEnter = NULL ;
+PerfCounter * ObjectMonitor::_sync_SlowNotify = NULL ;
+PerfCounter * ObjectMonitor::_sync_SlowNotifyAll = NULL ;
+PerfCounter * ObjectMonitor::_sync_FailedSpins = NULL ;
+PerfCounter * ObjectMonitor::_sync_SuccessfulSpins = NULL ;
+PerfCounter * ObjectMonitor::_sync_MonInCirculation = NULL ;
+PerfCounter * ObjectMonitor::_sync_MonScavenged = NULL ;
+PerfCounter * ObjectMonitor::_sync_Inflations = NULL ;
+PerfCounter * ObjectMonitor::_sync_Deflations = NULL ;
+PerfLongVariable * ObjectMonitor::_sync_MonExtant = NULL ;
+
+// One-shot global initialization for the sync subsystem.
+// We could also defer initialization and initialize on-demand
+// the first time we call inflate(). Initialization would
+// be protected - like so many things - by the MonitorCache_lock.
+
+void ObjectMonitor::Initialize () {
+ static int InitializationCompleted = 0 ;
+ assert (InitializationCompleted == 0, "invariant") ;
+ InitializationCompleted = 1 ;
+ if (UsePerfData) {
+ EXCEPTION_MARK ;
+ #define NEWPERFCOUNTER(n) {n = PerfDataManager::create_counter(SUN_RT, #n, PerfData::U_Events,CHECK); }
+ #define NEWPERFVARIABLE(n) {n = PerfDataManager::create_variable(SUN_RT, #n, PerfData::U_Events,CHECK); }
+ NEWPERFCOUNTER(_sync_Inflations) ;
+ NEWPERFCOUNTER(_sync_Deflations) ;
+ NEWPERFCOUNTER(_sync_ContendedLockAttempts) ;
+ NEWPERFCOUNTER(_sync_FutileWakeups) ;
+ NEWPERFCOUNTER(_sync_Parks) ;
+ NEWPERFCOUNTER(_sync_EmptyNotifications) ;
+ NEWPERFCOUNTER(_sync_Notifications) ;
+ NEWPERFCOUNTER(_sync_SlowEnter) ;
+ NEWPERFCOUNTER(_sync_SlowExit) ;
+ NEWPERFCOUNTER(_sync_SlowNotify) ;
+ NEWPERFCOUNTER(_sync_SlowNotifyAll) ;
+ NEWPERFCOUNTER(_sync_FailedSpins) ;
+ NEWPERFCOUNTER(_sync_SuccessfulSpins) ;
+ NEWPERFCOUNTER(_sync_PrivateA) ;
+ NEWPERFCOUNTER(_sync_PrivateB) ;
+ NEWPERFCOUNTER(_sync_MonInCirculation) ;
+ NEWPERFCOUNTER(_sync_MonScavenged) ;
+ NEWPERFVARIABLE(_sync_MonExtant) ;
+ #undef NEWPERFCOUNTER
+ }
+}
+
+
+// Compile-time asserts
+// When possible, it's better to catch errors deterministically at
+// compile-time than at runtime. The down-side to using compile-time
+// asserts is that error message -- often something about negative array
+// indices -- is opaque.
+
+#define CTASSERT(x) { int tag[1-(2*!(x))]; printf ("Tag @" INTPTR_FORMAT "\n", (intptr_t)tag); }
+
+void ObjectMonitor::ctAsserts() {
+ CTASSERT(offset_of (ObjectMonitor, _header) == 0);
+}
+
+
+static char * kvGet (char * kvList, const char * Key) {
+ if (kvList == NULL) return NULL ;
+ size_t n = strlen (Key) ;
+ char * Search ;
+ for (Search = kvList ; *Search ; Search += strlen(Search) + 1) {
+ if (strncmp (Search, Key, n) == 0) {
+ if (Search[n] == '=') return Search + n + 1 ;
+ if (Search[n] == 0) return (char *) "1" ;
+ }
+ }
+ return NULL ;
+}
+
+static int kvGetInt (char * kvList, const char * Key, int Default) {
+ char * v = kvGet (kvList, Key) ;
+ int rslt = v ? ::strtol (v, NULL, 0) : Default ;
+ if (Knob_ReportSettings && v != NULL) {
+ ::printf (" SyncKnob: %s %d(%d)\n", Key, rslt, Default) ;
+ ::fflush (stdout) ;
+ }
+ return rslt ;
+}
+
+void ObjectMonitor::DeferredInitialize () {
+ if (InitDone > 0) return ;
+ if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
+ while (InitDone != 1) ;
+ return ;
+ }
+
+ // One-shot global initialization ...
+ // The initialization is idempotent, so we don't need locks.
+ // In the future consider doing this via os::init_2().
+ // SyncKnobs consist of <Key>=<Value> pairs in the style
+ // of environment variables. Start by converting ':' to NUL.
+
+ if (SyncKnobs == NULL) SyncKnobs = "" ;
+
+ size_t sz = strlen (SyncKnobs) ;
+ char * knobs = (char *) malloc (sz + 2) ;
+ if (knobs == NULL) {
+ vm_exit_out_of_memory (sz + 2, "Parse SyncKnobs") ;
+ guarantee (0, "invariant") ;
+ }
+ strcpy (knobs, SyncKnobs) ;
+ knobs[sz+1] = 0 ;
+ for (char * p = knobs ; *p ; p++) {
+ if (*p == ':') *p = 0 ;
+ }
+
+ #define SETKNOB(x) { Knob_##x = kvGetInt (knobs, #x, Knob_##x); }
+ SETKNOB(ReportSettings) ;
+ SETKNOB(Verbose) ;
+ SETKNOB(FixedSpin) ;
+ SETKNOB(SpinLimit) ;
+ SETKNOB(SpinBase) ;
+ SETKNOB(SpinBackOff);
+ SETKNOB(CASPenalty) ;
+ SETKNOB(OXPenalty) ;
+ SETKNOB(LogSpins) ;
+ SETKNOB(SpinSetSucc) ;
+ SETKNOB(SuccEnabled) ;
+ SETKNOB(SuccRestrict) ;
+ SETKNOB(Penalty) ;
+ SETKNOB(Bonus) ;
+ SETKNOB(BonusB) ;
+ SETKNOB(Poverty) ;
+ SETKNOB(SpinAfterFutile) ;
+ SETKNOB(UsePause) ;
+ SETKNOB(SpinEarly) ;
+ SETKNOB(OState) ;
+ SETKNOB(MaxSpinners) ;
+ SETKNOB(PreSpin) ;
+ SETKNOB(ExitPolicy) ;
+ SETKNOB(QMode);
+ SETKNOB(ResetEvent) ;
+ SETKNOB(MoveNotifyee) ;
+ SETKNOB(FastHSSEC) ;
+ #undef SETKNOB
+
+ if (os::is_MP()) {
+ BackOffMask = (1 << Knob_SpinBackOff) - 1 ;
+ if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ;
+ // CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
+ } else {
+ Knob_SpinLimit = 0 ;
+ Knob_SpinBase = 0 ;
+ Knob_PreSpin = 0 ;
+ Knob_FixedSpin = -1 ;
+ }
+
+ if (Knob_LogSpins == 0) {
+ ObjectMonitor::_sync_FailedSpins = NULL ;
+ }
+
+ free (knobs) ;
+ OrderAccess::fence() ;
+ InitDone = 1 ;
+}
+
+#ifndef PRODUCT
+void ObjectMonitor::verify() {
+}
+
+void ObjectMonitor::print() {
+}
+#endif
--- a/hotspot/src/share/vm/runtime/objectMonitor.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/objectMonitor.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -22,6 +22,32 @@
*
*/
+
+// ObjectWaiter serves as a "proxy" or surrogate thread.
+// TODO-FIXME: Eliminate ObjectWaiter and use the thread-specific
+// ParkEvent instead. Beware, however, that the JVMTI code
+// knows about ObjectWaiters, so we'll have to reconcile that code.
+// See next_waiter(), first_waiter(), etc.
+
+class ObjectWaiter : public StackObj {
+ public:
+ enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
+ enum Sorted { PREPEND, APPEND, SORTED } ;
+ ObjectWaiter * volatile _next;
+ ObjectWaiter * volatile _prev;
+ Thread* _thread;
+ ParkEvent * _event;
+ volatile int _notified ;
+ volatile TStates TState ;
+ Sorted _Sorted ; // List placement disposition
+ bool _active ; // Contention monitoring is enabled
+ public:
+ ObjectWaiter(Thread* thread);
+
+ void wait_reenter_begin(ObjectMonitor *mon);
+ void wait_reenter_end(ObjectMonitor *mon);
+};
+
// WARNING:
// This is a very sensitive and fragile class. DO NOT make any
// change unless you are fully aware of the underlying semantics.
@@ -38,8 +64,6 @@
// It is also used as RawMonitor by the JVMTI
-class ObjectWaiter;
-
class ObjectMonitor {
public:
enum {
@@ -74,13 +98,16 @@
public:
- ObjectMonitor();
- ~ObjectMonitor();
-
markOop header() const;
void set_header(markOop hdr);
- intptr_t is_busy() const;
+ intptr_t is_busy() const {
+ // TODO-FIXME: merge _count and _waiters.
+ // TODO-FIXME: assert _owner == null implies _recursions = 0
+ // TODO-FIXME: assert _WaitSet != null implies _count > 0
+ return _count|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList ) ;
+ }
+
intptr_t is_entered(Thread* current) const;
void* owner() const;
@@ -91,13 +118,58 @@
intptr_t count() const;
void set_count(intptr_t count);
intptr_t contentions() const ;
+ intptr_t recursions() const { return _recursions; }
// JVM/DI GetMonitorInfo() needs this
- Thread * thread_of_waiter (ObjectWaiter *) ;
- ObjectWaiter * first_waiter () ;
- ObjectWaiter * next_waiter(ObjectWaiter* o);
+ ObjectWaiter* first_waiter() { return _WaitSet; }
+ ObjectWaiter* next_waiter(ObjectWaiter* o) { return o->_next; }
+ Thread* thread_of_waiter(ObjectWaiter* o) { return o->_thread; }
+
+ // initialize the monitor, exception the semaphore, all other fields
+ // are simple integers or pointers
+ ObjectMonitor() {
+ _header = NULL;
+ _count = 0;
+ _waiters = 0,
+ _recursions = 0;
+ _object = NULL;
+ _owner = NULL;
+ _WaitSet = NULL;
+ _WaitSetLock = 0 ;
+ _Responsible = NULL ;
+ _succ = NULL ;
+ _cxq = NULL ;
+ FreeNext = NULL ;
+ _EntryList = NULL ;
+ _SpinFreq = 0 ;
+ _SpinClock = 0 ;
+ OwnerIsThread = 0 ;
+ }
- intptr_t recursions() const { return _recursions; }
+ ~ObjectMonitor() {
+ // TODO: Add asserts ...
+ // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
+ // _count == 0 _EntryList == NULL etc
+ }
+
+private:
+ void Recycle () {
+ // TODO: add stronger asserts ...
+ // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
+ // _count == 0 EntryList == NULL
+ // _recursions == 0 _WaitSet == NULL
+ // TODO: assert (is_busy()|_recursions) == 0
+ _succ = NULL ;
+ _EntryList = NULL ;
+ _cxq = NULL ;
+ _WaitSet = NULL ;
+ _recursions = 0 ;
+ _SpinFreq = 0 ;
+ _SpinClock = 0 ;
+ OwnerIsThread = 0 ;
+ }
+
+public:
void* object() const;
void* object_addr();
@@ -122,22 +194,9 @@
intptr_t complete_exit(TRAPS);
void reenter(intptr_t recursions, TRAPS);
- int raw_enter(TRAPS);
- int raw_exit(TRAPS);
- int raw_wait(jlong millis, bool interruptable, TRAPS);
- int raw_notify(TRAPS);
- int raw_notifyAll(TRAPS);
-
private:
- // JVMTI support -- remove ASAP
- int SimpleEnter (Thread * Self) ;
- int SimpleExit (Thread * Self) ;
- int SimpleWait (Thread * Self, jlong millis) ;
- int SimpleNotify (Thread * Self, bool All) ;
-
- private:
- void Recycle () ;
void AddWaiter (ObjectWaiter * waiter) ;
+ static void DeferredInitialize();
ObjectWaiter * DequeueWaiter () ;
void DequeueSpecificWaiter (ObjectWaiter * waiter) ;
@@ -172,13 +231,17 @@
// The VM assumes write ordering wrt these fields, which can be
// read from other threads.
+ protected: // protected for jvmtiRawMonitor
void * volatile _owner; // pointer to owning thread OR BasicLock
volatile intptr_t _recursions; // recursion count, 0 for first entry
+ private:
int OwnerIsThread ; // _owner is (Thread *) vs SP/BasicLock
ObjectWaiter * volatile _cxq ; // LL of recently-arrived threads blocked on entry.
// The list is actually composed of WaitNodes, acting
// as proxies for Threads.
+ protected:
ObjectWaiter * volatile _EntryList ; // Threads blocked on entry or reentry.
+ private:
Thread * volatile _succ ; // Heir presumptive thread - used for futile wakeup throttling
Thread * volatile _Responsible ;
int _PromptDrain ; // rqst to drain cxq into EntryList ASAP
@@ -196,8 +259,12 @@
volatile intptr_t _count; // reference count to prevent reclaimation/deflation
// at stop-the-world time. See deflate_idle_monitors().
// _count is approximately |_WaitSet| + |_EntryList|
+ protected:
volatile intptr_t _waiters; // number of waiting threads
+ private:
+ protected:
ObjectWaiter * volatile _WaitSet; // LL of threads wait()ing on the monitor
+ private:
volatile int _WaitSetLock; // protects Wait Queue - simple spinlock
public:
@@ -205,4 +272,37 @@
ObjectMonitor * FreeNext ; // Free list linkage
intptr_t StatA, StatsB ;
+ public:
+ static void Initialize () ;
+ static PerfCounter * _sync_ContendedLockAttempts ;
+ static PerfCounter * _sync_FutileWakeups ;
+ static PerfCounter * _sync_Parks ;
+ static PerfCounter * _sync_EmptyNotifications ;
+ static PerfCounter * _sync_Notifications ;
+ static PerfCounter * _sync_SlowEnter ;
+ static PerfCounter * _sync_SlowExit ;
+ static PerfCounter * _sync_SlowNotify ;
+ static PerfCounter * _sync_SlowNotifyAll ;
+ static PerfCounter * _sync_FailedSpins ;
+ static PerfCounter * _sync_SuccessfulSpins ;
+ static PerfCounter * _sync_PrivateA ;
+ static PerfCounter * _sync_PrivateB ;
+ static PerfCounter * _sync_MonInCirculation ;
+ static PerfCounter * _sync_MonScavenged ;
+ static PerfCounter * _sync_Inflations ;
+ static PerfCounter * _sync_Deflations ;
+ static PerfLongVariable * _sync_MonExtant ;
+
+ public:
+ static int Knob_Verbose;
+ static int Knob_SpinLimit;
};
+
+#undef TEVENT
+#define TEVENT(nom) {if (SyncVerbose) FEVENT(nom); }
+
+#define FEVENT(nom) { static volatile int ctr = 0 ; int v = ++ctr ; if ((v & (v-1)) == 0) { ::printf (#nom " : %d \n", v); ::fflush(stdout); }}
+
+#undef TEVENT
+#define TEVENT(nom) {;}
+
--- a/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -104,7 +104,3 @@
_count = 0;
}
-
-// here are the platform-dependent bodies:
-
-# include "incls/_objectMonitor_pd.inline.hpp.incl"
--- a/hotspot/src/share/vm/runtime/os.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/os.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -736,8 +736,8 @@
}
// moved from debug.cpp (used to be find()) but still called from there
-// The print_pc parameter is only set by the debug code in one case
-void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
+// The verbose parameter is only set by the debug code in one case
+void os::print_location(outputStream* st, intptr_t x, bool verbose) {
address addr = (address)x;
CodeBlob* b = CodeCache::find_blob_unsafe(addr);
if (b != NULL) {
@@ -745,6 +745,7 @@
// the interpreter is generated into a buffer blob
InterpreterCodelet* i = Interpreter::codelet_containing(addr);
if (i != NULL) {
+ st->print_cr(INTPTR_FORMAT " is an Interpreter codelet", addr);
i->print_on(st);
return;
}
@@ -755,14 +756,14 @@
}
//
if (AdapterHandlerLibrary::contains(b)) {
- st->print_cr("Printing AdapterHandler");
+ st->print_cr(INTPTR_FORMAT " is an AdapterHandler", addr);
AdapterHandlerLibrary::print_handler_on(st, b);
}
// the stubroutines are generated into a buffer blob
StubCodeDesc* d = StubCodeDesc::desc_for(addr);
if (d != NULL) {
d->print_on(st);
- if (print_pc) st->cr();
+ if (verbose) st->cr();
return;
}
if (StubRoutines::contains(addr)) {
@@ -781,7 +782,7 @@
return;
}
}
- if (print_pc && b->is_nmethod()) {
+ if (verbose && b->is_nmethod()) {
ResourceMark rm;
st->print("%#p: Compiled ", addr);
((nmethod*)b)->method()->print_value_on(st);
@@ -789,11 +790,12 @@
st->cr();
return;
}
+ st->print(INTPTR_FORMAT " ", b);
if ( b->is_nmethod()) {
if (b->is_zombie()) {
- st->print_cr(INTPTR_FORMAT " is zombie nmethod", b);
+ st->print_cr("is zombie nmethod");
} else if (b->is_not_entrant()) {
- st->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b);
+ st->print_cr("is non-entrant nmethod");
}
}
b->print_on(st);
@@ -812,6 +814,7 @@
print = true;
}
if (print) {
+ st->print_cr(INTPTR_FORMAT " is an oop", addr);
oop(p)->print_on(st);
if (p != (HeapWord*)x && oop(p)->is_constMethod() &&
constMethodOop(p)->contains(addr)) {
@@ -855,12 +858,16 @@
thread->privileged_stack_top()->contains(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack "
"for thread: " INTPTR_FORMAT, addr, thread);
- thread->print_on(st);
+ if (verbose) thread->print_on(st);
return;
}
// If the addr is a java thread print information about that.
if (addr == (address)thread) {
- thread->print_on(st);
+ if (verbose) {
+ thread->print_on(st);
+ } else {
+ st->print_cr(INTPTR_FORMAT " is a thread", addr);
+ }
return;
}
// If the addr is in the stack region for this thread then report that
@@ -869,7 +876,7 @@
addr > (thread->stack_base() - thread->stack_size())) {
st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: "
INTPTR_FORMAT, addr, thread);
- thread->print_on(st);
+ if (verbose) thread->print_on(st);
return;
}
@@ -879,7 +886,7 @@
return;
}
- st->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr);
+ st->print_cr(INTPTR_FORMAT " is an unknown value", addr);
}
// Looks like all platforms except IA64 can use the same function to check
--- a/hotspot/src/share/vm/runtime/os.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/os.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -450,11 +450,12 @@
static void print_dll_info(outputStream* st);
static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len);
static void print_context(outputStream* st, void* context);
+ static void print_register_info(outputStream* st, void* context);
static void print_siginfo(outputStream* st, void* siginfo);
static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
static void print_date_and_time(outputStream* st);
- static void print_location(outputStream* st, intptr_t x, bool print_pc = false);
+ static void print_location(outputStream* st, intptr_t x, bool verbose = false);
// The following two functions are used by fatal error handler to trace
// native (C) frames. They are not part of frame.hpp/frame.cpp because
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/park.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+
+# include "incls/_precompiled.incl"
+# include "incls/_park.cpp.incl"
+
+
+// Lifecycle management for TSM ParkEvents.
+// ParkEvents are type-stable (TSM).
+// In our particular implementation they happen to be immortal.
+//
+// We manage concurrency on the FreeList with a CAS-based
+// detach-modify-reattach idiom that avoids the ABA problems
+// that would otherwise be present in a simple CAS-based
+// push-pop implementation. (push-one and pop-all)
+//
+// Caveat: Allocate() and Release() may be called from threads
+// other than the thread associated with the Event!
+// If we need to call Allocate() when running as the thread in
+// question then look for the PD calls to initialize native TLS.
+// Native TLS (Win32/Linux/Solaris) can only be initialized or
+// accessed by the associated thread.
+// See also pd_initialize().
+//
+// Note that we could defer associating a ParkEvent with a thread
+// until the 1st time the thread calls park(). unpark() calls to
+// an unprovisioned thread would be ignored. The first park() call
+// for a thread would allocate and associate a ParkEvent and return
+// immediately.
+
+volatile int ParkEvent::ListLock = 0 ;
+ParkEvent * volatile ParkEvent::FreeList = NULL ;
+
+ParkEvent * ParkEvent::Allocate (Thread * t) {
+ // In rare cases -- JVM_RawMonitor* operations -- we can find t == null.
+ ParkEvent * ev ;
+
+ // Start by trying to recycle an existing but unassociated
+ // ParkEvent from the global free list.
+ for (;;) {
+ ev = FreeList ;
+ if (ev == NULL) break ;
+ // 1: Detach - sequester or privatize the list
+ // Tantamount to ev = Swap (&FreeList, NULL)
+ if (Atomic::cmpxchg_ptr (NULL, &FreeList, ev) != ev) {
+ continue ;
+ }
+
+ // We've detached the list. The list in-hand is now
+ // local to this thread. This thread can operate on the
+ // list without risk of interference from other threads.
+ // 2: Extract -- pop the 1st element from the list.
+ ParkEvent * List = ev->FreeNext ;
+ if (List == NULL) break ;
+ for (;;) {
+ // 3: Try to reattach the residual list
+ guarantee (List != NULL, "invariant") ;
+ ParkEvent * Arv = (ParkEvent *) Atomic::cmpxchg_ptr (List, &FreeList, NULL) ;
+ if (Arv == NULL) break ;
+
+ // New nodes arrived. Try to detach the recent arrivals.
+ if (Atomic::cmpxchg_ptr (NULL, &FreeList, Arv) != Arv) {
+ continue ;
+ }
+ guarantee (Arv != NULL, "invariant") ;
+ // 4: Merge Arv into List
+ ParkEvent * Tail = List ;
+ while (Tail->FreeNext != NULL) Tail = Tail->FreeNext ;
+ Tail->FreeNext = Arv ;
+ }
+ break ;
+ }
+
+ if (ev != NULL) {
+ guarantee (ev->AssociatedWith == NULL, "invariant") ;
+ } else {
+ // Do this the hard way -- materialize a new ParkEvent.
+ // In rare cases an allocating thread might detach a long list --
+ // installing null into FreeList -- and then stall or be obstructed.
+ // A 2nd thread calling Allocate() would see FreeList == null.
+ // The list held privately by the 1st thread is unavailable to the 2nd thread.
+ // In that case the 2nd thread would have to materialize a new ParkEvent,
+ // even though free ParkEvents existed in the system. In this case we end up
+ // with more ParkEvents in circulation than we need, but the race is
+ // rare and the outcome is benign. Ideally, the # of extant ParkEvents
+ // is equal to the maximum # of threads that existed at any one time.
+ // Because of the race mentioned above, segments of the freelist
+ // can be transiently inaccessible. At worst we may end up with the
+ // # of ParkEvents in circulation slightly above the ideal.
+ // Note that if we didn't have the TSM/immortal constraint, then
+ // when reattaching, above, we could trim the list.
+ ev = new ParkEvent () ;
+ guarantee ((intptr_t(ev) & 0xFF) == 0, "invariant") ;
+ }
+ ev->reset() ; // courtesy to caller
+ ev->AssociatedWith = t ; // Associate ev with t
+ ev->FreeNext = NULL ;
+ return ev ;
+}
+
+void ParkEvent::Release (ParkEvent * ev) {
+ if (ev == NULL) return ;
+ guarantee (ev->FreeNext == NULL , "invariant") ;
+ ev->AssociatedWith = NULL ;
+ for (;;) {
+ // Push ev onto FreeList
+ // The mechanism is "half" lock-free.
+ ParkEvent * List = FreeList ;
+ ev->FreeNext = List ;
+ if (Atomic::cmpxchg_ptr (ev, &FreeList, List) == List) break ;
+ }
+}
+
+// Override operator new and delete so we can ensure that the
+// least significant byte of ParkEvent addresses is 0.
+// Beware that excessive address alignment is undesirable
+// as it can result in D$ index usage imbalance as
+// well as bank access imbalance on Niagara-like platforms,
+// although Niagara's hash function should help.
+
+void * ParkEvent::operator new (size_t sz) {
+ return (void *) ((intptr_t (CHeapObj::operator new (sz + 256)) + 256) & -256) ;
+}
+
+void ParkEvent::operator delete (void * a) {
+ // ParkEvents are type-stable and immortal ...
+ ShouldNotReachHere();
+}
+
+
+// 6399321 As a temporary measure we copied & modified the ParkEvent::
+// allocate() and release() code for use by Parkers. The Parker:: forms
+// will eventually be removed as we consolide and shift over to ParkEvents
+// for both builtin synchronization and JSR166 operations.
+
+volatile int Parker::ListLock = 0 ;
+Parker * volatile Parker::FreeList = NULL ;
+
+Parker * Parker::Allocate (JavaThread * t) {
+ guarantee (t != NULL, "invariant") ;
+ Parker * p ;
+
+ // Start by trying to recycle an existing but unassociated
+ // Parker from the global free list.
+ for (;;) {
+ p = FreeList ;
+ if (p == NULL) break ;
+ // 1: Detach
+ // Tantamount to p = Swap (&FreeList, NULL)
+ if (Atomic::cmpxchg_ptr (NULL, &FreeList, p) != p) {
+ continue ;
+ }
+
+ // We've detached the list. The list in-hand is now
+ // local to this thread. This thread can operate on the
+ // list without risk of interference from other threads.
+ // 2: Extract -- pop the 1st element from the list.
+ Parker * List = p->FreeNext ;
+ if (List == NULL) break ;
+ for (;;) {
+ // 3: Try to reattach the residual list
+ guarantee (List != NULL, "invariant") ;
+ Parker * Arv = (Parker *) Atomic::cmpxchg_ptr (List, &FreeList, NULL) ;
+ if (Arv == NULL) break ;
+
+ // New nodes arrived. Try to detach the recent arrivals.
+ if (Atomic::cmpxchg_ptr (NULL, &FreeList, Arv) != Arv) {
+ continue ;
+ }
+ guarantee (Arv != NULL, "invariant") ;
+ // 4: Merge Arv into List
+ Parker * Tail = List ;
+ while (Tail->FreeNext != NULL) Tail = Tail->FreeNext ;
+ Tail->FreeNext = Arv ;
+ }
+ break ;
+ }
+
+ if (p != NULL) {
+ guarantee (p->AssociatedWith == NULL, "invariant") ;
+ } else {
+ // Do this the hard way -- materialize a new Parker..
+ // In rare cases an allocating thread might detach
+ // a long list -- installing null into FreeList --and
+ // then stall. Another thread calling Allocate() would see
+ // FreeList == null and then invoke the ctor. In this case we
+ // end up with more Parkers in circulation than we need, but
+ // the race is rare and the outcome is benign.
+ // Ideally, the # of extant Parkers is equal to the
+ // maximum # of threads that existed at any one time.
+ // Because of the race mentioned above, segments of the
+ // freelist can be transiently inaccessible. At worst
+ // we may end up with the # of Parkers in circulation
+ // slightly above the ideal.
+ p = new Parker() ;
+ }
+ p->AssociatedWith = t ; // Associate p with t
+ p->FreeNext = NULL ;
+ return p ;
+}
+
+
+void Parker::Release (Parker * p) {
+ if (p == NULL) return ;
+ guarantee (p->AssociatedWith != NULL, "invariant") ;
+ guarantee (p->FreeNext == NULL , "invariant") ;
+ p->AssociatedWith = NULL ;
+ for (;;) {
+ // Push p onto FreeList
+ Parker * List = FreeList ;
+ p->FreeNext = List ;
+ if (Atomic::cmpxchg_ptr (p, &FreeList, List) == List) break ;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/park.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+/*
+ * Per-thread blocking support for JSR166. See the Java-level
+ * Documentation for rationale. Basically, park acts like wait, unpark
+ * like notify.
+ *
+ * 6271289 --
+ * To avoid errors where an os thread expires but the JavaThread still
+ * exists, Parkers are immortal (type-stable) and are recycled across
+ * new threads. This parallels the ParkEvent implementation.
+ * Because park-unpark allow spurious wakeups it is harmless if an
+ * unpark call unparks a new thread using the old Parker reference.
+ *
+ * In the future we'll want to think about eliminating Parker and using
+ * ParkEvent instead. There's considerable duplication between the two
+ * services.
+ *
+ */
+
+class Parker : public os::PlatformParker {
+private:
+ volatile int _counter ;
+ Parker * FreeNext ;
+ JavaThread * AssociatedWith ; // Current association
+
+public:
+ Parker() : PlatformParker() {
+ _counter = 0 ;
+ FreeNext = NULL ;
+ AssociatedWith = NULL ;
+ }
+protected:
+ ~Parker() { ShouldNotReachHere(); }
+public:
+ // For simplicity of interface with Java, all forms of park (indefinite,
+ // relative, and absolute) are multiplexed into one call.
+ void park(bool isAbsolute, jlong time);
+ void unpark();
+
+ // Lifecycle operators
+ static Parker * Allocate (JavaThread * t) ;
+ static void Release (Parker * e) ;
+private:
+ static Parker * volatile FreeList ;
+ static volatile int ListLock ;
+
+};
+
+/////////////////////////////////////////////////////////////
+//
+// ParkEvents are type-stable and immortal.
+//
+// Lifecycle: Once a ParkEvent is associated with a thread that ParkEvent remains
+// associated with the thread for the thread's entire lifetime - the relationship is
+// stable. A thread will be associated at most one ParkEvent. When the thread
+// expires, the ParkEvent moves to the EventFreeList. New threads attempt to allocate from
+// the EventFreeList before creating a new Event. Type-stability frees us from
+// worrying about stale Event or Thread references in the objectMonitor subsystem.
+// (A reference to ParkEvent is always valid, even though the event may no longer be associated
+// with the desired or expected thread. A key aspect of this design is that the callers of
+// park, unpark, etc must tolerate stale references and spurious wakeups).
+//
+// Only the "associated" thread can block (park) on the ParkEvent, although
+// any other thread can unpark a reachable parkevent. Park() is allowed to
+// return spuriously. In fact park-unpark a really just an optimization to
+// avoid unbounded spinning and surrender the CPU to be a polite system citizen.
+// A degenerate albeit "impolite" park-unpark implementation could simply return.
+// See http://blogs.sun.com/dave for more details.
+//
+// Eventually I'd like to eliminate Events and ObjectWaiters, both of which serve as
+// thread proxies, and simply make the THREAD structure type-stable and persistent.
+// Currently, we unpark events associated with threads, but ideally we'd just
+// unpark threads.
+//
+// The base-class, PlatformEvent, is platform-specific while the ParkEvent is
+// platform-independent. PlatformEvent provides park(), unpark(), etc., and
+// is abstract -- that is, a PlatformEvent should never be instantiated except
+// as part of a ParkEvent.
+// Equivalently we could have defined a platform-independent base-class that
+// exported Allocate(), Release(), etc. The platform-specific class would extend
+// that base-class, adding park(), unpark(), etc.
+//
+// A word of caution: The JVM uses 2 very similar constructs:
+// 1. ParkEvent are used for Java-level "monitor" synchronization.
+// 2. Parkers are used by JSR166-JUC park-unpark.
+//
+// We'll want to eventually merge these redundant facilities and use ParkEvent.
+
+
+class ParkEvent : public os::PlatformEvent {
+ private:
+ ParkEvent * FreeNext ;
+
+ // Current association
+ Thread * AssociatedWith ;
+ intptr_t RawThreadIdentity ; // LWPID etc
+ volatile int Incarnation ;
+
+ // diagnostic : keep track of last thread to wake this thread.
+ // this is useful for construction of dependency graphs.
+ void * LastWaker ;
+
+ public:
+ // MCS-CLH list linkage and Native Mutex/Monitor
+ ParkEvent * volatile ListNext ;
+ ParkEvent * volatile ListPrev ;
+ volatile intptr_t OnList ;
+ volatile int TState ;
+ volatile int Notified ; // for native monitor construct
+ volatile int IsWaiting ; // Enqueued on WaitSet
+
+
+ private:
+ static ParkEvent * volatile FreeList ;
+ static volatile int ListLock ;
+
+ // It's prudent to mark the dtor as "private"
+ // ensuring that it's not visible outside the package.
+ // Unfortunately gcc warns about such usage, so
+ // we revert to the less desirable "protected" visibility.
+ // The other compilers accept private dtors.
+
+ protected: // Ensure dtor is never invoked
+ ~ParkEvent() { guarantee (0, "invariant") ; }
+
+ ParkEvent() : PlatformEvent() {
+ AssociatedWith = NULL ;
+ FreeNext = NULL ;
+ ListNext = NULL ;
+ ListPrev = NULL ;
+ OnList = 0 ;
+ TState = 0 ;
+ Notified = 0 ;
+ IsWaiting = 0 ;
+ }
+
+ // We use placement-new to force ParkEvent instances to be
+ // aligned on 256-byte address boundaries. This ensures that the least
+ // significant byte of a ParkEvent address is always 0.
+
+ void * operator new (size_t sz) ;
+ void operator delete (void * a) ;
+
+ public:
+ static ParkEvent * Allocate (Thread * t) ;
+ static void Release (ParkEvent * e) ;
+} ;
--- a/hotspot/src/share/vm/runtime/relocator.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/relocator.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -435,6 +435,120 @@
}
}
+// Create a new array, copying the src array but adding a hole at
+// the specified location
+static typeArrayOop insert_hole_at(
+ size_t where, int hole_sz, typeArrayOop src) {
+ Thread* THREAD = Thread::current();
+ Handle src_hnd(THREAD, src);
+ typeArrayOop dst =
+ oopFactory::new_permanent_byteArray(src->length() + hole_sz, CHECK_NULL);
+ src = (typeArrayOop)src_hnd();
+
+ address src_addr = (address)src->byte_at_addr(0);
+ address dst_addr = (address)dst->byte_at_addr(0);
+
+ memcpy(dst_addr, src_addr, where);
+ memcpy(dst_addr + where + hole_sz,
+ src_addr + where, src->length() - where);
+ return dst;
+}
+
+// The width of instruction at "bci" is changing by "delta". Adjust the stack
+// map frames.
+void Relocator::adjust_stack_map_table(int bci, int delta) {
+ if (method()->has_stackmap_table()) {
+ typeArrayOop data = method()->stackmap_data();
+ // The data in the array is a classfile representation of the stackmap
+ // table attribute, less the initial u2 tag and u4 attribute_length fields.
+ stack_map_table_attribute* attr = stack_map_table_attribute::at(
+ (address)data->byte_at_addr(0) - (sizeof(u2) + sizeof(u4)));
+
+ int count = attr->number_of_entries();
+ stack_map_frame* frame = attr->entries();
+ int bci_iter = -1;
+ bool offset_adjusted = false; // only need to adjust one offset
+
+ for (int i = 0; i < count; ++i) {
+ int offset_delta = frame->offset_delta();
+ bci_iter += offset_delta;
+
+ if (!offset_adjusted && bci_iter > bci) {
+ int new_offset_delta = offset_delta + delta;
+
+ if (frame->is_valid_offset(new_offset_delta)) {
+ frame->set_offset_delta(new_offset_delta);
+ } else {
+ assert(frame->is_same_frame() ||
+ frame->is_same_frame_1_stack_item_frame(),
+ "Frame must be one of the compressed forms");
+ // The new delta exceeds the capacity of the 'same_frame' or
+ // 'same_frame_1_stack_item_frame' frame types. We need to
+ // convert these frames to the extended versions, but the extended
+ // version is bigger and requires more room. So we allocate a
+ // new array and copy the data, being sure to leave u2-sized hole
+ // right after the 'frame_type' for the new offset field.
+ //
+ // We can safely ignore the reverse situation as a small delta
+ // can still be used in an extended version of the frame.
+
+ size_t frame_offset = (address)frame - (address)data->byte_at_addr(0);
+
+ data = insert_hole_at(frame_offset + 1, 2, data);
+ if (data == NULL) {
+ return; // out-of-memory?
+ }
+
+ address frame_addr = (address)(data->byte_at_addr(0) + frame_offset);
+ frame = stack_map_frame::at(frame_addr);
+
+
+ // Now convert the frames in place
+ if (frame->is_same_frame()) {
+ same_frame_extended::create_at(frame_addr, new_offset_delta);
+ } else {
+ same_frame_1_stack_item_extended::create_at(
+ frame_addr, new_offset_delta, NULL);
+ // the verification_info_type should already be at the right spot
+ }
+ }
+ offset_adjusted = true; // needs to be done only once, since subsequent
+ // values are offsets from the current
+ }
+
+ // The stack map frame may contain verification types, if so we need to
+ // check and update any Uninitialized type's bci (no matter where it is).
+ int number_of_types = frame->number_of_types();
+ verification_type_info* types = frame->types();
+
+ for (int i = 0; i < number_of_types; ++i) {
+ if (types->is_uninitialized() && types->bci() > bci) {
+ types->set_bci(types->bci() + delta);
+ }
+ types = types->next();
+ }
+
+ // Full frame has stack values too
+ full_frame* ff = frame->as_full_frame();
+ if (ff != NULL) {
+ address eol = (address)types;
+ number_of_types = ff->stack_slots(eol);
+ types = ff->stack(eol);
+ for (int i = 0; i < number_of_types; ++i) {
+ if (types->is_uninitialized() && types->bci() > bci) {
+ types->set_bci(types->bci() + delta);
+ }
+ types = types->next();
+ }
+ }
+
+ frame = frame->next();
+ }
+
+ method()->set_stackmap_data(data); // in case it has changed
+ }
+}
+
bool Relocator::expand_code_array(int delta) {
int length = MAX2(code_length() + delta, code_length() * (100+code_slop_pct()) / 100);
@@ -499,6 +613,9 @@
// And local variable table...
adjust_local_var_table(bci, delta);
+ // Adjust stack maps
+ adjust_stack_map_table(bci, delta);
+
// Relocate the pending change stack...
for (int j = 0; j < _changes->length(); j++) {
ChangeItem* ci = _changes->at(j);
@@ -641,6 +758,7 @@
memmove(addr_at(bci +1 + new_pad),
addr_at(bci +1 + old_pad),
len * 4);
+ memset(addr_at(bci + 1), 0, new_pad); // pad must be 0
}
}
return true;
--- a/hotspot/src/share/vm/runtime/relocator.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/relocator.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -105,6 +105,7 @@
void adjust_exception_table(int bci, int delta);
void adjust_line_no_table (int bci, int delta);
void adjust_local_var_table(int bci, int delta);
+ void adjust_stack_map_table(int bci, int delta);
int get_orig_switch_pad (int bci, bool is_lookup_switch);
int rc_instr_len (int bci);
bool expand_code_array (int delta);
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -940,8 +940,7 @@
// as otherwise we may never deliver it.
if (thread()->has_async_condition()) {
ThreadInVMfromJavaNoAsyncException __tiv(thread());
- VM_DeoptimizeFrame deopt(thread(), caller_fr.id());
- VMThread::execute(&deopt);
+ Deoptimization::deoptimize_frame(thread(), caller_fr.id());
}
// If an exception has been installed we must check for a pending deoptimization
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -302,6 +302,9 @@
return (f <= (double)0.0) ? (double)0.0 - f : f;
}
+#endif
+
+#if defined(__SOFTFP__) || defined(PPC)
double SharedRuntime::dsqrt(double f) {
return sqrt(f);
}
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -116,6 +116,9 @@
#if defined(__SOFTFP__) || defined(E500V2)
static double dabs(double f);
+#endif
+
+#if defined(__SOFTFP__) || defined(PPC)
static double dsqrt(double f);
#endif
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -32,15 +32,12 @@
#define ATTR
#endif
-// Native markword accessors for synchronization and hashCode().
-//
// The "core" versions of monitor enter and exit reside in this file.
// The interpreter and compilers contain specialized transliterated
// variants of the enter-exit fast-path operations. See i486.ad fast_lock(),
// for instance. If you make changes here, make sure to modify the
// interpreter, and both C1 and C2 fast-path inline locking code emission.
//
-// TODO: merge the objectMonitor and synchronizer classes.
//
// -----------------------------------------------------------------------------
@@ -53,16 +50,6 @@
jlong, uintptr_t, char*, int, long);
HS_DTRACE_PROBE_DECL4(hotspot, monitor__waited,
jlong, uintptr_t, char*, int);
-HS_DTRACE_PROBE_DECL4(hotspot, monitor__notify,
- jlong, uintptr_t, char*, int);
-HS_DTRACE_PROBE_DECL4(hotspot, monitor__notifyAll,
- jlong, uintptr_t, char*, int);
-HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__enter,
- jlong, uintptr_t, char*, int);
-HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__entered,
- jlong, uintptr_t, char*, int);
-HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__exit,
- jlong, uintptr_t, char*, int);
#define DTRACE_MONITOR_PROBE_COMMON(klassOop, thread) \
char* bytes = NULL; \
@@ -99,61 +86,300 @@
#endif // ndef DTRACE_ENABLED
-// ObjectWaiter serves as a "proxy" or surrogate thread.
-// TODO-FIXME: Eliminate ObjectWaiter and use the thread-specific
-// ParkEvent instead. Beware, however, that the JVMTI code
-// knows about ObjectWaiters, so we'll have to reconcile that code.
-// See next_waiter(), first_waiter(), etc.
+// This exists only as a workaround of dtrace bug 6254741
+int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) {
+ DTRACE_MONITOR_PROBE(waited, monitor, obj(), thr);
+ return 0;
+}
+
+#define NINFLATIONLOCKS 256
+static volatile intptr_t InflationLocks [NINFLATIONLOCKS] ;
+
+ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ;
+ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ;
+ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ;
+int ObjectSynchronizer::gOmInUseCount = 0;
+static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache
+static volatile int MonitorFreeCount = 0 ; // # on gFreeList
+static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation
+#define CHAINMARKER ((oop)-1)
+
+// -----------------------------------------------------------------------------
+// Fast Monitor Enter/Exit
+// This the fast monitor enter. The interpreter and compiler use
+// some assembly copies of this code. Make sure update those code
+// if the following function is changed. The implementation is
+// extremely sensitive to race condition. Be careful.
+
+void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
+ if (UseBiasedLocking) {
+ if (!SafepointSynchronize::is_at_safepoint()) {
+ BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
+ if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
+ return;
+ }
+ } else {
+ assert(!attempt_rebias, "can not rebias toward VM thread");
+ BiasedLocking::revoke_at_safepoint(obj);
+ }
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+
+ slow_enter (obj, lock, THREAD) ;
+}
+
+void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
+ assert(!object->mark()->has_bias_pattern(), "should not see bias pattern here");
+ // if displaced header is null, the previous enter is recursive enter, no-op
+ markOop dhw = lock->displaced_header();
+ markOop mark ;
+ if (dhw == NULL) {
+ // Recursive stack-lock.
+ // Diagnostics -- Could be: stack-locked, inflating, inflated.
+ mark = object->mark() ;
+ assert (!mark->is_neutral(), "invariant") ;
+ if (mark->has_locker() && mark != markOopDesc::INFLATING()) {
+ assert(THREAD->is_lock_owned((address)mark->locker()), "invariant") ;
+ }
+ if (mark->has_monitor()) {
+ ObjectMonitor * m = mark->monitor() ;
+ assert(((oop)(m->object()))->mark() == mark, "invariant") ;
+ assert(m->is_entered(THREAD), "invariant") ;
+ }
+ return ;
+ }
+
+ mark = object->mark() ;
-class ObjectWaiter : public StackObj {
- public:
- enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
- enum Sorted { PREPEND, APPEND, SORTED } ;
- ObjectWaiter * volatile _next;
- ObjectWaiter * volatile _prev;
- Thread* _thread;
- ParkEvent * _event;
- volatile int _notified ;
- volatile TStates TState ;
- Sorted _Sorted ; // List placement disposition
- bool _active ; // Contention monitoring is enabled
- public:
- ObjectWaiter(Thread* thread) {
- _next = NULL;
- _prev = NULL;
- _notified = 0;
- TState = TS_RUN ;
- _thread = thread;
- _event = thread->_ParkEvent ;
- _active = false;
- assert (_event != NULL, "invariant") ;
+ // If the object is stack-locked by the current thread, try to
+ // swing the displaced header from the box back to the mark.
+ if (mark == (markOop) lock) {
+ assert (dhw->is_neutral(), "invariant") ;
+ if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) {
+ TEVENT (fast_exit: release stacklock) ;
+ return;
+ }
+ }
+
+ ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ;
+}
+
+// -----------------------------------------------------------------------------
+// Interpreter/Compiler Slow Case
+// This routine is used to handle interpreter/compiler slow case
+// We don't need to use fast path here, because it must have been
+// failed in the interpreter/compiler code.
+void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
+ markOop mark = obj->mark();
+ assert(!mark->has_bias_pattern(), "should not see bias pattern here");
+
+ if (mark->is_neutral()) {
+ // Anticipate successful CAS -- the ST of the displaced mark must
+ // be visible <= the ST performed by the CAS.
+ lock->set_displaced_header(mark);
+ if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
+ TEVENT (slow_enter: release stacklock) ;
+ return ;
+ }
+ // Fall through to inflate() ...
+ } else
+ if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
+ assert(lock != mark->locker(), "must not re-lock the same lock");
+ assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
+ lock->set_displaced_header(NULL);
+ return;
+ }
+
+#if 0
+ // The following optimization isn't particularly useful.
+ if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
+ lock->set_displaced_header (NULL) ;
+ return ;
+ }
+#endif
+
+ // The object header will never be displaced to this lock,
+ // so it does not matter what the value is, except that it
+ // must be non-zero to avoid looking like a re-entrant lock,
+ // and must not look locked either.
+ lock->set_displaced_header(markOopDesc::unused_mark());
+ ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
+}
+
+// This routine is used to handle interpreter/compiler slow case
+// We don't need to use fast path here, because it must have
+// failed in the interpreter/compiler code. Simply use the heavy
+// weight monitor should be ok, unless someone find otherwise.
+void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
+ fast_exit (object, lock, THREAD) ;
+}
+
+// -----------------------------------------------------------------------------
+// Class Loader support to workaround deadlocks on the class loader lock objects
+// Also used by GC
+// complete_exit()/reenter() are used to wait on a nested lock
+// i.e. to give up an outer lock completely and then re-enter
+// Used when holding nested locks - lock acquisition order: lock1 then lock2
+// 1) complete_exit lock1 - saving recursion count
+// 2) wait on lock2
+// 3) when notified on lock2, unlock lock2
+// 4) reenter lock1 with original recursion count
+// 5) lock lock2
+// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
+intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
+ TEVENT (complete_exit) ;
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
- void wait_reenter_begin(ObjectMonitor *mon) {
- JavaThread *jt = (JavaThread *)this->_thread;
- _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+
+ return monitor->complete_exit(THREAD);
+}
+
+// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
+void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) {
+ TEVENT (reenter) ;
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+
+ monitor->reenter(recursion, THREAD);
+}
+// -----------------------------------------------------------------------------
+// JNI locks on java objects
+// NOTE: must use heavy weight monitor to handle jni monitor enter
+void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { // possible entry from jni enter
+ // the current locking is from JNI instead of Java code
+ TEVENT (jni_enter) ;
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+ THREAD->set_current_pending_monitor_is_from_java(false);
+ ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
+ THREAD->set_current_pending_monitor_is_from_java(true);
+}
+
+// NOTE: must use heavy weight monitor to handle jni monitor enter
+bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
- void wait_reenter_end(ObjectMonitor *mon) {
- JavaThread *jt = (JavaThread *)this->_thread;
- JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj());
+ return monitor->try_enter(THREAD);
+}
+
+
+// NOTE: must use heavy weight monitor to handle jni monitor exit
+void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) {
+ TEVENT (jni_exit) ;
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ }
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj);
+ // If this thread has locked the object, exit the monitor. Note: can't use
+ // monitor->check(CHECK); must exit even if an exception is pending.
+ if (monitor->check(THREAD)) {
+ monitor->exit(THREAD);
}
-};
+}
+
+// -----------------------------------------------------------------------------
+// Internal VM locks on java objects
+// standard constructor, allows locking failures
+ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) {
+ _dolock = doLock;
+ _thread = thread;
+ debug_only(if (StrictSafepointChecks) _thread->check_for_valid_safepoint_state(false);)
+ _obj = obj;
-enum ManifestConstants {
- ClearResponsibleAtSTW = 0,
- MaximumRecheckInterval = 1000
-} ;
+ if (_dolock) {
+ TEVENT (ObjectLocker) ;
+
+ ObjectSynchronizer::fast_enter(_obj, &_lock, false, _thread);
+ }
+}
+
+ObjectLocker::~ObjectLocker() {
+ if (_dolock) {
+ ObjectSynchronizer::fast_exit(_obj(), &_lock, _thread);
+ }
+}
-#undef TEVENT
-#define TEVENT(nom) {if (SyncVerbose) FEVENT(nom); }
+// -----------------------------------------------------------------------------
+// Wait/Notify/NotifyAll
+// NOTE: must use heavy weight monitor to handle wait()
+void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+ if (millis < 0) {
+ TEVENT (wait - throw IAX) ;
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
+ }
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+ DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
+ monitor->wait(millis, true, THREAD);
+
+ /* This dummy call is in place to get around dtrace bug 6254741. Once
+ that's fixed we can uncomment the following line and remove the call */
+ // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
+ dtrace_waited_probe(monitor, obj, THREAD);
+}
-#define FEVENT(nom) { static volatile int ctr = 0 ; int v = ++ctr ; if ((v & (v-1)) == 0) { ::printf (#nom " : %d \n", v); ::fflush(stdout); }}
+void ObjectSynchronizer::waitUninterruptibly (Handle obj, jlong millis, TRAPS) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+ if (millis < 0) {
+ TEVENT (wait - throw IAX) ;
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
+ }
+ ObjectSynchronizer::inflate(THREAD, obj()) -> wait(millis, false, THREAD) ;
+}
+
+void ObjectSynchronizer::notify(Handle obj, TRAPS) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
-#undef TEVENT
-#define TEVENT(nom) {;}
+ markOop mark = obj->mark();
+ if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
+ return;
+ }
+ ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
+}
+// NOTE: see comment of notify()
+void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(obj, false, THREAD);
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+
+ markOop mark = obj->mark();
+ if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
+ return;
+ }
+ ObjectSynchronizer::inflate(THREAD, obj())->notifyAll(THREAD);
+}
+
+// -----------------------------------------------------------------------------
+// Hash Code handling
+//
// Performance concern:
// OrderAccess::storestore() calls release() which STs 0 into the global volatile
// OrderAccess::Dummy variable. This store is unnecessary for correctness.
@@ -188,44 +414,73 @@
static int MonitorScavengeThreshold = 1000000 ;
static volatile int ForceMonitorScavenge = 0 ; // Scavenge required and pending
-
-// Tunables ...
-// The knob* variables are effectively final. Once set they should
-// never be modified hence. Consider using __read_mostly with GCC.
+static markOop ReadStableMark (oop obj) {
+ markOop mark = obj->mark() ;
+ if (!mark->is_being_inflated()) {
+ return mark ; // normal fast-path return
+ }
-static int Knob_LogSpins = 0 ; // enable jvmstat tally for spins
-static int Knob_HandOff = 0 ;
-static int Knob_Verbose = 0 ;
-static int Knob_ReportSettings = 0 ;
+ int its = 0 ;
+ for (;;) {
+ markOop mark = obj->mark() ;
+ if (!mark->is_being_inflated()) {
+ return mark ; // normal fast-path return
+ }
+
+ // The object is being inflated by some other thread.
+ // The caller of ReadStableMark() must wait for inflation to complete.
+ // Avoid live-lock
+ // TODO: consider calling SafepointSynchronize::do_call_back() while
+ // spinning to see if there's a safepoint pending. If so, immediately
+ // yielding or blocking would be appropriate. Avoid spinning while
+ // there is a safepoint pending.
+ // TODO: add inflation contention performance counters.
+ // TODO: restrict the aggregate number of spinners.
-static int Knob_SpinLimit = 5000 ; // derived by an external tool -
-static int Knob_SpinBase = 0 ; // Floor AKA SpinMin
-static int Knob_SpinBackOff = 0 ; // spin-loop backoff
-static int Knob_CASPenalty = -1 ; // Penalty for failed CAS
-static int Knob_OXPenalty = -1 ; // Penalty for observed _owner change
-static int Knob_SpinSetSucc = 1 ; // spinners set the _succ field
-static int Knob_SpinEarly = 1 ;
-static int Knob_SuccEnabled = 1 ; // futile wake throttling
-static int Knob_SuccRestrict = 0 ; // Limit successors + spinners to at-most-one
-static int Knob_MaxSpinners = -1 ; // Should be a function of # CPUs
-static int Knob_Bonus = 100 ; // spin success bonus
-static int Knob_BonusB = 100 ; // spin success bonus
-static int Knob_Penalty = 200 ; // spin failure penalty
-static int Knob_Poverty = 1000 ;
-static int Knob_SpinAfterFutile = 1 ; // Spin after returning from park()
-static int Knob_FixedSpin = 0 ;
-static int Knob_OState = 3 ; // Spinner checks thread state of _owner
-static int Knob_UsePause = 1 ;
-static int Knob_ExitPolicy = 0 ;
-static int Knob_PreSpin = 10 ; // 20-100 likely better
-static int Knob_ResetEvent = 0 ;
-static int BackOffMask = 0 ;
-
-static int Knob_FastHSSEC = 0 ;
-static int Knob_MoveNotifyee = 2 ; // notify() - disposition of notifyee
-static int Knob_QMode = 0 ; // EntryList-cxq policy - queue discipline
-static volatile int InitDone = 0 ;
-
+ ++its ;
+ if (its > 10000 || !os::is_MP()) {
+ if (its & 1) {
+ os::NakedYield() ;
+ TEVENT (Inflate: INFLATING - yield) ;
+ } else {
+ // Note that the following code attenuates the livelock problem but is not
+ // a complete remedy. A more complete solution would require that the inflating
+ // thread hold the associated inflation lock. The following code simply restricts
+ // the number of spinners to at most one. We'll have N-2 threads blocked
+ // on the inflationlock, 1 thread holding the inflation lock and using
+ // a yield/park strategy, and 1 thread in the midst of inflation.
+ // A more refined approach would be to change the encoding of INFLATING
+ // to allow encapsulation of a native thread pointer. Threads waiting for
+ // inflation to complete would use CAS to push themselves onto a singly linked
+ // list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag
+ // and calling park(). When inflation was complete the thread that accomplished inflation
+ // would detach the list and set the markword to inflated with a single CAS and
+ // then for each thread on the list, set the flag and unpark() the thread.
+ // This is conceptually similar to muxAcquire-muxRelease, except that muxRelease
+ // wakes at most one thread whereas we need to wake the entire list.
+ int ix = (intptr_t(obj) >> 5) & (NINFLATIONLOCKS-1) ;
+ int YieldThenBlock = 0 ;
+ assert (ix >= 0 && ix < NINFLATIONLOCKS, "invariant") ;
+ assert ((NINFLATIONLOCKS & (NINFLATIONLOCKS-1)) == 0, "invariant") ;
+ Thread::muxAcquire (InflationLocks + ix, "InflationLock") ;
+ while (obj->mark() == markOopDesc::INFLATING()) {
+ // Beware: NakedYield() is advisory and has almost no effect on some platforms
+ // so we periodically call Self->_ParkEvent->park(1).
+ // We use a mixed spin/yield/block mechanism.
+ if ((YieldThenBlock++) >= 16) {
+ Thread::current()->_ParkEvent->park(1) ;
+ } else {
+ os::NakedYield() ;
+ }
+ }
+ Thread::muxRelease (InflationLocks + ix ) ;
+ TEVENT (Inflate: INFLATING - yield/park) ;
+ }
+ } else {
+ SpinPause() ; // SMP-polite spinning
+ }
+ }
+}
// hashCode() generation :
//
@@ -290,416 +545,272 @@
TEVENT (hashCode: GENERATE) ;
return value;
}
+//
+intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
+ if (UseBiasedLocking) {
+ // NOTE: many places throughout the JVM do not expect a safepoint
+ // to be taken here, in particular most operations on perm gen
+ // objects. However, we only ever bias Java instances and all of
+ // the call sites of identity_hash that might revoke biases have
+ // been checked to make sure they can handle a safepoint. The
+ // added check of the bias pattern is to avoid useless calls to
+ // thread-local storage.
+ if (obj->mark()->has_bias_pattern()) {
+ // Box and unbox the raw reference just in case we cause a STW safepoint.
+ Handle hobj (Self, obj) ;
+ // Relaxing assertion for bug 6320749.
+ assert (Universe::verify_in_progress() ||
+ !SafepointSynchronize::is_at_safepoint(),
+ "biases should not be seen by VM thread here");
+ BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
+ obj = hobj() ;
+ assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+ }
-void BasicLock::print_on(outputStream* st) const {
- st->print("monitor");
+ // hashCode() is a heap mutator ...
+ // Relaxing assertion for bug 6320749.
+ assert (Universe::verify_in_progress() ||
+ !SafepointSynchronize::is_at_safepoint(), "invariant") ;
+ assert (Universe::verify_in_progress() ||
+ Self->is_Java_thread() , "invariant") ;
+ assert (Universe::verify_in_progress() ||
+ ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
+
+ ObjectMonitor* monitor = NULL;
+ markOop temp, test;
+ intptr_t hash;
+ markOop mark = ReadStableMark (obj);
+
+ // object should remain ineligible for biased locking
+ assert (!mark->has_bias_pattern(), "invariant") ;
+
+ if (mark->is_neutral()) {
+ hash = mark->hash(); // this is a normal header
+ if (hash) { // if it has hash, just return it
+ return hash;
+ }
+ hash = get_next_hash(Self, obj); // allocate a new hash code
+ temp = mark->copy_set_hash(hash); // merge the hash code into header
+ // use (machine word version) atomic operation to install the hash
+ test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
+ if (test == mark) {
+ return hash;
+ }
+ // If atomic operation failed, we must inflate the header
+ // into heavy weight monitor. We could add more code here
+ // for fast path, but it does not worth the complexity.
+ } else if (mark->has_monitor()) {
+ monitor = mark->monitor();
+ temp = monitor->header();
+ assert (temp->is_neutral(), "invariant") ;
+ hash = temp->hash();
+ if (hash) {
+ return hash;
+ }
+ // Skip to the following code to reduce code size
+ } else if (Self->is_lock_owned((address)mark->locker())) {
+ temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
+ assert (temp->is_neutral(), "invariant") ;
+ hash = temp->hash(); // by current thread, check if the displaced
+ if (hash) { // header contains hash code
+ return hash;
+ }
+ // WARNING:
+ // The displaced header is strictly immutable.
+ // It can NOT be changed in ANY cases. So we have
+ // to inflate the header into heavyweight monitor
+ // even the current thread owns the lock. The reason
+ // is the BasicLock (stack slot) will be asynchronously
+ // read by other threads during the inflate() function.
+ // Any change to stack may not propagate to other threads
+ // correctly.
+ }
+
+ // Inflate the monitor to set hash code
+ monitor = ObjectSynchronizer::inflate(Self, obj);
+ // Load displaced header and check it has hash code
+ mark = monitor->header();
+ assert (mark->is_neutral(), "invariant") ;
+ hash = mark->hash();
+ if (hash == 0) {
+ hash = get_next_hash(Self, obj);
+ temp = mark->copy_set_hash(hash); // merge hash code into header
+ assert (temp->is_neutral(), "invariant") ;
+ test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
+ if (test != mark) {
+ // The only update to the header in the monitor (outside GC)
+ // is install the hash code. If someone add new usage of
+ // displaced header, please update this code
+ hash = test->hash();
+ assert (test->is_neutral(), "invariant") ;
+ assert (hash != 0, "Trivial unexpected object/monitor header usage.");
+ }
+ }
+ // We finally get the hash
+ return hash;
}
-void BasicLock::move_to(oop obj, BasicLock* dest) {
- // Check to see if we need to inflate the lock. This is only needed
- // if an object is locked using "this" lightweight monitor. In that
- // case, the displaced_header() is unlocked, because the
- // displaced_header() contains the header for the originally unlocked
- // object. However the object could have already been inflated. But it
- // does not matter, the inflation will just a no-op. For other cases,
- // the displaced header will be either 0x0 or 0x3, which are location
- // independent, therefore the BasicLock is free to move.
- //
- // During OSR we may need to relocate a BasicLock (which contains a
- // displaced word) from a location in an interpreter frame to a
- // new location in a compiled frame. "this" refers to the source
- // basiclock in the interpreter frame. "dest" refers to the destination
- // basiclock in the new compiled frame. We *always* inflate in move_to().
- // The always-Inflate policy works properly, but in 1.5.0 it can sometimes
- // cause performance problems in code that makes heavy use of a small # of
- // uncontended locks. (We'd inflate during OSR, and then sync performance
- // would subsequently plummet because the thread would be forced thru the slow-path).
- // This problem has been made largely moot on IA32 by inlining the inflated fast-path
- // operations in Fast_Lock and Fast_Unlock in i486.ad.
- //
- // Note that there is a way to safely swing the object's markword from
- // one stack location to another. This avoids inflation. Obviously,
- // we need to ensure that both locations refer to the current thread's stack.
- // There are some subtle concurrency issues, however, and since the benefit is
- // is small (given the support for inflated fast-path locking in the fast_lock, etc)
- // we'll leave that optimization for another time.
+// Deprecated -- use FastHashCode() instead.
- if (displaced_header()->is_neutral()) {
- ObjectSynchronizer::inflate_helper(obj);
- // WARNING: We can not put check here, because the inflation
- // will not update the displaced header. Once BasicLock is inflated,
- // no one should ever look at its content.
- } else {
- // Typically the displaced header will be 0 (recursive stack lock) or
- // unused_mark. Naively we'd like to assert that the displaced mark
- // value is either 0, neutral, or 3. But with the advent of the
- // store-before-CAS avoidance in fast_lock/compiler_lock_object
- // we can find any flavor mark in the displaced mark.
- }
-// [RGV] The next line appears to do nothing!
- intptr_t dh = (intptr_t) displaced_header();
- dest->set_displaced_header(displaced_header());
+intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) {
+ return FastHashCode (Thread::current(), obj()) ;
}
-// -----------------------------------------------------------------------------
-// standard constructor, allows locking failures
-ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) {
- _dolock = doLock;
- _thread = thread;
- debug_only(if (StrictSafepointChecks) _thread->check_for_valid_safepoint_state(false);)
- _obj = obj;
+bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* thread,
+ Handle h_obj) {
+ if (UseBiasedLocking) {
+ BiasedLocking::revoke_and_rebias(h_obj, false, thread);
+ assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+
+ assert(thread == JavaThread::current(), "Can only be called on current thread");
+ oop obj = h_obj();
+
+ markOop mark = ReadStableMark (obj) ;
- if (_dolock) {
- TEVENT (ObjectLocker) ;
-
- ObjectSynchronizer::fast_enter(_obj, &_lock, false, _thread);
+ // Uncontended case, header points to stack
+ if (mark->has_locker()) {
+ return thread->is_lock_owned((address)mark->locker());
}
-}
-
-ObjectLocker::~ObjectLocker() {
- if (_dolock) {
- ObjectSynchronizer::fast_exit(_obj(), &_lock, _thread);
+ // Contended case, header points to ObjectMonitor (tagged pointer)
+ if (mark->has_monitor()) {
+ ObjectMonitor* monitor = mark->monitor();
+ return monitor->is_entered(thread) != 0 ;
}
+ // Unlocked case, header in place
+ assert(mark->is_neutral(), "sanity check");
+ return false;
}
-// -----------------------------------------------------------------------------
+// Be aware of this method could revoke bias of the lock object.
+// This method querys the ownership of the lock handle specified by 'h_obj'.
+// If the current thread owns the lock, it returns owner_self. If no
+// thread owns the lock, it returns owner_none. Otherwise, it will return
+// ower_other.
+ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership
+(JavaThread *self, Handle h_obj) {
+ // The caller must beware this method can revoke bias, and
+ // revocation can result in a safepoint.
+ assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
+ assert (self->thread_state() != _thread_blocked , "invariant") ;
+ // Possible mark states: neutral, biased, stack-locked, inflated
+
+ if (UseBiasedLocking && h_obj()->mark()->has_bias_pattern()) {
+ // CASE: biased
+ BiasedLocking::revoke_and_rebias(h_obj, false, self);
+ assert(!h_obj->mark()->has_bias_pattern(),
+ "biases should be revoked by now");
+ }
-PerfCounter * ObjectSynchronizer::_sync_Inflations = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_Deflations = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_ContendedLockAttempts = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_FutileWakeups = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_Parks = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_EmptyNotifications = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_Notifications = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_PrivateA = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_PrivateB = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_SlowExit = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_SlowEnter = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_SlowNotify = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_SlowNotifyAll = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_FailedSpins = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_SuccessfulSpins = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_MonInCirculation = NULL ;
-PerfCounter * ObjectSynchronizer::_sync_MonScavenged = NULL ;
-PerfLongVariable * ObjectSynchronizer::_sync_MonExtant = NULL ;
+ assert(self == JavaThread::current(), "Can only be called on current thread");
+ oop obj = h_obj();
+ markOop mark = ReadStableMark (obj) ;
+
+ // CASE: stack-locked. Mark points to a BasicLock on the owner's stack.
+ if (mark->has_locker()) {
+ return self->is_lock_owned((address)mark->locker()) ?
+ owner_self : owner_other;
+ }
-// One-shot global initialization for the sync subsystem.
-// We could also defer initialization and initialize on-demand
-// the first time we call inflate(). Initialization would
-// be protected - like so many things - by the MonitorCache_lock.
+ // CASE: inflated. Mark (tagged pointer) points to an objectMonitor.
+ // The Object:ObjectMonitor relationship is stable as long as we're
+ // not at a safepoint.
+ if (mark->has_monitor()) {
+ void * owner = mark->monitor()->_owner ;
+ if (owner == NULL) return owner_none ;
+ return (owner == self ||
+ self->is_lock_owned((address)owner)) ? owner_self : owner_other;
+ }
+
+ // CASE: neutral
+ assert(mark->is_neutral(), "sanity check");
+ return owner_none ; // it's unlocked
+}
-void ObjectSynchronizer::Initialize () {
- static int InitializationCompleted = 0 ;
- assert (InitializationCompleted == 0, "invariant") ;
- InitializationCompleted = 1 ;
- if (UsePerfData) {
- EXCEPTION_MARK ;
- #define NEWPERFCOUNTER(n) {n = PerfDataManager::create_counter(SUN_RT, #n, PerfData::U_Events,CHECK); }
- #define NEWPERFVARIABLE(n) {n = PerfDataManager::create_variable(SUN_RT, #n, PerfData::U_Events,CHECK); }
- NEWPERFCOUNTER(_sync_Inflations) ;
- NEWPERFCOUNTER(_sync_Deflations) ;
- NEWPERFCOUNTER(_sync_ContendedLockAttempts) ;
- NEWPERFCOUNTER(_sync_FutileWakeups) ;
- NEWPERFCOUNTER(_sync_Parks) ;
- NEWPERFCOUNTER(_sync_EmptyNotifications) ;
- NEWPERFCOUNTER(_sync_Notifications) ;
- NEWPERFCOUNTER(_sync_SlowEnter) ;
- NEWPERFCOUNTER(_sync_SlowExit) ;
- NEWPERFCOUNTER(_sync_SlowNotify) ;
- NEWPERFCOUNTER(_sync_SlowNotifyAll) ;
- NEWPERFCOUNTER(_sync_FailedSpins) ;
- NEWPERFCOUNTER(_sync_SuccessfulSpins) ;
- NEWPERFCOUNTER(_sync_PrivateA) ;
- NEWPERFCOUNTER(_sync_PrivateB) ;
- NEWPERFCOUNTER(_sync_MonInCirculation) ;
- NEWPERFCOUNTER(_sync_MonScavenged) ;
- NEWPERFVARIABLE(_sync_MonExtant) ;
- #undef NEWPERFCOUNTER
+// FIXME: jvmti should call this
+JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
+ if (UseBiasedLocking) {
+ if (SafepointSynchronize::is_at_safepoint()) {
+ BiasedLocking::revoke_at_safepoint(h_obj);
+ } else {
+ BiasedLocking::revoke_and_rebias(h_obj, false, JavaThread::current());
+ }
+ assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
+ }
+
+ oop obj = h_obj();
+ address owner = NULL;
+
+ markOop mark = ReadStableMark (obj) ;
+
+ // Uncontended case, header points to stack
+ if (mark->has_locker()) {
+ owner = (address) mark->locker();
+ }
+
+ // Contended case, header points to ObjectMonitor (tagged pointer)
+ if (mark->has_monitor()) {
+ ObjectMonitor* monitor = mark->monitor();
+ assert(monitor != NULL, "monitor should be non-null");
+ owner = (address) monitor->owner();
+ }
+
+ if (owner != NULL) {
+ return Threads::owning_thread_from_monitor_owner(owner, doLock);
+ }
+
+ // Unlocked case, header in place
+ // Cannot have assertion since this object may have been
+ // locked by another thread when reaching here.
+ // assert(mark->is_neutral(), "sanity check");
+
+ return NULL;
+}
+// Visitors ...
+
+void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) {
+ ObjectMonitor* block = gBlockList;
+ ObjectMonitor* mid;
+ while (block) {
+ assert(block->object() == CHAINMARKER, "must be a block header");
+ for (int i = _BLOCKSIZE - 1; i > 0; i--) {
+ mid = block + i;
+ oop object = (oop) mid->object();
+ if (object != NULL) {
+ closure->do_monitor(mid);
+ }
+ }
+ block = (ObjectMonitor*) block->FreeNext;
}
}
-// Compile-time asserts
-// When possible, it's better to catch errors deterministically at
-// compile-time than at runtime. The down-side to using compile-time
-// asserts is that error message -- often something about negative array
-// indices -- is opaque.
-
-#define CTASSERT(x) { int tag[1-(2*!(x))]; printf ("Tag @" INTPTR_FORMAT "\n", (intptr_t)tag); }
-
-void ObjectMonitor::ctAsserts() {
- CTASSERT(offset_of (ObjectMonitor, _header) == 0);
-}
-
-static int Adjust (volatile int * adr, int dx) {
- int v ;
- for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
- return v ;
-}
-
-// Ad-hoc mutual exclusion primitives: SpinLock and Mux
-//
-// We employ SpinLocks _only for low-contention, fixed-length
-// short-duration critical sections where we're concerned
-// about native mutex_t or HotSpot Mutex:: latency.
-// The mux construct provides a spin-then-block mutual exclusion
-// mechanism.
-//
-// Testing has shown that contention on the ListLock guarding gFreeList
-// is common. If we implement ListLock as a simple SpinLock it's common
-// for the JVM to devolve to yielding with little progress. This is true
-// despite the fact that the critical sections protected by ListLock are
-// extremely short.
-//
-// TODO-FIXME: ListLock should be of type SpinLock.
-// We should make this a 1st-class type, integrated into the lock
-// hierarchy as leaf-locks. Critically, the SpinLock structure
-// should have sufficient padding to avoid false-sharing and excessive
-// cache-coherency traffic.
-
-
-typedef volatile int SpinLockT ;
-
-void Thread::SpinAcquire (volatile int * adr, const char * LockName) {
- if (Atomic::cmpxchg (1, adr, 0) == 0) {
- return ; // normal fast-path return
- }
-
- // Slow-path : We've encountered contention -- Spin/Yield/Block strategy.
- TEVENT (SpinAcquire - ctx) ;
- int ctr = 0 ;
- int Yields = 0 ;
- for (;;) {
- while (*adr != 0) {
- ++ctr ;
- if ((ctr & 0xFFF) == 0 || !os::is_MP()) {
- if (Yields > 5) {
- // Consider using a simple NakedSleep() instead.
- // Then SpinAcquire could be called by non-JVM threads
- Thread::current()->_ParkEvent->park(1) ;
- } else {
- os::NakedYield() ;
- ++Yields ;
- }
- } else {
- SpinPause() ;
- }
- }
- if (Atomic::cmpxchg (1, adr, 0) == 0) return ;
- }
-}
-
-void Thread::SpinRelease (volatile int * adr) {
- assert (*adr != 0, "invariant") ;
- OrderAccess::fence() ; // guarantee at least release consistency.
- // Roach-motel semantics.
- // It's safe if subsequent LDs and STs float "up" into the critical section,
- // but prior LDs and STs within the critical section can't be allowed
- // to reorder or float past the ST that releases the lock.
- *adr = 0 ;
+// Get the next block in the block list.
+static inline ObjectMonitor* next(ObjectMonitor* block) {
+ assert(block->object() == CHAINMARKER, "must be a block header");
+ block = block->FreeNext ;
+ assert(block == NULL || block->object() == CHAINMARKER, "must be a block header");
+ return block;
}
-// muxAcquire and muxRelease:
-//
-// * muxAcquire and muxRelease support a single-word lock-word construct.
-// The LSB of the word is set IFF the lock is held.
-// The remainder of the word points to the head of a singly-linked list
-// of threads blocked on the lock.
-//
-// * The current implementation of muxAcquire-muxRelease uses its own
-// dedicated Thread._MuxEvent instance. If we're interested in
-// minimizing the peak number of extant ParkEvent instances then
-// we could eliminate _MuxEvent and "borrow" _ParkEvent as long
-// as certain invariants were satisfied. Specifically, care would need
-// to be taken with regards to consuming unpark() "permits".
-// A safe rule of thumb is that a thread would never call muxAcquire()
-// if it's enqueued (cxq, EntryList, WaitList, etc) and will subsequently
-// park(). Otherwise the _ParkEvent park() operation in muxAcquire() could
-// consume an unpark() permit intended for monitorenter, for instance.
-// One way around this would be to widen the restricted-range semaphore
-// implemented in park(). Another alternative would be to provide
-// multiple instances of the PlatformEvent() for each thread. One
-// instance would be dedicated to muxAcquire-muxRelease, for instance.
-//
-// * Usage:
-// -- Only as leaf locks
-// -- for short-term locking only as muxAcquire does not perform
-// thread state transitions.
-//
-// Alternatives:
-// * We could implement muxAcquire and muxRelease with MCS or CLH locks
-// but with parking or spin-then-park instead of pure spinning.
-// * Use Taura-Oyama-Yonenzawa locks.
-// * It's possible to construct a 1-0 lock if we encode the lockword as
-// (List,LockByte). Acquire will CAS the full lockword while Release
-// will STB 0 into the LockByte. The 1-0 scheme admits stranding, so
-// acquiring threads use timers (ParkTimed) to detect and recover from
-// the stranding window. Thread/Node structures must be aligned on 256-byte
-// boundaries by using placement-new.
-// * Augment MCS with advisory back-link fields maintained with CAS().
-// Pictorially: LockWord -> T1 <-> T2 <-> T3 <-> ... <-> Tn <-> Owner.
-// The validity of the backlinks must be ratified before we trust the value.
-// If the backlinks are invalid the exiting thread must back-track through the
-// the forward links, which are always trustworthy.
-// * Add a successor indication. The LockWord is currently encoded as
-// (List, LOCKBIT:1). We could also add a SUCCBIT or an explicit _succ variable
-// to provide the usual futile-wakeup optimization.
-// See RTStt for details.
-// * Consider schedctl.sc_nopreempt to cover the critical section.
-//
-
-typedef volatile intptr_t MutexT ; // Mux Lock-word
-enum MuxBits { LOCKBIT = 1 } ;
-
-void Thread::muxAcquire (volatile intptr_t * Lock, const char * LockName) {
- intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
- if (w == 0) return ;
- if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- return ;
- }
-
- TEVENT (muxAcquire - Contention) ;
- ParkEvent * const Self = Thread::current()->_MuxEvent ;
- assert ((intptr_t(Self) & LOCKBIT) == 0, "invariant") ;
- for (;;) {
- int its = (os::is_MP() ? 100 : 0) + 1 ;
-
- // Optional spin phase: spin-then-park strategy
- while (--its >= 0) {
- w = *Lock ;
- if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- return ;
- }
- }
-
- Self->reset() ;
- Self->OnList = intptr_t(Lock) ;
- // The following fence() isn't _strictly necessary as the subsequent
- // CAS() both serializes execution and ratifies the fetched *Lock value.
- OrderAccess::fence();
- for (;;) {
- w = *Lock ;
- if ((w & LOCKBIT) == 0) {
- if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- Self->OnList = 0 ; // hygiene - allows stronger asserts
- return ;
- }
- continue ; // Interference -- *Lock changed -- Just retry
- }
- assert (w & LOCKBIT, "invariant") ;
- Self->ListNext = (ParkEvent *) (w & ~LOCKBIT );
- if (Atomic::cmpxchg_ptr (intptr_t(Self)|LOCKBIT, Lock, w) == w) break ;
- }
-
- while (Self->OnList != 0) {
- Self->park() ;
- }
- }
-}
-
-void Thread::muxAcquireW (volatile intptr_t * Lock, ParkEvent * ev) {
- intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
- if (w == 0) return ;
- if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- return ;
- }
-
- TEVENT (muxAcquire - Contention) ;
- ParkEvent * ReleaseAfter = NULL ;
- if (ev == NULL) {
- ev = ReleaseAfter = ParkEvent::Allocate (NULL) ;
- }
- assert ((intptr_t(ev) & LOCKBIT) == 0, "invariant") ;
- for (;;) {
- guarantee (ev->OnList == 0, "invariant") ;
- int its = (os::is_MP() ? 100 : 0) + 1 ;
-
- // Optional spin phase: spin-then-park strategy
- while (--its >= 0) {
- w = *Lock ;
- if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- if (ReleaseAfter != NULL) {
- ParkEvent::Release (ReleaseAfter) ;
- }
- return ;
+void ObjectSynchronizer::oops_do(OopClosure* f) {
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+ for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
+ assert(block->object() == CHAINMARKER, "must be a block header");
+ for (int i = 1; i < _BLOCKSIZE; i++) {
+ ObjectMonitor* mid = &block[i];
+ if (mid->object() != NULL) {
+ f->do_oop((oop*)mid->object_addr());
}
}
-
- ev->reset() ;
- ev->OnList = intptr_t(Lock) ;
- // The following fence() isn't _strictly necessary as the subsequent
- // CAS() both serializes execution and ratifies the fetched *Lock value.
- OrderAccess::fence();
- for (;;) {
- w = *Lock ;
- if ((w & LOCKBIT) == 0) {
- if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
- ev->OnList = 0 ;
- // We call ::Release while holding the outer lock, thus
- // artificially lengthening the critical section.
- // Consider deferring the ::Release() until the subsequent unlock(),
- // after we've dropped the outer lock.
- if (ReleaseAfter != NULL) {
- ParkEvent::Release (ReleaseAfter) ;
- }
- return ;
- }
- continue ; // Interference -- *Lock changed -- Just retry
- }
- assert (w & LOCKBIT, "invariant") ;
- ev->ListNext = (ParkEvent *) (w & ~LOCKBIT );
- if (Atomic::cmpxchg_ptr (intptr_t(ev)|LOCKBIT, Lock, w) == w) break ;
- }
-
- while (ev->OnList != 0) {
- ev->park() ;
- }
}
}
-// Release() must extract a successor from the list and then wake that thread.
-// It can "pop" the front of the list or use a detach-modify-reattach (DMR) scheme
-// similar to that used by ParkEvent::Allocate() and ::Release(). DMR-based
-// Release() would :
-// (A) CAS() or swap() null to *Lock, releasing the lock and detaching the list.
-// (B) Extract a successor from the private list "in-hand"
-// (C) attempt to CAS() the residual back into *Lock over null.
-// If there were any newly arrived threads and the CAS() would fail.
-// In that case Release() would detach the RATs, re-merge the list in-hand
-// with the RATs and repeat as needed. Alternately, Release() might
-// detach and extract a successor, but then pass the residual list to the wakee.
-// The wakee would be responsible for reattaching and remerging before it
-// competed for the lock.
-//
-// Both "pop" and DMR are immune from ABA corruption -- there can be
-// multiple concurrent pushers, but only one popper or detacher.
-// This implementation pops from the head of the list. This is unfair,
-// but tends to provide excellent throughput as hot threads remain hot.
-// (We wake recently run threads first).
-void Thread::muxRelease (volatile intptr_t * Lock) {
- for (;;) {
- const intptr_t w = Atomic::cmpxchg_ptr (0, Lock, LOCKBIT) ;
- assert (w & LOCKBIT, "invariant") ;
- if (w == LOCKBIT) return ;
- ParkEvent * List = (ParkEvent *) (w & ~LOCKBIT) ;
- assert (List != NULL, "invariant") ;
- assert (List->OnList == intptr_t(Lock), "invariant") ;
- ParkEvent * nxt = List->ListNext ;
-
- // The following CAS() releases the lock and pops the head element.
- if (Atomic::cmpxchg_ptr (intptr_t(nxt), Lock, w) != w) {
- continue ;
- }
- List->OnList = 0 ;
- OrderAccess::fence() ;
- List->unpark () ;
- return ;
- }
-}
-
+// -----------------------------------------------------------------------------
// ObjectMonitor Lifecycle
// -----------------------
// Inflation unlinks monitors from the global gFreeList and
@@ -718,41 +829,7 @@
// -- assigned to an object. The object is inflated and the mark refers
// to the objectmonitor.
//
-// TODO-FIXME:
-//
-// * We currently protect the gFreeList with a simple lock.
-// An alternate lock-free scheme would be to pop elements from the gFreeList
-// with CAS. This would be safe from ABA corruption as long we only
-// recycled previously appearing elements onto the list in deflate_idle_monitors()
-// at STW-time. Completely new elements could always be pushed onto the gFreeList
-// with CAS. Elements that appeared previously on the list could only
-// be installed at STW-time.
-//
-// * For efficiency and to help reduce the store-before-CAS penalty
-// the objectmonitors on gFreeList or local free lists should be ready to install
-// with the exception of _header and _object. _object can be set after inflation.
-// In particular, keep all objectMonitors on a thread's private list in ready-to-install
-// state with m.Owner set properly.
-//
-// * We could all diffuse contention by using multiple global (FreeList, Lock)
-// pairs -- threads could use trylock() and a cyclic-scan strategy to search for
-// an unlocked free list.
-//
-// * Add lifecycle tags and assert()s.
-//
-// * Be more consistent about when we clear an objectmonitor's fields:
-// A. After extracting the objectmonitor from a free list.
-// B. After adding an objectmonitor to a free list.
-//
-ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ;
-ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ;
-ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ;
-int ObjectSynchronizer::gOmInUseCount = 0;
-static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache
-static volatile int MonitorFreeCount = 0 ; // # on gFreeList
-static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation
-#define CHAINMARKER ((oop)-1)
// Constraining monitor pool growth via MonitorBound ...
//
@@ -768,41 +845,8 @@
// we'll incur more safepoints, which are harmful to performance.
// See also: GuaranteedSafepointInterval
//
-// As noted elsewhere, the correct long-term solution is to deflate at
-// monitorexit-time, in which case the number of inflated objects is bounded
-// by the number of threads. That policy obviates the need for scavenging at
-// STW safepoint time. As an aside, scavenging can be time-consuming when the
-// # of extant monitors is large. Unfortunately there's a day-1 assumption baked
-// into much HotSpot code that the object::monitor relationship, once established
-// or observed, will remain stable except over potential safepoints.
-//
-// We can use either a blocking synchronous VM operation or an async VM operation.
-// -- If we use a blocking VM operation :
-// Calls to ScavengeCheck() should be inserted only into 'safe' locations in paths
-// that lead to ::inflate() or ::omAlloc().
-// Even though the safepoint will not directly induce GC, a GC might
-// piggyback on the safepoint operation, so the caller should hold no naked oops.
-// Furthermore, monitor::object relationships are NOT necessarily stable over this call
-// unless the caller has made provisions to "pin" the object to the monitor, say
-// by incrementing the monitor's _count field.
-// -- If we use a non-blocking asynchronous VM operation :
-// the constraints above don't apply. The safepoint will fire in the future
-// at a more convenient time. On the other hand the latency between posting and
-// running the safepoint introduces or admits "slop" or laxity during which the
-// monitor population can climb further above the threshold. The monitor population,
-// however, tends to converge asymptotically over time to a count that's slightly
-// above the target value specified by MonitorBound. That is, we avoid unbounded
-// growth, albeit with some imprecision.
-//
// The current implementation uses asynchronous VM operations.
//
-// Ideally we'd check if (MonitorPopulation > MonitorBound) in omAlloc()
-// immediately before trying to grow the global list via allocation.
-// If the predicate was true then we'd induce a synchronous safepoint, wait
-// for the safepoint to complete, and then again to allocate from the global
-// free list. This approach is much simpler and precise, admitting no "slop".
-// Unfortunately we can't safely safepoint in the midst of omAlloc(), so
-// instead we use asynchronous safepoints.
static void InduceScavenge (Thread * Self, const char * Whence) {
// Induce STW safepoint to trim monitors
@@ -812,7 +856,7 @@
// TODO: assert thread state is reasonable
if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) {
- if (Knob_Verbose) {
+ if (ObjectMonitor::Knob_Verbose) {
::printf ("Monitor scavenge - Induced STW @%s (%d)\n", Whence, ForceMonitorScavenge) ;
::fflush(stdout) ;
}
@@ -822,7 +866,7 @@
// The VMThread will delete the op when completed.
VMThread::execute (new VM_ForceAsyncSafepoint()) ;
- if (Knob_Verbose) {
+ if (ObjectMonitor::Knob_Verbose) {
::printf ("Monitor scavenge - STW posted @%s (%d)\n", Whence, ForceMonitorScavenge) ;
::fflush(stdout) ;
}
@@ -844,7 +888,6 @@
assert(freetally == Self->omFreeCount, "free count off");
}
*/
-
ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
// A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the
@@ -974,12 +1017,6 @@
// attempt failed. This doesn't allow unbounded #s of monitors to
// accumulate on a thread's free list.
//
-// In the future the usage of omRelease() might change and monitors
-// could migrate between free lists. In that case to avoid excessive
-// accumulation we could limit omCount to (omProvision*2), otherwise return
-// the objectMonitor to the global list. We should drain (return) in reasonable chunks.
-// That is, *not* one-at-a-time.
-
void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m, bool fromPerThreadAlloc) {
guarantee (m->object() == NULL, "invariant") ;
@@ -1082,15 +1119,6 @@
TEVENT (omFlush) ;
}
-
-// Get the next block in the block list.
-static inline ObjectMonitor* next(ObjectMonitor* block) {
- assert(block->object() == CHAINMARKER, "must be a block header");
- block = block->FreeNext ;
- assert(block == NULL || block->object() == CHAINMARKER, "must be a block header");
- return block;
-}
-
// Fast path code shared by multiple functions
ObjectMonitor* ObjectSynchronizer::inflate_helper(oop obj) {
markOop mark = obj->mark();
@@ -1102,79 +1130,10 @@
return ObjectSynchronizer::inflate(Thread::current(), obj);
}
+
// Note that we could encounter some performance loss through false-sharing as
// multiple locks occupy the same $ line. Padding might be appropriate.
-#define NINFLATIONLOCKS 256
-static volatile intptr_t InflationLocks [NINFLATIONLOCKS] ;
-
-static markOop ReadStableMark (oop obj) {
- markOop mark = obj->mark() ;
- if (!mark->is_being_inflated()) {
- return mark ; // normal fast-path return
- }
-
- int its = 0 ;
- for (;;) {
- markOop mark = obj->mark() ;
- if (!mark->is_being_inflated()) {
- return mark ; // normal fast-path return
- }
-
- // The object is being inflated by some other thread.
- // The caller of ReadStableMark() must wait for inflation to complete.
- // Avoid live-lock
- // TODO: consider calling SafepointSynchronize::do_call_back() while
- // spinning to see if there's a safepoint pending. If so, immediately
- // yielding or blocking would be appropriate. Avoid spinning while
- // there is a safepoint pending.
- // TODO: add inflation contention performance counters.
- // TODO: restrict the aggregate number of spinners.
-
- ++its ;
- if (its > 10000 || !os::is_MP()) {
- if (its & 1) {
- os::NakedYield() ;
- TEVENT (Inflate: INFLATING - yield) ;
- } else {
- // Note that the following code attenuates the livelock problem but is not
- // a complete remedy. A more complete solution would require that the inflating
- // thread hold the associated inflation lock. The following code simply restricts
- // the number of spinners to at most one. We'll have N-2 threads blocked
- // on the inflationlock, 1 thread holding the inflation lock and using
- // a yield/park strategy, and 1 thread in the midst of inflation.
- // A more refined approach would be to change the encoding of INFLATING
- // to allow encapsulation of a native thread pointer. Threads waiting for
- // inflation to complete would use CAS to push themselves onto a singly linked
- // list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag
- // and calling park(). When inflation was complete the thread that accomplished inflation
- // would detach the list and set the markword to inflated with a single CAS and
- // then for each thread on the list, set the flag and unpark() the thread.
- // This is conceptually similar to muxAcquire-muxRelease, except that muxRelease
- // wakes at most one thread whereas we need to wake the entire list.
- int ix = (intptr_t(obj) >> 5) & (NINFLATIONLOCKS-1) ;
- int YieldThenBlock = 0 ;
- assert (ix >= 0 && ix < NINFLATIONLOCKS, "invariant") ;
- assert ((NINFLATIONLOCKS & (NINFLATIONLOCKS-1)) == 0, "invariant") ;
- Thread::muxAcquire (InflationLocks + ix, "InflationLock") ;
- while (obj->mark() == markOopDesc::INFLATING()) {
- // Beware: NakedYield() is advisory and has almost no effect on some platforms
- // so we periodically call Self->_ParkEvent->park(1).
- // We use a mixed spin/yield/block mechanism.
- if ((YieldThenBlock++) >= 16) {
- Thread::current()->_ParkEvent->park(1) ;
- } else {
- os::NakedYield() ;
- }
- }
- Thread::muxRelease (InflationLocks + ix ) ;
- TEVENT (Inflate: INFLATING - yield/park) ;
- }
- } else {
- SpinPause() ; // SMP-polite spinning
- }
- }
-}
ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {
// Inflate mutates the heap ...
@@ -1242,7 +1201,7 @@
m->_Responsible = NULL ;
m->OwnerIsThread = 0 ;
m->_recursions = 0 ;
- m->_SpinDuration = Knob_SpinLimit ; // Consider: maintain by type/class
+ m->_SpinDuration = ObjectMonitor::Knob_SpinLimit ; // Consider: maintain by type/class
markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ;
if (cmp != mark) {
@@ -1302,7 +1261,7 @@
// Hopefully the performance counters are allocated on distinct cache lines
// to avoid false sharing on MP systems ...
- if (_sync_Inflations != NULL) _sync_Inflations->inc() ;
+ if (ObjectMonitor::_sync_Inflations != NULL) ObjectMonitor::_sync_Inflations->inc() ;
TEVENT(Inflate: overwrite stacklock) ;
if (TraceMonitorInflation) {
if (object->is_instance()) {
@@ -1335,7 +1294,7 @@
m->OwnerIsThread = 1 ;
m->_recursions = 0 ;
m->_Responsible = NULL ;
- m->_SpinDuration = Knob_SpinLimit ; // consider: keep metastats by type/class
+ m->_SpinDuration = ObjectMonitor::Knob_SpinLimit ; // consider: keep metastats by type/class
if (Atomic::cmpxchg_ptr (markOopDesc::encode(m), object->mark_addr(), mark) != mark) {
m->set_object (NULL) ;
@@ -1352,7 +1311,7 @@
// Hopefully the performance counters are allocated on distinct
// cache lines to avoid false sharing on MP systems ...
- if (_sync_Inflations != NULL) _sync_Inflations->inc() ;
+ if (ObjectMonitor::_sync_Inflations != NULL) ObjectMonitor::_sync_Inflations->inc() ;
TEVENT(Inflate: overwrite neutral) ;
if (TraceMonitorInflation) {
if (object->is_instance()) {
@@ -1366,547 +1325,9 @@
}
}
-
-// This the fast monitor enter. The interpreter and compiler use
-// some assembly copies of this code. Make sure update those code
-// if the following function is changed. The implementation is
-// extremely sensitive to race condition. Be careful.
-
-void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
- if (UseBiasedLocking) {
- if (!SafepointSynchronize::is_at_safepoint()) {
- BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
- if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
- return;
- }
- } else {
- assert(!attempt_rebias, "can not rebias toward VM thread");
- BiasedLocking::revoke_at_safepoint(obj);
- }
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- slow_enter (obj, lock, THREAD) ;
-}
-
-void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
- assert(!object->mark()->has_bias_pattern(), "should not see bias pattern here");
- // if displaced header is null, the previous enter is recursive enter, no-op
- markOop dhw = lock->displaced_header();
- markOop mark ;
- if (dhw == NULL) {
- // Recursive stack-lock.
- // Diagnostics -- Could be: stack-locked, inflating, inflated.
- mark = object->mark() ;
- assert (!mark->is_neutral(), "invariant") ;
- if (mark->has_locker() && mark != markOopDesc::INFLATING()) {
- assert(THREAD->is_lock_owned((address)mark->locker()), "invariant") ;
- }
- if (mark->has_monitor()) {
- ObjectMonitor * m = mark->monitor() ;
- assert(((oop)(m->object()))->mark() == mark, "invariant") ;
- assert(m->is_entered(THREAD), "invariant") ;
- }
- return ;
- }
-
- mark = object->mark() ;
-
- // If the object is stack-locked by the current thread, try to
- // swing the displaced header from the box back to the mark.
- if (mark == (markOop) lock) {
- assert (dhw->is_neutral(), "invariant") ;
- if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) {
- TEVENT (fast_exit: release stacklock) ;
- return;
- }
- }
-
- ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ;
-}
-
-// This routine is used to handle interpreter/compiler slow case
-// We don't need to use fast path here, because it must have been
-// failed in the interpreter/compiler code.
-void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
- markOop mark = obj->mark();
- assert(!mark->has_bias_pattern(), "should not see bias pattern here");
-
- if (mark->is_neutral()) {
- // Anticipate successful CAS -- the ST of the displaced mark must
- // be visible <= the ST performed by the CAS.
- lock->set_displaced_header(mark);
- if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
- TEVENT (slow_enter: release stacklock) ;
- return ;
- }
- // Fall through to inflate() ...
- } else
- if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
- assert(lock != mark->locker(), "must not re-lock the same lock");
- assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
- lock->set_displaced_header(NULL);
- return;
- }
-
-#if 0
- // The following optimization isn't particularly useful.
- if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
- lock->set_displaced_header (NULL) ;
- return ;
- }
-#endif
-
- // The object header will never be displaced to this lock,
- // so it does not matter what the value is, except that it
- // must be non-zero to avoid looking like a re-entrant lock,
- // and must not look locked either.
- lock->set_displaced_header(markOopDesc::unused_mark());
- ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
-}
-
-// This routine is used to handle interpreter/compiler slow case
-// We don't need to use fast path here, because it must have
-// failed in the interpreter/compiler code. Simply use the heavy
-// weight monitor should be ok, unless someone find otherwise.
-void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
- fast_exit (object, lock, THREAD) ;
-}
-
-// NOTE: must use heavy weight monitor to handle jni monitor enter
-void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { // possible entry from jni enter
- // the current locking is from JNI instead of Java code
- TEVENT (jni_enter) ;
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
- THREAD->set_current_pending_monitor_is_from_java(false);
- ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
- THREAD->set_current_pending_monitor_is_from_java(true);
-}
-
-// NOTE: must use heavy weight monitor to handle jni monitor enter
-bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj());
- return monitor->try_enter(THREAD);
-}
-
-
-// NOTE: must use heavy weight monitor to handle jni monitor exit
-void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) {
- TEVENT (jni_exit) ;
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- }
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
-
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj);
- // If this thread has locked the object, exit the monitor. Note: can't use
- // monitor->check(CHECK); must exit even if an exception is pending.
- if (monitor->check(THREAD)) {
- monitor->exit(THREAD);
- }
-}
-
-// complete_exit()/reenter() are used to wait on a nested lock
-// i.e. to give up an outer lock completely and then re-enter
-// Used when holding nested locks - lock acquisition order: lock1 then lock2
-// 1) complete_exit lock1 - saving recursion count
-// 2) wait on lock2
-// 3) when notified on lock2, unlock lock2
-// 4) reenter lock1 with original recursion count
-// 5) lock lock2
-// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
-intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
- TEVENT (complete_exit) ;
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
-
- return monitor->complete_exit(THREAD);
-}
-
-// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
-void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) {
- TEVENT (reenter) ;
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
-
- monitor->reenter(recursion, THREAD);
-}
-
-// This exists only as a workaround of dtrace bug 6254741
-int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) {
- DTRACE_MONITOR_PROBE(waited, monitor, obj(), thr);
- return 0;
-}
-
-// NOTE: must use heavy weight monitor to handle wait()
-void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
- if (millis < 0) {
- TEVENT (wait - throw IAX) ;
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
- }
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
- DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
- monitor->wait(millis, true, THREAD);
-
- /* This dummy call is in place to get around dtrace bug 6254741. Once
- that's fixed we can uncomment the following line and remove the call */
- // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
- dtrace_waited_probe(monitor, obj, THREAD);
-}
-
-void ObjectSynchronizer::waitUninterruptibly (Handle obj, jlong millis, TRAPS) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
- if (millis < 0) {
- TEVENT (wait - throw IAX) ;
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
- }
- ObjectSynchronizer::inflate(THREAD, obj()) -> wait(millis, false, THREAD) ;
-}
-
-void ObjectSynchronizer::notify(Handle obj, TRAPS) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- markOop mark = obj->mark();
- if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
- return;
- }
- ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
-}
-
-// NOTE: see comment of notify()
-void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(obj, false, THREAD);
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- markOop mark = obj->mark();
- if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
- return;
- }
- ObjectSynchronizer::inflate(THREAD, obj())->notifyAll(THREAD);
-}
-
-intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
- if (UseBiasedLocking) {
- // NOTE: many places throughout the JVM do not expect a safepoint
- // to be taken here, in particular most operations on perm gen
- // objects. However, we only ever bias Java instances and all of
- // the call sites of identity_hash that might revoke biases have
- // been checked to make sure they can handle a safepoint. The
- // added check of the bias pattern is to avoid useless calls to
- // thread-local storage.
- if (obj->mark()->has_bias_pattern()) {
- // Box and unbox the raw reference just in case we cause a STW safepoint.
- Handle hobj (Self, obj) ;
- // Relaxing assertion for bug 6320749.
- assert (Universe::verify_in_progress() ||
- !SafepointSynchronize::is_at_safepoint(),
- "biases should not be seen by VM thread here");
- BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
- obj = hobj() ;
- assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
- }
+// Note that we could encounter some performance loss through false-sharing as
+// multiple locks occupy the same $ line. Padding might be appropriate.
- // hashCode() is a heap mutator ...
- // Relaxing assertion for bug 6320749.
- assert (Universe::verify_in_progress() ||
- !SafepointSynchronize::is_at_safepoint(), "invariant") ;
- assert (Universe::verify_in_progress() ||
- Self->is_Java_thread() , "invariant") ;
- assert (Universe::verify_in_progress() ||
- ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
-
- ObjectMonitor* monitor = NULL;
- markOop temp, test;
- intptr_t hash;
- markOop mark = ReadStableMark (obj);
-
- // object should remain ineligible for biased locking
- assert (!mark->has_bias_pattern(), "invariant") ;
-
- if (mark->is_neutral()) {
- hash = mark->hash(); // this is a normal header
- if (hash) { // if it has hash, just return it
- return hash;
- }
- hash = get_next_hash(Self, obj); // allocate a new hash code
- temp = mark->copy_set_hash(hash); // merge the hash code into header
- // use (machine word version) atomic operation to install the hash
- test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
- if (test == mark) {
- return hash;
- }
- // If atomic operation failed, we must inflate the header
- // into heavy weight monitor. We could add more code here
- // for fast path, but it does not worth the complexity.
- } else if (mark->has_monitor()) {
- monitor = mark->monitor();
- temp = monitor->header();
- assert (temp->is_neutral(), "invariant") ;
- hash = temp->hash();
- if (hash) {
- return hash;
- }
- // Skip to the following code to reduce code size
- } else if (Self->is_lock_owned((address)mark->locker())) {
- temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
- assert (temp->is_neutral(), "invariant") ;
- hash = temp->hash(); // by current thread, check if the displaced
- if (hash) { // header contains hash code
- return hash;
- }
- // WARNING:
- // The displaced header is strictly immutable.
- // It can NOT be changed in ANY cases. So we have
- // to inflate the header into heavyweight monitor
- // even the current thread owns the lock. The reason
- // is the BasicLock (stack slot) will be asynchronously
- // read by other threads during the inflate() function.
- // Any change to stack may not propagate to other threads
- // correctly.
- }
-
- // Inflate the monitor to set hash code
- monitor = ObjectSynchronizer::inflate(Self, obj);
- // Load displaced header and check it has hash code
- mark = monitor->header();
- assert (mark->is_neutral(), "invariant") ;
- hash = mark->hash();
- if (hash == 0) {
- hash = get_next_hash(Self, obj);
- temp = mark->copy_set_hash(hash); // merge hash code into header
- assert (temp->is_neutral(), "invariant") ;
- test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
- if (test != mark) {
- // The only update to the header in the monitor (outside GC)
- // is install the hash code. If someone add new usage of
- // displaced header, please update this code
- hash = test->hash();
- assert (test->is_neutral(), "invariant") ;
- assert (hash != 0, "Trivial unexpected object/monitor header usage.");
- }
- }
- // We finally get the hash
- return hash;
-}
-
-// Deprecated -- use FastHashCode() instead.
-
-intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) {
- return FastHashCode (Thread::current(), obj()) ;
-}
-
-bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* thread,
- Handle h_obj) {
- if (UseBiasedLocking) {
- BiasedLocking::revoke_and_rebias(h_obj, false, thread);
- assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- assert(thread == JavaThread::current(), "Can only be called on current thread");
- oop obj = h_obj();
-
- markOop mark = ReadStableMark (obj) ;
-
- // Uncontended case, header points to stack
- if (mark->has_locker()) {
- return thread->is_lock_owned((address)mark->locker());
- }
- // Contended case, header points to ObjectMonitor (tagged pointer)
- if (mark->has_monitor()) {
- ObjectMonitor* monitor = mark->monitor();
- return monitor->is_entered(thread) != 0 ;
- }
- // Unlocked case, header in place
- assert(mark->is_neutral(), "sanity check");
- return false;
-}
-
-// Be aware of this method could revoke bias of the lock object.
-// This method querys the ownership of the lock handle specified by 'h_obj'.
-// If the current thread owns the lock, it returns owner_self. If no
-// thread owns the lock, it returns owner_none. Otherwise, it will return
-// ower_other.
-ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership
-(JavaThread *self, Handle h_obj) {
- // The caller must beware this method can revoke bias, and
- // revocation can result in a safepoint.
- assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
- assert (self->thread_state() != _thread_blocked , "invariant") ;
-
- // Possible mark states: neutral, biased, stack-locked, inflated
-
- if (UseBiasedLocking && h_obj()->mark()->has_bias_pattern()) {
- // CASE: biased
- BiasedLocking::revoke_and_rebias(h_obj, false, self);
- assert(!h_obj->mark()->has_bias_pattern(),
- "biases should be revoked by now");
- }
-
- assert(self == JavaThread::current(), "Can only be called on current thread");
- oop obj = h_obj();
- markOop mark = ReadStableMark (obj) ;
-
- // CASE: stack-locked. Mark points to a BasicLock on the owner's stack.
- if (mark->has_locker()) {
- return self->is_lock_owned((address)mark->locker()) ?
- owner_self : owner_other;
- }
-
- // CASE: inflated. Mark (tagged pointer) points to an objectMonitor.
- // The Object:ObjectMonitor relationship is stable as long as we're
- // not at a safepoint.
- if (mark->has_monitor()) {
- void * owner = mark->monitor()->_owner ;
- if (owner == NULL) return owner_none ;
- return (owner == self ||
- self->is_lock_owned((address)owner)) ? owner_self : owner_other;
- }
-
- // CASE: neutral
- assert(mark->is_neutral(), "sanity check");
- return owner_none ; // it's unlocked
-}
-
-// FIXME: jvmti should call this
-JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
- if (UseBiasedLocking) {
- if (SafepointSynchronize::is_at_safepoint()) {
- BiasedLocking::revoke_at_safepoint(h_obj);
- } else {
- BiasedLocking::revoke_and_rebias(h_obj, false, JavaThread::current());
- }
- assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- }
-
- oop obj = h_obj();
- address owner = NULL;
-
- markOop mark = ReadStableMark (obj) ;
-
- // Uncontended case, header points to stack
- if (mark->has_locker()) {
- owner = (address) mark->locker();
- }
-
- // Contended case, header points to ObjectMonitor (tagged pointer)
- if (mark->has_monitor()) {
- ObjectMonitor* monitor = mark->monitor();
- assert(monitor != NULL, "monitor should be non-null");
- owner = (address) monitor->owner();
- }
-
- if (owner != NULL) {
- return Threads::owning_thread_from_monitor_owner(owner, doLock);
- }
-
- // Unlocked case, header in place
- // Cannot have assertion since this object may have been
- // locked by another thread when reaching here.
- // assert(mark->is_neutral(), "sanity check");
-
- return NULL;
-}
-
-// Iterate through monitor cache and attempt to release thread's monitors
-// Gives up on a particular monitor if an exception occurs, but continues
-// the overall iteration, swallowing the exception.
-class ReleaseJavaMonitorsClosure: public MonitorClosure {
-private:
- TRAPS;
-
-public:
- ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
- void do_monitor(ObjectMonitor* mid) {
- if (mid->owner() == THREAD) {
- (void)mid->complete_exit(CHECK);
- }
- }
-};
-
-// Release all inflated monitors owned by THREAD. Lightweight monitors are
-// ignored. This is meant to be called during JNI thread detach which assumes
-// all remaining monitors are heavyweight. All exceptions are swallowed.
-// Scanning the extant monitor list can be time consuming.
-// A simple optimization is to add a per-thread flag that indicates a thread
-// called jni_monitorenter() during its lifetime.
-//
-// Instead of No_Savepoint_Verifier it might be cheaper to
-// use an idiom of the form:
-// auto int tmp = SafepointSynchronize::_safepoint_counter ;
-// <code that must not run at safepoint>
-// guarantee (((tmp ^ _safepoint_counter) | (tmp & 1)) == 0) ;
-// Since the tests are extremely cheap we could leave them enabled
-// for normal product builds.
-
-void ObjectSynchronizer::release_monitors_owned_by_thread(TRAPS) {
- assert(THREAD == JavaThread::current(), "must be current Java thread");
- No_Safepoint_Verifier nsv ;
- ReleaseJavaMonitorsClosure rjmc(THREAD);
- Thread::muxAcquire(&ListLock, "release_monitors_owned_by_thread");
- ObjectSynchronizer::monitors_iterate(&rjmc);
- Thread::muxRelease(&ListLock);
- THREAD->clear_pending_exception();
-}
-
-// Visitors ...
-
-void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) {
- ObjectMonitor* block = gBlockList;
- ObjectMonitor* mid;
- while (block) {
- assert(block->object() == CHAINMARKER, "must be a block header");
- for (int i = _BLOCKSIZE - 1; i > 0; i--) {
- mid = block + i;
- oop object = (oop) mid->object();
- if (object != NULL) {
- closure->do_monitor(mid);
- }
- }
- block = (ObjectMonitor*) block->FreeNext;
- }
-}
-
-void ObjectSynchronizer::oops_do(OopClosure* f) {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
- for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
- assert(block->object() == CHAINMARKER, "must be a block header");
- for (int i = 1; i < _BLOCKSIZE; i++) {
- ObjectMonitor* mid = &block[i];
- if (mid->object() != NULL) {
- f->do_oop((oop*)mid->object_addr());
- }
- }
- }
-}
// Deflate_idle_monitors() is called at all safepoints, immediately
// after all mutators are stopped, but before any objects have moved.
@@ -1936,12 +1357,11 @@
// which in turn can mean large(r) numbers of objectmonitors in circulation.
// This is an unfortunate aspect of this design.
//
-// Another refinement would be to refrain from calling deflate_idle_monitors()
-// except at stop-the-world points associated with garbage collections.
-//
-// An even better solution would be to deflate on-the-fly, aggressively,
-// at monitorexit-time as is done in EVM's metalock or Relaxed Locks.
+enum ManifestConstants {
+ ClearResponsibleAtSTW = 0,
+ MaximumRecheckInterval = 1000
+} ;
// Deflate a single monitor if not in use
// Return true if deflated, false if in use
@@ -2088,7 +1508,7 @@
// Consider: audit gFreeList to ensure that MonitorFreeCount and list agree.
- if (Knob_Verbose) {
+ if (ObjectMonitor::Knob_Verbose) {
::printf ("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n",
nInCirculation, nInuse, nScavenged, ForceMonitorScavenge,
MonitorPopulation, MonitorFreeCount) ;
@@ -2107,8 +1527,8 @@
}
Thread::muxRelease (&ListLock) ;
- if (_sync_Deflations != NULL) _sync_Deflations->inc(nScavenged) ;
- if (_sync_MonExtant != NULL) _sync_MonExtant ->set_value(nInCirculation);
+ if (ObjectMonitor::_sync_Deflations != NULL) ObjectMonitor::_sync_Deflations->inc(nScavenged) ;
+ if (ObjectMonitor::_sync_MonExtant != NULL) ObjectMonitor::_sync_MonExtant ->set_value(nInCirculation);
// TODO: Add objectMonitor leak detection.
// Audit/inventory the objectMonitors -- make sure they're all accounted for.
@@ -2116,2810 +1536,49 @@
GVars.stwCycle ++ ;
}
-// A macro is used below because there may already be a pending
-// exception which should not abort the execution of the routines
-// which use this (which is why we don't put this into check_slow and
-// call it with a CHECK argument).
-
-#define CHECK_OWNER() \
- do { \
- if (THREAD != _owner) { \
- if (THREAD->is_lock_owned((address) _owner)) { \
- _owner = THREAD ; /* Convert from basiclock addr to Thread addr */ \
- _recursions = 0; \
- OwnerIsThread = 1 ; \
- } else { \
- TEVENT (Throw IMSX) ; \
- THROW(vmSymbols::java_lang_IllegalMonitorStateException()); \
- } \
- } \
- } while (false)
-
-// TODO-FIXME: eliminate ObjectWaiters. Replace this visitor/enumerator
-// interface with a simple FirstWaitingThread(), NextWaitingThread() interface.
-
-ObjectWaiter* ObjectMonitor::first_waiter() {
- return _WaitSet;
-}
-
-ObjectWaiter* ObjectMonitor::next_waiter(ObjectWaiter* o) {
- return o->_next;
-}
-
-Thread* ObjectMonitor::thread_of_waiter(ObjectWaiter* o) {
- return o->_thread;
-}
-
-// initialize the monitor, exception the semaphore, all other fields
-// are simple integers or pointers
-ObjectMonitor::ObjectMonitor() {
- _header = NULL;
- _count = 0;
- _waiters = 0,
- _recursions = 0;
- _object = NULL;
- _owner = NULL;
- _WaitSet = NULL;
- _WaitSetLock = 0 ;
- _Responsible = NULL ;
- _succ = NULL ;
- _cxq = NULL ;
- FreeNext = NULL ;
- _EntryList = NULL ;
- _SpinFreq = 0 ;
- _SpinClock = 0 ;
- OwnerIsThread = 0 ;
-}
-
-ObjectMonitor::~ObjectMonitor() {
- // TODO: Add asserts ...
- // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
- // _count == 0 _EntryList == NULL etc
-}
+// Monitor cleanup on JavaThread::exit
-intptr_t ObjectMonitor::is_busy() const {
- // TODO-FIXME: merge _count and _waiters.
- // TODO-FIXME: assert _owner == null implies _recursions = 0
- // TODO-FIXME: assert _WaitSet != null implies _count > 0
- return _count|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList ) ;
-}
-
-void ObjectMonitor::Recycle () {
- // TODO: add stronger asserts ...
- // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
- // _count == 0 EntryList == NULL
- // _recursions == 0 _WaitSet == NULL
- // TODO: assert (is_busy()|_recursions) == 0
- _succ = NULL ;
- _EntryList = NULL ;
- _cxq = NULL ;
- _WaitSet = NULL ;
- _recursions = 0 ;
- _SpinFreq = 0 ;
- _SpinClock = 0 ;
- OwnerIsThread = 0 ;
-}
-
-// WaitSet management ...
+// Iterate through monitor cache and attempt to release thread's monitors
+// Gives up on a particular monitor if an exception occurs, but continues
+// the overall iteration, swallowing the exception.
+class ReleaseJavaMonitorsClosure: public MonitorClosure {
+private:
+ TRAPS;
-inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
- assert(node != NULL, "should not dequeue NULL node");
- assert(node->_prev == NULL, "node already in list");
- assert(node->_next == NULL, "node already in list");
- // put node at end of queue (circular doubly linked list)
- if (_WaitSet == NULL) {
- _WaitSet = node;
- node->_prev = node;
- node->_next = node;
- } else {
- ObjectWaiter* head = _WaitSet ;
- ObjectWaiter* tail = head->_prev;
- assert(tail->_next == head, "invariant check");
- tail->_next = node;
- head->_prev = node;
- node->_next = head;
- node->_prev = tail;
- }
-}
-
-inline ObjectWaiter* ObjectMonitor::DequeueWaiter() {
- // dequeue the very first waiter
- ObjectWaiter* waiter = _WaitSet;
- if (waiter) {
- DequeueSpecificWaiter(waiter);
- }
- return waiter;
-}
-
-inline void ObjectMonitor::DequeueSpecificWaiter(ObjectWaiter* node) {
- assert(node != NULL, "should not dequeue NULL node");
- assert(node->_prev != NULL, "node already removed from list");
- assert(node->_next != NULL, "node already removed from list");
- // when the waiter has woken up because of interrupt,
- // timeout or other spurious wake-up, dequeue the
- // waiter from waiting list
- ObjectWaiter* next = node->_next;
- if (next == node) {
- assert(node->_prev == node, "invariant check");
- _WaitSet = NULL;
- } else {
- ObjectWaiter* prev = node->_prev;
- assert(prev->_next == node, "invariant check");
- assert(next->_prev == node, "invariant check");
- next->_prev = prev;
- prev->_next = next;
- if (_WaitSet == node) {
- _WaitSet = next;
+public:
+ ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
+ void do_monitor(ObjectMonitor* mid) {
+ if (mid->owner() == THREAD) {
+ (void)mid->complete_exit(CHECK);
}
}
- node->_next = NULL;
- node->_prev = NULL;
-}
-
-static char * kvGet (char * kvList, const char * Key) {
- if (kvList == NULL) return NULL ;
- size_t n = strlen (Key) ;
- char * Search ;
- for (Search = kvList ; *Search ; Search += strlen(Search) + 1) {
- if (strncmp (Search, Key, n) == 0) {
- if (Search[n] == '=') return Search + n + 1 ;
- if (Search[n] == 0) return (char *) "1" ;
- }
- }
- return NULL ;
-}
-
-static int kvGetInt (char * kvList, const char * Key, int Default) {
- char * v = kvGet (kvList, Key) ;
- int rslt = v ? ::strtol (v, NULL, 0) : Default ;
- if (Knob_ReportSettings && v != NULL) {
- ::printf (" SyncKnob: %s %d(%d)\n", Key, rslt, Default) ;
- ::fflush (stdout) ;
- }
- return rslt ;
-}
-
-// By convention we unlink a contending thread from EntryList|cxq immediately
-// after the thread acquires the lock in ::enter(). Equally, we could defer
-// unlinking the thread until ::exit()-time.
-
-void ObjectMonitor::UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode)
-{
- assert (_owner == Self, "invariant") ;
- assert (SelfNode->_thread == Self, "invariant") ;
-
- if (SelfNode->TState == ObjectWaiter::TS_ENTER) {
- // Normal case: remove Self from the DLL EntryList .
- // This is a constant-time operation.
- ObjectWaiter * nxt = SelfNode->_next ;
- ObjectWaiter * prv = SelfNode->_prev ;
- if (nxt != NULL) nxt->_prev = prv ;
- if (prv != NULL) prv->_next = nxt ;
- if (SelfNode == _EntryList ) _EntryList = nxt ;
- assert (nxt == NULL || nxt->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- assert (prv == NULL || prv->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- TEVENT (Unlink from EntryList) ;
- } else {
- guarantee (SelfNode->TState == ObjectWaiter::TS_CXQ, "invariant") ;
- // Inopportune interleaving -- Self is still on the cxq.
- // This usually means the enqueue of self raced an exiting thread.
- // Normally we'll find Self near the front of the cxq, so
- // dequeueing is typically fast. If needbe we can accelerate
- // this with some MCS/CHL-like bidirectional list hints and advisory
- // back-links so dequeueing from the interior will normally operate
- // in constant-time.
- // Dequeue Self from either the head (with CAS) or from the interior
- // with a linear-time scan and normal non-atomic memory operations.
- // CONSIDER: if Self is on the cxq then simply drain cxq into EntryList
- // and then unlink Self from EntryList. We have to drain eventually,
- // so it might as well be now.
-
- ObjectWaiter * v = _cxq ;
- assert (v != NULL, "invariant") ;
- if (v != SelfNode || Atomic::cmpxchg_ptr (SelfNode->_next, &_cxq, v) != v) {
- // The CAS above can fail from interference IFF a "RAT" arrived.
- // In that case Self must be in the interior and can no longer be
- // at the head of cxq.
- if (v == SelfNode) {
- assert (_cxq != v, "invariant") ;
- v = _cxq ; // CAS above failed - start scan at head of list
- }
- ObjectWaiter * p ;
- ObjectWaiter * q = NULL ;
- for (p = v ; p != NULL && p != SelfNode; p = p->_next) {
- q = p ;
- assert (p->TState == ObjectWaiter::TS_CXQ, "invariant") ;
- }
- assert (v != SelfNode, "invariant") ;
- assert (p == SelfNode, "Node not found on cxq") ;
- assert (p != _cxq, "invariant") ;
- assert (q != NULL, "invariant") ;
- assert (q->_next == p, "invariant") ;
- q->_next = p->_next ;
- }
- TEVENT (Unlink from cxq) ;
- }
-
- // Diagnostic hygiene ...
- SelfNode->_prev = (ObjectWaiter *) 0xBAD ;
- SelfNode->_next = (ObjectWaiter *) 0xBAD ;
- SelfNode->TState = ObjectWaiter::TS_RUN ;
-}
-
-// Caveat: TryLock() is not necessarily serializing if it returns failure.
-// Callers must compensate as needed.
-
-int ObjectMonitor::TryLock (Thread * Self) {
- for (;;) {
- void * own = _owner ;
- if (own != NULL) return 0 ;
- if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
- // Either guarantee _recursions == 0 or set _recursions = 0.
- assert (_recursions == 0, "invariant") ;
- assert (_owner == Self, "invariant") ;
- // CONSIDER: set or assert that OwnerIsThread == 1
- return 1 ;
- }
- // The lock had been free momentarily, but we lost the race to the lock.
- // Interference -- the CAS failed.
- // We can either return -1 or retry.
- // Retry doesn't make as much sense because the lock was just acquired.
- if (true) return -1 ;
- }
-}
-
-// NotRunnable() -- informed spinning
-//
-// Don't bother spinning if the owner is not eligible to drop the lock.
-// Peek at the owner's schedctl.sc_state and Thread._thread_values and
-// spin only if the owner thread is _thread_in_Java or _thread_in_vm.
-// The thread must be runnable in order to drop the lock in timely fashion.
-// If the _owner is not runnable then spinning will not likely be
-// successful (profitable).
-//
-// Beware -- the thread referenced by _owner could have died
-// so a simply fetch from _owner->_thread_state might trap.
-// Instead, we use SafeFetchXX() to safely LD _owner->_thread_state.
-// Because of the lifecycle issues the schedctl and _thread_state values
-// observed by NotRunnable() might be garbage. NotRunnable must
-// tolerate this and consider the observed _thread_state value
-// as advisory.
-//
-// Beware too, that _owner is sometimes a BasicLock address and sometimes
-// a thread pointer. We differentiate the two cases with OwnerIsThread.
-// Alternately, we might tag the type (thread pointer vs basiclock pointer)
-// with the LSB of _owner. Another option would be to probablistically probe
-// the putative _owner->TypeTag value.
-//
-// Checking _thread_state isn't perfect. Even if the thread is
-// in_java it might be blocked on a page-fault or have been preempted
-// and sitting on a ready/dispatch queue. _thread state in conjunction
-// with schedctl.sc_state gives us a good picture of what the
-// thread is doing, however.
-//
-// TODO: check schedctl.sc_state.
-// We'll need to use SafeFetch32() to read from the schedctl block.
-// See RFE #5004247 and http://sac.sfbay.sun.com/Archives/CaseLog/arc/PSARC/2005/351/
-//
-// The return value from NotRunnable() is *advisory* -- the
-// result is based on sampling and is not necessarily coherent.
-// The caller must tolerate false-negative and false-positive errors.
-// Spinning, in general, is probabilistic anyway.
-
-
-int ObjectMonitor::NotRunnable (Thread * Self, Thread * ox) {
- // Check either OwnerIsThread or ox->TypeTag == 2BAD.
- if (!OwnerIsThread) return 0 ;
-
- if (ox == NULL) return 0 ;
-
- // Avoid transitive spinning ...
- // Say T1 spins or blocks trying to acquire L. T1._Stalled is set to L.
- // Immediately after T1 acquires L it's possible that T2, also
- // spinning on L, will see L.Owner=T1 and T1._Stalled=L.
- // This occurs transiently after T1 acquired L but before
- // T1 managed to clear T1.Stalled. T2 does not need to abort
- // its spin in this circumstance.
- intptr_t BlockedOn = SafeFetchN ((intptr_t *) &ox->_Stalled, intptr_t(1)) ;
-
- if (BlockedOn == 1) return 1 ;
- if (BlockedOn != 0) {
- return BlockedOn != intptr_t(this) && _owner == ox ;
- }
-
- assert (sizeof(((JavaThread *)ox)->_thread_state == sizeof(int)), "invariant") ;
- int jst = SafeFetch32 ((int *) &((JavaThread *) ox)->_thread_state, -1) ; ;
- // consider also: jst != _thread_in_Java -- but that's overspecific.
- return jst == _thread_blocked || jst == _thread_in_native ;
-}
-
-
-// Adaptive spin-then-block - rational spinning
-//
-// Note that we spin "globally" on _owner with a classic SMP-polite TATAS
-// algorithm. On high order SMP systems it would be better to start with
-// a brief global spin and then revert to spinning locally. In the spirit of MCS/CLH,
-// a contending thread could enqueue itself on the cxq and then spin locally
-// on a thread-specific variable such as its ParkEvent._Event flag.
-// That's left as an exercise for the reader. Note that global spinning is
-// not problematic on Niagara, as the L2$ serves the interconnect and has both
-// low latency and massive bandwidth.
-//
-// Broadly, we can fix the spin frequency -- that is, the % of contended lock
-// acquisition attempts where we opt to spin -- at 100% and vary the spin count
-// (duration) or we can fix the count at approximately the duration of
-// a context switch and vary the frequency. Of course we could also
-// vary both satisfying K == Frequency * Duration, where K is adaptive by monitor.
-// See http://j2se.east/~dice/PERSIST/040824-AdaptiveSpinning.html.
-//
-// This implementation varies the duration "D", where D varies with
-// the success rate of recent spin attempts. (D is capped at approximately
-// length of a round-trip context switch). The success rate for recent
-// spin attempts is a good predictor of the success rate of future spin
-// attempts. The mechanism adapts automatically to varying critical
-// section length (lock modality), system load and degree of parallelism.
-// D is maintained per-monitor in _SpinDuration and is initialized
-// optimistically. Spin frequency is fixed at 100%.
-//
-// Note that _SpinDuration is volatile, but we update it without locks
-// or atomics. The code is designed so that _SpinDuration stays within
-// a reasonable range even in the presence of races. The arithmetic
-// operations on _SpinDuration are closed over the domain of legal values,
-// so at worst a race will install and older but still legal value.
-// At the very worst this introduces some apparent non-determinism.
-// We might spin when we shouldn't or vice-versa, but since the spin
-// count are relatively short, even in the worst case, the effect is harmless.
-//
-// Care must be taken that a low "D" value does not become an
-// an absorbing state. Transient spinning failures -- when spinning
-// is overall profitable -- should not cause the system to converge
-// on low "D" values. We want spinning to be stable and predictable
-// and fairly responsive to change and at the same time we don't want
-// it to oscillate, become metastable, be "too" non-deterministic,
-// or converge on or enter undesirable stable absorbing states.
-//
-// We implement a feedback-based control system -- using past behavior
-// to predict future behavior. We face two issues: (a) if the
-// input signal is random then the spin predictor won't provide optimal
-// results, and (b) if the signal frequency is too high then the control
-// system, which has some natural response lag, will "chase" the signal.
-// (b) can arise from multimodal lock hold times. Transient preemption
-// can also result in apparent bimodal lock hold times.
-// Although sub-optimal, neither condition is particularly harmful, as
-// in the worst-case we'll spin when we shouldn't or vice-versa.
-// The maximum spin duration is rather short so the failure modes aren't bad.
-// To be conservative, I've tuned the gain in system to bias toward
-// _not spinning. Relatedly, the system can sometimes enter a mode where it
-// "rings" or oscillates between spinning and not spinning. This happens
-// when spinning is just on the cusp of profitability, however, so the
-// situation is not dire. The state is benign -- there's no need to add
-// hysteresis control to damp the transition rate between spinning and
-// not spinning.
-//
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-//
-// Spin-then-block strategies ...
-//
-// Thoughts on ways to improve spinning :
-//
-// * Periodically call {psr_}getloadavg() while spinning, and
-// permit unbounded spinning if the load average is <
-// the number of processors. Beware, however, that getloadavg()
-// is exceptionally fast on solaris (about 1/10 the cost of a full
-// spin cycle, but quite expensive on linux. Beware also, that
-// multiple JVMs could "ring" or oscillate in a feedback loop.
-// Sufficient damping would solve that problem.
-//
-// * We currently use spin loops with iteration counters to approximate
-// spinning for some interval. Given the availability of high-precision
-// time sources such as gethrtime(), %TICK, %STICK, RDTSC, etc., we should
-// someday reimplement the spin loops to duration-based instead of iteration-based.
-//
-// * Don't spin if there are more than N = (CPUs/2) threads
-// currently spinning on the monitor (or globally).
-// That is, limit the number of concurrent spinners.
-// We might also limit the # of spinners in the JVM, globally.
-//
-// * If a spinning thread observes _owner change hands it should
-// abort the spin (and park immediately) or at least debit
-// the spin counter by a large "penalty".
-//
-// * Classically, the spin count is either K*(CPUs-1) or is a
-// simple constant that approximates the length of a context switch.
-// We currently use a value -- computed by a special utility -- that
-// approximates round-trip context switch times.
-//
-// * Normally schedctl_start()/_stop() is used to advise the kernel
-// to avoid preempting threads that are running in short, bounded
-// critical sections. We could use the schedctl hooks in an inverted
-// sense -- spinners would set the nopreempt flag, but poll the preempt
-// pending flag. If a spinner observed a pending preemption it'd immediately
-// abort the spin and park. As such, the schedctl service acts as
-// a preemption warning mechanism.
-//
-// * In lieu of spinning, if the system is running below saturation
-// (that is, loadavg() << #cpus), we can instead suppress futile
-// wakeup throttling, or even wake more than one successor at exit-time.
-// The net effect is largely equivalent to spinning. In both cases,
-// contending threads go ONPROC and opportunistically attempt to acquire
-// the lock, decreasing lock handover latency at the expense of wasted
-// cycles and context switching.
-//
-// * We might to spin less after we've parked as the thread will
-// have less $ and TLB affinity with the processor.
-// Likewise, we might spin less if we come ONPROC on a different
-// processor or after a long period (>> rechose_interval).
-//
-// * A table-driven state machine similar to Solaris' dispadmin scheduling
-// tables might be a better design. Instead of encoding information in
-// _SpinDuration, _SpinFreq and _SpinClock we'd just use explicit,
-// discrete states. Success or failure during a spin would drive
-// state transitions, and each state node would contain a spin count.
-//
-// * If the processor is operating in a mode intended to conserve power
-// (such as Intel's SpeedStep) or to reduce thermal output (thermal
-// step-down mode) then the Java synchronization subsystem should
-// forgo spinning.
-//
-// * The minimum spin duration should be approximately the worst-case
-// store propagation latency on the platform. That is, the time
-// it takes a store on CPU A to become visible on CPU B, where A and
-// B are "distant".
-//
-// * We might want to factor a thread's priority in the spin policy.
-// Threads with a higher priority might spin for slightly longer.
-// Similarly, if we use back-off in the TATAS loop, lower priority
-// threads might back-off longer. We don't currently use a
-// thread's priority when placing it on the entry queue. We may
-// want to consider doing so in future releases.
-//
-// * We might transiently drop a thread's scheduling priority while it spins.
-// SCHED_BATCH on linux and FX scheduling class at priority=0 on Solaris
-// would suffice. We could even consider letting the thread spin indefinitely at
-// a depressed or "idle" priority. This brings up fairness issues, however --
-// in a saturated system a thread would with a reduced priority could languish
-// for extended periods on the ready queue.
-//
-// * While spinning try to use the otherwise wasted time to help the VM make
-// progress:
-//
-// -- YieldTo() the owner, if the owner is OFFPROC but ready
-// Done our remaining quantum directly to the ready thread.
-// This helps "push" the lock owner through the critical section.
-// It also tends to improve affinity/locality as the lock
-// "migrates" less frequently between CPUs.
-// -- Walk our own stack in anticipation of blocking. Memoize the roots.
-// -- Perform strand checking for other thread. Unpark potential strandees.
-// -- Help GC: trace or mark -- this would need to be a bounded unit of work.
-// Unfortunately this will pollute our $ and TLBs. Recall that we
-// spin to avoid context switching -- context switching has an
-// immediate cost in latency, a disruptive cost to other strands on a CMT
-// processor, and an amortized cost because of the D$ and TLB cache
-// reload transient when the thread comes back ONPROC and repopulates
-// $s and TLBs.
-// -- call getloadavg() to see if the system is saturated. It'd probably
-// make sense to call getloadavg() half way through the spin.
-// If the system isn't at full capacity the we'd simply reset
-// the spin counter to and extend the spin attempt.
-// -- Doug points out that we should use the same "helping" policy
-// in thread.yield().
-//
-// * Try MONITOR-MWAIT on systems that support those instructions.
-//
-// * The spin statistics that drive spin decisions & frequency are
-// maintained in the objectmonitor structure so if we deflate and reinflate
-// we lose spin state. In practice this is not usually a concern
-// as the default spin state after inflation is aggressive (optimistic)
-// and tends toward spinning. So in the worst case for a lock where
-// spinning is not profitable we may spin unnecessarily for a brief
-// period. But then again, if a lock is contended it'll tend not to deflate
-// in the first place.
-
-
-intptr_t ObjectMonitor::SpinCallbackArgument = 0 ;
-int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL ;
-
-// Spinning: Fixed frequency (100%), vary duration
-
-int ObjectMonitor::TrySpin_VaryDuration (Thread * Self) {
-
- // Dumb, brutal spin. Good for comparative measurements against adaptive spinning.
- int ctr = Knob_FixedSpin ;
- if (ctr != 0) {
- while (--ctr >= 0) {
- if (TryLock (Self) > 0) return 1 ;
- SpinPause () ;
- }
- return 0 ;
- }
-
- for (ctr = Knob_PreSpin + 1; --ctr >= 0 ; ) {
- if (TryLock(Self) > 0) {
- // Increase _SpinDuration ...
- // Note that we don't clamp SpinDuration precisely at SpinLimit.
- // Raising _SpurDuration to the poverty line is key.
- int x = _SpinDuration ;
- if (x < Knob_SpinLimit) {
- if (x < Knob_Poverty) x = Knob_Poverty ;
- _SpinDuration = x + Knob_BonusB ;
- }
- return 1 ;
- }
- SpinPause () ;
- }
-
- // Admission control - verify preconditions for spinning
- //
- // We always spin a little bit, just to prevent _SpinDuration == 0 from
- // becoming an absorbing state. Put another way, we spin briefly to
- // sample, just in case the system load, parallelism, contention, or lock
- // modality changed.
- //
- // Consider the following alternative:
- // Periodically set _SpinDuration = _SpinLimit and try a long/full
- // spin attempt. "Periodically" might mean after a tally of
- // the # of failed spin attempts (or iterations) reaches some threshold.
- // This takes us into the realm of 1-out-of-N spinning, where we
- // hold the duration constant but vary the frequency.
-
- ctr = _SpinDuration ;
- if (ctr < Knob_SpinBase) ctr = Knob_SpinBase ;
- if (ctr <= 0) return 0 ;
-
- if (Knob_SuccRestrict && _succ != NULL) return 0 ;
- if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
- TEVENT (Spin abort - notrunnable [TOP]);
- return 0 ;
- }
-
- int MaxSpin = Knob_MaxSpinners ;
- if (MaxSpin >= 0) {
- if (_Spinner > MaxSpin) {
- TEVENT (Spin abort -- too many spinners) ;
- return 0 ;
- }
- // Slighty racy, but benign ...
- Adjust (&_Spinner, 1) ;
- }
-
- // We're good to spin ... spin ingress.
- // CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
- // when preparing to LD...CAS _owner, etc and the CAS is likely
- // to succeed.
- int hits = 0 ;
- int msk = 0 ;
- int caspty = Knob_CASPenalty ;
- int oxpty = Knob_OXPenalty ;
- int sss = Knob_SpinSetSucc ;
- if (sss && _succ == NULL ) _succ = Self ;
- Thread * prv = NULL ;
-
- // There are three ways to exit the following loop:
- // 1. A successful spin where this thread has acquired the lock.
- // 2. Spin failure with prejudice
- // 3. Spin failure without prejudice
-
- while (--ctr >= 0) {
-
- // Periodic polling -- Check for pending GC
- // Threads may spin while they're unsafe.
- // We don't want spinning threads to delay the JVM from reaching
- // a stop-the-world safepoint or to steal cycles from GC.
- // If we detect a pending safepoint we abort in order that
- // (a) this thread, if unsafe, doesn't delay the safepoint, and (b)
- // this thread, if safe, doesn't steal cycles from GC.
- // This is in keeping with the "no loitering in runtime" rule.
- // We periodically check to see if there's a safepoint pending.
- if ((ctr & 0xFF) == 0) {
- if (SafepointSynchronize::do_call_back()) {
- TEVENT (Spin: safepoint) ;
- goto Abort ; // abrupt spin egress
- }
- if (Knob_UsePause & 1) SpinPause () ;
-
- int (*scb)(intptr_t,int) = SpinCallbackFunction ;
- if (hits > 50 && scb != NULL) {
- int abend = (*scb)(SpinCallbackArgument, 0) ;
- }
- }
-
- if (Knob_UsePause & 2) SpinPause() ;
-
- // Exponential back-off ... Stay off the bus to reduce coherency traffic.
- // This is useful on classic SMP systems, but is of less utility on
- // N1-style CMT platforms.
- //
- // Trade-off: lock acquisition latency vs coherency bandwidth.
- // Lock hold times are typically short. A histogram
- // of successful spin attempts shows that we usually acquire
- // the lock early in the spin. That suggests we want to
- // sample _owner frequently in the early phase of the spin,
- // but then back-off and sample less frequently as the spin
- // progresses. The back-off makes a good citizen on SMP big
- // SMP systems. Oversampling _owner can consume excessive
- // coherency bandwidth. Relatedly, if we _oversample _owner we
- // can inadvertently interfere with the the ST m->owner=null.
- // executed by the lock owner.
- if (ctr & msk) continue ;
- ++hits ;
- if ((hits & 0xF) == 0) {
- // The 0xF, above, corresponds to the exponent.
- // Consider: (msk+1)|msk
- msk = ((msk << 2)|3) & BackOffMask ;
- }
-
- // Probe _owner with TATAS
- // If this thread observes the monitor transition or flicker
- // from locked to unlocked to locked, then the odds that this
- // thread will acquire the lock in this spin attempt go down
- // considerably. The same argument applies if the CAS fails
- // or if we observe _owner change from one non-null value to
- // another non-null value. In such cases we might abort
- // the spin without prejudice or apply a "penalty" to the
- // spin count-down variable "ctr", reducing it by 100, say.
-
- Thread * ox = (Thread *) _owner ;
- if (ox == NULL) {
- ox = (Thread *) Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
- if (ox == NULL) {
- // The CAS succeeded -- this thread acquired ownership
- // Take care of some bookkeeping to exit spin state.
- if (sss && _succ == Self) {
- _succ = NULL ;
- }
- if (MaxSpin > 0) Adjust (&_Spinner, -1) ;
-
- // Increase _SpinDuration :
- // The spin was successful (profitable) so we tend toward
- // longer spin attempts in the future.
- // CONSIDER: factor "ctr" into the _SpinDuration adjustment.
- // If we acquired the lock early in the spin cycle it
- // makes sense to increase _SpinDuration proportionally.
- // Note that we don't clamp SpinDuration precisely at SpinLimit.
- int x = _SpinDuration ;
- if (x < Knob_SpinLimit) {
- if (x < Knob_Poverty) x = Knob_Poverty ;
- _SpinDuration = x + Knob_Bonus ;
- }
- return 1 ;
- }
-
- // The CAS failed ... we can take any of the following actions:
- // * penalize: ctr -= Knob_CASPenalty
- // * exit spin with prejudice -- goto Abort;
- // * exit spin without prejudice.
- // * Since CAS is high-latency, retry again immediately.
- prv = ox ;
- TEVENT (Spin: cas failed) ;
- if (caspty == -2) break ;
- if (caspty == -1) goto Abort ;
- ctr -= caspty ;
- continue ;
- }
-
- // Did lock ownership change hands ?
- if (ox != prv && prv != NULL ) {
- TEVENT (spin: Owner changed)
- if (oxpty == -2) break ;
- if (oxpty == -1) goto Abort ;
- ctr -= oxpty ;
- }
- prv = ox ;
-
- // Abort the spin if the owner is not executing.
- // The owner must be executing in order to drop the lock.
- // Spinning while the owner is OFFPROC is idiocy.
- // Consider: ctr -= RunnablePenalty ;
- if (Knob_OState && NotRunnable (Self, ox)) {
- TEVENT (Spin abort - notrunnable);
- goto Abort ;
- }
- if (sss && _succ == NULL ) _succ = Self ;
- }
-
- // Spin failed with prejudice -- reduce _SpinDuration.
- // TODO: Use an AIMD-like policy to adjust _SpinDuration.
- // AIMD is globally stable.
- TEVENT (Spin failure) ;
- {
- int x = _SpinDuration ;
- if (x > 0) {
- // Consider an AIMD scheme like: x -= (x >> 3) + 100
- // This is globally sample and tends to damp the response.
- x -= Knob_Penalty ;
- if (x < 0) x = 0 ;
- _SpinDuration = x ;
- }
- }
-
- Abort:
- if (MaxSpin >= 0) Adjust (&_Spinner, -1) ;
- if (sss && _succ == Self) {
- _succ = NULL ;
- // Invariant: after setting succ=null a contending thread
- // must recheck-retry _owner before parking. This usually happens
- // in the normal usage of TrySpin(), but it's safest
- // to make TrySpin() as foolproof as possible.
- OrderAccess::fence() ;
- if (TryLock(Self) > 0) return 1 ;
- }
- return 0 ;
-}
-
-#define TrySpin TrySpin_VaryDuration
-
-static void DeferredInitialize () {
- if (InitDone > 0) return ;
- if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
- while (InitDone != 1) ;
- return ;
- }
-
- // One-shot global initialization ...
- // The initialization is idempotent, so we don't need locks.
- // In the future consider doing this via os::init_2().
- // SyncKnobs consist of <Key>=<Value> pairs in the style
- // of environment variables. Start by converting ':' to NUL.
-
- if (SyncKnobs == NULL) SyncKnobs = "" ;
-
- size_t sz = strlen (SyncKnobs) ;
- char * knobs = (char *) malloc (sz + 2) ;
- if (knobs == NULL) {
- vm_exit_out_of_memory (sz + 2, "Parse SyncKnobs") ;
- guarantee (0, "invariant") ;
- }
- strcpy (knobs, SyncKnobs) ;
- knobs[sz+1] = 0 ;
- for (char * p = knobs ; *p ; p++) {
- if (*p == ':') *p = 0 ;
- }
-
- #define SETKNOB(x) { Knob_##x = kvGetInt (knobs, #x, Knob_##x); }
- SETKNOB(ReportSettings) ;
- SETKNOB(Verbose) ;
- SETKNOB(FixedSpin) ;
- SETKNOB(SpinLimit) ;
- SETKNOB(SpinBase) ;
- SETKNOB(SpinBackOff);
- SETKNOB(CASPenalty) ;
- SETKNOB(OXPenalty) ;
- SETKNOB(LogSpins) ;
- SETKNOB(SpinSetSucc) ;
- SETKNOB(SuccEnabled) ;
- SETKNOB(SuccRestrict) ;
- SETKNOB(Penalty) ;
- SETKNOB(Bonus) ;
- SETKNOB(BonusB) ;
- SETKNOB(Poverty) ;
- SETKNOB(SpinAfterFutile) ;
- SETKNOB(UsePause) ;
- SETKNOB(SpinEarly) ;
- SETKNOB(OState) ;
- SETKNOB(MaxSpinners) ;
- SETKNOB(PreSpin) ;
- SETKNOB(ExitPolicy) ;
- SETKNOB(QMode);
- SETKNOB(ResetEvent) ;
- SETKNOB(MoveNotifyee) ;
- SETKNOB(FastHSSEC) ;
- #undef SETKNOB
-
- if (os::is_MP()) {
- BackOffMask = (1 << Knob_SpinBackOff) - 1 ;
- if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ;
- // CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
- } else {
- Knob_SpinLimit = 0 ;
- Knob_SpinBase = 0 ;
- Knob_PreSpin = 0 ;
- Knob_FixedSpin = -1 ;
- }
-
- if (Knob_LogSpins == 0) {
- ObjectSynchronizer::_sync_FailedSpins = NULL ;
- }
-
- free (knobs) ;
- OrderAccess::fence() ;
- InitDone = 1 ;
-}
-
-// Theory of operations -- Monitors lists, thread residency, etc:
-//
-// * A thread acquires ownership of a monitor by successfully
-// CAS()ing the _owner field from null to non-null.
-//
-// * Invariant: A thread appears on at most one monitor list --
-// cxq, EntryList or WaitSet -- at any one time.
-//
-// * Contending threads "push" themselves onto the cxq with CAS
-// and then spin/park.
-//
-// * After a contending thread eventually acquires the lock it must
-// dequeue itself from either the EntryList or the cxq.
-//
-// * The exiting thread identifies and unparks an "heir presumptive"
-// tentative successor thread on the EntryList. Critically, the
-// exiting thread doesn't unlink the successor thread from the EntryList.
-// After having been unparked, the wakee will recontend for ownership of
-// the monitor. The successor (wakee) will either acquire the lock or
-// re-park itself.
-//
-// Succession is provided for by a policy of competitive handoff.
-// The exiting thread does _not_ grant or pass ownership to the
-// successor thread. (This is also referred to as "handoff" succession").
-// Instead the exiting thread releases ownership and possibly wakes
-// a successor, so the successor can (re)compete for ownership of the lock.
-// If the EntryList is empty but the cxq is populated the exiting
-// thread will drain the cxq into the EntryList. It does so by
-// by detaching the cxq (installing null with CAS) and folding
-// the threads from the cxq into the EntryList. The EntryList is
-// doubly linked, while the cxq is singly linked because of the
-// CAS-based "push" used to enqueue recently arrived threads (RATs).
-//
-// * Concurrency invariants:
-//
-// -- only the monitor owner may access or mutate the EntryList.
-// The mutex property of the monitor itself protects the EntryList
-// from concurrent interference.
-// -- Only the monitor owner may detach the cxq.
-//
-// * The monitor entry list operations avoid locks, but strictly speaking
-// they're not lock-free. Enter is lock-free, exit is not.
-// See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html
-//
-// * The cxq can have multiple concurrent "pushers" but only one concurrent
-// detaching thread. This mechanism is immune from the ABA corruption.
-// More precisely, the CAS-based "push" onto cxq is ABA-oblivious.
-//
-// * Taken together, the cxq and the EntryList constitute or form a
-// single logical queue of threads stalled trying to acquire the lock.
-// We use two distinct lists to improve the odds of a constant-time
-// dequeue operation after acquisition (in the ::enter() epilog) and
-// to reduce heat on the list ends. (c.f. Michael Scott's "2Q" algorithm).
-// A key desideratum is to minimize queue & monitor metadata manipulation
-// that occurs while holding the monitor lock -- that is, we want to
-// minimize monitor lock holds times. Note that even a small amount of
-// fixed spinning will greatly reduce the # of enqueue-dequeue operations
-// on EntryList|cxq. That is, spinning relieves contention on the "inner"
-// locks and monitor metadata.
-//
-// Cxq points to the the set of Recently Arrived Threads attempting entry.
-// Because we push threads onto _cxq with CAS, the RATs must take the form of
-// a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when
-// the unlocking thread notices that EntryList is null but _cxq is != null.
-//
-// The EntryList is ordered by the prevailing queue discipline and
-// can be organized in any convenient fashion, such as a doubly-linked list or
-// a circular doubly-linked list. Critically, we want insert and delete operations
-// to operate in constant-time. If we need a priority queue then something akin
-// to Solaris' sleepq would work nicely. Viz.,
-// http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.
-// Queue discipline is enforced at ::exit() time, when the unlocking thread
-// drains the cxq into the EntryList, and orders or reorders the threads on the
-// EntryList accordingly.
-//
-// Barring "lock barging", this mechanism provides fair cyclic ordering,
-// somewhat similar to an elevator-scan.
-//
-// * The monitor synchronization subsystem avoids the use of native
-// synchronization primitives except for the narrow platform-specific
-// park-unpark abstraction. See the comments in os_solaris.cpp regarding
-// the semantics of park-unpark. Put another way, this monitor implementation
-// depends only on atomic operations and park-unpark. The monitor subsystem
-// manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the
-// underlying OS manages the READY<->RUN transitions.
-//
-// * Waiting threads reside on the WaitSet list -- wait() puts
-// the caller onto the WaitSet.
-//
-// * notify() or notifyAll() simply transfers threads from the WaitSet to
-// either the EntryList or cxq. Subsequent exit() operations will
-// unpark the notifyee. Unparking a notifee in notify() is inefficient -
-// it's likely the notifyee would simply impale itself on the lock held
-// by the notifier.
-//
-// * An interesting alternative is to encode cxq as (List,LockByte) where
-// the LockByte is 0 iff the monitor is owned. _owner is simply an auxiliary
-// variable, like _recursions, in the scheme. The threads or Events that form
-// the list would have to be aligned in 256-byte addresses. A thread would
-// try to acquire the lock or enqueue itself with CAS, but exiting threads
-// could use a 1-0 protocol and simply STB to set the LockByte to 0.
-// Note that is is *not* word-tearing, but it does presume that full-word
-// CAS operations are coherent with intermix with STB operations. That's true
-// on most common processors.
-//
-// * See also http://blogs.sun.com/dave
-
-
-void ATTR ObjectMonitor::EnterI (TRAPS) {
- Thread * Self = THREAD ;
- assert (Self->is_Java_thread(), "invariant") ;
- assert (((JavaThread *) Self)->thread_state() == _thread_blocked , "invariant") ;
-
- // Try the lock - TATAS
- if (TryLock (Self) > 0) {
- assert (_succ != Self , "invariant") ;
- assert (_owner == Self , "invariant") ;
- assert (_Responsible != Self , "invariant") ;
- return ;
- }
-
- DeferredInitialize () ;
-
- // We try one round of spinning *before* enqueueing Self.
- //
- // If the _owner is ready but OFFPROC we could use a YieldTo()
- // operation to donate the remainder of this thread's quantum
- // to the owner. This has subtle but beneficial affinity
- // effects.
-
- if (TrySpin (Self) > 0) {
- assert (_owner == Self , "invariant") ;
- assert (_succ != Self , "invariant") ;
- assert (_Responsible != Self , "invariant") ;
- return ;
- }
-
- // The Spin failed -- Enqueue and park the thread ...
- assert (_succ != Self , "invariant") ;
- assert (_owner != Self , "invariant") ;
- assert (_Responsible != Self , "invariant") ;
-
- // Enqueue "Self" on ObjectMonitor's _cxq.
- //
- // Node acts as a proxy for Self.
- // As an aside, if were to ever rewrite the synchronization code mostly
- // in Java, WaitNodes, ObjectMonitors, and Events would become 1st-class
- // Java objects. This would avoid awkward lifecycle and liveness issues,
- // as well as eliminate a subset of ABA issues.
- // TODO: eliminate ObjectWaiter and enqueue either Threads or Events.
- //
-
- ObjectWaiter node(Self) ;
- Self->_ParkEvent->reset() ;
- node._prev = (ObjectWaiter *) 0xBAD ;
- node.TState = ObjectWaiter::TS_CXQ ;
-
- // Push "Self" onto the front of the _cxq.
- // Once on cxq/EntryList, Self stays on-queue until it acquires the lock.
- // Note that spinning tends to reduce the rate at which threads
- // enqueue and dequeue on EntryList|cxq.
- ObjectWaiter * nxt ;
- for (;;) {
- node._next = nxt = _cxq ;
- if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
-
- // Interference - the CAS failed because _cxq changed. Just retry.
- // As an optional optimization we retry the lock.
- if (TryLock (Self) > 0) {
- assert (_succ != Self , "invariant") ;
- assert (_owner == Self , "invariant") ;
- assert (_Responsible != Self , "invariant") ;
- return ;
- }
- }
-
- // Check for cxq|EntryList edge transition to non-null. This indicates
- // the onset of contention. While contention persists exiting threads
- // will use a ST:MEMBAR:LD 1-1 exit protocol. When contention abates exit
- // operations revert to the faster 1-0 mode. This enter operation may interleave
- // (race) a concurrent 1-0 exit operation, resulting in stranding, so we
- // arrange for one of the contending thread to use a timed park() operations
- // to detect and recover from the race. (Stranding is form of progress failure
- // where the monitor is unlocked but all the contending threads remain parked).
- // That is, at least one of the contended threads will periodically poll _owner.
- // One of the contending threads will become the designated "Responsible" thread.
- // The Responsible thread uses a timed park instead of a normal indefinite park
- // operation -- it periodically wakes and checks for and recovers from potential
- // strandings admitted by 1-0 exit operations. We need at most one Responsible
- // thread per-monitor at any given moment. Only threads on cxq|EntryList may
- // be responsible for a monitor.
- //
- // Currently, one of the contended threads takes on the added role of "Responsible".
- // A viable alternative would be to use a dedicated "stranding checker" thread
- // that periodically iterated over all the threads (or active monitors) and unparked
- // successors where there was risk of stranding. This would help eliminate the
- // timer scalability issues we see on some platforms as we'd only have one thread
- // -- the checker -- parked on a timer.
-
- if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
- // Try to assume the role of responsible thread for the monitor.
- // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=Self }
- Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
- }
-
- // The lock have been released while this thread was occupied queueing
- // itself onto _cxq. To close the race and avoid "stranding" and
- // progress-liveness failure we must resample-retry _owner before parking.
- // Note the Dekker/Lamport duality: ST cxq; MEMBAR; LD Owner.
- // In this case the ST-MEMBAR is accomplished with CAS().
- //
- // TODO: Defer all thread state transitions until park-time.
- // Since state transitions are heavy and inefficient we'd like
- // to defer the state transitions until absolutely necessary,
- // and in doing so avoid some transitions ...
-
- TEVENT (Inflated enter - Contention) ;
- int nWakeups = 0 ;
- int RecheckInterval = 1 ;
-
- for (;;) {
-
- if (TryLock (Self) > 0) break ;
- assert (_owner != Self, "invariant") ;
-
- if ((SyncFlags & 2) && _Responsible == NULL) {
- Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
- }
-
- // park self
- if (_Responsible == Self || (SyncFlags & 1)) {
- TEVENT (Inflated enter - park TIMED) ;
- Self->_ParkEvent->park ((jlong) RecheckInterval) ;
- // Increase the RecheckInterval, but clamp the value.
- RecheckInterval *= 8 ;
- if (RecheckInterval > 1000) RecheckInterval = 1000 ;
- } else {
- TEVENT (Inflated enter - park UNTIMED) ;
- Self->_ParkEvent->park() ;
- }
-
- if (TryLock(Self) > 0) break ;
-
- // The lock is still contested.
- // Keep a tally of the # of futile wakeups.
- // Note that the counter is not protected by a lock or updated by atomics.
- // That is by design - we trade "lossy" counters which are exposed to
- // races during updates for a lower probe effect.
- TEVENT (Inflated enter - Futile wakeup) ;
- if (ObjectSynchronizer::_sync_FutileWakeups != NULL) {
- ObjectSynchronizer::_sync_FutileWakeups->inc() ;
- }
- ++ nWakeups ;
-
- // Assuming this is not a spurious wakeup we'll normally find _succ == Self.
- // We can defer clearing _succ until after the spin completes
- // TrySpin() must tolerate being called with _succ == Self.
- // Try yet another round of adaptive spinning.
- if ((Knob_SpinAfterFutile & 1) && TrySpin (Self) > 0) break ;
-
- // We can find that we were unpark()ed and redesignated _succ while
- // we were spinning. That's harmless. If we iterate and call park(),
- // park() will consume the event and return immediately and we'll
- // just spin again. This pattern can repeat, leaving _succ to simply
- // spin on a CPU. Enable Knob_ResetEvent to clear pending unparks().
- // Alternately, we can sample fired() here, and if set, forgo spinning
- // in the next iteration.
-
- if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
- Self->_ParkEvent->reset() ;
- OrderAccess::fence() ;
- }
- if (_succ == Self) _succ = NULL ;
-
- // Invariant: after clearing _succ a thread *must* retry _owner before parking.
- OrderAccess::fence() ;
- }
-
- // Egress :
- // Self has acquired the lock -- Unlink Self from the cxq or EntryList.
- // Normally we'll find Self on the EntryList .
- // From the perspective of the lock owner (this thread), the
- // EntryList is stable and cxq is prepend-only.
- // The head of cxq is volatile but the interior is stable.
- // In addition, Self.TState is stable.
-
- assert (_owner == Self , "invariant") ;
- assert (object() != NULL , "invariant") ;
- // I'd like to write:
- // guarantee (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
- // but as we're at a safepoint that's not safe.
-
- UnlinkAfterAcquire (Self, &node) ;
- if (_succ == Self) _succ = NULL ;
-
- assert (_succ != Self, "invariant") ;
- if (_Responsible == Self) {
- _Responsible = NULL ;
- // Dekker pivot-point.
- // Consider OrderAccess::storeload() here
-
- // We may leave threads on cxq|EntryList without a designated
- // "Responsible" thread. This is benign. When this thread subsequently
- // exits the monitor it can "see" such preexisting "old" threads --
- // threads that arrived on the cxq|EntryList before the fence, above --
- // by LDing cxq|EntryList. Newly arrived threads -- that is, threads
- // that arrive on cxq after the ST:MEMBAR, above -- will set Responsible
- // non-null and elect a new "Responsible" timer thread.
- //
- // This thread executes:
- // ST Responsible=null; MEMBAR (in enter epilog - here)
- // LD cxq|EntryList (in subsequent exit)
- //
- // Entering threads in the slow/contended path execute:
- // ST cxq=nonnull; MEMBAR; LD Responsible (in enter prolog)
- // The (ST cxq; MEMBAR) is accomplished with CAS().
- //
- // The MEMBAR, above, prevents the LD of cxq|EntryList in the subsequent
- // exit operation from floating above the ST Responsible=null.
- //
- // In *practice* however, EnterI() is always followed by some atomic
- // operation such as the decrement of _count in ::enter(). Those atomics
- // obviate the need for the explicit MEMBAR, above.
- }
-
- // We've acquired ownership with CAS().
- // CAS is serializing -- it has MEMBAR/FENCE-equivalent semantics.
- // But since the CAS() this thread may have also stored into _succ,
- // EntryList, cxq or Responsible. These meta-data updates must be
- // visible __before this thread subsequently drops the lock.
- // Consider what could occur if we didn't enforce this constraint --
- // STs to monitor meta-data and user-data could reorder with (become
- // visible after) the ST in exit that drops ownership of the lock.
- // Some other thread could then acquire the lock, but observe inconsistent
- // or old monitor meta-data and heap data. That violates the JMM.
- // To that end, the 1-0 exit() operation must have at least STST|LDST
- // "release" barrier semantics. Specifically, there must be at least a
- // STST|LDST barrier in exit() before the ST of null into _owner that drops
- // the lock. The barrier ensures that changes to monitor meta-data and data
- // protected by the lock will be visible before we release the lock, and
- // therefore before some other thread (CPU) has a chance to acquire the lock.
- // See also: http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
- //
- // Critically, any prior STs to _succ or EntryList must be visible before
- // the ST of null into _owner in the *subsequent* (following) corresponding
- // monitorexit. Recall too, that in 1-0 mode monitorexit does not necessarily
- // execute a serializing instruction.
-
- if (SyncFlags & 8) {
- OrderAccess::fence() ;
- }
- return ;
-}
-
-// ExitSuspendEquivalent:
-// A faster alternate to handle_special_suspend_equivalent_condition()
-//
-// handle_special_suspend_equivalent_condition() unconditionally
-// acquires the SR_lock. On some platforms uncontended MutexLocker()
-// operations have high latency. Note that in ::enter() we call HSSEC
-// while holding the monitor, so we effectively lengthen the critical sections.
-//
-// There are a number of possible solutions:
-//
-// A. To ameliorate the problem we might also defer state transitions
-// to as late as possible -- just prior to parking.
-// Given that, we'd call HSSEC after having returned from park(),
-// but before attempting to acquire the monitor. This is only a
-// partial solution. It avoids calling HSSEC while holding the
-// monitor (good), but it still increases successor reacquisition latency --
-// the interval between unparking a successor and the time the successor
-// resumes and retries the lock. See ReenterI(), which defers state transitions.
-// If we use this technique we can also avoid EnterI()-exit() loop
-// in ::enter() where we iteratively drop the lock and then attempt
-// to reacquire it after suspending.
-//
-// B. In the future we might fold all the suspend bits into a
-// composite per-thread suspend flag and then update it with CAS().
-// Alternately, a Dekker-like mechanism with multiple variables
-// would suffice:
-// ST Self->_suspend_equivalent = false
-// MEMBAR
-// LD Self_>_suspend_flags
-//
-
-
-bool ObjectMonitor::ExitSuspendEquivalent (JavaThread * jSelf) {
- int Mode = Knob_FastHSSEC ;
- if (Mode && !jSelf->is_external_suspend()) {
- assert (jSelf->is_suspend_equivalent(), "invariant") ;
- jSelf->clear_suspend_equivalent() ;
- if (2 == Mode) OrderAccess::storeload() ;
- if (!jSelf->is_external_suspend()) return false ;
- // We raced a suspension -- fall thru into the slow path
- TEVENT (ExitSuspendEquivalent - raced) ;
- jSelf->set_suspend_equivalent() ;
- }
- return jSelf->handle_special_suspend_equivalent_condition() ;
-}
-
-
-// ReenterI() is a specialized inline form of the latter half of the
-// contended slow-path from EnterI(). We use ReenterI() only for
-// monitor reentry in wait().
-//
-// In the future we should reconcile EnterI() and ReenterI(), adding
-// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
-// loop accordingly.
-
-void ATTR ObjectMonitor::ReenterI (Thread * Self, ObjectWaiter * SelfNode) {
- assert (Self != NULL , "invariant") ;
- assert (SelfNode != NULL , "invariant") ;
- assert (SelfNode->_thread == Self , "invariant") ;
- assert (_waiters > 0 , "invariant") ;
- assert (((oop)(object()))->mark() == markOopDesc::encode(this) , "invariant") ;
- assert (((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
- JavaThread * jt = (JavaThread *) Self ;
-
- int nWakeups = 0 ;
- for (;;) {
- ObjectWaiter::TStates v = SelfNode->TState ;
- guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
- assert (_owner != Self, "invariant") ;
-
- if (TryLock (Self) > 0) break ;
- if (TrySpin (Self) > 0) break ;
-
- TEVENT (Wait Reentry - parking) ;
-
- // State transition wrappers around park() ...
- // ReenterI() wisely defers state transitions until
- // it's clear we must park the thread.
- {
- OSThreadContendState osts(Self->osthread());
- ThreadBlockInVM tbivm(jt);
-
- // cleared by handle_special_suspend_equivalent_condition()
- // or java_suspend_self()
- jt->set_suspend_equivalent();
- if (SyncFlags & 1) {
- Self->_ParkEvent->park ((jlong)1000) ;
- } else {
- Self->_ParkEvent->park () ;
- }
-
- // were we externally suspended while we were waiting?
- for (;;) {
- if (!ExitSuspendEquivalent (jt)) break ;
- if (_succ == Self) { _succ = NULL; OrderAccess::fence(); }
- jt->java_suspend_self();
- jt->set_suspend_equivalent();
- }
- }
-
- // Try again, but just so we distinguish between futile wakeups and
- // successful wakeups. The following test isn't algorithmically
- // necessary, but it helps us maintain sensible statistics.
- if (TryLock(Self) > 0) break ;
-
- // The lock is still contested.
- // Keep a tally of the # of futile wakeups.
- // Note that the counter is not protected by a lock or updated by atomics.
- // That is by design - we trade "lossy" counters which are exposed to
- // races during updates for a lower probe effect.
- TEVENT (Wait Reentry - futile wakeup) ;
- ++ nWakeups ;
-
- // Assuming this is not a spurious wakeup we'll normally
- // find that _succ == Self.
- if (_succ == Self) _succ = NULL ;
-
- // Invariant: after clearing _succ a contending thread
- // *must* retry _owner before parking.
- OrderAccess::fence() ;
-
- if (ObjectSynchronizer::_sync_FutileWakeups != NULL) {
- ObjectSynchronizer::_sync_FutileWakeups->inc() ;
- }
- }
-
- // Self has acquired the lock -- Unlink Self from the cxq or EntryList .
- // Normally we'll find Self on the EntryList.
- // Unlinking from the EntryList is constant-time and atomic-free.
- // From the perspective of the lock owner (this thread), the
- // EntryList is stable and cxq is prepend-only.
- // The head of cxq is volatile but the interior is stable.
- // In addition, Self.TState is stable.
-
- assert (_owner == Self, "invariant") ;
- assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
- UnlinkAfterAcquire (Self, SelfNode) ;
- if (_succ == Self) _succ = NULL ;
- assert (_succ != Self, "invariant") ;
- SelfNode->TState = ObjectWaiter::TS_RUN ;
- OrderAccess::fence() ; // see comments at the end of EnterI()
-}
-
-bool ObjectMonitor::try_enter(Thread* THREAD) {
- if (THREAD != _owner) {
- if (THREAD->is_lock_owned ((address)_owner)) {
- assert(_recursions == 0, "internal state error");
- _owner = THREAD ;
- _recursions = 1 ;
- OwnerIsThread = 1 ;
- return true;
- }
- if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
- return false;
- }
- return true;
- } else {
- _recursions++;
- return true;
- }
-}
-
-void ATTR ObjectMonitor::enter(TRAPS) {
- // The following code is ordered to check the most common cases first
- // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
- Thread * const Self = THREAD ;
- void * cur ;
-
- cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
- if (cur == NULL) {
- // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
- assert (_recursions == 0 , "invariant") ;
- assert (_owner == Self, "invariant") ;
- // CONSIDER: set or assert OwnerIsThread == 1
- return ;
- }
-
- if (cur == Self) {
- // TODO-FIXME: check for integer overflow! BUGID 6557169.
- _recursions ++ ;
- return ;
- }
-
- if (Self->is_lock_owned ((address)cur)) {
- assert (_recursions == 0, "internal state error");
- _recursions = 1 ;
- // Commute owner from a thread-specific on-stack BasicLockObject address to
- // a full-fledged "Thread *".
- _owner = Self ;
- OwnerIsThread = 1 ;
- return ;
- }
-
- // We've encountered genuine contention.
- assert (Self->_Stalled == 0, "invariant") ;
- Self->_Stalled = intptr_t(this) ;
-
- // Try one round of spinning *before* enqueueing Self
- // and before going through the awkward and expensive state
- // transitions. The following spin is strictly optional ...
- // Note that if we acquire the monitor from an initial spin
- // we forgo posting JVMTI events and firing DTRACE probes.
- if (Knob_SpinEarly && TrySpin (Self) > 0) {
- assert (_owner == Self , "invariant") ;
- assert (_recursions == 0 , "invariant") ;
- assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
- Self->_Stalled = 0 ;
- return ;
- }
-
- assert (_owner != Self , "invariant") ;
- assert (_succ != Self , "invariant") ;
- assert (Self->is_Java_thread() , "invariant") ;
- JavaThread * jt = (JavaThread *) Self ;
- assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
- assert (jt->thread_state() != _thread_blocked , "invariant") ;
- assert (this->object() != NULL , "invariant") ;
- assert (_count >= 0, "invariant") ;
-
- // Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
- // Ensure the object-monitor relationship remains stable while there's contention.
- Atomic::inc_ptr(&_count);
-
- { // Change java thread status to indicate blocked on monitor enter.
- JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
-
- DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
- if (JvmtiExport::should_post_monitor_contended_enter()) {
- JvmtiExport::post_monitor_contended_enter(jt, this);
- }
-
- OSThreadContendState osts(Self->osthread());
- ThreadBlockInVM tbivm(jt);
-
- Self->set_current_pending_monitor(this);
-
- // TODO-FIXME: change the following for(;;) loop to straight-line code.
- for (;;) {
- jt->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition()
- // or java_suspend_self()
-
- EnterI (THREAD) ;
-
- if (!ExitSuspendEquivalent(jt)) break ;
-
- //
- // We have acquired the contended monitor, but while we were
- // waiting another thread suspended us. We don't want to enter
- // the monitor while suspended because that would surprise the
- // thread that suspended us.
- //
- _recursions = 0 ;
- _succ = NULL ;
- exit (Self) ;
-
- jt->java_suspend_self();
- }
- Self->set_current_pending_monitor(NULL);
- }
-
- Atomic::dec_ptr(&_count);
- assert (_count >= 0, "invariant") ;
- Self->_Stalled = 0 ;
-
- // Must either set _recursions = 0 or ASSERT _recursions == 0.
- assert (_recursions == 0 , "invariant") ;
- assert (_owner == Self , "invariant") ;
- assert (_succ != Self , "invariant") ;
- assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
-
- // The thread -- now the owner -- is back in vm mode.
- // Report the glorious news via TI,DTrace and jvmstat.
- // The probe effect is non-trivial. All the reportage occurs
- // while we hold the monitor, increasing the length of the critical
- // section. Amdahl's parallel speedup law comes vividly into play.
- //
- // Another option might be to aggregate the events (thread local or
- // per-monitor aggregation) and defer reporting until a more opportune
- // time -- such as next time some thread encounters contention but has
- // yet to acquire the lock. While spinning that thread could
- // spinning we could increment JVMStat counters, etc.
-
- DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
- if (JvmtiExport::should_post_monitor_contended_entered()) {
- JvmtiExport::post_monitor_contended_entered(jt, this);
- }
- if (ObjectSynchronizer::_sync_ContendedLockAttempts != NULL) {
- ObjectSynchronizer::_sync_ContendedLockAttempts->inc() ;
- }
-}
-
-void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
- assert (_owner == Self, "invariant") ;
-
- // Exit protocol:
- // 1. ST _succ = wakee
- // 2. membar #loadstore|#storestore;
- // 2. ST _owner = NULL
- // 3. unpark(wakee)
-
- _succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
- ParkEvent * Trigger = Wakee->_event ;
+};
- // Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
- // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
- // out-of-scope (non-extant).
- Wakee = NULL ;
-
- // Drop the lock
- OrderAccess::release_store_ptr (&_owner, NULL) ;
- OrderAccess::fence() ; // ST _owner vs LD in unpark()
-
- // TODO-FIXME:
- // If there's a safepoint pending the best policy would be to
- // get _this thread to a safepoint and only wake the successor
- // after the safepoint completed. monitorexit uses a "leaf"
- // state transition, however, so this thread can't become
- // safe at this point in time. (Its stack isn't walkable).
- // The next best thing is to defer waking the successor by
- // adding to a list of thread to be unparked after at the
- // end of the forthcoming STW).
- if (SafepointSynchronize::do_call_back()) {
- TEVENT (unpark before SAFEPOINT) ;
- }
-
- // Possible optimizations ...
- //
- // * Consider: set Wakee->UnparkTime = timeNow()
- // When the thread wakes up it'll compute (timeNow() - Self->UnparkTime()).
- // By measuring recent ONPROC latency we can approximate the
- // system load. In turn, we can feed that information back
- // into the spinning & succession policies.
- // (ONPROC latency correlates strongly with load).
- //
- // * Pull affinity:
- // If the wakee is cold then transiently setting it's affinity
- // to the current CPU is a good idea.
- // See http://j2se.east/~dice/PERSIST/050624-PullAffinity.txt
- DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
- Trigger->unpark() ;
-
- // Maintain stats and report events to JVMTI
- if (ObjectSynchronizer::_sync_Parks != NULL) {
- ObjectSynchronizer::_sync_Parks->inc() ;
- }
-}
-
-
-// exit()
-// ~~~~~~
-// Note that the collector can't reclaim the objectMonitor or deflate
-// the object out from underneath the thread calling ::exit() as the
-// thread calling ::exit() never transitions to a stable state.
-// This inhibits GC, which in turn inhibits asynchronous (and
-// inopportune) reclamation of "this".
-//
-// We'd like to assert that: (THREAD->thread_state() != _thread_blocked) ;
-// There's one exception to the claim above, however. EnterI() can call
-// exit() to drop a lock if the acquirer has been externally suspended.
-// In that case exit() is called with _thread_state as _thread_blocked,
-// but the monitor's _count field is > 0, which inhibits reclamation.
-//
-// 1-0 exit
-// ~~~~~~~~
-// ::exit() uses a canonical 1-1 idiom with a MEMBAR although some of
-// the fast-path operators have been optimized so the common ::exit()
-// operation is 1-0. See i486.ad fast_unlock(), for instance.
-// The code emitted by fast_unlock() elides the usual MEMBAR. This
-// greatly improves latency -- MEMBAR and CAS having considerable local
-// latency on modern processors -- but at the cost of "stranding". Absent the
-// MEMBAR, a thread in fast_unlock() can race a thread in the slow
-// ::enter() path, resulting in the entering thread being stranding
-// and a progress-liveness failure. Stranding is extremely rare.
-// We use timers (timed park operations) & periodic polling to detect
-// and recover from stranding. Potentially stranded threads periodically
-// wake up and poll the lock. See the usage of the _Responsible variable.
-//
-// The CAS() in enter provides for safety and exclusion, while the CAS or
-// MEMBAR in exit provides for progress and avoids stranding. 1-0 locking
-// eliminates the CAS/MEMBAR from the exist path, but it admits stranding.
-// We detect and recover from stranding with timers.
+// Release all inflated monitors owned by THREAD. Lightweight monitors are
+// ignored. This is meant to be called during JNI thread detach which assumes
+// all remaining monitors are heavyweight. All exceptions are swallowed.
+// Scanning the extant monitor list can be time consuming.
+// A simple optimization is to add a per-thread flag that indicates a thread
+// called jni_monitorenter() during its lifetime.
//
-// If a thread transiently strands it'll park until (a) another
-// thread acquires the lock and then drops the lock, at which time the
-// exiting thread will notice and unpark the stranded thread, or, (b)
-// the timer expires. If the lock is high traffic then the stranding latency
-// will be low due to (a). If the lock is low traffic then the odds of
-// stranding are lower, although the worst-case stranding latency
-// is longer. Critically, we don't want to put excessive load in the
-// platform's timer subsystem. We want to minimize both the timer injection
-// rate (timers created/sec) as well as the number of timers active at
-// any one time. (more precisely, we want to minimize timer-seconds, which is
-// the integral of the # of active timers at any instant over time).
-// Both impinge on OS scalability. Given that, at most one thread parked on
-// a monitor will use a timer.
-
-void ATTR ObjectMonitor::exit(TRAPS) {
- Thread * Self = THREAD ;
- if (THREAD != _owner) {
- if (THREAD->is_lock_owned((address) _owner)) {
- // Transmute _owner from a BasicLock pointer to a Thread address.
- // We don't need to hold _mutex for this transition.
- // Non-null to Non-null is safe as long as all readers can
- // tolerate either flavor.
- assert (_recursions == 0, "invariant") ;
- _owner = THREAD ;
- _recursions = 0 ;
- OwnerIsThread = 1 ;
- } else {
- // NOTE: we need to handle unbalanced monitor enter/exit
- // in native code by throwing an exception.
- // TODO: Throw an IllegalMonitorStateException ?
- TEVENT (Exit - Throw IMSX) ;
- assert(false, "Non-balanced monitor enter/exit!");
- if (false) {
- THROW(vmSymbols::java_lang_IllegalMonitorStateException());
- }
- return;
- }
- }
-
- if (_recursions != 0) {
- _recursions--; // this is simple recursive enter
- TEVENT (Inflated exit - recursive) ;
- return ;
- }
-
- // Invariant: after setting Responsible=null an thread must execute
- // a MEMBAR or other serializing instruction before fetching EntryList|cxq.
- if ((SyncFlags & 4) == 0) {
- _Responsible = NULL ;
- }
-
- for (;;) {
- assert (THREAD == _owner, "invariant") ;
-
- // Fast-path monitor exit:
- //
- // Observe the Dekker/Lamport duality:
- // A thread in ::exit() executes:
- // ST Owner=null; MEMBAR; LD EntryList|cxq.
- // A thread in the contended ::enter() path executes the complementary:
- // ST EntryList|cxq = nonnull; MEMBAR; LD Owner.
- //
- // Note that there's a benign race in the exit path. We can drop the
- // lock, another thread can reacquire the lock immediately, and we can
- // then wake a thread unnecessarily (yet another flavor of futile wakeup).
- // This is benign, and we've structured the code so the windows are short
- // and the frequency of such futile wakeups is low.
- //
- // We could eliminate the race by encoding both the "LOCKED" state and
- // the queue head in a single word. Exit would then use either CAS to
- // clear the LOCKED bit/byte. This precludes the desirable 1-0 optimization,
- // however.
- //
- // Possible fast-path ::exit() optimization:
- // The current fast-path exit implementation fetches both cxq and EntryList.
- // See also i486.ad fast_unlock(). Testing has shown that two LDs
- // isn't measurably slower than a single LD on any platforms.
- // Still, we could reduce the 2 LDs to one or zero by one of the following:
- //
- // - Use _count instead of cxq|EntryList
- // We intend to eliminate _count, however, when we switch
- // to on-the-fly deflation in ::exit() as is used in
- // Metalocks and RelaxedLocks.
- //
- // - Establish the invariant that cxq == null implies EntryList == null.
- // set cxq == EMPTY (1) to encode the state where cxq is empty
- // by EntryList != null. EMPTY is a distinguished value.
- // The fast-path exit() would fetch cxq but not EntryList.
- //
- // - Encode succ as follows:
- // succ = t : Thread t is the successor -- t is ready or is spinning.
- // Exiting thread does not need to wake a successor.
- // succ = 0 : No successor required -> (EntryList|cxq) == null
- // Exiting thread does not need to wake a successor
- // succ = 1 : Successor required -> (EntryList|cxq) != null and
- // logically succ == null.
- // Exiting thread must wake a successor.
- //
- // The 1-1 fast-exit path would appear as :
- // _owner = null ; membar ;
- // if (_succ == 1 && CAS (&_owner, null, Self) == null) goto SlowPath
- // goto FastPathDone ;
- //
- // and the 1-0 fast-exit path would appear as:
- // if (_succ == 1) goto SlowPath
- // Owner = null ;
- // goto FastPathDone
- //
- // - Encode the LSB of _owner as 1 to indicate that exit()
- // must use the slow-path and make a successor ready.
- // (_owner & 1) == 0 IFF succ != null || (EntryList|cxq) == null
- // (_owner & 1) == 0 IFF succ == null && (EntryList|cxq) != null (obviously)
- // The 1-0 fast exit path would read:
- // if (_owner != Self) goto SlowPath
- // _owner = null
- // goto FastPathDone
-
- if (Knob_ExitPolicy == 0) {
- // release semantics: prior loads and stores from within the critical section
- // must not float (reorder) past the following store that drops the lock.
- // On SPARC that requires MEMBAR #loadstore|#storestore.
- // But of course in TSO #loadstore|#storestore is not required.
- // I'd like to write one of the following:
- // A. OrderAccess::release() ; _owner = NULL
- // B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
- // Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
- // store into a _dummy variable. That store is not needed, but can result
- // in massive wasteful coherency traffic on classic SMP systems.
- // Instead, I use release_store(), which is implemented as just a simple
- // ST on x64, x86 and SPARC.
- OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
- OrderAccess::storeload() ; // See if we need to wake a successor
- if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
- TEVENT (Inflated exit - simple egress) ;
- return ;
- }
- TEVENT (Inflated exit - complex egress) ;
-
- // Normally the exiting thread is responsible for ensuring succession,
- // but if other successors are ready or other entering threads are spinning
- // then this thread can simply store NULL into _owner and exit without
- // waking a successor. The existence of spinners or ready successors
- // guarantees proper succession (liveness). Responsibility passes to the
- // ready or running successors. The exiting thread delegates the duty.
- // More precisely, if a successor already exists this thread is absolved
- // of the responsibility of waking (unparking) one.
- //
- // The _succ variable is critical to reducing futile wakeup frequency.
- // _succ identifies the "heir presumptive" thread that has been made
- // ready (unparked) but that has not yet run. We need only one such
- // successor thread to guarantee progress.
- // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
- // section 3.3 "Futile Wakeup Throttling" for details.
- //
- // Note that spinners in Enter() also set _succ non-null.
- // In the current implementation spinners opportunistically set
- // _succ so that exiting threads might avoid waking a successor.
- // Another less appealing alternative would be for the exiting thread
- // to drop the lock and then spin briefly to see if a spinner managed
- // to acquire the lock. If so, the exiting thread could exit
- // immediately without waking a successor, otherwise the exiting
- // thread would need to dequeue and wake a successor.
- // (Note that we'd need to make the post-drop spin short, but no
- // shorter than the worst-case round-trip cache-line migration time.
- // The dropped lock needs to become visible to the spinner, and then
- // the acquisition of the lock by the spinner must become visible to
- // the exiting thread).
- //
-
- // It appears that an heir-presumptive (successor) must be made ready.
- // Only the current lock owner can manipulate the EntryList or
- // drain _cxq, so we need to reacquire the lock. If we fail
- // to reacquire the lock the responsibility for ensuring succession
- // falls to the new owner.
- //
- if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
- return ;
- }
- TEVENT (Exit - Reacquired) ;
- } else {
- if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
- OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
- OrderAccess::storeload() ;
- // Ratify the previously observed values.
- if (_cxq == NULL || _succ != NULL) {
- TEVENT (Inflated exit - simple egress) ;
- return ;
- }
-
- // inopportune interleaving -- the exiting thread (this thread)
- // in the fast-exit path raced an entering thread in the slow-enter
- // path.
- // We have two choices:
- // A. Try to reacquire the lock.
- // If the CAS() fails return immediately, otherwise
- // we either restart/rerun the exit operation, or simply
- // fall-through into the code below which wakes a successor.
- // B. If the elements forming the EntryList|cxq are TSM
- // we could simply unpark() the lead thread and return
- // without having set _succ.
- if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
- TEVENT (Inflated exit - reacquired succeeded) ;
- return ;
- }
- TEVENT (Inflated exit - reacquired failed) ;
- } else {
- TEVENT (Inflated exit - complex egress) ;
- }
- }
-
- guarantee (_owner == THREAD, "invariant") ;
-
- // Select an appropriate successor ("heir presumptive") from the EntryList
- // and make it ready. Generally we just wake the head of EntryList .
- // There's no algorithmic constraint that we use the head - it's just
- // a policy decision. Note that the thread at head of the EntryList
- // remains at the head until it acquires the lock. This means we'll
- // repeatedly wake the same thread until it manages to grab the lock.
- // This is generally a good policy - if we're seeing lots of futile wakeups
- // at least we're waking/rewaking a thread that's like to be hot or warm
- // (have residual D$ and TLB affinity).
- //
- // "Wakeup locality" optimization:
- // http://j2se.east/~dice/PERSIST/040825-WakeLocality.txt
- // In the future we'll try to bias the selection mechanism
- // to preferentially pick a thread that recently ran on
- // a processor element that shares cache with the CPU on which
- // the exiting thread is running. We need access to Solaris'
- // schedctl.sc_cpu to make that work.
- //
- ObjectWaiter * w = NULL ;
- int QMode = Knob_QMode ;
-
- if (QMode == 2 && _cxq != NULL) {
- // QMode == 2 : cxq has precedence over EntryList.
- // Try to directly wake a successor from the cxq.
- // If successful, the successor will need to unlink itself from cxq.
- w = _cxq ;
- assert (w != NULL, "invariant") ;
- assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
- ExitEpilog (Self, w) ;
- return ;
- }
-
- if (QMode == 3 && _cxq != NULL) {
- // Aggressively drain cxq into EntryList at the first opportunity.
- // This policy ensure that recently-run threads live at the head of EntryList.
- // Drain _cxq into EntryList - bulk transfer.
- // First, detach _cxq.
- // The following loop is tantamount to: w = swap (&cxq, NULL)
- w = _cxq ;
- for (;;) {
- assert (w != NULL, "Invariant") ;
- ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
- if (u == w) break ;
- w = u ;
- }
- assert (w != NULL , "invariant") ;
-
- ObjectWaiter * q = NULL ;
- ObjectWaiter * p ;
- for (p = w ; p != NULL ; p = p->_next) {
- guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
- p->TState = ObjectWaiter::TS_ENTER ;
- p->_prev = q ;
- q = p ;
- }
-
- // Append the RATs to the EntryList
- // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
- ObjectWaiter * Tail ;
- for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
- if (Tail == NULL) {
- _EntryList = w ;
- } else {
- Tail->_next = w ;
- w->_prev = Tail ;
- }
-
- // Fall thru into code that tries to wake a successor from EntryList
- }
-
- if (QMode == 4 && _cxq != NULL) {
- // Aggressively drain cxq into EntryList at the first opportunity.
- // This policy ensure that recently-run threads live at the head of EntryList.
-
- // Drain _cxq into EntryList - bulk transfer.
- // First, detach _cxq.
- // The following loop is tantamount to: w = swap (&cxq, NULL)
- w = _cxq ;
- for (;;) {
- assert (w != NULL, "Invariant") ;
- ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
- if (u == w) break ;
- w = u ;
- }
- assert (w != NULL , "invariant") ;
-
- ObjectWaiter * q = NULL ;
- ObjectWaiter * p ;
- for (p = w ; p != NULL ; p = p->_next) {
- guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
- p->TState = ObjectWaiter::TS_ENTER ;
- p->_prev = q ;
- q = p ;
- }
-
- // Prepend the RATs to the EntryList
- if (_EntryList != NULL) {
- q->_next = _EntryList ;
- _EntryList->_prev = q ;
- }
- _EntryList = w ;
-
- // Fall thru into code that tries to wake a successor from EntryList
- }
-
- w = _EntryList ;
- if (w != NULL) {
- // I'd like to write: guarantee (w->_thread != Self).
- // But in practice an exiting thread may find itself on the EntryList.
- // Lets say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and
- // then calls exit(). Exit release the lock by setting O._owner to NULL.
- // Lets say T1 then stalls. T2 acquires O and calls O.notify(). The
- // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
- // release the lock "O". T2 resumes immediately after the ST of null into
- // _owner, above. T2 notices that the EntryList is populated, so it
- // reacquires the lock and then finds itself on the EntryList.
- // Given all that, we have to tolerate the circumstance where "w" is
- // associated with Self.
- assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- ExitEpilog (Self, w) ;
- return ;
- }
-
- // If we find that both _cxq and EntryList are null then just
- // re-run the exit protocol from the top.
- w = _cxq ;
- if (w == NULL) continue ;
-
- // Drain _cxq into EntryList - bulk transfer.
- // First, detach _cxq.
- // The following loop is tantamount to: w = swap (&cxq, NULL)
- for (;;) {
- assert (w != NULL, "Invariant") ;
- ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
- if (u == w) break ;
- w = u ;
- }
- TEVENT (Inflated exit - drain cxq into EntryList) ;
-
- assert (w != NULL , "invariant") ;
- assert (_EntryList == NULL , "invariant") ;
-
- // Convert the LIFO SLL anchored by _cxq into a DLL.
- // The list reorganization step operates in O(LENGTH(w)) time.
- // It's critical that this step operate quickly as
- // "Self" still holds the outer-lock, restricting parallelism
- // and effectively lengthening the critical section.
- // Invariant: s chases t chases u.
- // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
- // we have faster access to the tail.
-
- if (QMode == 1) {
- // QMode == 1 : drain cxq to EntryList, reversing order
- // We also reverse the order of the list.
- ObjectWaiter * s = NULL ;
- ObjectWaiter * t = w ;
- ObjectWaiter * u = NULL ;
- while (t != NULL) {
- guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
- t->TState = ObjectWaiter::TS_ENTER ;
- u = t->_next ;
- t->_prev = u ;
- t->_next = s ;
- s = t;
- t = u ;
- }
- _EntryList = s ;
- assert (s != NULL, "invariant") ;
- } else {
- // QMode == 0 or QMode == 2
- _EntryList = w ;
- ObjectWaiter * q = NULL ;
- ObjectWaiter * p ;
- for (p = w ; p != NULL ; p = p->_next) {
- guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
- p->TState = ObjectWaiter::TS_ENTER ;
- p->_prev = q ;
- q = p ;
- }
- }
-
- // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
- // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
-
- // See if we can abdicate to a spinner instead of waking a thread.
- // A primary goal of the implementation is to reduce the
- // context-switch rate.
- if (_succ != NULL) continue;
-
- w = _EntryList ;
- if (w != NULL) {
- guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- ExitEpilog (Self, w) ;
- return ;
- }
- }
-}
-// complete_exit exits a lock returning recursion count
-// complete_exit/reenter operate as a wait without waiting
-// complete_exit requires an inflated monitor
-// The _owner field is not always the Thread addr even with an
-// inflated monitor, e.g. the monitor can be inflated by a non-owning
-// thread due to contention.
-intptr_t ObjectMonitor::complete_exit(TRAPS) {
- Thread * const Self = THREAD;
- assert(Self->is_Java_thread(), "Must be Java thread!");
- JavaThread *jt = (JavaThread *)THREAD;
-
- DeferredInitialize();
-
- if (THREAD != _owner) {
- if (THREAD->is_lock_owned ((address)_owner)) {
- assert(_recursions == 0, "internal state error");
- _owner = THREAD ; /* Convert from basiclock addr to Thread addr */
- _recursions = 0 ;
- OwnerIsThread = 1 ;
- }
- }
-
- guarantee(Self == _owner, "complete_exit not owner");
- intptr_t save = _recursions; // record the old recursion count
- _recursions = 0; // set the recursion level to be 0
- exit (Self) ; // exit the monitor
- guarantee (_owner != Self, "invariant");
- return save;
-}
-
-// reenter() enters a lock and sets recursion count
-// complete_exit/reenter operate as a wait without waiting
-void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
- Thread * const Self = THREAD;
- assert(Self->is_Java_thread(), "Must be Java thread!");
- JavaThread *jt = (JavaThread *)THREAD;
-
- guarantee(_owner != Self, "reenter already owner");
- enter (THREAD); // enter the monitor
- guarantee (_recursions == 0, "reenter recursion");
- _recursions = recursions;
- return;
-}
-
-// Note: a subset of changes to ObjectMonitor::wait()
-// will need to be replicated in complete_exit above
-void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
- Thread * const Self = THREAD ;
- assert(Self->is_Java_thread(), "Must be Java thread!");
- JavaThread *jt = (JavaThread *)THREAD;
-
- DeferredInitialize () ;
-
- // Throw IMSX or IEX.
- CHECK_OWNER();
-
- // check for a pending interrupt
- if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
- // post monitor waited event. Note that this is past-tense, we are done waiting.
- if (JvmtiExport::should_post_monitor_waited()) {
- // Note: 'false' parameter is passed here because the
- // wait was not timed out due to thread interrupt.
- JvmtiExport::post_monitor_waited(jt, this, false);
- }
- TEVENT (Wait - Throw IEX) ;
- THROW(vmSymbols::java_lang_InterruptedException());
- return ;
- }
- TEVENT (Wait) ;
-
- assert (Self->_Stalled == 0, "invariant") ;
- Self->_Stalled = intptr_t(this) ;
- jt->set_current_waiting_monitor(this);
-
- // create a node to be put into the queue
- // Critically, after we reset() the event but prior to park(), we must check
- // for a pending interrupt.
- ObjectWaiter node(Self);
- node.TState = ObjectWaiter::TS_WAIT ;
- Self->_ParkEvent->reset() ;
- OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
-
- // Enter the waiting queue, which is a circular doubly linked list in this case
- // but it could be a priority queue or any data structure.
- // _WaitSetLock protects the wait queue. Normally the wait queue is accessed only
- // by the the owner of the monitor *except* in the case where park()
- // returns because of a timeout of interrupt. Contention is exceptionally rare
- // so we use a simple spin-lock instead of a heavier-weight blocking lock.
-
- Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
- AddWaiter (&node) ;
- Thread::SpinRelease (&_WaitSetLock) ;
-
- if ((SyncFlags & 4) == 0) {
- _Responsible = NULL ;
- }
- intptr_t save = _recursions; // record the old recursion count
- _waiters++; // increment the number of waiters
- _recursions = 0; // set the recursion level to be 1
- exit (Self) ; // exit the monitor
- guarantee (_owner != Self, "invariant") ;
-
- // As soon as the ObjectMonitor's ownership is dropped in the exit()
- // call above, another thread can enter() the ObjectMonitor, do the
- // notify(), and exit() the ObjectMonitor. If the other thread's
- // exit() call chooses this thread as the successor and the unpark()
- // call happens to occur while this thread is posting a
- // MONITOR_CONTENDED_EXIT event, then we run the risk of the event
- // handler using RawMonitors and consuming the unpark().
- //
- // To avoid the problem, we re-post the event. This does no harm
- // even if the original unpark() was not consumed because we are the
- // chosen successor for this monitor.
- if (node._notified != 0 && _succ == Self) {
- node._event->unpark();
- }
-
- // The thread is on the WaitSet list - now park() it.
- // On MP systems it's conceivable that a brief spin before we park
- // could be profitable.
- //
- // TODO-FIXME: change the following logic to a loop of the form
- // while (!timeout && !interrupted && _notified == 0) park()
-
- int ret = OS_OK ;
- int WasNotified = 0 ;
- { // State transition wrappers
- OSThread* osthread = Self->osthread();
- OSThreadWaitState osts(osthread, true);
- {
- ThreadBlockInVM tbivm(jt);
- // Thread is in thread_blocked state and oop access is unsafe.
- jt->set_suspend_equivalent();
-
- if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
- // Intentionally empty
- } else
- if (node._notified == 0) {
- if (millis <= 0) {
- Self->_ParkEvent->park () ;
- } else {
- ret = Self->_ParkEvent->park (millis) ;
- }
- }
-
- // were we externally suspended while we were waiting?
- if (ExitSuspendEquivalent (jt)) {
- // TODO-FIXME: add -- if succ == Self then succ = null.
- jt->java_suspend_self();
- }
-
- } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
-
-
- // Node may be on the WaitSet, the EntryList (or cxq), or in transition
- // from the WaitSet to the EntryList.
- // See if we need to remove Node from the WaitSet.
- // We use double-checked locking to avoid grabbing _WaitSetLock
- // if the thread is not on the wait queue.
- //
- // Note that we don't need a fence before the fetch of TState.
- // In the worst case we'll fetch a old-stale value of TS_WAIT previously
- // written by the is thread. (perhaps the fetch might even be satisfied
- // by a look-aside into the processor's own store buffer, although given
- // the length of the code path between the prior ST and this load that's
- // highly unlikely). If the following LD fetches a stale TS_WAIT value
- // then we'll acquire the lock and then re-fetch a fresh TState value.
- // That is, we fail toward safety.
-
- if (node.TState == ObjectWaiter::TS_WAIT) {
- Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
- if (node.TState == ObjectWaiter::TS_WAIT) {
- DequeueSpecificWaiter (&node) ; // unlink from WaitSet
- assert(node._notified == 0, "invariant");
- node.TState = ObjectWaiter::TS_RUN ;
- }
- Thread::SpinRelease (&_WaitSetLock) ;
- }
+// Instead of No_Savepoint_Verifier it might be cheaper to
+// use an idiom of the form:
+// auto int tmp = SafepointSynchronize::_safepoint_counter ;
+// <code that must not run at safepoint>
+// guarantee (((tmp ^ _safepoint_counter) | (tmp & 1)) == 0) ;
+// Since the tests are extremely cheap we could leave them enabled
+// for normal product builds.
- // The thread is now either on off-list (TS_RUN),
- // on the EntryList (TS_ENTER), or on the cxq (TS_CXQ).
- // The Node's TState variable is stable from the perspective of this thread.
- // No other threads will asynchronously modify TState.
- guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ;
- OrderAccess::loadload() ;
- if (_succ == Self) _succ = NULL ;
- WasNotified = node._notified ;
-
- // Reentry phase -- reacquire the monitor.
- // re-enter contended monitor after object.wait().
- // retain OBJECT_WAIT state until re-enter successfully completes
- // Thread state is thread_in_vm and oop access is again safe,
- // although the raw address of the object may have changed.
- // (Don't cache naked oops over safepoints, of course).
-
- // post monitor waited event. Note that this is past-tense, we are done waiting.
- if (JvmtiExport::should_post_monitor_waited()) {
- JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
- }
- OrderAccess::fence() ;
-
- assert (Self->_Stalled != 0, "invariant") ;
- Self->_Stalled = 0 ;
-
- assert (_owner != Self, "invariant") ;
- ObjectWaiter::TStates v = node.TState ;
- if (v == ObjectWaiter::TS_RUN) {
- enter (Self) ;
- } else {
- guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
- ReenterI (Self, &node) ;
- node.wait_reenter_end(this);
- }
-
- // Self has reacquired the lock.
- // Lifecycle - the node representing Self must not appear on any queues.
- // Node is about to go out-of-scope, but even if it were immortal we wouldn't
- // want residual elements associated with this thread left on any lists.
- guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ;
- assert (_owner == Self, "invariant") ;
- assert (_succ != Self , "invariant") ;
- } // OSThreadWaitState()
-
- jt->set_current_waiting_monitor(NULL);
-
- guarantee (_recursions == 0, "invariant") ;
- _recursions = save; // restore the old recursion count
- _waiters--; // decrement the number of waiters
-
- // Verify a few postconditions
- assert (_owner == Self , "invariant") ;
- assert (_succ != Self , "invariant") ;
- assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
-
- if (SyncFlags & 32) {
- OrderAccess::fence() ;
- }
-
- // check if the notification happened
- if (!WasNotified) {
- // no, it could be timeout or Thread.interrupt() or both
- // check for interrupt event, otherwise it is timeout
- if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
- TEVENT (Wait - throw IEX from epilog) ;
- THROW(vmSymbols::java_lang_InterruptedException());
- }
- }
-
- // NOTE: Spurious wake up will be consider as timeout.
- // Monitor notify has precedence over thread interrupt.
-}
-
-
-// Consider:
-// If the lock is cool (cxq == null && succ == null) and we're on an MP system
-// then instead of transferring a thread from the WaitSet to the EntryList
-// we might just dequeue a thread from the WaitSet and directly unpark() it.
-
-void ObjectMonitor::notify(TRAPS) {
- CHECK_OWNER();
- if (_WaitSet == NULL) {
- TEVENT (Empty-Notify) ;
- return ;
- }
- DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
-
- int Policy = Knob_MoveNotifyee ;
-
- Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
- ObjectWaiter * iterator = DequeueWaiter() ;
- if (iterator != NULL) {
- TEVENT (Notify1 - Transfer) ;
- guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
- guarantee (iterator->_notified == 0, "invariant") ;
- // Disposition - what might we do with iterator ?
- // a. add it directly to the EntryList - either tail or head.
- // b. push it onto the front of the _cxq.
- // For now we use (a).
- if (Policy != 4) {
- iterator->TState = ObjectWaiter::TS_ENTER ;
- }
- iterator->_notified = 1 ;
-
- ObjectWaiter * List = _EntryList ;
- if (List != NULL) {
- assert (List->_prev == NULL, "invariant") ;
- assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- assert (List != iterator, "invariant") ;
- }
-
- if (Policy == 0) { // prepend to EntryList
- if (List == NULL) {
- iterator->_next = iterator->_prev = NULL ;
- _EntryList = iterator ;
- } else {
- List->_prev = iterator ;
- iterator->_next = List ;
- iterator->_prev = NULL ;
- _EntryList = iterator ;
- }
- } else
- if (Policy == 1) { // append to EntryList
- if (List == NULL) {
- iterator->_next = iterator->_prev = NULL ;
- _EntryList = iterator ;
- } else {
- // CONSIDER: finding the tail currently requires a linear-time walk of
- // the EntryList. We can make tail access constant-time by converting to
- // a CDLL instead of using our current DLL.
- ObjectWaiter * Tail ;
- for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
- assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
- Tail->_next = iterator ;
- iterator->_prev = Tail ;
- iterator->_next = NULL ;
- }
- } else
- if (Policy == 2) { // prepend to cxq
- // prepend to cxq
- if (List == NULL) {
- iterator->_next = iterator->_prev = NULL ;
- _EntryList = iterator ;
- } else {
- iterator->TState = ObjectWaiter::TS_CXQ ;
- for (;;) {
- ObjectWaiter * Front = _cxq ;
- iterator->_next = Front ;
- if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
- break ;
- }
- }
- }
- } else
- if (Policy == 3) { // append to cxq
- iterator->TState = ObjectWaiter::TS_CXQ ;
- for (;;) {
- ObjectWaiter * Tail ;
- Tail = _cxq ;
- if (Tail == NULL) {
- iterator->_next = NULL ;
- if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
- break ;
- }
- } else {
- while (Tail->_next != NULL) Tail = Tail->_next ;
- Tail->_next = iterator ;
- iterator->_prev = Tail ;
- iterator->_next = NULL ;
- break ;
- }
- }
- } else {
- ParkEvent * ev = iterator->_event ;
- iterator->TState = ObjectWaiter::TS_RUN ;
- OrderAccess::fence() ;
- ev->unpark() ;
- }
-
- if (Policy < 4) {
- iterator->wait_reenter_begin(this);
- }
-
- // _WaitSetLock protects the wait queue, not the EntryList. We could
- // move the add-to-EntryList operation, above, outside the critical section
- // protected by _WaitSetLock. In practice that's not useful. With the
- // exception of wait() timeouts and interrupts the monitor owner
- // is the only thread that grabs _WaitSetLock. There's almost no contention
- // on _WaitSetLock so it's not profitable to reduce the length of the
- // critical section.
- }
-
- Thread::SpinRelease (&_WaitSetLock) ;
-
- if (iterator != NULL && ObjectSynchronizer::_sync_Notifications != NULL) {
- ObjectSynchronizer::_sync_Notifications->inc() ;
- }
-}
-
-
-void ObjectMonitor::notifyAll(TRAPS) {
- CHECK_OWNER();
- ObjectWaiter* iterator;
- if (_WaitSet == NULL) {
- TEVENT (Empty-NotifyAll) ;
- return ;
- }
- DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
-
- int Policy = Knob_MoveNotifyee ;
- int Tally = 0 ;
- Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
-
- for (;;) {
- iterator = DequeueWaiter () ;
- if (iterator == NULL) break ;
- TEVENT (NotifyAll - Transfer1) ;
- ++Tally ;
-
- // Disposition - what might we do with iterator ?
- // a. add it directly to the EntryList - either tail or head.
- // b. push it onto the front of the _cxq.
- // For now we use (a).
- //
- // TODO-FIXME: currently notifyAll() transfers the waiters one-at-a-time from the waitset
- // to the EntryList. This could be done more efficiently with a single bulk transfer,
- // but in practice it's not time-critical. Beware too, that in prepend-mode we invert the
- // order of the waiters. Lets say that the waitset is "ABCD" and the EntryList is "XYZ".
- // After a notifyAll() in prepend mode the waitset will be empty and the EntryList will
- // be "DCBAXYZ".
-
- guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
- guarantee (iterator->_notified == 0, "invariant") ;
- iterator->_notified = 1 ;
- if (Policy != 4) {
- iterator->TState = ObjectWaiter::TS_ENTER ;
- }
-
- ObjectWaiter * List = _EntryList ;
- if (List != NULL) {
- assert (List->_prev == NULL, "invariant") ;
- assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- assert (List != iterator, "invariant") ;
- }
-
- if (Policy == 0) { // prepend to EntryList
- if (List == NULL) {
- iterator->_next = iterator->_prev = NULL ;
- _EntryList = iterator ;
- } else {
- List->_prev = iterator ;
- iterator->_next = List ;
- iterator->_prev = NULL ;
- _EntryList = iterator ;
- }
- } else
- if (Policy == 1) { // append to EntryList
- if (List == NULL) {
- iterator->_next = iterator->_prev = NULL ;
- _EntryList = iterator ;
- } else {
- // CONSIDER: finding the tail currently requires a linear-time walk of
- // the EntryList. We can make tail access constant-time by converting to
- // a CDLL instead of using our current DLL.
- ObjectWaiter * Tail ;
- for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
- assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
- Tail->_next = iterator ;
- iterator->_prev = Tail ;
- iterator->_next = NULL ;
- }
- } else
- if (Policy == 2) { // prepend to cxq
- // prepend to cxq
- iterator->TState = ObjectWaiter::TS_CXQ ;
- for (;;) {
- ObjectWaiter * Front = _cxq ;
- iterator->_next = Front ;
- if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
- break ;
- }
- }
- } else
- if (Policy == 3) { // append to cxq
- iterator->TState = ObjectWaiter::TS_CXQ ;
- for (;;) {
- ObjectWaiter * Tail ;
- Tail = _cxq ;
- if (Tail == NULL) {
- iterator->_next = NULL ;
- if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
- break ;
- }
- } else {
- while (Tail->_next != NULL) Tail = Tail->_next ;
- Tail->_next = iterator ;
- iterator->_prev = Tail ;
- iterator->_next = NULL ;
- break ;
- }
- }
- } else {
- ParkEvent * ev = iterator->_event ;
- iterator->TState = ObjectWaiter::TS_RUN ;
- OrderAccess::fence() ;
- ev->unpark() ;
- }
-
- if (Policy < 4) {
- iterator->wait_reenter_begin(this);
- }
-
- // _WaitSetLock protects the wait queue, not the EntryList. We could
- // move the add-to-EntryList operation, above, outside the critical section
- // protected by _WaitSetLock. In practice that's not useful. With the
- // exception of wait() timeouts and interrupts the monitor owner
- // is the only thread that grabs _WaitSetLock. There's almost no contention
- // on _WaitSetLock so it's not profitable to reduce the length of the
- // critical section.
- }
-
- Thread::SpinRelease (&_WaitSetLock) ;
-
- if (Tally != 0 && ObjectSynchronizer::_sync_Notifications != NULL) {
- ObjectSynchronizer::_sync_Notifications->inc(Tally) ;
- }
+void ObjectSynchronizer::release_monitors_owned_by_thread(TRAPS) {
+ assert(THREAD == JavaThread::current(), "must be current Java thread");
+ No_Safepoint_Verifier nsv ;
+ ReleaseJavaMonitorsClosure rjmc(THREAD);
+ Thread::muxAcquire(&ListLock, "release_monitors_owned_by_thread");
+ ObjectSynchronizer::monitors_iterate(&rjmc);
+ Thread::muxRelease(&ListLock);
+ THREAD->clear_pending_exception();
}
-// check_slow() is a misnomer. It's called to simply to throw an IMSX exception.
-// TODO-FIXME: remove check_slow() -- it's likely dead.
-
-void ObjectMonitor::check_slow(TRAPS) {
- TEVENT (check_slow - throw IMSX) ;
- assert(THREAD != _owner && !THREAD->is_lock_owned((address) _owner), "must not be owner");
- THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
-}
-
-
-// -------------------------------------------------------------------------
-// The raw monitor subsystem is entirely distinct from normal
-// java-synchronization or jni-synchronization. raw monitors are not
-// associated with objects. They can be implemented in any manner
-// that makes sense. The original implementors decided to piggy-back
-// the raw-monitor implementation on the existing Java objectMonitor mechanism.
-// This flaw needs to fixed. We should reimplement raw monitors as sui-generis.
-// Specifically, we should not implement raw monitors via java monitors.
-// Time permitting, we should disentangle and deconvolve the two implementations
-// and move the resulting raw monitor implementation over to the JVMTI directories.
-// Ideally, the raw monitor implementation would be built on top of
-// park-unpark and nothing else.
-//
-// raw monitors are used mainly by JVMTI
-// The raw monitor implementation borrows the ObjectMonitor structure,
-// but the operators are degenerate and extremely simple.
-//
-// Mixed use of a single objectMonitor instance -- as both a raw monitor
-// and a normal java monitor -- is not permissible.
-//
-// Note that we use the single RawMonitor_lock to protect queue operations for
-// _all_ raw monitors. This is a scalability impediment, but since raw monitor usage
-// is deprecated and rare, this is not of concern. The RawMonitor_lock can not
-// be held indefinitely. The critical sections must be short and bounded.
-//
-// -------------------------------------------------------------------------
-
-int ObjectMonitor::SimpleEnter (Thread * Self) {
- for (;;) {
- if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
- return OS_OK ;
- }
-
- ObjectWaiter Node (Self) ;
- Self->_ParkEvent->reset() ; // strictly optional
- Node.TState = ObjectWaiter::TS_ENTER ;
-
- RawMonitor_lock->lock_without_safepoint_check() ;
- Node._next = _EntryList ;
- _EntryList = &Node ;
- OrderAccess::fence() ;
- if (_owner == NULL && Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
- _EntryList = Node._next ;
- RawMonitor_lock->unlock() ;
- return OS_OK ;
- }
- RawMonitor_lock->unlock() ;
- while (Node.TState == ObjectWaiter::TS_ENTER) {
- Self->_ParkEvent->park() ;
- }
- }
-}
-
-int ObjectMonitor::SimpleExit (Thread * Self) {
- guarantee (_owner == Self, "invariant") ;
- OrderAccess::release_store_ptr (&_owner, NULL) ;
- OrderAccess::fence() ;
- if (_EntryList == NULL) return OS_OK ;
- ObjectWaiter * w ;
-
- RawMonitor_lock->lock_without_safepoint_check() ;
- w = _EntryList ;
- if (w != NULL) {
- _EntryList = w->_next ;
- }
- RawMonitor_lock->unlock() ;
- if (w != NULL) {
- guarantee (w ->TState == ObjectWaiter::TS_ENTER, "invariant") ;
- ParkEvent * ev = w->_event ;
- w->TState = ObjectWaiter::TS_RUN ;
- OrderAccess::fence() ;
- ev->unpark() ;
- }
- return OS_OK ;
-}
-
-int ObjectMonitor::SimpleWait (Thread * Self, jlong millis) {
- guarantee (_owner == Self , "invariant") ;
- guarantee (_recursions == 0, "invariant") ;
-
- ObjectWaiter Node (Self) ;
- Node._notified = 0 ;
- Node.TState = ObjectWaiter::TS_WAIT ;
-
- RawMonitor_lock->lock_without_safepoint_check() ;
- Node._next = _WaitSet ;
- _WaitSet = &Node ;
- RawMonitor_lock->unlock() ;
-
- SimpleExit (Self) ;
- guarantee (_owner != Self, "invariant") ;
-
- int ret = OS_OK ;
- if (millis <= 0) {
- Self->_ParkEvent->park();
- } else {
- ret = Self->_ParkEvent->park(millis);
- }
-
- // If thread still resides on the waitset then unlink it.
- // Double-checked locking -- the usage is safe in this context
- // as we TState is volatile and the lock-unlock operators are
- // serializing (barrier-equivalent).
-
- if (Node.TState == ObjectWaiter::TS_WAIT) {
- RawMonitor_lock->lock_without_safepoint_check() ;
- if (Node.TState == ObjectWaiter::TS_WAIT) {
- // Simple O(n) unlink, but performance isn't critical here.
- ObjectWaiter * p ;
- ObjectWaiter * q = NULL ;
- for (p = _WaitSet ; p != &Node; p = p->_next) {
- q = p ;
- }
- guarantee (p == &Node, "invariant") ;
- if (q == NULL) {
- guarantee (p == _WaitSet, "invariant") ;
- _WaitSet = p->_next ;
- } else {
- guarantee (p == q->_next, "invariant") ;
- q->_next = p->_next ;
- }
- Node.TState = ObjectWaiter::TS_RUN ;
- }
- RawMonitor_lock->unlock() ;
- }
-
- guarantee (Node.TState == ObjectWaiter::TS_RUN, "invariant") ;
- SimpleEnter (Self) ;
-
- guarantee (_owner == Self, "invariant") ;
- guarantee (_recursions == 0, "invariant") ;
- return ret ;
-}
-
-int ObjectMonitor::SimpleNotify (Thread * Self, bool All) {
- guarantee (_owner == Self, "invariant") ;
- if (_WaitSet == NULL) return OS_OK ;
-
- // We have two options:
- // A. Transfer the threads from the WaitSet to the EntryList
- // B. Remove the thread from the WaitSet and unpark() it.
- //
- // We use (B), which is crude and results in lots of futile
- // context switching. In particular (B) induces lots of contention.
-
- ParkEvent * ev = NULL ; // consider using a small auto array ...
- RawMonitor_lock->lock_without_safepoint_check() ;
- for (;;) {
- ObjectWaiter * w = _WaitSet ;
- if (w == NULL) break ;
- _WaitSet = w->_next ;
- if (ev != NULL) { ev->unpark(); ev = NULL; }
- ev = w->_event ;
- OrderAccess::loadstore() ;
- w->TState = ObjectWaiter::TS_RUN ;
- OrderAccess::storeload();
- if (!All) break ;
- }
- RawMonitor_lock->unlock() ;
- if (ev != NULL) ev->unpark();
- return OS_OK ;
-}
-
-// Any JavaThread will enter here with state _thread_blocked
-int ObjectMonitor::raw_enter(TRAPS) {
- TEVENT (raw_enter) ;
- void * Contended ;
-
- // don't enter raw monitor if thread is being externally suspended, it will
- // surprise the suspender if a "suspended" thread can still enter monitor
- JavaThread * jt = (JavaThread *)THREAD;
- if (THREAD->is_Java_thread()) {
- jt->SR_lock()->lock_without_safepoint_check();
- while (jt->is_external_suspend()) {
- jt->SR_lock()->unlock();
- jt->java_suspend_self();
- jt->SR_lock()->lock_without_safepoint_check();
- }
- // guarded by SR_lock to avoid racing with new external suspend requests.
- Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
- jt->SR_lock()->unlock();
- } else {
- Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
- }
-
- if (Contended == THREAD) {
- _recursions ++ ;
- return OM_OK ;
- }
-
- if (Contended == NULL) {
- guarantee (_owner == THREAD, "invariant") ;
- guarantee (_recursions == 0, "invariant") ;
- return OM_OK ;
- }
-
- THREAD->set_current_pending_monitor(this);
-
- if (!THREAD->is_Java_thread()) {
- // No other non-Java threads besides VM thread would acquire
- // a raw monitor.
- assert(THREAD->is_VM_thread(), "must be VM thread");
- SimpleEnter (THREAD) ;
- } else {
- guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
- for (;;) {
- jt->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or
- // java_suspend_self()
- SimpleEnter (THREAD) ;
-
- // were we externally suspended while we were waiting?
- if (!jt->handle_special_suspend_equivalent_condition()) break ;
-
- // This thread was externally suspended
- //
- // This logic isn't needed for JVMTI raw monitors,
- // but doesn't hurt just in case the suspend rules change. This
- // logic is needed for the ObjectMonitor.wait() reentry phase.
- // We have reentered the contended monitor, but while we were
- // waiting another thread suspended us. We don't want to reenter
- // the monitor while suspended because that would surprise the
- // thread that suspended us.
- //
- // Drop the lock -
- SimpleExit (THREAD) ;
-
- jt->java_suspend_self();
- }
-
- assert(_owner == THREAD, "Fatal error with monitor owner!");
- assert(_recursions == 0, "Fatal error with monitor recursions!");
- }
-
- THREAD->set_current_pending_monitor(NULL);
- guarantee (_recursions == 0, "invariant") ;
- return OM_OK;
-}
-
-// Used mainly for JVMTI raw monitor implementation
-// Also used for ObjectMonitor::wait().
-int ObjectMonitor::raw_exit(TRAPS) {
- TEVENT (raw_exit) ;
- if (THREAD != _owner) {
- return OM_ILLEGAL_MONITOR_STATE;
- }
- if (_recursions > 0) {
- --_recursions ;
- return OM_OK ;
- }
-
- void * List = _EntryList ;
- SimpleExit (THREAD) ;
-
- return OM_OK;
-}
-
-// Used for JVMTI raw monitor implementation.
-// All JavaThreads will enter here with state _thread_blocked
-
-int ObjectMonitor::raw_wait(jlong millis, bool interruptible, TRAPS) {
- TEVENT (raw_wait) ;
- if (THREAD != _owner) {
- return OM_ILLEGAL_MONITOR_STATE;
- }
-
- // To avoid spurious wakeups we reset the parkevent -- This is strictly optional.
- // The caller must be able to tolerate spurious returns from raw_wait().
- THREAD->_ParkEvent->reset() ;
- OrderAccess::fence() ;
-
- // check interrupt event
- if (interruptible && Thread::is_interrupted(THREAD, true)) {
- return OM_INTERRUPTED;
- }
-
- intptr_t save = _recursions ;
- _recursions = 0 ;
- _waiters ++ ;
- if (THREAD->is_Java_thread()) {
- guarantee (((JavaThread *) THREAD)->thread_state() == _thread_blocked, "invariant") ;
- ((JavaThread *)THREAD)->set_suspend_equivalent();
- }
- int rv = SimpleWait (THREAD, millis) ;
- _recursions = save ;
- _waiters -- ;
-
- guarantee (THREAD == _owner, "invariant") ;
- if (THREAD->is_Java_thread()) {
- JavaThread * jSelf = (JavaThread *) THREAD ;
- for (;;) {
- if (!jSelf->handle_special_suspend_equivalent_condition()) break ;
- SimpleExit (THREAD) ;
- jSelf->java_suspend_self();
- SimpleEnter (THREAD) ;
- jSelf->set_suspend_equivalent() ;
- }
- }
- guarantee (THREAD == _owner, "invariant") ;
-
- if (interruptible && Thread::is_interrupted(THREAD, true)) {
- return OM_INTERRUPTED;
- }
- return OM_OK ;
-}
-
-int ObjectMonitor::raw_notify(TRAPS) {
- TEVENT (raw_notify) ;
- if (THREAD != _owner) {
- return OM_ILLEGAL_MONITOR_STATE;
- }
- SimpleNotify (THREAD, false) ;
- return OM_OK;
-}
-
-int ObjectMonitor::raw_notifyAll(TRAPS) {
- TEVENT (raw_notifyAll) ;
- if (THREAD != _owner) {
- return OM_ILLEGAL_MONITOR_STATE;
- }
- SimpleNotify (THREAD, true) ;
- return OM_OK;
-}
-
-#ifndef PRODUCT
-void ObjectMonitor::verify() {
-}
-
-void ObjectMonitor::print() {
-}
-#endif
-
//------------------------------------------------------------------------------
// Non-product code
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -22,53 +22,6 @@
*
*/
-class BasicLock VALUE_OBJ_CLASS_SPEC {
- friend class VMStructs;
- private:
- volatile markOop _displaced_header;
- public:
- markOop displaced_header() const { return _displaced_header; }
- void set_displaced_header(markOop header) { _displaced_header = header; }
-
- void print_on(outputStream* st) const;
-
- // move a basic lock (used during deoptimization
- void move_to(oop obj, BasicLock* dest);
-
- static int displaced_header_offset_in_bytes() { return offset_of(BasicLock, _displaced_header); }
-};
-
-// A BasicObjectLock associates a specific Java object with a BasicLock.
-// It is currently embedded in an interpreter frame.
-
-// Because some machines have alignment restrictions on the control stack,
-// the actual space allocated by the interpreter may include padding words
-// after the end of the BasicObjectLock. Also, in order to guarantee
-// alignment of the embedded BasicLock objects on such machines, we
-// put the embedded BasicLock at the beginning of the struct.
-
-class BasicObjectLock VALUE_OBJ_CLASS_SPEC {
- friend class VMStructs;
- private:
- BasicLock _lock; // the lock, must be double word aligned
- oop _obj; // object holds the lock;
-
- public:
- // Manipulation
- oop obj() const { return _obj; }
- void set_obj(oop obj) { _obj = obj; }
- BasicLock* lock() { return &_lock; }
-
- // Note: Use frame::interpreter_frame_monitor_size() for the size of BasicObjectLocks
- // in interpreter activation frames since it includes machine-specific padding.
- static int size() { return sizeof(BasicObjectLock)/wordSize; }
-
- // GC support
- void oops_do(OopClosure* f) { f->do_oop(&_obj); }
-
- static int obj_offset_in_bytes() { return offset_of(BasicObjectLock, _obj); }
- static int lock_offset_in_bytes() { return offset_of(BasicObjectLock, _lock); }
-};
class ObjectMonitor;
@@ -163,6 +116,8 @@
static void verify() PRODUCT_RETURN;
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
+ static void RegisterSpinCallback (int (*)(intptr_t, int), intptr_t) ;
+
private:
enum { _BLOCKSIZE = 128 };
static ObjectMonitor* gBlockList;
@@ -170,30 +125,6 @@
static ObjectMonitor * volatile gOmInUseList; // for moribund thread, so monitors they inflated still get scanned
static int gOmInUseCount;
- public:
- static void Initialize () ;
- static PerfCounter * _sync_ContendedLockAttempts ;
- static PerfCounter * _sync_FutileWakeups ;
- static PerfCounter * _sync_Parks ;
- static PerfCounter * _sync_EmptyNotifications ;
- static PerfCounter * _sync_Notifications ;
- static PerfCounter * _sync_SlowEnter ;
- static PerfCounter * _sync_SlowExit ;
- static PerfCounter * _sync_SlowNotify ;
- static PerfCounter * _sync_SlowNotifyAll ;
- static PerfCounter * _sync_FailedSpins ;
- static PerfCounter * _sync_SuccessfulSpins ;
- static PerfCounter * _sync_PrivateA ;
- static PerfCounter * _sync_PrivateB ;
- static PerfCounter * _sync_MonInCirculation ;
- static PerfCounter * _sync_MonScavenged ;
- static PerfCounter * _sync_Inflations ;
- static PerfCounter * _sync_Deflations ;
- static PerfLongVariable * _sync_MonExtant ;
-
- public:
- static void RegisterSpinCallback (int (*)(intptr_t, int), intptr_t) ;
-
};
// ObjectLocker enforced balanced locking and can never thrown an
--- a/hotspot/src/share/vm/runtime/thread.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/thread.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -1199,6 +1199,7 @@
_exception_pc = 0;
_exception_handler_pc = 0;
_exception_stack_size = 0;
+ _is_method_handle_return = 0;
_jvmti_thread_state= NULL;
_should_post_on_exceptions_flag = JNI_FALSE;
_jvmti_get_loaded_classes_closure = NULL;
@@ -2921,6 +2922,9 @@
// So that JDK version can be used as a discrimintor when parsing arguments
JDK_Version_init();
+ // Update/Initialize System properties after JDK version number is known
+ Arguments::init_version_specific_system_properties();
+
// Parse arguments
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
@@ -2992,8 +2996,8 @@
// crash Linux VM, see notes in os_linux.cpp.
main_thread->create_stack_guard_pages();
- // Initialize Java-Leve synchronization subsystem
- ObjectSynchronizer::Initialize() ;
+ // Initialize Java-Level synchronization subsystem
+ ObjectMonitor::Initialize() ;
// Initialize global modules
jint status = init_globals();
@@ -3962,215 +3966,272 @@
}
}
-
-// Lifecycle management for TSM ParkEvents.
-// ParkEvents are type-stable (TSM).
-// In our particular implementation they happen to be immortal.
+// Internal SpinLock and Mutex
+// Based on ParkEvent
+
+// Ad-hoc mutual exclusion primitives: SpinLock and Mux
//
-// We manage concurrency on the FreeList with a CAS-based
-// detach-modify-reattach idiom that avoids the ABA problems
-// that would otherwise be present in a simple CAS-based
-// push-pop implementation. (push-one and pop-all)
+// We employ SpinLocks _only for low-contention, fixed-length
+// short-duration critical sections where we're concerned
+// about native mutex_t or HotSpot Mutex:: latency.
+// The mux construct provides a spin-then-block mutual exclusion
+// mechanism.
+//
+// Testing has shown that contention on the ListLock guarding gFreeList
+// is common. If we implement ListLock as a simple SpinLock it's common
+// for the JVM to devolve to yielding with little progress. This is true
+// despite the fact that the critical sections protected by ListLock are
+// extremely short.
//
-// Caveat: Allocate() and Release() may be called from threads
-// other than the thread associated with the Event!
-// If we need to call Allocate() when running as the thread in
-// question then look for the PD calls to initialize native TLS.
-// Native TLS (Win32/Linux/Solaris) can only be initialized or
-// accessed by the associated thread.
-// See also pd_initialize().
-//
-// Note that we could defer associating a ParkEvent with a thread
-// until the 1st time the thread calls park(). unpark() calls to
-// an unprovisioned thread would be ignored. The first park() call
-// for a thread would allocate and associate a ParkEvent and return
-// immediately.
-
-volatile int ParkEvent::ListLock = 0 ;
-ParkEvent * volatile ParkEvent::FreeList = NULL ;
-
-ParkEvent * ParkEvent::Allocate (Thread * t) {
- // In rare cases -- JVM_RawMonitor* operations -- we can find t == null.
- ParkEvent * ev ;
-
- // Start by trying to recycle an existing but unassociated
- // ParkEvent from the global free list.
+// TODO-FIXME: ListLock should be of type SpinLock.
+// We should make this a 1st-class type, integrated into the lock
+// hierarchy as leaf-locks. Critically, the SpinLock structure
+// should have sufficient padding to avoid false-sharing and excessive
+// cache-coherency traffic.
+
+
+typedef volatile int SpinLockT ;
+
+void Thread::SpinAcquire (volatile int * adr, const char * LockName) {
+ if (Atomic::cmpxchg (1, adr, 0) == 0) {
+ return ; // normal fast-path return
+ }
+
+ // Slow-path : We've encountered contention -- Spin/Yield/Block strategy.
+ TEVENT (SpinAcquire - ctx) ;
+ int ctr = 0 ;
+ int Yields = 0 ;
for (;;) {
- ev = FreeList ;
- if (ev == NULL) break ;
- // 1: Detach - sequester or privatize the list
- // Tantamount to ev = Swap (&FreeList, NULL)
- if (Atomic::cmpxchg_ptr (NULL, &FreeList, ev) != ev) {
- continue ;
- }
-
- // We've detached the list. The list in-hand is now
- // local to this thread. This thread can operate on the
- // list without risk of interference from other threads.
- // 2: Extract -- pop the 1st element from the list.
- ParkEvent * List = ev->FreeNext ;
- if (List == NULL) break ;
- for (;;) {
- // 3: Try to reattach the residual list
- guarantee (List != NULL, "invariant") ;
- ParkEvent * Arv = (ParkEvent *) Atomic::cmpxchg_ptr (List, &FreeList, NULL) ;
- if (Arv == NULL) break ;
-
- // New nodes arrived. Try to detach the recent arrivals.
- if (Atomic::cmpxchg_ptr (NULL, &FreeList, Arv) != Arv) {
- continue ;
+ while (*adr != 0) {
+ ++ctr ;
+ if ((ctr & 0xFFF) == 0 || !os::is_MP()) {
+ if (Yields > 5) {
+ // Consider using a simple NakedSleep() instead.
+ // Then SpinAcquire could be called by non-JVM threads
+ Thread::current()->_ParkEvent->park(1) ;
+ } else {
+ os::NakedYield() ;
+ ++Yields ;
+ }
+ } else {
+ SpinPause() ;
}
- guarantee (Arv != NULL, "invariant") ;
- // 4: Merge Arv into List
- ParkEvent * Tail = List ;
- while (Tail->FreeNext != NULL) Tail = Tail->FreeNext ;
- Tail->FreeNext = Arv ;
- }
- break ;
- }
-
- if (ev != NULL) {
- guarantee (ev->AssociatedWith == NULL, "invariant") ;
- } else {
- // Do this the hard way -- materialize a new ParkEvent.
- // In rare cases an allocating thread might detach a long list --
- // installing null into FreeList -- and then stall or be obstructed.
- // A 2nd thread calling Allocate() would see FreeList == null.
- // The list held privately by the 1st thread is unavailable to the 2nd thread.
- // In that case the 2nd thread would have to materialize a new ParkEvent,
- // even though free ParkEvents existed in the system. In this case we end up
- // with more ParkEvents in circulation than we need, but the race is
- // rare and the outcome is benign. Ideally, the # of extant ParkEvents
- // is equal to the maximum # of threads that existed at any one time.
- // Because of the race mentioned above, segments of the freelist
- // can be transiently inaccessible. At worst we may end up with the
- // # of ParkEvents in circulation slightly above the ideal.
- // Note that if we didn't have the TSM/immortal constraint, then
- // when reattaching, above, we could trim the list.
- ev = new ParkEvent () ;
- guarantee ((intptr_t(ev) & 0xFF) == 0, "invariant") ;
- }
- ev->reset() ; // courtesy to caller
- ev->AssociatedWith = t ; // Associate ev with t
- ev->FreeNext = NULL ;
- return ev ;
-}
-
-void ParkEvent::Release (ParkEvent * ev) {
- if (ev == NULL) return ;
- guarantee (ev->FreeNext == NULL , "invariant") ;
- ev->AssociatedWith = NULL ;
- for (;;) {
- // Push ev onto FreeList
- // The mechanism is "half" lock-free.
- ParkEvent * List = FreeList ;
- ev->FreeNext = List ;
- if (Atomic::cmpxchg_ptr (ev, &FreeList, List) == List) break ;
+ }
+ if (Atomic::cmpxchg (1, adr, 0) == 0) return ;
}
}
-// Override operator new and delete so we can ensure that the
-// least significant byte of ParkEvent addresses is 0.
-// Beware that excessive address alignment is undesirable
-// as it can result in D$ index usage imbalance as
-// well as bank access imbalance on Niagara-like platforms,
-// although Niagara's hash function should help.
-
-void * ParkEvent::operator new (size_t sz) {
- return (void *) ((intptr_t (CHeapObj::operator new (sz + 256)) + 256) & -256) ;
-}
-
-void ParkEvent::operator delete (void * a) {
- // ParkEvents are type-stable and immortal ...
- ShouldNotReachHere();
+void Thread::SpinRelease (volatile int * adr) {
+ assert (*adr != 0, "invariant") ;
+ OrderAccess::fence() ; // guarantee at least release consistency.
+ // Roach-motel semantics.
+ // It's safe if subsequent LDs and STs float "up" into the critical section,
+ // but prior LDs and STs within the critical section can't be allowed
+ // to reorder or float past the ST that releases the lock.
+ *adr = 0 ;
}
-
-// 6399321 As a temporary measure we copied & modified the ParkEvent::
-// allocate() and release() code for use by Parkers. The Parker:: forms
-// will eventually be removed as we consolide and shift over to ParkEvents
-// for both builtin synchronization and JSR166 operations.
-
-volatile int Parker::ListLock = 0 ;
-Parker * volatile Parker::FreeList = NULL ;
-
-Parker * Parker::Allocate (JavaThread * t) {
- guarantee (t != NULL, "invariant") ;
- Parker * p ;
-
- // Start by trying to recycle an existing but unassociated
- // Parker from the global free list.
+// muxAcquire and muxRelease:
+//
+// * muxAcquire and muxRelease support a single-word lock-word construct.
+// The LSB of the word is set IFF the lock is held.
+// The remainder of the word points to the head of a singly-linked list
+// of threads blocked on the lock.
+//
+// * The current implementation of muxAcquire-muxRelease uses its own
+// dedicated Thread._MuxEvent instance. If we're interested in
+// minimizing the peak number of extant ParkEvent instances then
+// we could eliminate _MuxEvent and "borrow" _ParkEvent as long
+// as certain invariants were satisfied. Specifically, care would need
+// to be taken with regards to consuming unpark() "permits".
+// A safe rule of thumb is that a thread would never call muxAcquire()
+// if it's enqueued (cxq, EntryList, WaitList, etc) and will subsequently
+// park(). Otherwise the _ParkEvent park() operation in muxAcquire() could
+// consume an unpark() permit intended for monitorenter, for instance.
+// One way around this would be to widen the restricted-range semaphore
+// implemented in park(). Another alternative would be to provide
+// multiple instances of the PlatformEvent() for each thread. One
+// instance would be dedicated to muxAcquire-muxRelease, for instance.
+//
+// * Usage:
+// -- Only as leaf locks
+// -- for short-term locking only as muxAcquire does not perform
+// thread state transitions.
+//
+// Alternatives:
+// * We could implement muxAcquire and muxRelease with MCS or CLH locks
+// but with parking or spin-then-park instead of pure spinning.
+// * Use Taura-Oyama-Yonenzawa locks.
+// * It's possible to construct a 1-0 lock if we encode the lockword as
+// (List,LockByte). Acquire will CAS the full lockword while Release
+// will STB 0 into the LockByte. The 1-0 scheme admits stranding, so
+// acquiring threads use timers (ParkTimed) to detect and recover from
+// the stranding window. Thread/Node structures must be aligned on 256-byte
+// boundaries by using placement-new.
+// * Augment MCS with advisory back-link fields maintained with CAS().
+// Pictorially: LockWord -> T1 <-> T2 <-> T3 <-> ... <-> Tn <-> Owner.
+// The validity of the backlinks must be ratified before we trust the value.
+// If the backlinks are invalid the exiting thread must back-track through the
+// the forward links, which are always trustworthy.
+// * Add a successor indication. The LockWord is currently encoded as
+// (List, LOCKBIT:1). We could also add a SUCCBIT or an explicit _succ variable
+// to provide the usual futile-wakeup optimization.
+// See RTStt for details.
+// * Consider schedctl.sc_nopreempt to cover the critical section.
+//
+
+
+typedef volatile intptr_t MutexT ; // Mux Lock-word
+enum MuxBits { LOCKBIT = 1 } ;
+
+void Thread::muxAcquire (volatile intptr_t * Lock, const char * LockName) {
+ intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
+ if (w == 0) return ;
+ if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ return ;
+ }
+
+ TEVENT (muxAcquire - Contention) ;
+ ParkEvent * const Self = Thread::current()->_MuxEvent ;
+ assert ((intptr_t(Self) & LOCKBIT) == 0, "invariant") ;
for (;;) {
- p = FreeList ;
- if (p == NULL) break ;
- // 1: Detach
- // Tantamount to p = Swap (&FreeList, NULL)
- if (Atomic::cmpxchg_ptr (NULL, &FreeList, p) != p) {
- continue ;
- }
-
- // We've detached the list. The list in-hand is now
- // local to this thread. This thread can operate on the
- // list without risk of interference from other threads.
- // 2: Extract -- pop the 1st element from the list.
- Parker * List = p->FreeNext ;
- if (List == NULL) break ;
- for (;;) {
- // 3: Try to reattach the residual list
- guarantee (List != NULL, "invariant") ;
- Parker * Arv = (Parker *) Atomic::cmpxchg_ptr (List, &FreeList, NULL) ;
- if (Arv == NULL) break ;
-
- // New nodes arrived. Try to detach the recent arrivals.
- if (Atomic::cmpxchg_ptr (NULL, &FreeList, Arv) != Arv) {
- continue ;
+ int its = (os::is_MP() ? 100 : 0) + 1 ;
+
+ // Optional spin phase: spin-then-park strategy
+ while (--its >= 0) {
+ w = *Lock ;
+ if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ return ;
+ }
+ }
+
+ Self->reset() ;
+ Self->OnList = intptr_t(Lock) ;
+ // The following fence() isn't _strictly necessary as the subsequent
+ // CAS() both serializes execution and ratifies the fetched *Lock value.
+ OrderAccess::fence();
+ for (;;) {
+ w = *Lock ;
+ if ((w & LOCKBIT) == 0) {
+ if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ Self->OnList = 0 ; // hygiene - allows stronger asserts
+ return ;
+ }
+ continue ; // Interference -- *Lock changed -- Just retry
}
- guarantee (Arv != NULL, "invariant") ;
- // 4: Merge Arv into List
- Parker * Tail = List ;
- while (Tail->FreeNext != NULL) Tail = Tail->FreeNext ;
- Tail->FreeNext = Arv ;
- }
- break ;
- }
-
- if (p != NULL) {
- guarantee (p->AssociatedWith == NULL, "invariant") ;
- } else {
- // Do this the hard way -- materialize a new Parker..
- // In rare cases an allocating thread might detach
- // a long list -- installing null into FreeList --and
- // then stall. Another thread calling Allocate() would see
- // FreeList == null and then invoke the ctor. In this case we
- // end up with more Parkers in circulation than we need, but
- // the race is rare and the outcome is benign.
- // Ideally, the # of extant Parkers is equal to the
- // maximum # of threads that existed at any one time.
- // Because of the race mentioned above, segments of the
- // freelist can be transiently inaccessible. At worst
- // we may end up with the # of Parkers in circulation
- // slightly above the ideal.
- p = new Parker() ;
- }
- p->AssociatedWith = t ; // Associate p with t
- p->FreeNext = NULL ;
- return p ;
-}
-
-
-void Parker::Release (Parker * p) {
- if (p == NULL) return ;
- guarantee (p->AssociatedWith != NULL, "invariant") ;
- guarantee (p->FreeNext == NULL , "invariant") ;
- p->AssociatedWith = NULL ;
- for (;;) {
- // Push p onto FreeList
- Parker * List = FreeList ;
- p->FreeNext = List ;
- if (Atomic::cmpxchg_ptr (p, &FreeList, List) == List) break ;
+ assert (w & LOCKBIT, "invariant") ;
+ Self->ListNext = (ParkEvent *) (w & ~LOCKBIT );
+ if (Atomic::cmpxchg_ptr (intptr_t(Self)|LOCKBIT, Lock, w) == w) break ;
+ }
+
+ while (Self->OnList != 0) {
+ Self->park() ;
+ }
}
}
+void Thread::muxAcquireW (volatile intptr_t * Lock, ParkEvent * ev) {
+ intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
+ if (w == 0) return ;
+ if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ return ;
+ }
+
+ TEVENT (muxAcquire - Contention) ;
+ ParkEvent * ReleaseAfter = NULL ;
+ if (ev == NULL) {
+ ev = ReleaseAfter = ParkEvent::Allocate (NULL) ;
+ }
+ assert ((intptr_t(ev) & LOCKBIT) == 0, "invariant") ;
+ for (;;) {
+ guarantee (ev->OnList == 0, "invariant") ;
+ int its = (os::is_MP() ? 100 : 0) + 1 ;
+
+ // Optional spin phase: spin-then-park strategy
+ while (--its >= 0) {
+ w = *Lock ;
+ if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ if (ReleaseAfter != NULL) {
+ ParkEvent::Release (ReleaseAfter) ;
+ }
+ return ;
+ }
+ }
+
+ ev->reset() ;
+ ev->OnList = intptr_t(Lock) ;
+ // The following fence() isn't _strictly necessary as the subsequent
+ // CAS() both serializes execution and ratifies the fetched *Lock value.
+ OrderAccess::fence();
+ for (;;) {
+ w = *Lock ;
+ if ((w & LOCKBIT) == 0) {
+ if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
+ ev->OnList = 0 ;
+ // We call ::Release while holding the outer lock, thus
+ // artificially lengthening the critical section.
+ // Consider deferring the ::Release() until the subsequent unlock(),
+ // after we've dropped the outer lock.
+ if (ReleaseAfter != NULL) {
+ ParkEvent::Release (ReleaseAfter) ;
+ }
+ return ;
+ }
+ continue ; // Interference -- *Lock changed -- Just retry
+ }
+ assert (w & LOCKBIT, "invariant") ;
+ ev->ListNext = (ParkEvent *) (w & ~LOCKBIT );
+ if (Atomic::cmpxchg_ptr (intptr_t(ev)|LOCKBIT, Lock, w) == w) break ;
+ }
+
+ while (ev->OnList != 0) {
+ ev->park() ;
+ }
+ }
+}
+
+// Release() must extract a successor from the list and then wake that thread.
+// It can "pop" the front of the list or use a detach-modify-reattach (DMR) scheme
+// similar to that used by ParkEvent::Allocate() and ::Release(). DMR-based
+// Release() would :
+// (A) CAS() or swap() null to *Lock, releasing the lock and detaching the list.
+// (B) Extract a successor from the private list "in-hand"
+// (C) attempt to CAS() the residual back into *Lock over null.
+// If there were any newly arrived threads and the CAS() would fail.
+// In that case Release() would detach the RATs, re-merge the list in-hand
+// with the RATs and repeat as needed. Alternately, Release() might
+// detach and extract a successor, but then pass the residual list to the wakee.
+// The wakee would be responsible for reattaching and remerging before it
+// competed for the lock.
+//
+// Both "pop" and DMR are immune from ABA corruption -- there can be
+// multiple concurrent pushers, but only one popper or detacher.
+// This implementation pops from the head of the list. This is unfair,
+// but tends to provide excellent throughput as hot threads remain hot.
+// (We wake recently run threads first).
+
+void Thread::muxRelease (volatile intptr_t * Lock) {
+ for (;;) {
+ const intptr_t w = Atomic::cmpxchg_ptr (0, Lock, LOCKBIT) ;
+ assert (w & LOCKBIT, "invariant") ;
+ if (w == LOCKBIT) return ;
+ ParkEvent * List = (ParkEvent *) (w & ~LOCKBIT) ;
+ assert (List != NULL, "invariant") ;
+ assert (List->OnList == intptr_t(Lock), "invariant") ;
+ ParkEvent * nxt = List->ListNext ;
+
+ // The following CAS() releases the lock and pops the head element.
+ if (Atomic::cmpxchg_ptr (intptr_t(nxt), Lock, w) != w) {
+ continue ;
+ }
+ List->OnList = 0 ;
+ OrderAccess::fence() ;
+ List->unpark () ;
+ return ;
+ }
+}
+
+
void Threads::verify() {
ALL_JAVA_THREADS(p) {
p->verify();
--- a/hotspot/src/share/vm/runtime/thread.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/thread.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -30,6 +30,7 @@
class ThreadStatistics;
class ConcurrentLocksDump;
class ParkEvent ;
+class Parker;
class ciEnv;
class CompileThread;
@@ -544,7 +545,6 @@
static void muxAcquire (volatile intptr_t * Lock, const char * Name) ;
static void muxAcquireW (volatile intptr_t * Lock, ParkEvent * ev) ;
static void muxRelease (volatile intptr_t * Lock) ;
-
};
// Inline implementation of Thread::current()
@@ -1769,100 +1769,3 @@
}
};
-// ParkEvents are type-stable and immortal.
-//
-// Lifecycle: Once a ParkEvent is associated with a thread that ParkEvent remains
-// associated with the thread for the thread's entire lifetime - the relationship is
-// stable. A thread will be associated at most one ParkEvent. When the thread
-// expires, the ParkEvent moves to the EventFreeList. New threads attempt to allocate from
-// the EventFreeList before creating a new Event. Type-stability frees us from
-// worrying about stale Event or Thread references in the objectMonitor subsystem.
-// (A reference to ParkEvent is always valid, even though the event may no longer be associated
-// with the desired or expected thread. A key aspect of this design is that the callers of
-// park, unpark, etc must tolerate stale references and spurious wakeups).
-//
-// Only the "associated" thread can block (park) on the ParkEvent, although
-// any other thread can unpark a reachable parkevent. Park() is allowed to
-// return spuriously. In fact park-unpark a really just an optimization to
-// avoid unbounded spinning and surrender the CPU to be a polite system citizen.
-// A degenerate albeit "impolite" park-unpark implementation could simply return.
-// See http://blogs.sun.com/dave for more details.
-//
-// Eventually I'd like to eliminate Events and ObjectWaiters, both of which serve as
-// thread proxies, and simply make the THREAD structure type-stable and persistent.
-// Currently, we unpark events associated with threads, but ideally we'd just
-// unpark threads.
-//
-// The base-class, PlatformEvent, is platform-specific while the ParkEvent is
-// platform-independent. PlatformEvent provides park(), unpark(), etc., and
-// is abstract -- that is, a PlatformEvent should never be instantiated except
-// as part of a ParkEvent.
-// Equivalently we could have defined a platform-independent base-class that
-// exported Allocate(), Release(), etc. The platform-specific class would extend
-// that base-class, adding park(), unpark(), etc.
-//
-// A word of caution: The JVM uses 2 very similar constructs:
-// 1. ParkEvent are used for Java-level "monitor" synchronization.
-// 2. Parkers are used by JSR166-JUC park-unpark.
-//
-// We'll want to eventually merge these redundant facilities and use ParkEvent.
-
-
-class ParkEvent : public os::PlatformEvent {
- private:
- ParkEvent * FreeNext ;
-
- // Current association
- Thread * AssociatedWith ;
- intptr_t RawThreadIdentity ; // LWPID etc
- volatile int Incarnation ;
-
- // diagnostic : keep track of last thread to wake this thread.
- // this is useful for construction of dependency graphs.
- void * LastWaker ;
-
- public:
- // MCS-CLH list linkage and Native Mutex/Monitor
- ParkEvent * volatile ListNext ;
- ParkEvent * volatile ListPrev ;
- volatile intptr_t OnList ;
- volatile int TState ;
- volatile int Notified ; // for native monitor construct
- volatile int IsWaiting ; // Enqueued on WaitSet
-
-
- private:
- static ParkEvent * volatile FreeList ;
- static volatile int ListLock ;
-
- // It's prudent to mark the dtor as "private"
- // ensuring that it's not visible outside the package.
- // Unfortunately gcc warns about such usage, so
- // we revert to the less desirable "protected" visibility.
- // The other compilers accept private dtors.
-
- protected: // Ensure dtor is never invoked
- ~ParkEvent() { guarantee (0, "invariant") ; }
-
- ParkEvent() : PlatformEvent() {
- AssociatedWith = NULL ;
- FreeNext = NULL ;
- ListNext = NULL ;
- ListPrev = NULL ;
- OnList = 0 ;
- TState = 0 ;
- Notified = 0 ;
- IsWaiting = 0 ;
- }
-
- // We use placement-new to force ParkEvent instances to be
- // aligned on 256-byte address boundaries. This ensures that the least
- // significant byte of a ParkEvent address is always 0.
-
- void * operator new (size_t sz) ;
- void operator delete (void * a) ;
-
- public:
- static ParkEvent * Allocate (Thread * t) ;
- static void Release (ParkEvent * e) ;
-} ;
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -86,6 +86,7 @@
nonstatic_field(constantPoolOopDesc, _tags, typeArrayOop) \
nonstatic_field(constantPoolOopDesc, _cache, constantPoolCacheOop) \
nonstatic_field(constantPoolOopDesc, _pool_holder, klassOop) \
+ nonstatic_field(constantPoolOopDesc, _operands, typeArrayOop) \
nonstatic_field(constantPoolOopDesc, _length, int) \
nonstatic_field(constantPoolCacheOopDesc, _length, int) \
nonstatic_field(constantPoolCacheOopDesc, _constant_pool, constantPoolOop) \
@@ -1527,6 +1528,17 @@
\
declare_constant(symbolOopDesc::max_symbol_length) \
\
+ /*************************************************/ \
+ /* constantPoolOop layout enum for InvokeDynamic */ \
+ /*************************************************/ \
+ \
+ declare_constant(constantPoolOopDesc::_multi_operand_count_offset) \
+ declare_constant(constantPoolOopDesc::_multi_operand_base_offset) \
+ declare_constant(constantPoolOopDesc::_indy_bsm_offset) \
+ declare_constant(constantPoolOopDesc::_indy_nt_offset) \
+ declare_constant(constantPoolOopDesc::_indy_argc_offset) \
+ declare_constant(constantPoolOopDesc::_indy_argv_offset) \
+ \
/*********************************************/ \
/* ConstantPoolCacheEntry FlagBitValues enum */ \
/*********************************************/ \
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -100,7 +100,7 @@
void VM_DeoptimizeFrame::doit() {
- Deoptimization::deoptimize_frame(_thread, _id);
+ Deoptimization::deoptimize_frame_internal(_thread, _id);
}
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -231,12 +231,18 @@
bool allow_nested_vm_operations() const { return true; }
};
+
+// Deopt helper that can deoptimize frames in threads other than the
+// current thread. Only used through Deoptimization::deoptimize_frame.
class VM_DeoptimizeFrame: public VM_Operation {
+ friend class Deoptimization;
+
private:
JavaThread* _thread;
intptr_t* _id;
+ VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id);
+
public:
- VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id);
VMOp_Type type() const { return VMOp_DeoptimizeFrame; }
void doit();
bool allow_nested_vm_operations() const { return true; }
--- a/hotspot/src/share/vm/utilities/constantTag.hpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/utilities/constantTag.hpp Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,13 @@
bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; }
+ bool is_loadable_constant() const {
+ return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) ||
+ is_method_type() || is_method_handle() ||
+ is_unresolved_klass() || is_unresolved_string() ||
+ is_object());
+ }
+
constantTag() {
_tag = JVM_CONSTANT_Invalid;
}
--- a/hotspot/src/share/vm/utilities/debug.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/utilities/debug.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -51,14 +51,16 @@
void warning(const char* format, ...) {
- // In case error happens before init or during shutdown
- if (tty == NULL) ostream_init();
+ if (PrintWarnings) {
+ // In case error happens before init or during shutdown
+ if (tty == NULL) ostream_init();
- tty->print("%s warning: ", VM_Version::vm_name());
- va_list ap;
- va_start(ap, format);
- tty->vprint_cr(format, ap);
- va_end(ap);
+ tty->print("%s warning: ", VM_Version::vm_name());
+ va_list ap;
+ va_start(ap, format);
+ tty->vprint_cr(format, ap);
+ va_end(ap);
+ }
if (BreakAtWarning) BREAKPOINT;
}
--- a/hotspot/src/share/vm/utilities/exceptions.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -61,6 +61,18 @@
ShouldNotReachHere();
}
+#ifdef ASSERT
+ // Check for trying to throw stack overflow before initialization is complete
+ // to prevent infinite recursion trying to initialize stack overflow without
+ // adequate stack space.
+ // This can happen with stress testing a large value of StackShadowPages
+ if (h_exception()->klass() == SystemDictionary::StackOverflowError_klass()) {
+ instanceKlass* ik = instanceKlass::cast(h_exception->klass());
+ assert(ik->is_initialized(),
+ "need to increase min_stack_allowed calculation");
+ }
+#endif // ASSERT
+
if (thread->is_VM_thread()
|| thread->is_Compiler_thread() ) {
// We do not care what kind of exception we get for the vm-thread or a thread which
@@ -91,7 +103,6 @@
thread->set_pending_exception(Universe::vm_exception(), file, line);
return true;
}
-
return false;
}
@@ -193,6 +204,7 @@
klassOop k = SystemDictionary::StackOverflowError_klass();
oop e = instanceKlass::cast(k)->allocate_instance(CHECK);
exception = Handle(THREAD, e); // fill_in_stack trace does gc
+ assert(instanceKlass::cast(k)->is_initialized(), "need to increase min_stack_allowed calculation");
if (StackTraceInThrowable) {
java_lang_Throwable::fill_in_stack_trace(exception);
}
--- a/hotspot/src/share/vm/utilities/vmError.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -455,6 +455,14 @@
st->cr();
}
+ STEP(105, "(printing register info)")
+
+ // decode register contents if possible
+ if (_verbose && _context && Universe::is_fully_initialized()) {
+ os::print_register_info(st, _context);
+ st->cr();
+ }
+
STEP(110, "(printing stack bounds)" )
if (_verbose) {
@@ -522,7 +530,7 @@
STEP(135, "(printing target Java thread stack)" )
// printing Java thread stack trace if it is involved in GC crash
- if (_verbose && (_thread->is_Named_thread())) {
+ if (_verbose && _thread && (_thread->is_Named_thread())) {
JavaThread* jt = ((NamedThread *)_thread)->processed_thread();
if (jt != NULL) {
st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id());
@@ -608,6 +616,14 @@
st->cr();
}
+ STEP(195, "(printing code cache information)" )
+
+ if (_verbose && Universe::is_fully_initialized()) {
+ // print code cache information before vm abort
+ CodeCache::print_bounds(st);
+ st->cr();
+ }
+
STEP(200, "(printing dynamic libraries)" )
if (_verbose) {
--- a/hotspot/test/Makefile Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/test/Makefile Sat Nov 13 18:56:50 2010 -0800
@@ -78,7 +78,11 @@
TEST_ROOT := $(shell pwd)
# Root of all test results
-ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+ifdef ALT_OUTPUTDIR
+ ABS_BUILD_ROOT = $(ALT_OUTPUTDIR)/$(PLATFORM)-$(ARCH)
+else
+ ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+endif
ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput
# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
--- a/hotspot/test/compiler/6603011/Test.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/test/compiler/6603011/Test.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -108,8 +108,10 @@
if (quo != quo0 || rem != rem0) {
if (VERBOSE) {
- System.out.println(" " + dividend + " / " + divisor() + " = " +
- quo + ", " + dividend + " % " + divisor() + " = " + rem);
+ System.out.println("Computed: " + dividend + " / " + divisor() + " = " +
+ quo + ", " + dividend + " % " + divisor() + " = " + rem );
+ System.out.println("expected: " + dividend + " / " + divisor() + " = " +
+ quo0 + ", " + dividend + " % " + divisor() + " = " + rem0);
// Report sign of rem failure
if (rem != 0 && (rem ^ dividend) < 0) {
System.out.println(" rem & dividend have different signs");
@@ -168,7 +170,7 @@
for (int i = start; i <= end; i++) {
for (int s = 0; s < 64; s += 4) {
total++;
- long dividend = i << s;
+ long dividend = ((long)i) << s;
if (!checkL(dividend)) {
wrong++;
// Stop on the first failure
--- a/hotspot/test/compiler/6857159/Test6857159.java Fri Nov 12 08:41:03 2010 -0500
+++ b/hotspot/test/compiler/6857159/Test6857159.java Sat Nov 13 18:56:50 2010 -0800
@@ -54,7 +54,7 @@
}
public static void main(String[] args) throws Exception {
- for (int i = 0; i < 100000; i++) {
+ for (int i = 0; i < 20000; i++) {
Thread t = null;
switch (i % 3) {
case 0: t = new ct0(); break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6991596/Test6991596.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6991596
+ * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC
+ *
+ * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596
+ */
+
+import java.dyn.*;
+
+public class Test6991596 {
+ private static final Class CLASS = Test6991596.class;
+ private static final String NAME = "foo";
+ private static final boolean DEBUG = false;
+
+ public static void main(String[] args) throws Throwable {
+ testboolean();
+ testbyte();
+ testchar();
+ testshort();
+ testint();
+ testlong();
+ }
+
+ // Helpers to get various methods.
+ static MethodHandle getmh1(Class ret, Class arg) {
+ return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
+ }
+ static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
+ return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+ }
+ static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
+ return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+ }
+
+ // test adapter_opt_i2i
+ static void testboolean() throws Throwable {
+ boolean[] a = new boolean[] {
+ true,
+ false
+ };
+ for (int i = 0; i < a.length; i++) {
+ doboolean(a[i]);
+ }
+ }
+ static void doboolean(boolean x) throws Throwable {
+ if (DEBUG) System.out.println("boolean=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class);
+ // TODO add this for all cases when the bugs are fixed.
+ //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class);
+ boolean a = mh1.<boolean>invokeExact((boolean) x);
+ boolean b = mh2.<boolean>invokeExact(x);
+ //boolean c = mh3.<boolean>invokeExact((boolean) x);
+ assert a == b : a + " != " + b;
+ //assert c == x : c + " != " + x;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class );
+ MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class);
+ byte a = mh1.<byte>invokeExact((byte) (x ? 1 : 0));
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, boolean.class);
+ char a = mh1.<char>invokeExact((char) (x ? 1 : 0));
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, boolean.class);
+ short a = mh1.<short>invokeExact((short) (x ? 1 : 0));
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+ }
+
+ static void testbyte() throws Throwable {
+ byte[] a = new byte[] {
+ Byte.MIN_VALUE,
+ Byte.MIN_VALUE + 1,
+ -0x0F,
+ -1,
+ 0,
+ 1,
+ 0x0F,
+ Byte.MAX_VALUE - 1,
+ Byte.MAX_VALUE
+ };
+ for (int i = 0; i < a.length; i++) {
+ dobyte(a[i]);
+ }
+ }
+ static void dobyte(byte x) throws Throwable {
+ if (DEBUG) System.out.println("byte=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class);
+ boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+ boolean b = mh2.<boolean>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class);
+ MethodHandle mh2 = getmh2(mh1, byte.class, byte.class);
+ byte a = mh1.<byte>invokeExact((byte) x);
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, byte.class);
+ char a = mh1.<char>invokeExact((char) x);
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, byte.class);
+ short a = mh1.<short>invokeExact((short) x);
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+ }
+
+ static void testchar() throws Throwable {
+ char[] a = new char[] {
+ Character.MIN_VALUE,
+ Character.MIN_VALUE + 1,
+ 0x000F,
+ 0x00FF,
+ 0x0FFF,
+ Character.MAX_VALUE - 1,
+ Character.MAX_VALUE
+ };
+ for (int i = 0; i < a.length; i++) {
+ dochar(a[i]);
+ }
+ }
+ static void dochar(char x) throws Throwable {
+ if (DEBUG) System.out.println("char=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, char.class);
+ boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+ boolean b = mh2.<boolean>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class);
+ MethodHandle mh2 = getmh2(mh1, byte.class, char.class);
+ byte a = mh1.<byte>invokeExact((byte) x);
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, char.class);
+ char a = mh1.<char>invokeExact((char) x);
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, char.class);
+ short a = mh1.<short>invokeExact((short) x);
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+ }
+
+ static void testshort() throws Throwable {
+ short[] a = new short[] {
+ Short.MIN_VALUE,
+ Short.MIN_VALUE + 1,
+ -0x0FFF,
+ -0x00FF,
+ -0x000F,
+ -1,
+ 0,
+ 1,
+ 0x000F,
+ 0x00FF,
+ 0x0FFF,
+ Short.MAX_VALUE - 1,
+ Short.MAX_VALUE
+ };
+ for (int i = 0; i < a.length; i++) {
+ doshort(a[i]);
+ }
+ }
+ static void doshort(short x) throws Throwable {
+ if (DEBUG) System.out.println("short=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, short.class);
+ boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+ boolean b = mh2.<boolean>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class);
+ MethodHandle mh2 = getmh2(mh1, byte.class, short.class);
+ byte a = mh1.<byte>invokeExact((byte) x);
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, short.class);
+ char a = mh1.<char>invokeExact((char) x);
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, short.class);
+ short a = mh1.<short>invokeExact((short) x);
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+ }
+
+ static void testint() throws Throwable {
+ int[] a = new int[] {
+ Integer.MIN_VALUE,
+ Integer.MIN_VALUE + 1,
+ -0x0FFFFFFF,
+ -0x00FFFFFF,
+ -0x000FFFFF,
+ -0x0000FFFF,
+ -0x00000FFF,
+ -0x000000FF,
+ -0x0000000F,
+ -1,
+ 0,
+ 1,
+ 0x0000000F,
+ 0x000000FF,
+ 0x00000FFF,
+ 0x0000FFFF,
+ 0x000FFFFF,
+ 0x00FFFFFF,
+ 0x0FFFFFFF,
+ Integer.MAX_VALUE - 1,
+ Integer.MAX_VALUE
+ };
+ for (int i = 0; i < a.length; i++) {
+ doint(a[i]);
+ }
+ }
+ static void doint(int x) throws Throwable {
+ if (DEBUG) System.out.println("int=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, int.class);
+ boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+ boolean b = mh2.<boolean>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class);
+ MethodHandle mh2 = getmh2(mh1, byte.class, int.class);
+ byte a = mh1.<byte>invokeExact((byte) x);
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, int.class);
+ char a = mh1.<char>invokeExact((char) x);
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, int.class);
+ short a = mh1.<short>invokeExact((short) x);
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // int
+ {
+ MethodHandle mh1 = getmh1( int.class, int.class);
+ MethodHandle mh2 = getmh2(mh1, int.class, int.class);
+ int a = mh1.<int>invokeExact((int) x);
+ int b = mh2.<int>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+ }
+
+ // test adapter_opt_l2i
+ static void testlong() throws Throwable {
+ long[] a = new long[] {
+ Long.MIN_VALUE,
+ Long.MIN_VALUE + 1,
+ -0x000000000FFFFFFFL,
+ -0x0000000000FFFFFFL,
+ -0x00000000000FFFFFL,
+ -0x000000000000FFFFL,
+ -0x0000000000000FFFL,
+ -0x00000000000000FFL,
+ -0x000000000000000FL,
+ -1L,
+ 0L,
+ 1L,
+ 0x000000000000000FL,
+ 0x00000000000000FFL,
+ 0x0000000000000FFFL,
+ 0x0000000000000FFFL,
+ 0x000000000000FFFFL,
+ 0x00000000000FFFFFL,
+ 0x0000000000FFFFFFL,
+ 0x000000000FFFFFFFL,
+ Long.MAX_VALUE - 1,
+ Long.MAX_VALUE
+ };
+ for (int i = 0; i < a.length; i++) {
+ dolong(a[i]);
+ }
+ }
+ static void dolong(long x) throws Throwable {
+ if (DEBUG) System.out.println("long=" + x);
+
+ // boolean
+ {
+ MethodHandle mh1 = getmh1( boolean.class, boolean.class);
+ MethodHandle mh2 = getmh2(mh1, boolean.class, long.class);
+ boolean a = mh1.<boolean>invokeExact((x & 1L) == 1L);
+ boolean b = mh2.<boolean>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // byte
+ {
+ MethodHandle mh1 = getmh1( byte.class, byte.class);
+ MethodHandle mh2 = getmh2(mh1, byte.class, long.class);
+ byte a = mh1.<byte>invokeExact((byte) x);
+ byte b = mh2.<byte>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // char
+ {
+ MethodHandle mh1 = getmh1( char.class, char.class);
+ MethodHandle mh2 = getmh2(mh1, char.class, long.class);
+ char a = mh1.<char>invokeExact((char) x);
+ char b = mh2.<char>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // short
+ {
+ MethodHandle mh1 = getmh1( short.class, short.class);
+ MethodHandle mh2 = getmh2(mh1, short.class, long.class);
+ short a = mh1.<short>invokeExact((short) x);
+ short b = mh2.<short>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ // int
+ {
+ MethodHandle mh1 = getmh1( int.class, int.class);
+ MethodHandle mh2 = getmh2(mh1, int.class, long.class);
+ int a = mh1.<int>invokeExact((int) x);
+ int b = mh2.<int>invokeExact(x);
+ assert a == b : a + " != " + b;
+ }
+
+ }
+
+ // to int
+ public static boolean foo(boolean i) { return i; }
+ public static byte foo(byte i) { return i; }
+ public static char foo(char i) { return i; }
+ public static short foo(short i) { return i; }
+ public static int foo(int i) { return i; }
+}
--- a/jaxp/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/jaxp/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
d57197d22c2bfc39d1a860040f655b466ab46f52 jdk7-b114
dc1612e1d3ac08eb8fcad764daff21c9247d33c9 jdk7-b115
f8d4e6c6cfce1cda23fcbd144628a9791a9e1a63 jdk7-b116
+9ee4d96e893436a48607924227dadd2d93b9b00d jdk7-b117
+b2f6d9c4f12ffd307a5de40455b2b61b31a5cb79 jdk7-b118
--- a/jaxws/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/jaxws/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
400f494c81c5ec87714b705648afbb3cb680bf73 jdk7-b114
824cc44bd6eba9abae07cc420f7fe3926c1adbd9 jdk7-b115
376ac153078dd3b5f6d4a0981feee092c1492c96 jdk7-b116
+1320fb3bb588298c79716bd2d10b5b4afacb9370 jdk7-b117
+19a2fab3f91a275f90791c15d1c21a24e820ff2d jdk7-b118
--- a/jdk/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
e250cef36ea05e627e7e6f7d75e5e19f529e2ba3 jdk7-b114
449bad8d67b5808ecf0f927683acc0a5940f8c85 jdk7-b115
1657ed4e1d86c8aa2028ab5a41f9da1ac4a369f8 jdk7-b116
+3e6726bbf80a4254ecd01051c8ed77ee19325e46 jdk7-b117
+b357910aa04aead2a16b6d6ff395a8df4b51d1dd jdk7-b118
--- a/jdk/make/javax/sound/jsoundds/Makefile Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/make/javax/sound/jsoundds/Makefile Sat Nov 13 18:56:50 2010 -0800
@@ -53,7 +53,7 @@
#
# Extra cc/linker flags.
#
-LDLIBS += dsound.lib winmm.lib user32.lib
+LDLIBS += dsound.lib winmm.lib user32.lib ole32.lib
CPPFLAGS += \
-DUSE_DAUDIO=TRUE \
-I$(SHARE_SRC)/native/com/sun/media/sound \
--- a/jdk/make/sun/javazic/tzdata/VERSION Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/make/sun/javazic/tzdata/VERSION Sat Nov 13 18:56:50 2010 -0800
@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-tzdata2010l
+tzdata2010o
--- a/jdk/make/sun/javazic/tzdata/asia Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/make/sun/javazic/tzdata/asia Sat Nov 13 18:56:50 2010 -0800
@@ -569,8 +569,8 @@
Rule HK 1954 1964 - Mar Sun>=18 3:30 1:00 S
Rule HK 1954 only - Oct 31 3:30 0 -
Rule HK 1955 1964 - Nov Sun>=1 3:30 0 -
-Rule HK 1965 1977 - Apr Sun>=16 3:30 1:00 S
-Rule HK 1965 1977 - Oct Sun>=16 3:30 0 -
+Rule HK 1965 1976 - Apr Sun>=16 3:30 1:00 S
+Rule HK 1965 1976 - Oct Sun>=16 3:30 0 -
Rule HK 1973 only - Dec 30 3:30 1:00 S
Rule HK 1979 only - May Sun>=8 3:30 1:00 S
Rule HK 1979 only - Oct Sun>=16 3:30 0 -
--- a/jdk/make/sun/javazic/tzdata/australasia Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/make/sun/javazic/tzdata/australasia Sat Nov 13 18:56:50 2010 -0800
@@ -306,13 +306,26 @@
# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
# </a>
+# From Alexander Krivenyshev (2010-10-24):
+# According to Radio Fiji and Fiji Times online, Fiji will end DST 3
+# weeks earlier than expected - on March 6, 2011, not March 27, 2011...
+# Here is confirmation from Government of the Republic of the Fiji Islands,
+# Ministry of Information (fiji.gov.fj) web site:
+# <a href="http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155">
+# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
+# </a>
+# or
+# <a href="http://www.worldtimezone.com/dst_news/dst_news_fiji04.html">
+# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
+# </a>
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 S
Rule Fiji 1999 2000 - Feb lastSun 3:00 0 -
Rule Fiji 2009 only - Nov 29 2:00 1:00 S
Rule Fiji 2010 only - Mar lastSun 3:00 0 -
Rule Fiji 2010 only - Oct 24 2:00 1:00 S
-Rule Fiji 2011 only - Mar lastSun 3:00 0 -
+Rule Fiji 2011 only - Mar Sun>=1 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Fiji 11:53:40 - LMT 1915 Oct 26 # Suva
12:00 Fiji FJ%sT # Fiji Time
@@ -509,11 +522,21 @@
# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
# </a>
+# From Raymond Hughes (2010-10-07):
+# Please see
+# <a href="http://www.mcil.gov.ws">
+# http://www.mcil.gov.ws
+# </a>,
+# the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
+# September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
+# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
+# backwards from 1:00am to 12:00am"
+
Zone Pacific/Apia 12:33:04 - LMT 1879 Jul 5
-11:26:56 - LMT 1911
-11:30 - SAMT 1950 # Samoa Time
-11:00 - WST 2010 Sep 26
- -11:00 1:00 WSDT 2011 Apr 3
+ -11:00 1:00 WSDT 2011 Apr 3 1:00
-11:00 - WST
# Solomon Is
--- a/jdk/make/sun/javazic/tzdata/zone.tab Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/make/sun/javazic/tzdata/zone.tab Sat Nov 13 18:56:50 2010 -0800
@@ -63,7 +63,7 @@
AQ -6736+06253 Antarctica/Mawson Mawson Station, Holme Bay
AQ -6835+07758 Antarctica/Davis Davis Station, Vestfold Hills
AQ -6617+11031 Antarctica/Casey Casey Station, Bailey Peninsula
-AQ -7824+10654 Antarctica/Vostok Vostok Station, S Magnetic Pole
+AQ -7824+10654 Antarctica/Vostok Vostok Station, Lake Vostok
AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie
AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I
AQ -5430+15857 Antarctica/Macquarie Macquarie Island Station, Macquarie Island
--- a/jdk/src/share/classes/java/awt/BasicStroke.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/BasicStroke.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package java.awt;
+import java.beans.ConstructorProperties;
+
/**
* The <code>BasicStroke</code> class defines a basic set of rendering
* attributes for the outlines of graphics primitives, which are rendered
@@ -183,6 +185,7 @@
* <code>dash</code> is zero
* @throws IllegalArgumentException if dash lengths are all zero.
*/
+ @ConstructorProperties({ "lineWidth", "endCap", "lineJoin", "miterLimit", "dashArray", "dashPhase" })
public BasicStroke(float width, int cap, int join, float miterlimit,
float dash[], float dash_phase) {
if (width < 0.0f) {
--- a/jdk/src/share/classes/java/awt/GradientPaint.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/GradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The <code>GradientPaint</code> class provides a way to fill
@@ -166,6 +167,7 @@
* @throws NullPointerException if either one of colors or points
* is null
*/
+ @ConstructorProperties({ "point1", "color1", "point2", "color2", "cyclic" })
public GradientPaint(Point2D pt1,
Color color1,
Point2D pt2,
--- a/jdk/src/share/classes/java/awt/GridBagConstraints.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/GridBagConstraints.java Sat Nov 13 18:56:50 2010 -0800
@@ -126,7 +126,7 @@
/**
* Place the component centered along the edge of its display area
* associated with the start of a page for the current
- * <code>ComponentOrienation</code>. Equal to NORTH for horizontal
+ * {@code ComponentOrientation}. Equal to NORTH for horizontal
* orientations.
*/
public static final int PAGE_START = 19;
@@ -134,7 +134,7 @@
/**
* Place the component centered along the edge of its display area
* associated with the end of a page for the current
- * <code>ComponentOrienation</code>. Equal to SOUTH for horizontal
+ * {@code ComponentOrientation}. Equal to SOUTH for horizontal
* orientations.
*/
public static final int PAGE_END = 20;
@@ -142,7 +142,7 @@
/**
* Place the component centered along the edge of its display area where
* lines of text would normally begin for the current
- * <code>ComponentOrienation</code>. Equal to WEST for horizontal,
+ * {@code ComponentOrientation}. Equal to WEST for horizontal,
* left-to-right orientations and EAST for horizontal, right-to-left
* orientations.
*/
@@ -151,7 +151,7 @@
/**
* Place the component centered along the edge of its display area where
* lines of text would normally end for the current
- * <code>ComponentOrienation</code>. Equal to EAST for horizontal,
+ * {@code ComponentOrientation}. Equal to EAST for horizontal,
* left-to-right orientations and WEST for horizontal, right-to-left
* orientations.
*/
@@ -160,7 +160,7 @@
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally begin for the current
- * <code>ComponentOrienation</code>. Equal to NORTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHWEST for horizontal,
* left-to-right orientations and NORTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -169,7 +169,7 @@
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally end for the current
- * <code>ComponentOrienation</code>. Equal to NORTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHEAST for horizontal,
* left-to-right orientations and NORTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -178,7 +178,7 @@
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally start for the current
- * <code>ComponentOrienation</code>. Equal to SOUTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHWEST for horizontal,
* left-to-right orientations and SOUTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -187,7 +187,7 @@
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally end for the current
- * <code>ComponentOrienation</code>. Equal to SOUTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHEAST for horizontal,
* left-to-right orientations and SOUTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -437,7 +437,7 @@
* <code>LINE_START</code>, <code>LINE_END</code>,
* <code>FIRST_LINE_START</code>, <code>FIRST_LINE_END</code>,
* <code>LAST_LINE_START</code> and <code>LAST_LINE_END</code>. The
- * baseline relvative values are:
+ * baseline relative values are:
* <code>BASELINE</code>, <code>BASELINE_LEADING</code>,
* <code>BASELINE_TRAILING</code>,
* <code>ABOVE_BASELINE</code>, <code>ABOVE_BASELINE_LEADING</code>,
--- a/jdk/src/share/classes/java/awt/LinearGradientPaint.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/LinearGradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2008, 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,10 @@
package java.awt;
import java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The {@code LinearGradientPaint} class provides a way to fill
@@ -271,6 +271,7 @@
* or a {@code fractions} value is less than 0.0 or greater than 1.0,
* or the {@code fractions} are not provided in strictly increasing order
*/
+ @ConstructorProperties({ "startPoint", "endPoint", "fractions", "colors", "cycleMethod", "colorSpace", "transform" })
public LinearGradientPaint(Point2D start, Point2D end,
float[] fractions, Color[] colors,
CycleMethod cycleMethod,
--- a/jdk/src/share/classes/java/awt/RadialGradientPaint.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/RadialGradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2008, 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.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The {@code RadialGradientPaint} class provides a way to fill a shape with
@@ -428,6 +429,7 @@
* or a {@code fractions} value is less than 0.0 or greater than 1.0,
* or the {@code fractions} are not provided in strictly increasing order
*/
+ @ConstructorProperties({ "centerPoint", "radius", "focusPoint", "fractions", "colors", "cycleMethod", "colorSpace", "transform" })
public RadialGradientPaint(Point2D center,
float radius,
Point2D focus,
--- a/jdk/src/share/classes/java/awt/Scrollbar.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/Scrollbar.java Sat Nov 13 18:56:50 2010 -0800
@@ -213,7 +213,8 @@
* The size of the <code>Scrollbar</code>'s bubble.
* When a scroll bar is used to select a range of values,
* the visibleAmount represents the size of this range.
- * This is visually indicated by the size of the bubble.
+ * Depending on platform, this may be visually indicated
+ * by the size of the bubble.
*
* @serial
* @see #getVisibleAmount
@@ -637,6 +638,8 @@
* bubble (also called a thumb or scroll box), usually gives a
* visual representation of the relationship of the visible
* amount to the range of the scroll bar.
+ * Note that depending on platform, the value of the visible amount property
+ * may not be visually indicated by the size of the bubble.
* <p>
* The scroll bar's bubble may not be displayed when it is not
* moveable (e.g. when it takes up the entire length of the
@@ -670,6 +673,8 @@
* bubble (also called a thumb or scroll box), usually gives a
* visual representation of the relationship of the visible
* amount to the range of the scroll bar.
+ * Note that depending on platform, the value of the visible amount property
+ * may not be visually indicated by the size of the bubble.
* <p>
* The scroll bar's bubble may not be displayed when it is not
* moveable (e.g. when it takes up the entire length of the
--- a/jdk/src/share/classes/java/awt/Toolkit.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/Toolkit.java Sat Nov 13 18:56:50 2010 -0800
@@ -1831,7 +1831,11 @@
desktopProperties.put(name, newValue);
}
- desktopPropsSupport.firePropertyChange(name, oldValue, newValue);
+ // Don't fire change event if old and new values are null.
+ // It helps to avoid recursive resending of WM_THEMECHANGED
+ if (oldValue != null || newValue != null) {
+ desktopPropsSupport.firePropertyChange(name, oldValue, newValue);
+ }
}
/**
--- a/jdk/src/share/classes/java/awt/geom/AffineTransform.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/awt/geom/AffineTransform.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package java.awt.geom;
import java.awt.Shape;
+import java.beans.ConstructorProperties;
/**
* The <code>AffineTransform</code> class represents a 2D affine transform
@@ -508,6 +509,7 @@
* @param m12 the Y coordinate translation element of the 3x3 matrix
* @since 1.2
*/
+ @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
public AffineTransform(float m00, float m10,
float m01, float m11,
float m02, float m12) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/dyn/BootstrapMethod.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation on InvokeDynamic method calls which requests the JVM to use a specific
+ * <a href="package-summary.html#bsm">bootstrap method</a>
+ * to link the call. This annotation is not retained as such in the class file,
+ * but is transformed into a constant-pool entry for the invokedynamic instruction which
+ * specifies the desired bootstrap method.
+ * <p>
+ * If only the <code>value</code> is given, it must name a subclass of {@link CallSite}
+ * with a constructor which accepts a class, string, and method type.
+ * If the <code>value</code> and <code>name</code> are both given, there must be
+ * a static method in the given class of the given name which accepts a class, string,
+ * and method type, and returns a reference coercible to {@link CallSite}.
+ * <p>
+ * This annotation can be placed either on the return type of a single {@link InvokeDynamic}
+ * call (see examples) or else it can be placed on an enclosing class or method, where it
+ * determines a default bootstrap method for any {@link InvokeDynamic} calls which are not
+ * specifically annotated with a bootstrap method.
+ * Every {@link InvokeDynamic} call must be given a bootstrap method.
+ * <p>
+ * Examples:
+<blockquote><pre>
+@BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
+String x = (String) InvokeDynamic.greet();
+//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
+@BootstrapMethod(MyCallSite.class)
+void example() throws Throwable {
+ InvokeDynamic.greet();
+ //BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
+}
+</pre></blockquote>
+ * <p>
+ */
+@Target({ElementType.TYPE_USE,
+ // For defaulting every indy site within a class or method; cf. @SuppressWarnings:
+ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR
+ })
+@Retention(RetentionPolicy.SOURCE)
+public @interface BootstrapMethod {
+ /** The class containing the bootstrap method. */
+ Class<?> value();
+
+ /** The name of the bootstrap method.
+ * If this is the empty string, an instance of the bootstrap class is created,
+ * and a constructor is invoked.
+ * Otherwise, there must be a static method of the required name.
+ */
+ String name() default ""; // empty string denotes a constructor with 'new'
+
+ /** The argument types of the bootstrap method, as passed out by the JVM.
+ * There is usually no reason to override the default.
+ */
+ Class<?>[] arguments() default {Class.class, String.class, MethodType.class};
+}
--- a/jdk/src/share/classes/java/dyn/CallSite.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/CallSite.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,56 +25,26 @@
package java.dyn;
-import sun.dyn.Access;
-import sun.dyn.MemberName;
-import sun.dyn.CallSiteImpl;
+import sun.dyn.*;
+import java.util.Collection;
/**
- * A {@code CallSite} reifies an {@code invokedynamic} instruction from bytecode,
- * and controls its linkage.
- * Every linked {@code CallSite} object corresponds to a distinct instance
- * of the {@code invokedynamic} instruction, and vice versa.
- * <p>
- * Every linked {@code CallSite} object has one state variable,
- * a {@link MethodHandle} reference called the {@code target}.
- * This reference is never null. Though it can change its value
- * successive values must always have exactly the {@link MethodType method type}
- * called for by the bytecodes of the associated {@code invokedynamic} instruction
- * <p>
- * It is the responsibility of each class's
- * {@link Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
- * to produce call sites which have been pre-linked to an initial target method.
- * The required {@link MethodType type} for the target method is a parameter
- * to each bootstrap method call.
- * <p>
- * The bootstrap method may elect to produce call sites of a
- * language-specific subclass of {@code CallSite}. In such a case,
- * the subclass may claim responsibility for initializing its target to
- * a non-null value, by overriding {@link #initialTarget}.
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * Every call to a {@code CallSite} is delegated to the site's current target.
* <p>
- * An {@code invokedynamic} instruction which has not yet been executed
- * is said to be <em>unlinked</em>. When an unlinked call site is executed,
- * the containing class's bootstrap method is called to manufacture a call site,
- * for the instruction. If the bootstrap method does not assign a non-null
- * value to the new call site's target variable, the method {@link #initialTarget}
- * is called to produce the new call site's first target method.
+ * A call site is initially created in an <em>unlinked</em> state,
+ * which is distinguished by a null target variable.
+ * Before the call site may be invoked (and before certain other
+ * operations are attempted), the call site must be linked to
+ * a non-null target.
* <p>
- * A freshly-created {@code CallSite} object is not yet in a linked state.
- * An unlinked {@code CallSite} object reports null for its {@code callerClass}.
- * When the JVM receives a {@code CallSite} object from a bootstrap method,
- * it first ensures that its target is non-null and of the correct type.
- * The JVM then links the {@code CallSite} object to the call site instruction,
- * enabling the {@code callerClass} to return the class in which the instruction occurs.
- * <p>
- * Next, the JVM links the instruction to the {@code CallSite}, at which point
- * any further execution of the {@code invokedynamic} instruction implicitly
- * invokes the current target of the {@code CallSite} object.
- * After this two-way linkage, both the instruction and the {@code CallSite}
- * object are said to be linked.
- * <p>
- * This state of linkage continues until the method containing the
- * dynamic call site is garbage collected, or the dynamic call site
- * is invalidated by an explicit request.
+ * A call site may be <em>relinked</em> by changing its target.
+ * The new target must be non-null and must have the same
+ * {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
* <p>
* Linkage happens once in the lifetime of any given {@code CallSite} object.
* Because of call site invalidation, this linkage can be repeated for
@@ -87,6 +57,10 @@
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
+@BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
+static void test() throws Throwable {
+ InvokeDynamic.baz("baz arg", 2, 3.14);
+}
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
}
@@ -96,17 +70,16 @@
Class thisClass = lookup.lookupClass(); // (who am I?)
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
- Linkage.registerBootstrapMethod("bootstrapDynamic");
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
}
</pre></blockquote>
- * @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG
*/
public class CallSite
+ implements MethodHandleProvider
{
private static final Access IMPL_TOKEN = Access.getToken();
@@ -209,6 +182,7 @@
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
+ * @deprecated transitional form defined in EDR but removed in PFD
*/
protected MethodHandle initialTarget(Class<?> callerClass, String name, MethodType type) {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
@@ -278,16 +252,44 @@
*/
@Override
public String toString() {
- StringBuilder buf = new StringBuilder("CallSite#");
- buf.append(hashCode());
- if (!isLinked())
- buf.append("[unlinked]");
- else
- buf.append("[")
- .append("from ").append(vmmethod.getDeclaringClass().getName())
- .append(" : ").append(getTarget().type())
- .append(" => ").append(getTarget())
- .append("]");
- return buf.toString();
+ return "CallSite"+(target == null ? "" : target.type());
}
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle equivalent to an invokedynamic instruction
+ * which has been linked to this call site.
+ * <p>If this call site is a {@link ConstantCallSite}, this method
+ * simply returns the call site's target, since that will not change.
+ * <p>Otherwise, this method is equivalent to the following code:
+ * <p><blockquote><pre>
+ * MethodHandle getTarget, invoker, result;
+ * getTarget = MethodHandles.lookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
+ * invoker = MethodHandles.exactInvoker(this.type());
+ * result = MethodHandles.foldArguments(invoker, getTarget)
+ * </pre></blockquote>
+ * @return a method handle which always invokes this call site's current target
+ */
+ public final MethodHandle dynamicInvoker() {
+ if (this instanceof ConstantCallSite)
+ return getTarget(); // will not change dynamically
+ MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
+ MethodHandle invoker = MethodHandles.exactInvoker(this.type());
+ return MethodHandles.foldArguments(invoker, getTarget);
+ }
+ private static final MethodHandle GET_TARGET;
+ static {
+ try {
+ GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP.
+ findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+ } catch (NoAccessException ignore) {
+ throw new InternalError();
+ }
+ }
+
+ /** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
+ public final MethodHandle asMethodHandle() { return dynamicInvoker(); }
+
+ /** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
+ public final MethodHandle asMethodHandle(MethodType type) { return dynamicInvoker().asType(type); }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/dyn/ClassValue.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Lazily associate a computed value with (potentially) every class.
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class ClassValue<T> {
+ /**
+ * Compute the given class's derived value for this {@code ClassValue}.
+ * <p>
+ * This method will be invoked within the first thread that accesses
+ * the value with the {@link #get}.
+ * <p>
+ * Normally, this method is invoked at most once per class,
+ * but it may be invoked again in case of subsequent invocations
+ * of {@link #remove} followed by {@link #get}.
+ *
+ * @return the computed value for this thread-local
+ */
+ protected abstract T computeValue(Class<?> type);
+
+ /**
+ * Creates a new class value.
+ */
+ protected ClassValue() {
+ }
+
+ /**
+ * Returns the value for the given class.
+ * If no value has yet been computed, it is obtained by
+ * by an invocation of the {@link #computeValue} method.
+ * <p>
+ * The actual installation of the value on the class
+ * is performed while the class's synchronization lock
+ * is held. At that point, if racing threads have
+ * computed values, one is chosen, and returned to
+ * all the racing threads.
+ *
+ * @return the current thread's value of this thread-local
+ */
+ public T get(Class<?> type) {
+ ClassValueMap map = getMap(type);
+ if (map != null) {
+ Object x = map.get(this);
+ if (x != null) {
+ return (T) map.unmaskNull(x);
+ }
+ }
+ return setComputedValue(type);
+ }
+
+ /**
+ * Removes the associated value for the given class.
+ * If this value is subsequently {@linkplain #get read} for the same class,
+ * its value will be reinitialized by invoking its {@link #computeValue} method.
+ * This may result in an additional invocation of the
+ * {@code computeValue} method for the given class.
+ */
+ public void remove(Class<?> type) {
+ ClassValueMap map = getMap(type);
+ if (map != null) {
+ synchronized (map) {
+ map.remove(this);
+ }
+ }
+ }
+
+ /// Implementation...
+
+ /** The hash code for this type is based on the identity of the object,
+ * and is well-dispersed for power-of-two tables.
+ */
+ public final int hashCode() { return hashCode; }
+ private final int hashCode = HASH_CODES.getAndAdd(0x61c88647);
+ private static final AtomicInteger HASH_CODES = new AtomicInteger();
+
+ private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+
+ /** Slow path for {@link #get}. */
+ private T setComputedValue(Class<?> type) {
+ ClassValueMap map = getMap(type);
+ if (map == null) {
+ map = initializeMap(type);
+ }
+ T value = computeValue(type);
+ STORE_BARRIER.lazySet(0);
+ // All stores pending from computeValue are completed.
+ synchronized (map) {
+ // Warm up the table with a null entry.
+ map.preInitializeEntry(this);
+ }
+ // All stores pending from table expansion are completed.
+ synchronized (map) {
+ value = (T) map.initializeEntry(this, value);
+ // One might fear a possible race condition here
+ // if the code for map.put has flushed the write
+ // to map.table[*] before the writes to the Map.Entry
+ // are done. This is not possible, since we have
+ // warmed up the table with an empty entry.
+ }
+ return value;
+ }
+
+ // Replace this map by a per-class slot.
+ private static final WeakHashMap<Class<?>, ClassValueMap> ROOT
+ = new WeakHashMap<Class<?>, ClassValueMap>();
+
+ private static ClassValueMap getMap(Class<?> type) {
+ return ROOT.get(type);
+ }
+
+ private static ClassValueMap initializeMap(Class<?> type) {
+ synchronized (ClassValue.class) {
+ ClassValueMap map = ROOT.get(type);
+ if (map == null)
+ ROOT.put(type, map = new ClassValueMap());
+ return map;
+ }
+ }
+
+ static class ClassValueMap extends WeakHashMap<ClassValue, Object> {
+ /** Make sure this table contains an Entry for the given key, even if it is empty. */
+ void preInitializeEntry(ClassValue key) {
+ if (!this.containsKey(key))
+ this.put(key, null);
+ }
+ /** Make sure this table contains a non-empty Entry for the given key. */
+ Object initializeEntry(ClassValue key, Object value) {
+ Object prior = this.get(key);
+ if (prior != null) {
+ return unmaskNull(prior);
+ }
+ this.put(key, maskNull(value));
+ return value;
+ }
+
+ Object maskNull(Object x) {
+ return x == null ? this : x;
+ }
+ Object unmaskNull(Object x) {
+ return x == this ? null : x;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/dyn/ConstantCallSite.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+/**
+ * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
+ * The only way to relink an {@code invokedynamic} instruction bound to a {@code ConstantCallSite} is
+ * to invalidate the instruction as a whole.
+ * @author John Rose, JSR 292 EG
+ */
+public class ConstantCallSite extends CallSite {
+ /** Create a call site with a permanent target. */
+ public ConstantCallSite(MethodHandle target) {
+ super(target);
+ }
+ /** Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target. */
+ @Override public final void setTarget(MethodHandle ignore) {
+ throw new IllegalArgumentException("ConstantCallSite");
+ }
+}
--- a/jdk/src/share/classes/java/dyn/InvokeDynamic.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/InvokeDynamic.java Sat Nov 13 18:56:50 2010 -0800
@@ -35,7 +35,7 @@
* The target method is a property of the reified {@linkplain CallSite call site object}
* which is linked to each active {@code invokedynamic} instruction.
* The call site object is initially produced by a
- * {@linkplain java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
+ * {@linkplain BootstrapMethod bootstrap method}
* associated with the class whose bytecodes include the dynamic call site.
* <p>
* The type {@code InvokeDynamic} has no particular meaning as a
@@ -45,22 +45,31 @@
* It may be imported for ease of use.
* <p>
* Here are some examples:
- * <p><blockquote><pre>
- * Object x; String s; int i;
- * x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
- * s = InvokeDynamic.<String>hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
- * InvokeDynamic.<void>cogito(); // cogito()V
- * i = InvokeDynamic.<int>#"op:+"(2, 3); // "op:+"(II)I
- * </pre></blockquote>
+<blockquote><pre><!-- see indy-demo/src/JavaDocExamples.java -->
+@BootstrapMethod(value=Here.class, name="bootstrapDynamic")
+static void example() throws Throwable {
+ Object x; String s; int i;
+ x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
+ s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
+ InvokeDynamic.cogito(); // cogito()V
+ i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
+}
+static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
+</pre></blockquote>
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
+ * <p>
* The argument types are taken directly from the actual arguments,
- * while the return type is taken from the type parameter.
- * (This type parameter may be a primtive, and it defaults to {@code Object}.)
+ * while the return type corresponds to the target of the assignment.
+ * (Currently, the return type must be given as a false type parameter.
+ * This type parameter is an irregular use of the generic type syntax,
+ * and is likely to change in favor of a convention based on target typing.)
+ * <p>
* The final example uses a special syntax for uttering non-Java names.
* Any name legal to the JVM may be given between the double quotes.
+ * <p>
* None of these calls is complete without a bootstrap method,
- * which must be registered by the static initializer of the enclosing class.
+ * which must be declared for the enclosing class or method.
* @author John Rose, JSR 292 EG
*/
@MethodHandle.PolymorphicSignature
--- a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java Sat Nov 13 18:56:50 2010 -0800
@@ -28,15 +28,11 @@
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
* failed to find its
- * {@linkplain Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method},
+ * {@linkplain BootstrapMethod bootstrap method},
* or the bootstrap method has
* failed to provide a
* {@linkplain CallSite} call site with a non-null {@linkplain MethodHandle target}
* of the correct {@linkplain MethodType method type}.
- * <p>
- * The bootstrap method must have been declared during a class's initialization
- * by a call to one of the overloadings of
- * {@link Linkage#registerBootstrapMethod registerBootstrapMethod}.
*
* @author John Rose, JSR 292 EG
* @since 1.7
--- a/jdk/src/share/classes/java/dyn/JavaMethodHandle.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.dyn;
-
-import sun.dyn.Access;
-
-/**
- * A Java method handle is a deprecated proposal for extending
- * the basic method handle type with additional
- * programmer defined methods and fields.
- * Its behavior as a method handle is determined at instance creation time,
- * by providing the new instance with an "entry point" method handle
- * to handle calls. This entry point must accept a leading argument
- * whose type is the Java method handle itself or a supertype, and the
- * entry point is always called with the Java method handle itself as
- * the first argument. This is similar to ordinary virtual methods, which also
- * accept the receiver object {@code this} as an implicit leading argument.
- * The {@code MethodType} of the Java method handle is the same as that
- * of the entry point method handle, with the leading parameter type
- * omitted.
- * <p>
- * Here is an example of usage, creating a hybrid object/functional datum:
- * <p><blockquote><pre>
- * class Greeter extends JavaMethodHandle {
- * private String greeting = "hello";
- * public void setGreeting(String s) { greeting = s; }
- * public void run() { System.out.println(greeting+", "+greetee); }
- * private final String greetee;
- * Greeter(String greetee) {
- * super(RUN); // alternatively, super("run")
- * this.greetee = greetee;
- * }
- * // the entry point function is computed once:
- * private static final MethodHandle RUN
- * = MethodHandles.lookup().findVirtual(Greeter.class, "run",
- * MethodType.make(void.class));
- * }
- * // class Main { public static void main(String... av) { ...
- * Greeter greeter = new Greeter("world");
- * greeter.run(); // prints "hello, world"
- * // Statically typed method handle invocation (most direct):
- * MethodHandle mh = greeter;
- * mh.<void>invokeExact(); // also prints "hello, world"
- * // Dynamically typed method handle invocation:
- * MethodHandles.invokeExact(greeter); // also prints "hello, world"
- * greeter.setGreeting("howdy");
- * mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
- * </pre></blockquote>
- * <p>
- * In the example of {@code Greeter}, the method {@code run} provides the entry point.
- * The entry point need not be a constant value; it may be independently
- * computed in each call to the constructor. The entry point does not
- * even need to be a method on the {@code Greeter} class, though
- * that is the typical case.
- * <p>
- * The entry point may also be provided symbolically, in which case the the
- * {@code JavaMethodHandle} constructor performs the lookup of the entry point.
- * This makes it possible to use {@code JavaMethodHandle} to create an anonymous
- * inner class:
- * <p><blockquote><pre>
- * // We can also do this with symbolic names and/or inner classes:
- * MethodHandles.invokeExact(new JavaMethodHandle("yow") {
- * void yow() { System.out.println("yow, world"); }
- * });
- * </pre></blockquote>
- * <p>
- * Here is similar lower-level code which works in terms of a bound method handle.
- * <p><blockquote><pre>
- * class Greeter {
- * public void run() { System.out.println("hello, "+greetee); }
- * private final String greetee;
- * Greeter(String greetee) { this.greetee = greetee; }
- * // the entry point function is computed once:
- * private static final MethodHandle RUN
- * = MethodHandles.findVirtual(Greeter.class, "run",
- * MethodType.make(void.class));
- * }
- * // class Main { public static void main(String... av) { ...
- * Greeter greeter = new Greeter("world");
- * greeter.run(); // prints "hello, world"
- * MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
- * mh.invokeExact(); // also prints "hello, world"
- * </pre></blockquote>
- * Note that the method handle must be separately created as a view on the base object.
- * This increases footprint, complexity, and dynamic indirections.
- * <p>
- * Here is a pure functional value expressed most concisely as an anonymous inner class:
- * <p><blockquote><pre>
- * // class Main { public static void main(String... av) { ...
- * final String greetee = "world";
- * MethodHandle greeter = new JavaMethodHandle("run") {
- * private void run() { System.out.println("hello, "+greetee); }
- * }
- * greeter.invokeExact(); // prints "hello, world"
- * </pre></blockquote>
- * <p>
- * Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
- * and instantiated as an anonymous class. The data structure is a handle to 1-D array,
- * with a specialized index type (long). It is created by inner class, and uses
- * signature-polymorphic APIs throughout.
- * <p><blockquote><pre>
- * abstract class AssignableMethodHandle extends JavaMethodHandle {
- * private final MethodHandle setter;
- * public MethodHandle setter() { return setter; }
- * public AssignableMethodHandle(String get, String set) {
- * super(get);
- * MethodType getType = this.type();
- * MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
- * this.setter = MethodHandles.publicLookup().bind(this, set, setType);
- * }
- * }
- * // class Main { public static void main(String... av) { ...
- * final Number[] stuff = { 123, 456 };
- * AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
- * public Number get(long i) { return stuff[(int)i]; }
- * public void set(long i, Object x) { stuff[(int)i] = x; }
- * }
- * int x = (Integer) stuffPtr.<Number>invokeExact(1L); // 456
- * stuffPtr.setter().<void>invokeExact(0L, (Number) 789); // replaces 123 with 789
- * </pre></blockquote>
- * @see MethodHandle
- * @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
- * an interface-based API for mixing method handle behavior with other classes.
- * @author John Rose, JSR 292 EG
- */
-public abstract class JavaMethodHandle
- // Note: This is an implementation inheritance hack, and will be removed
- // with a JVM change which moves the required hidden behavior onto this class.
- extends sun.dyn.BoundMethodHandle
-{
- private static final Access IMPL_TOKEN = Access.getToken();
-
- /**
- * When creating a {@code JavaMethodHandle}, the actual method handle
- * invocation behavior will be delegated to the specified {@code entryPoint}.
- * This may be any method handle which can take the newly constructed object
- * as a leading parameter.
- * <p>
- * The method handle type of {@code this} (i.e, the fully constructed object)
- * will be {@code entryPoint}, minus the leading argument.
- * The leading argument will be bound to {@code this} on every method
- * handle invocation.
- * @param entryPoint the method handle to handle calls
- */
- protected JavaMethodHandle(MethodHandle entryPoint) {
- super(entryPoint);
- }
-
- /**
- * Create a method handle whose entry point is a non-static method
- * visible in the exact (most specific) class of
- * the newly constructed object.
- * <p>
- * The method is specified by name and type, as if via this expression:
- * {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}.
- * The class defining the method might be an anonymous inner class.
- * <p>
- * The method handle type of {@code this} (i.e, the fully constructed object)
- * will be the given method handle type.
- * A call to {@code this} will invoke the selected method.
- * The receiver argument will be bound to {@code this} on every method
- * handle invocation.
- * <p>
- * <i>Rationale:</i>
- * Although this constructor may seem to be a mere luxury,
- * it is not subsumed by the more general constructor which
- * takes any {@code MethodHandle} as the entry point argument.
- * In order to convert an entry point name to a method handle,
- * the self-class of the object is required (in order to do
- * the lookup). The self-class, in turn, is generally not
- * available at the time of the constructor invocation,
- * due to the rules of Java and the JVM verifier.
- * One cannot call {@code this.getClass()}, because
- * the value of {@code this} is inaccessible at the point
- * of the constructor call. (Changing this would require
- * change to the Java language, verifiers, and compilers.)
- * In particular, this constructor allows {@code JavaMethodHandle}s
- * to be created in combination with the anonymous inner class syntax.
- * @param entryPointName the name of the entry point method
- * @param type (optional) the desired type of the method handle
- */
- protected JavaMethodHandle(String entryPointName, MethodType type) {
- super(entryPointName, type, true);
-
- }
-
- /**
- * Create a method handle whose entry point is a non-static method
- * visible in the exact (most specific) class of
- * the newly constructed object.
- * <p>
- * The method is specified only by name.
- * There must be exactly one method of that name visible in the object class,
- * either inherited or locally declared.
- * (That is, the method must not be overloaded.)
- * <p>
- * The method handle type of {@code this} (i.e, the fully constructed object)
- * will be the same as the type of the selected non-static method.
- * The receiver argument will be bound to {@code this} on every method
- * handle invocation.
- * <p>ISSUE: This signature wildcarding feature does not correspond to
- * any MethodHandles.Lookup API element. Can we eliminate it?
- * Alternatively, it is useful for naming non-overloaded methods.
- * Shall we make type arguments optional in the Lookup methods,
- * throwing an error in cases of ambiguity?
- * <p>
- * For this method's rationale, see the documentation
- * for {@link #JavaMethodHandle(String,MethodType)}.
- * @param entryPointName the name of the entry point method
- */
- protected JavaMethodHandle(String entryPointName) {
- super(entryPointName, (MethodType) null, false);
- }
-}
--- a/jdk/src/share/classes/java/dyn/Linkage.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/Linkage.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,7 +25,6 @@
package java.dyn;
-import java.lang.annotation.Annotation;
import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
@@ -56,11 +55,7 @@
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
* <li>the name of the method being invoked (a {@link String})
* <li>the type of the method being invoked (a {@link MethodType})
- * <li><em>TBD</em> optionally, an unordered array of {@link Annotation}s attached to the call site
- * <em>(Until this feature is implemented, this will always receive an empty array.)</em>
* </ul>
- * <em>(TBD: The final argument type may be missing from the method handle's type.
- * Additional arguments may be added in the future.)</em>
* The bootstrap method acts as a factory method which accepts the given arguments
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
* <p>
@@ -86,6 +81,7 @@
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
@@ -97,14 +93,9 @@
static private void checkBSM(MethodHandle mh) {
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
- if (mh.type() == BOOTSTRAP_METHOD_TYPE_2)
- // For now, always pass an empty array for the Annotations argument
- mh = MethodHandles.insertArguments(mh, BOOTSTRAP_METHOD_TYPE_2.parameterCount()-1,
- (Object)NO_ANNOTATIONS);
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
throw new WrongMethodTypeException(mh.toString());
}
- static private final Annotation[] NO_ANNOTATIONS = { };
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
@@ -115,6 +106,7 @@
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(Class<?> runtime, String name) {
@@ -131,6 +123,7 @@
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(String name) {
@@ -142,18 +135,10 @@
void registerBootstrapMethodLookup(Class<?> callerClass, Class<?> runtime, String name) {
Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
MethodHandle bootstrapMethod;
- // Try both types. TBD
try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE_2);
+ bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
} catch (NoAccessException ex) {
- bootstrapMethod = null;
- }
- if (bootstrapMethod == null) {
- try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
- } catch (NoAccessException ex) {
- throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
- }
+ throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
checkBSM(bootstrapMethod);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
@@ -172,6 +157,7 @@
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
+ * @deprecated
*/
public static
MethodHandle getBootstrapMethod(Class callerClass) {
@@ -188,10 +174,6 @@
public static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
- static final MethodType BOOTSTRAP_METHOD_TYPE_2
- = MethodType.methodType(CallSite.class,
- Class.class, String.class, MethodType.class,
- Annotation[].class);
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
--- a/jdk/src/share/classes/java/dyn/LinkagePermission.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/LinkagePermission.java Sat Nov 13 18:56:50 2010 -0800
@@ -31,6 +31,7 @@
import java.util.StringTokenizer;
/**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
@@ -52,13 +53,6 @@
* </tr>
*
* <tr>
- * <td>registerBootstrapMethod.{class name}</td>
- * <td>Specifying a bootstrap method for {@code invokedynamic} instructions within a class of the given name</td>
- * <td>An attacker could attempt to attach a bootstrap method to a class which
- * has just been loaded, thus gaining control of its {@code invokedynamic} calls.</td>
- * </tr>
- *
- * <tr>
* <td>invalidateAll</td>
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
* <td>This could allow an attacker to slow down the system,
@@ -73,8 +67,9 @@
* <td>See {@code invalidateAll}.</td>
* </tr>
* </table>
+ * <p>ISSUE: Is this still needed?
*
- * @see java.security.RuntimePermission
+ * @see java.lang.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
@@ -86,7 +81,7 @@
/**
* Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as
- * "registerBootstrapMethod", "invalidateCallerClass.*", etc. An asterisk
+ * "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
--- a/jdk/src/share/classes/java/dyn/MethodHandle.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/MethodHandle.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,11 +36,13 @@
/**
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
- * conversion or substitution of arguments or return values.
+ * transformations of arguments or return values.
+ * (These transformations include conversion, insertion, deletion,
+ * substitution. See the methods of this class and of {@link MethodHandles}.)
* <p>
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
- * A method handle must be invoked under a signature which exactly matches
+ * A method handle must be invoked under a signature which matches
* the method handle's own {@link MethodType method type}.
* <p>
* Every method handle confesses its type via the {@code type} accessor.
@@ -174,9 +176,10 @@
* merely a documentation convention. These type parameters do
* not play a role in type-checking method handle invocations.
* <p>
- * Note: Like classes and strings, method handles that correspond directly
- * to fields and methods can be represented directly as constants to be
- * loaded by {@code ldc} bytecodes.
+ * Like classes and strings, method handles that correspond to accessible
+ * fields, methods, and constructors can be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * Loading such a constant causes the component classes of its type to be loaded as necessary.
*
* @see MethodType
* @see MethodHandles
@@ -186,6 +189,7 @@
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden state onto this class.
extends MethodHandleImpl
+ implements MethodHandleProvider
{
private static Access IMPL_TOKEN = Access.getToken();
@@ -197,7 +201,7 @@
* those methods which are signature polymorphic.
*/
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.TYPE})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@interface PolymorphicSignature { }
private MethodType type;
@@ -274,10 +278,14 @@
* and performing simple conversions for arguments and return types.
* The signature at the call site of {@code invokeGeneric} must
* have the same arity as this method handle's {@code type}.
- * The same conversions are allowed on arguments or return values as are supported by
- * by {@link MethodHandles#convertArguments}.
+ * <p>
* If the call site signature exactly matches this method handle's {@code type},
* the call proceeds as if by {@link #invokeExact}.
+ * <p>
+ * Otherwise, the call proceeds as if this method handle were first
+ * adjusted by calling {@link #asType} to adjust this method handle
+ * to the required type, and then the call proceeds as if by
+ * {@link #invokeExact} on the adjusted method handle.
*/
public final native @PolymorphicSignature <R,A> R invokeGeneric(A... args) throws Throwable;
@@ -538,4 +546,10 @@
public final MethodHandle bindTo(Object x) {
return MethodHandles.insertArguments(this, 0, x);
}
+
+ /** Implementation of {@link MethodHandleProvider}, which returns {@code this}. */
+ public final MethodHandle asMethodHandle() { return this; }
+
+ /** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
+ public final MethodHandle asMethodHandle(MethodType type) { return this.asType(type); }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/dyn/MethodHandleProvider.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.dyn;
+
+/**
+ * An interface for an object to provide a target {@linkplain MethodHandle method handle} to a {@code invokedynamic} instruction.
+ * There are many function-like objects in various Java APIs.
+ * This interface provides a standard way for such function-like objects to be bound
+ * to a dynamic call site, by providing a view of their behavior in the form of a low-level method handle.
+ * <p>
+ * The type {@link MethodHandle} is a concrete class whose implementation
+ * hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
+ * It cannot also serve as a base type for user-defined functional APIs.
+ * For this reason, {@code MethodHandle} cannot be subclassed to add new
+ * behavior to method handles. But this interface can be used to provide
+ * a link between a user-defined function and the {@code invokedynamic}
+ * instruction and the method handle API.
+ */
+public interface MethodHandleProvider {
+ /** Produce a method handle which will serve as a behavioral proxy for the current object.
+ * The type and invocation behavior of the proxy method handle are user-defined,
+ * and should have some relation to the intended meaning of the original object itself.
+ * <p>
+ * The current object may have a changeable behavior.
+ * For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
+ * In such a case, it is <em>incorrect</em> for {@code asMethodHandle} to return
+ * a method handle whose behavior may diverge from that of the current object.
+ * Rather, the returned method handle must stably and permanently access
+ * the behavior of the current object, even if that behavior is changeable.
+ * <p>
+ * The reference identity of the proxy method handle is not guaranteed to
+ * have any particular relation to the reference identity of the object.
+ * In particular, several objects with the same intended meaning could
+ * share a common method handle, or the same object could return different
+ * method handles at different times. In the latter case, the different
+ * method handles should have the same type and invocation behavior,
+ * and be usable from any thread at any time.
+ * In particular, if a MethodHandleProvider is bound to an <code>invokedynamic</code>
+ * call site, the proxy method handle extracted at the time of binding
+ * will be used for an unlimited time, until the call site is rebound.
+ * <p>
+ * The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
+ * for this method simply returns {@code this}.
+ */
+ public MethodHandle asMethodHandle();
+
+ /** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
+ * As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
+ * proxy method handle is user-defined. But the type must be the given type,
+ * or else a {@link WrongMethodTypeException} must be thrown.
+ * <p>
+ * If the current object somehow represents a variadic or overloaded behavior,
+ * the method handle returned for a given type might represent only a subset of
+ * the current object's repertoire of behaviors, which correspond to that type.
+ */
+ public MethodHandle asMethodHandle(MethodType type) throws WrongMethodTypeException;
+}
--- a/jdk/src/share/classes/java/dyn/MethodHandles.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/MethodHandles.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,15 +25,12 @@
package java.dyn;
-import java.lang.reflect.Constructor;
+import java.lang.reflect.*;
import sun.dyn.Access;
import sun.dyn.MemberName;
import sun.dyn.MethodHandleImpl;
import sun.dyn.util.VerifyAccess;
import sun.dyn.util.Wrapper;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,6 +78,14 @@
* Return a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible fields and methods.
+ * <p>
+ * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+ * of this lookup object will be {@link java.lang.Object}.
+ * <p>
+ * The lookup class can be changed to any other class {@code C} using an expression of the form
+ * {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}.
+ * Since all classes have equal access to public names,
+ * such a change would confer no new access rights.
*/
public static Lookup publicLookup() {
return Lookup.PUBLIC_LOOKUP;
@@ -90,9 +95,10 @@
* A <em>lookup object</em> is a factory for creating method handles,
* when the creation requires access checking.
* Method handles do not perform
- * access checks when they are called; this is a major difference
+ * access checks when they are called, but rather when they are created.
+ * (This is a major difference
* from reflective {@link Method}, which performs access checking
- * against every caller, on every call.
+ * against every caller, on every call.)
* Therefore, method handle access
* restrictions must be enforced when a method handle is created.
* The caller class against which those restrictions are enforced
@@ -107,7 +113,7 @@
* It may then use this factory to create method handles on
* all of its methods, including private ones.
* It may also delegate the lookup (e.g., to a metaobject protocol)
- * by passing the {@code Lookup} object to other code.
+ * by passing the lookup object to other code.
* If this other code creates method handles, they will be access
* checked against the original lookup class, and not with any higher
* privileges.
@@ -125,23 +131,28 @@
* It can also fail if a security manager is installed and refuses
* access. In any of these cases, an exception will be
* thrown from the attempted lookup.
+ * <p>
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
* under which the lookup class could have compiled a call to {@code M}.
- * At least some of these error conditions are likely to be
- * represented by checked exceptions in the final version of this API.
+ * This rule is applied even if the Java compiler might have created
+ * an wrapper method to access a private method of another class
+ * in the same top-level declaration.
+ * For example, a lookup object created for a nested class {@code C.D}
+ * can access private members within other related classes such as
+ * {@code C}, {@code C.D.E}, or {@code C.B}.
*/
public static final
class Lookup {
/** The class on behalf of whom the lookup is being performed. */
private final Class<?> lookupClass;
- /** The allowed sorts of members which may be looked up (public, etc.), with STRICT for package. */
+ /** The allowed sorts of members which may be looked up (public, etc.), with STATIC for package. */
private final int allowedModes;
private static final int
PUBLIC = Modifier.PUBLIC,
- PACKAGE = Modifier.STRICT,
+ PACKAGE = Modifier.STATIC,
PROTECTED = Modifier.PROTECTED,
PRIVATE = Modifier.PRIVATE,
ALL_MODES = (PUBLIC | PACKAGE | PROTECTED | PRIVATE),
@@ -155,8 +166,10 @@
/** Which class is performing the lookup? It is this class against
* which checks are performed for visibility and access permissions.
* <p>
- * This value is null if and only if this lookup was produced
- * by {@link MethodHandles#publicLookup}.
+ * The class implies a maximum level of access permission,
+ * but the permissions may be additionally limited by the bitmask
+ * {@link #lookupModes}, which controls whether non-public members
+ * can be accessed.
*/
public Class<?> lookupClass() {
return lookupClass;
@@ -168,10 +181,15 @@
}
/** Which types of members can this lookup object produce?
- * The result is a bit-mask of the modifier bits PUBLIC, PROTECTED, PRIVATE, and STRICT.
- * The modifier bit STRICT stands in for the (non-existent) package protection mode.
+ * The result is a bit-mask of the {@link Modifier} bits
+ * {@linkplain Modifier#PUBLIC PUBLIC (0x01)},
+ * {@linkplain Modifier#PROTECTED PROTECTED (0x02)},
+ * {@linkplain Modifier#PRIVATE PRIVATE (0x04)},
+ * and {@linkplain Modifier#STATIC STATIC (0x08)}.
+ * The modifier bit {@code STATIC} stands in for the package protection mode,
+ * which does not have an explicit modifier bit.
*/
- int lookupModes() {
+ public int lookupModes() {
return allowedModes & ALL_MODES;
}
@@ -621,32 +639,32 @@
/// Helper methods, all package-private.
- MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) {
+ MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
- MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) {
+ MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic,
- boolean searchSupers, Class<?> specialCaller) {
+ boolean searchSupers, Class<?> specialCaller) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller);
}
- void checkSymbolicClass(Class<?> refc) {
+ void checkSymbolicClass(Class<?> refc) throws NoAccessException {
Class<?> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller))
throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller);
}
- void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) {
+ void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws NoAccessException {
String message;
if (m.isConstructor())
message = "expected a method, not a constructor";
@@ -659,7 +677,7 @@
throw newNoAccessException(message, m, lookupClass());
}
- void checkAccess(Class<?> refc, MemberName m) {
+ void checkAccess(Class<?> refc, MemberName m) throws NoAccessException {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
@@ -695,14 +713,14 @@
return "member is private to package";
}
- void checkSpecialCaller(Class<?> specialCaller) {
+ void checkSpecialCaller(Class<?> specialCaller) throws NoAccessException {
if (allowedModes == TRUSTED) return;
if (!VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))
throw newNoAccessException("no private access for invokespecial",
new MemberName(specialCaller), lookupClass());
}
- MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) {
+ MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws NoAccessException {
// The accessing class only has the right to use a protected member
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if (!method.isProtected() || method.isStatic()
@@ -712,7 +730,7 @@
else
return restrictReceiver(method, mh, lookupClass());
}
- MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) {
+ MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws NoAccessException {
assert(!method.isStatic());
Class<?> defc = method.getDeclaringClass(); // receiver type of mh is too wide
if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
@@ -898,11 +916,16 @@
* @return a method handle which always invokes the call site's target
*/
public static
- MethodHandle dynamicInvoker(CallSite site) {
+ MethodHandle dynamicInvoker(CallSite site) throws NoAccessException {
MethodHandle getCSTarget = GET_TARGET;
- if (getCSTarget == null)
- GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
- findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+ if (getCSTarget == null) {
+ try {
+ GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
+ findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+ } catch (NoAccessException ex) {
+ throw new InternalError();
+ }
+ }
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, getCSTarget, site);
MethodHandle invoker = exactInvoker(site.type());
return foldArguments(invoker, getTarget);
@@ -1260,17 +1283,20 @@
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
- * MethodHandle cat = MethodHandles.lookup().
- * findVirtual(String.class, "concat", String.class, String.class);
- * System.out.println(cat.<String>invokeExact("x", "y")); // xy
+ * import static java.dyn.MethodHandles.*;
+ * import static java.dyn.MethodType.*;
+ * ...
+ * MethodHandle cat = lookup().findVirtual(String.class,
+ * "concat", methodType(String.class, String.class));
+ * System.out.println((String) cat.invokeExact("x", "y")); // xy
* MethodHandle d0 = dropArguments(cat, 0, String.class);
- * System.out.println(d0.<String>invokeExact("x", "y", "z")); // xy
+ * System.out.println((String) d0.invokeExact("x", "y", "z")); // yz
* MethodHandle d1 = dropArguments(cat, 1, String.class);
- * System.out.println(d1.<String>invokeExact("x", "y", "z")); // xz
+ * System.out.println((String) d1.invokeExact("x", "y", "z")); // xz
* MethodHandle d2 = dropArguments(cat, 2, String.class);
- * System.out.println(d2.<String>invokeExact("x", "y", "z")); // yz
- * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
- * System.out.println(d12.<String>invokeExact("w", "x", "y", "z")); // wz
+ * System.out.println((String) d2.invokeExact("x", "y", "z")); // xy
+ * MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+ * System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
* </pre></blockquote>
* @param target the method handle to invoke after the argument is dropped
* @param valueTypes the type(s) of the argument to drop
@@ -1562,4 +1588,107 @@
MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
}
+
+ /**
+ * Produce a wrapper instance of the given "SAM" type which redirects its calls to the given method handle.
+ * A SAM type is a type which declares a single abstract method.
+ * Additionally, it must have either no constructor (as an interface)
+ * or have a public or protected constructor of zero arguments (as a class).
+ * <p>
+ * The resulting instance of the required SAM type will respond to
+ * invocation of the SAM type's single abstract method by calling
+ * the given {@code target} on the incoming arguments,
+ * and returning or throwing whatever the {@code target}
+ * returns or throws. The invocation will be as if by
+ * {@code target.invokeExact}.
+ * <p>
+ * The method handle may throw an <em>undeclared exception</em>,
+ * which means any checked exception (or other checked throwable)
+ * not declared by the SAM type's single abstract method.
+ * If this happens, the throwable will be wrapped in an instance
+ * of {@link UndeclaredThrowableException} and thrown in that
+ * wrapped form.
+ * <p>
+ * The wrapper instance is guaranteed to be of a non-public
+ * implementation class C in a package containing no classes
+ * or methods except system-defined classes and methods.
+ * The implementation class C will have no public supertypes
+ * or public methods beyond the following:
+ * <ul>
+ * <li>the SAM type itself and any methods in the SAM type
+ * <li>the supertypes of the SAM type (if any) and their methods
+ * <li>{@link Object} and its methods
+ * <li>{@link MethodHandleProvider} and its methods
+ * </ul>
+ * <p>
+ * No stable mapping is promised between the SAM type and
+ * the implementation class C. Over time, several implementation
+ * classes might be used for the same SAM type.
+ * <p>
+ * This method is not guaranteed to return a distinct
+ * wrapper object for each separate call. If the JVM is able
+ * to prove that a wrapper has already been created for a given
+ * method handle, or for another method handle with the
+ * same behavior, the JVM may return that wrapper in place of
+ * a new wrapper.
+ * @param target the method handle to invoke from the wrapper
+ * @param samType the desired type of the wrapper, a SAM type
+ * @return a correctly-typed wrapper for the given {@code target}
+ * @throws IllegalArgumentException if the {@code target} throws
+ * an undeclared exception
+ */
+ // ISSUE: Should we delegate equals/hashCode to the targets?
+ // Not useful unless there is a stable equals/hashCode behavior
+ // for MethodHandle, and for MethodHandleProvider.asMethodHandle.
+ public static
+ <T> T asInstance(MethodHandle target, Class<T> samType) {
+ // POC implementation only; violates the above contract several ways
+ final Method sam = getSamMethod(samType);
+ if (sam == null)
+ throw new IllegalArgumentException("not a SAM type: "+samType.getName());
+ MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes());
+ if (!samMT.equals(target.type()))
+ throw new IllegalArgumentException("wrong method type");
+ final MethodHandle mh = target;
+ return samType.cast(Proxy.newProxyInstance(
+ samType.getClassLoader(),
+ new Class[]{ samType, MethodHandleProvider.class },
+ new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getDeclaringClass() == MethodHandleProvider.class) {
+ return method.invoke(mh, args);
+ }
+ assert method.equals(sam) : method;
+ return mh.invokeVarargs(args);
+ }
+ }));
+ }
+
+ private static
+ Method getSamMethod(Class<?> samType) {
+ Method sam = null;
+ for (Method m : samType.getMethods()) {
+ int mod = m.getModifiers();
+ if (Modifier.isAbstract(mod)) {
+ if (sam != null)
+ return null; // too many abstract methods
+ sam = m;
+ }
+ }
+ if (!samType.isInterface() && getSamConstructor(samType) == null)
+ return null; // wrong kind of constructor
+ return sam;
+ }
+
+ private static
+ Constructor getSamConstructor(Class<?> samType) {
+ for (Constructor c : samType.getDeclaredConstructors()) {
+ if (c.getParameterTypes().length == 0) {
+ int mod = c.getModifiers();
+ if (Modifier.isPublic(mod) || Modifier.isProtected(mod))
+ return c;
+ }
+ }
+ return null;
+ }
}
--- a/jdk/src/share/classes/java/dyn/MethodType.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/MethodType.java Sat Nov 13 18:56:50 2010 -0800
@@ -40,24 +40,37 @@
* returned by a method handle, or the arguments and return type passed
* and expected by a method handle caller. Method types must be properly
* matched between a method handle and all its callers,
- * and the JVM's operations enforce this matching at all times.
+ * and the JVM's operations enforce this matching at, specifically
+ * during calls to {@link MethodHandle#invokeExact}
+ * and {@link MethodHandle#invokeGeneric}, and during execution
+ * of {@code invokedynamic} instructions.
* <p>
* The structure is a return type accompanied by any number of parameter types.
- * The types (primitive, void, and reference) are represented by Class objects.
+ * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
+ * (For ease of exposition, we treat {@code void} as if it were a type.
+ * In fact, it denotes the absence of a return type.)
* <p>
- * All instances of <code>MethodType</code> are immutable.
+ * All instances of {@code MethodType} are immutable.
* Two instances are completely interchangeable if they compare equal.
* Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
* <p>
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
* <p>
- * Note: Like classes and strings, method types can be represented directly
- * as constants to be loaded by {@code ldc} bytecodes.
+ * {@code MethodType} objects are sometimes derived from bytecode instructions
+ * such as {@code invokedynamic}, specifically from the type descriptor strings associated
+ * with the instructions in a class file's constant pool.
+ * When this occurs, any classes named in the descriptor strings must be loaded.
+ * (But they need not be initialized.)
+ * This loading may occur at any time before the {@code MethodType} object is first derived.
+ * <p>
+ * Like classes and strings, method types can be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * Loading such a constant causes its component classes to be loaded as necessary.
* @author John Rose, JSR 292 EG
*/
public final
-class MethodType {
+class MethodType implements java.lang.reflect.Type {
private final Class<?> rtype;
private final Class<?>[] ptypes;
private MethodTypeForm form; // erased form, plus cached data about primitives
@@ -636,11 +649,11 @@
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Find or create an instance of the given method type.
- * Any class or interface name embedded in the signature string
+ * Any class or interface name embedded in the descriptor string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
* on the given loader (or if it is null, on the system class loader).
* <p>
- * Note that it is possible to build method types which cannot be
+ * Note that it is possible to encounter method types which cannot be
* constructed by this method, because their component types are
* not all reachable from a common class loader.
* <p>
@@ -662,8 +675,11 @@
}
/**
- * Create a bytecode signature representation of the type.
- * Note that this is not a strict inverse of
+ * Create a bytecode descriptor representation of the method type.
+ * <p>
+ * Note that this is not a strict inverse of {@link #fromMethodDescriptorString}.
+ * Two distinct classes which share a common name but have different class loaders
+ * will appear identical when viewed within descriptor strings.
* <p>
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
--- a/jdk/src/share/classes/java/dyn/NoAccessException.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/NoAccessException.java Sat Nov 13 18:56:50 2010 -0800
@@ -37,7 +37,7 @@
* @author John Rose, JSR 292 EG
* @since 1.7
*/
-public class NoAccessException extends RuntimeException {
+public class NoAccessException extends ReflectiveOperationException {
private static final long serialVersionUID = 292L;
/**
--- a/jdk/src/share/classes/java/dyn/package-info.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/dyn/package-info.java Sat Nov 13 18:56:50 2010 -0800
@@ -40,20 +40,18 @@
* The JVM links any such call (regardless of signature) to a dynamically
* typed method handle invocation. In the case of {@code invokeGeneric},
* argument and return value conversions are applied.
+ * </li>
*
- * <li>In source code, the class {@link java.dyn.InvokeDynamic} appears to accept
+ * <li>In source code, the class {@link java.dyn.InvokeDynamic InvokeDynamic} appears to accept
* any static method invocation, of any name and any signature.
* But instead of emitting
* an {@code invokestatic} instruction for such a call, the Java compiler emits
* an {@code invokedynamic} instruction with the given name and signature.
- *
- * <li>When the JVM links an {@code invokedynamic} instruction, it calls the
- * {@linkplain java.dyn.Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method}
- * of the containing class to obtain a {@linkplain java.dyn.CallSite call site} object through which
- * the call site will link its target {@linkplain java.dyn.MethodHandle method handle}.
+ * </li>
*
* <li>The JVM bytecode format supports immediate constants of
- * the classes {@link java.dyn.MethodHandle} and {@link java.dyn.MethodType}.
+ * the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
+ * </li>
* </ul>
*
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
@@ -65,18 +63,50 @@
* The first byte is the opcode 186 (hexadecimal {@code BA}).
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
* The final two bytes are reserved for future use and required to be zero.
- * The constant pool reference is to a entry with tag {@code CONSTANT_NameAndType}
- * (decimal 12). It is thus not a method reference of any sort, but merely
- * the method name, argument types, and return type of the dynamic call site.
- * <em>(TBD: The EG is discussing the possibility of a special constant pool entry type,
- * so that other information may be added, such as a per-instruction bootstrap
- * method and/or annotations.)</em>
+ * The constant pool reference of an {@code invokedynamic} instruction is to a entry
+ * with tag {@code CONSTANT_InvokeDynamic} (decimal 17). See below for its format.
+ * The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
+ * the dynamic invocation name, and the argument types and return type of the call.
+ * <p>
+ * Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
+ * Multiple instances of an {@code invokedynamic} instruction can share a single
+ * {@code CONSTANT_InvokeDynamic} entry.
+ * In any case, distinct call sites always have distinct linkage state.
+ * <p>
+ * Moreover, for the purpose of distinguishing dynamic call sites,
+ * the JVM is allowed (but not required) to make internal copies
+ * of {@code invokedynamic} instructions, each one
+ * constituting a separate dynamic call site with its own linkage state.
+ * Such copying, if it occurs, cannot be observed except indirectly via
+ * execution of bootstrap methods and target methods.
+ * <p>
+ * A dynamic call site is originally in an unlinked state. In this state, there is
+ * no target method for the call site to invoke.
+ * A dynamic call site is linked by means of a bootstrap method,
+ * as <a href="#bsm">described below</a>.
+ * <p>
+ * <em>(Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
+ * instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
+ * bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
+ *
+ * <h3>constant pool entries for {@code invokedynamic} instructions</h3>
+ * If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
+ * it must contain exactly four more bytes.
+ * The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
+ * entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
+ * The first index specifies a bootstrap method used by the associated dynamic call sites.
+ * The second index specifies the method name, argument types, and return type of the dynamic call site.
+ * The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
+ * except that the {@code CONSTANT_Class} reference in a {@code CONSTANT_Methodref} entry
+ * is replaced by a bootstrap method reference.
*
* <h3>constant pool entries for {@code MethodType}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
- * it must contain exactly two more bytes, which are an index to a {@code CONSTANT_Utf8}
- * entry which represents a method type signature. The JVM will ensure that on first
- * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType}
+ * it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
+ * entry which represents a method type signature.
+ * <p>
+ * The JVM will ensure that on first
+ * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType}
* will be created which represents the signature.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
@@ -86,12 +116,15 @@
* <h3>constant pool entries for {@code MethodHandle}s</h3>
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* it must contain exactly three more bytes. The first byte after the tag is a subtag
- * value in the range 1 through 9, and the last two are an index to a
+ * value which must be in the range 1 through 9, and the last two must be an index to a
* {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
* {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
* for which a method handle is to be created.
+ * Furthermore, the subtag value and the type of the constant index value
+ * must agree according to the table below.
+ * <p>
* The JVM will ensure that on first execution of an {@code ldc} instruction
- * for this entry, a {@link java.dyn.MethodHandle} will be created which represents
+ * for this entry, a {@link java.dyn.MethodHandle MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
* <p>
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
@@ -126,6 +159,129 @@
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
* may force class initialization on their first invocation, just like the corresponding bytecodes.
*
+ * <h2><a name="bsm"></a>Bootstrap Methods</h2>
+ * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
+ * the call site must first be <em>linked</em>.
+ * Linking is accomplished by calling a <em>bootstrap method</em>
+ * which is given the static information content of the call site,
+ * and which must produce a {@link java.dyn.MethodHandle method handle}
+ * that gives the behavior of the call site.
+ * <p>
+ * Each {@code invokedynamic} instruction statically specifies its own
+ * bootstrap method as a constant pool reference.
+ * The constant pool reference also specifies the call site's name and type signature,
+ * just like {@code invokevirtual} and the other invoke instructions.
+ * <p>
+ * Linking starts with resolving the constant pool entry for the
+ * bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for
+ * the type signature of the dynamic call site.
+ * This resolution process may trigger class loading.
+ * It may therefore throw an error if a class fails to load.
+ * This error becomes the abnormal termination of the dynamic
+ * call site execution.
+ * Linkage does not trigger class initialization.
+ * <p>
+ * Next, the bootstrap method call is started, with four values being stacked:
+ * <ul>
+ * <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
+ * <li>a {@code Class}, the <em>caller class</em> in which dynamic call site occurs </li>
+ * <li>a {@code String}, the method name mentioned in the call site </li>
+ * <li>a {@code MethodType}, the resolved type signature of the call </li>
+ * </ul>
+ * The method handle is then applied to the other values as if by
+ * {@linkplain java.dyn.MethodHandle#invokeGeneric the <code>invokeGeneric</code> method}.
+ * The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
+ * or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
+ * The method {@linkplain java.dyn.MethodHandleProvider#asMethodHandle asMethodHandle}
+ * is then called on the returned value. The result of that second
+ * call is the {@code MethodHandle} which becomes the
+ * permanent binding for the dynamic call site.
+ * That method handle's type must be exactly equal to the type
+ * derived from the dynamic call site signature and passed to
+ * the bootstrap method.
+ * <p>
+ * After resolution, the linkage process may fail in a variety of ways.
+ * All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
+ * which is thrown as the abnormal termination of the dynamic call
+ * site execution.
+ * The following circumstances will cause this:
+ * <ul>
+ * <li>the bootstrap method invocation completes abnormally </li>
+ * <li>the result from the bootstrap invocation is not a reference to
+ * an object of type {@link java.dyn.MethodHandleProvider MethodHandleProvider} </li>
+ * <li>the call to {@code asMethodHandle} completes abnormally </li>
+ * <li>the call to {@code asMethodHandle} fails to return a reference to
+ * an object of type {@link java.dyn.MethodHandle MethodHandle} </li>
+ * <li>the method handle produced by {@code asMethodHandle} does not have
+ * the expected {@code MethodType} </li>
+ * </ul>
+ * <h3>timing of linkage</h3>
+ * A dynamic call site is linked just before its first execution.
+ * The bootstrap method call implementing the linkage occurs within
+ * a thread that is attempting a first execution.
+ * <p>
+ * If there are several such threads, the JVM picks one thread
+ * and runs the bootstrap method while the others wait for the
+ * invocation to terminate normally or abnormally.
+ * <p>
+ * After a bootstrap method is called and a method handle target
+ * successfully extracted, the JVM attempts to link the instruction
+ * being executed to the target method handle.
+ * This may fail if there has been intervening linkage
+ * or invalidation event for the same instruction.
+ * If such a failure occurs, the dynamic call site must be
+ * re-executed from the beginning, either re-linking it
+ * (if it has been invalidated) or invoking the target
+ * (if it the instruction has been linked by some other means).
+ * <p>
+ * If the instruction is linked successfully, the target method
+ * handle is invoked to complete the instruction execution.
+ * The state of linkage continues until the method containing the
+ * dynamic call site is garbage collected, or the dynamic call site
+ * is invalidated by an explicit request,
+ * such as {@link java.dyn.Linkage#invalidateCallerClass Linkage.invalidateCallerClass}.
+ * <p>
+ * In an application which requires dynamic call sites with individually
+ * mutable behaviors, their bootstrap methods should produce distinct
+ * {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
+ * <p>
+ * If a class containing {@code invokedynamic} instructions
+ * is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
+ * subsequent execution of those {@code invokedynamic} instructions
+ * will require linking.
+ * It is as if they had never been executed in the first place.
+ * (However, invalidation does not cause constant pool entries to be
+ * resolved a second time.)
+ * <p>
+ * Invalidation events and bootstrap method calls for a particular
+ * dynamic call site are globally ordered relative to each other.
+ * When an invokedynamic instruction is invalidated, if there is
+ * simultaneously a bootstrap method invocation in process
+ * (in the same thread or a different thread), the result
+ * eventually returned must not be used to link the call site.
+ * Put another way, when a call site is invalidated, its
+ * subsequent linkage (if any) must be performed by a bootstrap method
+ * call initiated after the invalidation occurred.
+ * <p>
+ * If several threads simultaneously execute a bootstrap method for a single dynamic
+ * call site, the JVM must choose one target object and installs it visibly to
+ * all threads. Any other bootstrap method calls are allowed to complete, but their
+ * results are ignored, and their dynamic call site invocations proceed with the originally
+ * chosen target object.
+ * <p>
+ * The JVM is free to duplicate dynamic call sites.
+ * This means that, even if a class contains just one {@code invokedynamic}
+ * instruction, its bootstrap method may be executed several times,
+ * once for each duplicate. Thus, bootstrap method code should not
+ * assume an exclusive one-to-one correspondence between particular occurrences
+ * of {@code invokedynamic} bytecodes in class files and linkage events.
+ * <p>
+ * In principle, each individual execution of an {@code invokedynamic}
+ * instruction could be deemed (by a conforming implementation) to be a separate
+ * duplicate, requiring its own execution of the bootstrap method.
+ * However, implementations are expected to perform code duplication
+ * (if at all) in order to improve performance, not make it worse.
+ *
* @author John Rose, JSR 292 EG
*/
--- a/jdk/src/share/classes/java/text/DateFormatSymbols.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java Sat Nov 13 18:56:50 2010 -0800
@@ -44,11 +44,12 @@
import java.lang.ref.SoftReference;
import java.text.spi.DateFormatSymbolsProvider;
import java.util.Arrays;
-import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.spi.LocaleServiceProvider;
import sun.util.LocaleServiceProviderPool;
import sun.util.TimeZoneNameUtility;
@@ -321,20 +322,64 @@
* @since 1.6
*/
public static final DateFormatSymbols getInstance(Locale locale) {
+ DateFormatSymbols dfs = getProviderInstance(locale);
+ if (dfs != null) {
+ return dfs;
+ }
+ return (DateFormatSymbols) getCachedInstance(locale).clone();
+ }
+
+ /**
+ * Returns a DateFormatSymbols provided by a provider or found in
+ * the cache. Note that this method returns a cached instance,
+ * not its clone. Therefore, the instance should never be given to
+ * an application.
+ */
+ static final DateFormatSymbols getInstanceRef(Locale locale) {
+ DateFormatSymbols dfs = getProviderInstance(locale);
+ if (dfs != null) {
+ return dfs;
+ }
+ return getCachedInstance(locale);
+ }
+
+ private static DateFormatSymbols getProviderInstance(Locale locale) {
+ DateFormatSymbols providersInstance = null;
// Check whether a provider can provide an implementation that's closer
// to the requested locale than what the Java runtime itself can provide.
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
if (pool.hasProviders()) {
- DateFormatSymbols providersInstance = pool.getLocalizedObject(
- DateFormatSymbolsGetter.INSTANCE, locale);
- if (providersInstance != null) {
- return providersInstance;
+ providersInstance = pool.getLocalizedObject(
+ DateFormatSymbolsGetter.INSTANCE, locale);
+ }
+ return providersInstance;
+ }
+
+ /**
+ * Returns a cached DateFormatSymbols if it's found in the
+ * cache. Otherwise, this method returns a newly cached instance
+ * for the given locale.
+ */
+ private static DateFormatSymbols getCachedInstance(Locale locale) {
+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+ DateFormatSymbols dfs = null;
+ if (ref == null || (dfs = ref.get()) == null) {
+ dfs = new DateFormatSymbols(locale);
+ ref = new SoftReference<DateFormatSymbols>(dfs);
+ SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
+ if (x != null) {
+ DateFormatSymbols y = x.get();
+ if (y != null) {
+ dfs = y;
+ } else {
+ // Replace the empty SoftReference with ref.
+ cachedInstances.put(locale, ref);
+ }
}
}
-
- return new DateFormatSymbols(locale);
+ return dfs;
}
/**
@@ -597,56 +642,44 @@
static final int millisPerHour = 60*60*1000;
/**
- * Cache to hold the FormatData and TimeZoneNames ResourceBundles
- * of a Locale.
- */
- private static Hashtable cachedLocaleData = new Hashtable(3);
-
- /**
- * Look up resource data for the desiredLocale in the cache; update the
- * cache if necessary.
+ * Cache to hold DateFormatSymbols instances per Locale.
*/
- private static ResourceBundle cacheLookup(Locale desiredLocale) {
- ResourceBundle rb;
- SoftReference data
- = (SoftReference)cachedLocaleData.get(desiredLocale);
- if (data == null) {
- rb = LocaleData.getDateFormatData(desiredLocale);
- data = new SoftReference(rb);
- cachedLocaleData.put(desiredLocale, data);
- } else {
- if ((rb = (ResourceBundle)data.get()) == null) {
- rb = LocaleData.getDateFormatData(desiredLocale);
- data = new SoftReference(rb);
- }
- }
- return rb;
- }
+ private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
+ = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
private void initializeData(Locale desiredLocale) {
- int i;
- ResourceBundle resource = cacheLookup(desiredLocale);
+ locale = desiredLocale;
- // FIXME: cache only ResourceBundle. Hence every time, will do
- // getObject(). This won't be necessary if the Resource itself
- // is cached.
- eras = (String[])resource.getObject("Eras");
+ // Copy values of a cached instance if any.
+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+ DateFormatSymbols dfs;
+ if (ref != null && (dfs = ref.get()) != null) {
+ copyMembers(dfs, this);
+ return;
+ }
+
+ // Initialize the fields from the ResourceBundle for locale.
+ ResourceBundle resource = LocaleData.getDateFormatData(locale);
+
+ eras = resource.getStringArray("Eras");
months = resource.getStringArray("MonthNames");
shortMonths = resource.getStringArray("MonthAbbreviations");
- String[] lWeekdays = resource.getStringArray("DayNames");
- weekdays = new String[8];
- weekdays[0] = ""; // 1-based
- for (i=0; i<lWeekdays.length; i++)
- weekdays[i+1] = lWeekdays[i];
- String[] sWeekdays = resource.getStringArray("DayAbbreviations");
- shortWeekdays = new String[8];
- shortWeekdays[0] = ""; // 1-based
- for (i=0; i<sWeekdays.length; i++)
- shortWeekdays[i+1] = sWeekdays[i];
ampms = resource.getStringArray("AmPmMarkers");
localPatternChars = resource.getString("DateTimePatternChars");
- locale = desiredLocale;
+ // Day of week names are stored in a 1-based array.
+ weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
+ shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
+ }
+
+ private static String[] toOneBasedArray(String[] src) {
+ int len = src.length;
+ String[] dst = new String[len + 1];
+ dst[0] = "";
+ for (int i = 0; i < len; i++) {
+ dst[i + 1] = src[i];
+ }
+ return dst;
}
/**
--- a/jdk/src/share/classes/java/text/DecimalFormat.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/text/DecimalFormat.java Sat Nov 13 18:56:50 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,9 +46,10 @@
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Currency;
-import java.util.Hashtable;
import java.util.Locale;
import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import sun.util.resources.LocaleData;
@@ -394,14 +395,14 @@
public DecimalFormat() {
Locale def = Locale.getDefault(Locale.Category.FORMAT);
// try to get the pattern from the cache
- String pattern = (String) cachedLocaleData.get(def);
+ String pattern = cachedLocaleData.get(def);
if (pattern == null) { /* cache miss */
// Get the pattern for the default locale.
ResourceBundle rb = LocaleData.getNumberFormatData(def);
String[] all = rb.getStringArray("NumberPatterns");
pattern = all[0];
/* update cache */
- cachedLocaleData.put(def, pattern);
+ cachedLocaleData.putIfAbsent(def, pattern);
}
// Always applyPattern after the symbols are set
@@ -3272,5 +3273,6 @@
/**
* Cache to hold the NumberPattern of a Locale.
*/
- private static Hashtable cachedLocaleData = new Hashtable(3);
+ private static final ConcurrentMap<Locale, String> cachedLocaleData
+ = new ConcurrentHashMap<Locale, String>(3);
}
--- a/jdk/src/share/classes/java/text/SimpleDateFormat.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java Sat Nov 13 18:56:50 2010 -0800
@@ -44,13 +44,14 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import sun.util.calendar.CalendarUtils;
import sun.util.calendar.ZoneInfoFile;
import sun.util.resources.LocaleData;
@@ -503,14 +504,14 @@
/**
* Cache to hold the DateTimePatterns of a Locale.
*/
- private static Hashtable<String,String[]> cachedLocaleData
- = new Hashtable<String,String[]>(3);
+ private static final ConcurrentMap<String, String[]> cachedLocaleData
+ = new ConcurrentHashMap<String, String[]>(3);
/**
* Cache NumberFormat instances with Locale key.
*/
- private static Hashtable<Locale,NumberFormat> cachedNumberFormatData
- = new Hashtable<Locale,NumberFormat>(3);
+ private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
+ = new ConcurrentHashMap<Locale, NumberFormat>(3);
/**
* The Locale used to instantiate this
@@ -579,7 +580,7 @@
initializeCalendar(locale);
this.pattern = pattern;
- this.formatData = DateFormatSymbols.getInstance(locale);
+ this.formatData = DateFormatSymbols.getInstanceRef(locale);
this.locale = locale;
initialize(locale);
}
@@ -632,9 +633,9 @@
dateTimePatterns = r.getStringArray("DateTimePatterns");
}
/* update cache */
- cachedLocaleData.put(key, dateTimePatterns);
+ cachedLocaleData.putIfAbsent(key, dateTimePatterns);
}
- formatData = DateFormatSymbols.getInstance(loc);
+ formatData = DateFormatSymbols.getInstanceRef(loc);
if ((timeStyle >= 0) && (dateStyle >= 0)) {
Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
dateTimePatterns[dateStyle + 4]};
@@ -665,7 +666,7 @@
numberFormat.setGroupingUsed(false);
/* update cache */
- cachedNumberFormatData.put(loc, numberFormat);
+ cachedNumberFormatData.putIfAbsent(loc, numberFormat);
}
numberFormat = (NumberFormat) numberFormat.clone();
@@ -897,7 +898,7 @@
* so we can call it from readObject().
*/
private void initializeDefaultCentury() {
- calendar.setTime( new Date() );
+ calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add( Calendar.YEAR, -80 );
parseAmbiguousDatesAsAfter(calendar.getTime());
}
@@ -921,7 +922,7 @@
* @since 1.2
*/
public void set2DigitYearStart(Date startDate) {
- parseAmbiguousDatesAsAfter(startDate);
+ parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
}
/**
@@ -934,7 +935,7 @@
* @since 1.2
*/
public Date get2DigitYearStart() {
- return defaultCenturyStart;
+ return (Date) defaultCenturyStart.clone();
}
/**
--- a/jdk/src/share/classes/java/util/Calendar.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/util/Calendar.java Sat Nov 13 18:56:50 2010 -0800
@@ -51,6 +51,8 @@
import java.security.ProtectionDomain;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import sun.util.BuddhistCalendar;
import sun.util.calendar.ZoneInfo;
import sun.util.resources.LocaleData;
@@ -837,7 +839,8 @@
* Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
* of a Locale.
*/
- private static Hashtable<Locale, int[]> cachedLocaleData = new Hashtable<Locale, int[]>(3);
+ private static final ConcurrentMap<Locale, int[]> cachedLocaleData
+ = new ConcurrentHashMap<Locale, int[]>(3);
// Special values of stamp[]
/**
@@ -1022,7 +1025,7 @@
// returns a BuddhistCalendar instance.
if ("th".equals(aLocale.getLanguage())
&& ("TH".equals(aLocale.getCountry()))) {
- cal = new BuddhistCalendar(zone, aLocale);
+ cal = new BuddhistCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
@@ -2588,7 +2591,7 @@
data = new int[2];
data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
- cachedLocaleData.put(desiredLocale, data);
+ cachedLocaleData.putIfAbsent(desiredLocale, data);
}
firstDayOfWeek = data[0];
minimalDaysInFirstWeek = data[1];
--- a/jdk/src/share/classes/java/util/Locale.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/util/Locale.java Sat Nov 13 18:56:50 2010 -0800
@@ -758,7 +758,7 @@
}
private static void initDefault() {
- String language, region, country, variant;
+ String language, region, script, country, variant;
language = AccessController.doPrivileged(
new GetPropertyAction("user.language", "en"));
// for compatibility, check for old user.region property
@@ -774,43 +774,41 @@
country = region;
variant = "";
}
+ script = "";
} else {
+ script = AccessController.doPrivileged(
+ new GetPropertyAction("user.script", ""));
country = AccessController.doPrivileged(
new GetPropertyAction("user.country", ""));
variant = AccessController.doPrivileged(
new GetPropertyAction("user.variant", ""));
}
- defaultLocale = getInstance(language, country, variant);
+ defaultLocale = getInstance(language, script, country, variant, null);
}
private static void initDefault(Locale.Category category) {
- String language, region, country, variant;
+ // make sure defaultLocale is initialized
+ if (defaultLocale == null) {
+ initDefault();
+ }
+
+ Locale defaultCategoryLocale = getInstance(
+ AccessController.doPrivileged(
+ new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
+ AccessController.doPrivileged(
+ new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
+ AccessController.doPrivileged(
+ new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
+ AccessController.doPrivileged(
+ new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
+ null);
+
switch (category) {
case DISPLAY:
- language = AccessController.doPrivileged(
- new GetPropertyAction("user.language.display", ""));
- if ("".equals(language)) {
- defaultDisplayLocale = getDefault();
- } else {
- country = AccessController.doPrivileged(
- new GetPropertyAction("user.country.display", ""));
- variant = AccessController.doPrivileged(
- new GetPropertyAction("user.variant.display", ""));
- defaultDisplayLocale = getInstance(language, country, variant);
- }
+ defaultDisplayLocale = defaultCategoryLocale;
break;
case FORMAT:
- language = AccessController.doPrivileged(
- new GetPropertyAction("user.language.format", ""));
- if ("".equals(language)) {
- defaultFormatLocale = getDefault();
- } else {
- country = AccessController.doPrivileged(
- new GetPropertyAction("user.country.format", ""));
- variant = AccessController.doPrivileged(
- new GetPropertyAction("user.variant.format", ""));
- defaultFormatLocale = getInstance(language, country, variant);
- }
+ defaultFormatLocale = defaultCategoryLocale;
break;
}
}
@@ -2124,13 +2122,31 @@
* Category used to represent the default locale for
* displaying user interfaces.
*/
- DISPLAY,
+ DISPLAY("user.language.display",
+ "user.script.display",
+ "user.country.display",
+ "user.variant.display"),
/**
* Category used to represent the default locale for
* formatting dates, numbers, and/or currencies.
*/
- FORMAT,
+ FORMAT("user.language.format",
+ "user.script.format",
+ "user.country.format",
+ "user.variant.format");
+
+ Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
+ this.languageKey = languageKey;
+ this.scriptKey = scriptKey;
+ this.countryKey = countryKey;
+ this.variantKey = variantKey;
+ }
+
+ final String languageKey;
+ final String scriptKey;
+ final String countryKey;
+ final String variantKey;
}
/**
--- a/jdk/src/share/classes/java/util/TimeZone.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/java/util/TimeZone.java Sat Nov 13 18:56:50 2010 -0800
@@ -160,11 +160,6 @@
private static final int ONE_HOUR = 60*ONE_MINUTE;
private static final int ONE_DAY = 24*ONE_HOUR;
- /**
- * Cache to hold the SimpleDateFormat objects for a Locale.
- */
- private static Hashtable cachedLocaleData = new Hashtable(3);
-
// Proclaim serialization compatibility with JDK 1.1
static final long serialVersionUID = 3581463369166924961L;
--- a/jdk/src/share/classes/javax/swing/BorderFactory.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/BorderFactory.java Sat Nov 13 18:56:50 2010 -0800
@@ -24,8 +24,10 @@
*/
package javax.swing;
+import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
+import java.awt.Paint;
import javax.swing.border.*;
/**
@@ -636,4 +638,125 @@
Icon tileIcon) {
return new MatteBorder(top, left, bottom, right, tileIcon);
}
+
+//// StrokeBorder //////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a border of the specified {@code stroke}.
+ * The component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @return the {@code Border} object
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ *
+ * @since 1.7
+ */
+ public static Border createStrokeBorder(BasicStroke stroke) {
+ return new StrokeBorder(stroke);
+ }
+
+ /**
+ * Creates a border of the specified {@code stroke} and {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @param paint the {@link Paint} object used to generate a color
+ * @return the {@code Border} object
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ *
+ * @since 1.7
+ */
+ public static Border createStrokeBorder(BasicStroke stroke, Paint paint) {
+ return new StrokeBorder(stroke, paint);
+ }
+
+//// DashedBorder //////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ private static Border sharedDashedBorder;
+
+ /**
+ * Creates a dashed border of the specified {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ * The width of a dash line is equal to {@code 1}.
+ * The relative length of a dash line and
+ * the relative spacing between dash lines are equal to {@code 1}.
+ * A dash line is not rounded.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @return the {@code Border} object
+ *
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint) {
+ return createDashedBorder(paint, 1.0f, 1.0f, 1.0f, false);
+ }
+
+ /**
+ * Creates a dashed border of the specified {@code paint},
+ * relative {@code length}, and relative {@code spacing}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ * The width of a dash line is equal to {@code 1}.
+ * A dash line is not rounded.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @param length the relative length of a dash line
+ * @param spacing the relative spacing between dash lines
+ * @return the {@code Border} object
+ *
+ * @throws IllegalArgumentException if the specified {@code length} is less than {@code 1}, or
+ * if the specified {@code spacing} is less than {@code 0}
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint, float length, float spacing) {
+ return createDashedBorder(paint, 1.0f, length, spacing, false);
+ }
+
+ /**
+ * Creates a dashed border of the specified {@code paint}, {@code thickness},
+ * line shape, relative {@code length}, and relative {@code spacing}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @param thickness the width of a dash line
+ * @param length the relative length of a dash line
+ * @param spacing the relative spacing between dash lines
+ * @param rounded whether or not line ends should be round
+ * @return the {@code Border} object
+ *
+ * @throws IllegalArgumentException if the specified {@code thickness} is less than {@code 1}, or
+ * if the specified {@code length} is less than {@code 1}, or
+ * if the specified {@code spacing} is less than {@code 0}
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint, float thickness, float length, float spacing, boolean rounded) {
+ boolean shared = !rounded && (paint == null) && (thickness == 1.0f) && (length == 1.0f) && (spacing == 1.0f);
+ if (shared && (sharedDashedBorder != null)) {
+ return sharedDashedBorder;
+ }
+ if (thickness < 1.0f) {
+ throw new IllegalArgumentException("thickness is less than 1");
+ }
+ if (length < 1.0f) {
+ throw new IllegalArgumentException("length is less than 1");
+ }
+ if (spacing < 0.0f) {
+ throw new IllegalArgumentException("spacing is less than 0");
+ }
+ int cap = rounded ? BasicStroke.CAP_ROUND : BasicStroke.CAP_SQUARE;
+ int join = rounded ? BasicStroke.JOIN_ROUND : BasicStroke.JOIN_MITER;
+ float[] array = { thickness * (length - 1.0f), thickness * (spacing + 1.0f) };
+ Border border = createStrokeBorder(new BasicStroke(thickness, cap, join, thickness * 2.0f, array, 0.0f), paint);
+ if (shared) {
+ sharedDashedBorder = border;
+ }
+ return border;
+ }
}
--- a/jdk/src/share/classes/javax/swing/DebugGraphics.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/DebugGraphics.java Sat Nov 13 18:56:50 2010 -0800
@@ -1322,13 +1322,11 @@
}
String toShortString() {
- StringBuffer buffer = new StringBuffer("Graphics" + (isDrawingBuffer() ? "<B>" : "") + "(" + graphicsID + "-" + debugOptions + ")");
- return buffer.toString();
+ return "Graphics" + (isDrawingBuffer() ? "<B>" : "") + "(" + graphicsID + "-" + debugOptions + ")";
}
String pointToString(int x, int y) {
- StringBuffer buffer = new StringBuffer("(" + x + ", " + y + ")");
- return buffer.toString();
+ return "(" + x + ", " + y + ")";
}
/** Enables/disables diagnostic information about every graphics
--- a/jdk/src/share/classes/javax/swing/JComponent.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/JComponent.java Sat Nov 13 18:56:50 2010 -0800
@@ -4783,21 +4783,11 @@
* @param y the y value of the dirty region
* @param width the width of the dirty region
* @param height the height of the dirty region
+ * @see #isPaintingOrigin()
* @see java.awt.Component#isShowing
* @see RepaintManager#addDirtyRegion
*/
public void repaint(long tm, int x, int y, int width, int height) {
- Container p = this;
- while ((p = p.getParent()) instanceof JComponent) {
- JComponent jp = (JComponent) p;
- if (jp.isPaintingOrigin()) {
- Rectangle rectangle = SwingUtilities.convertRectangle(
- this, new Rectangle(x, y, width, height), jp);
- jp.repaint(tm,
- rectangle.x, rectangle.y, rectangle.width, rectangle.height);
- return;
- }
- }
RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, height);
}
@@ -4808,6 +4798,7 @@
* currently pending events have been dispatched.
*
* @param r a <code>Rectangle</code> containing the dirty region
+ * @see #isPaintingOrigin()
* @see java.awt.Component#isShowing
* @see RepaintManager#addDirtyRegion
*/
@@ -4912,13 +4903,19 @@
}
/**
- * Returns true if a paint triggered on a child component should cause
+ * Returns {@code true} if a paint triggered on a child component should cause
* painting to originate from this Component, or one of its ancestors.
+ * <p/>
+ * Calling {@link JComponent#repaint} on a Swing component will be delegated to
+ * the first ancestor which {@code isPaintingOrigin()} returns {@true},
+ * if there are any.
+ * <p/>
+ * {@code JComponent} subclasses that need to be repainted when any of their
+ * children are repainted should override this method to return {@code true}.
*
- * @return true if painting should originate from this Component or
- * one of its ancestors.
- */
- boolean isPaintingOrigin() {
+ * @return always returns {@code false}
+ */
+ protected boolean isPaintingOrigin() {
return false;
}
--- a/jdk/src/share/classes/javax/swing/JDialog.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/JDialog.java Sat Nov 13 18:56:50 2010 -0800
@@ -303,10 +303,9 @@
* @param modal specifies whether dialog blocks user input to other top-level
* windows when shown. If {@code true}, the modality type property is set to
* {@code DEFAULT_MODALITY_TYPE}, otherwise the dialog is modeless.
- * @param gc the {@code GraphicsConfiguration}
- * of the target screen device. If {@code gc} is
- * {@code null}, the same
- * {@code GraphicsConfiguration} as the owning Frame is used.
+ * @param gc the {@code GraphicsConfiguration} of the target screen device;
+ * if {@code null}, the default system {@code GraphicsConfiguration}
+ * is assumed
* @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()}
* returns {@code true}.
* @see java.awt.Dialog.ModalityType
@@ -441,10 +440,9 @@
* @param modal specifies whether dialog blocks user input to other top-level
* windows when shown. If {@code true}, the modality type property is set to
* {@code DEFAULT_MODALITY_TYPE}, otherwise the dialog is modeless
- * @param gc the {@code GraphicsConfiguration}
- * of the target screen device. If {@code gc} is
- * {@code null}, the same
- * {@code GraphicsConfiguration} as the owning Dialog is used.
+ * @param gc the {@code GraphicsConfiguration} of the target screen device;
+ * if {@code null}, the default system {@code GraphicsConfiguration}
+ * is assumed
* @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()}
* returns {@code true}.
* @see java.awt.Dialog.ModalityType
@@ -612,10 +610,8 @@
* windows when shown. {@code null} value and unsupported modality
* types are equivalent to {@code MODELESS}
* @param gc the {@code GraphicsConfiguration} of the target screen device;
- * if {@code null}, the {@code GraphicsConfiguration} from the owning
- * window is used; if {@code owner} is also {@code null}, the
- * system default {@code GraphicsConfiguration} is assumed
- *
+ * if {@code null}, the default system {@code GraphicsConfiguration}
+ * is assumed
* @throws IllegalArgumentException
* if the {@code owner} is not an instance of {@link java.awt.Dialog Dialog}
* or {@link java.awt.Frame Frame}
--- a/jdk/src/share/classes/javax/swing/JLayer.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/JLayer.java Sat Nov 13 18:56:50 2010 -0800
@@ -384,7 +384,7 @@
* @return true
* @see JComponent#isPaintingOrigin()
*/
- boolean isPaintingOrigin() {
+ protected boolean isPaintingOrigin() {
return true;
}
--- a/jdk/src/share/classes/javax/swing/JViewport.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/JViewport.java Sat Nov 13 18:56:50 2010 -0800
@@ -637,14 +637,14 @@
}
/**
- * Returns true if scroll mode is a BACKINGSTORE_SCROLL_MODE to cause
- * painting to originate from <code>JViewport</code>, or one of its
- * ancestors. Otherwise returns false.
+ * Returns true if scroll mode is a {@code BACKINGSTORE_SCROLL_MODE} to cause
+ * painting to originate from {@code JViewport}, or one of its
+ * ancestors. Otherwise returns {@code false}.
*
- * @return true if if scroll mode is a BACKINGSTORE_SCROLL_MODE.
+ * @return true if if scroll mode is a {@code BACKINGSTORE_SCROLL_MODE}.
* @see JComponent#isPaintingOrigin()
*/
- boolean isPaintingOrigin() {
+ protected boolean isPaintingOrigin() {
return scrollMode == BACKINGSTORE_SCROLL_MODE;
}
--- a/jdk/src/share/classes/javax/swing/RepaintManager.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/RepaintManager.java Sat Nov 13 18:56:50 2010 -0800
@@ -438,6 +438,7 @@
* @param y Y coordinate of the region to repaint
* @param w Width of the region to repaint
* @param h Height of the region to repaint
+ * @see JComponent#isPaintingOrigin()
* @see JComponent#repaint
*/
public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
@@ -447,6 +448,16 @@
delegate.addDirtyRegion(c, x, y, w, h);
return;
}
+ Container p = c;
+ while ((p = p.getParent()) instanceof JComponent) {
+ JComponent jp = (JComponent) p;
+ if (jp.isPaintingOrigin()) {
+ Rectangle rectangle = SwingUtilities.convertRectangle(
+ c, new Rectangle(x, y, w, h), jp);
+ jp.repaint(0, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+ return;
+ }
+ }
addDirtyRegion0(c, x, y, w, h);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/swing/border/StrokeBorder.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javax.swing.border;
+
+import java.awt.BasicStroke;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.beans.ConstructorProperties;
+
+/**
+ * A class which implements a border of an arbitrary stroke.
+ * <p>
+ * <strong>Warning:</strong>
+ * Serialized objects of this class will not be compatible with
+ * future Swing releases. The current serialization support is
+ * appropriate for short term storage or RMI
+ * between applications running the same version of Swing.
+ * As of 1.4, support for long term storage of all JavaBeans™
+ * has been added to the <code>java.beans</code> package.
+ * Please see {@link java.beans.XMLEncoder}.
+ *
+ * @author Sergey A. Malenkov
+ *
+ * @since 1.7
+ */
+public class StrokeBorder extends AbstractBorder {
+ private final BasicStroke stroke;
+ private final Paint paint;
+
+ /**
+ * Creates a border of the specified {@code stroke}.
+ * The component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ */
+ public StrokeBorder(BasicStroke stroke) {
+ this(stroke, null);
+ }
+
+ /**
+ * Creates a border of the specified {@code stroke} and {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @param paint the {@link Paint} object used to generate a color
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ */
+ @ConstructorProperties({ "stroke", "paint" })
+ public StrokeBorder(BasicStroke stroke, Paint paint) {
+ if (stroke == null) {
+ throw new NullPointerException("border's stroke");
+ }
+ this.stroke = stroke;
+ this.paint = paint;
+ }
+
+ /**
+ * Paints the border for the specified component
+ * with the specified position and size.
+ *
+ * @param c the component for which this border is being painted
+ * @param g the paint graphics
+ * @param x the x position of the painted border
+ * @param y the y position of the painted border
+ * @param width the width of the painted border
+ * @param height the height of the painted border
+ *
+ * @throws NullPointerException if the specified {@code c} or {@code g} are {@code null}
+ */
+ @Override
+ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+ float size = this.stroke.getLineWidth();
+ if (size > 0.0f) {
+ g = g.create();
+ if (g instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setStroke(this.stroke);
+ g2d.setPaint(this.paint != null ? this.paint : c.getForeground());
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.draw(new Rectangle2D.Float(x + size / 2, y + size / 2, width - size, height - size));
+ }
+ g.dispose();
+ }
+ }
+
+ /**
+ * Reinitializes the {@code insets} parameter
+ * with this border's current insets.
+ * All insets are equal to the line width of the stroke.
+ *
+ * @param c the component for which this border insets value applies
+ * @param insets the {@code Insets} object to be reinitialized
+ * @return the reinitialized {@code insets} parameter
+ *
+ * @throws NullPointerException if the specified {@code insets} is {@code null}
+ */
+ @Override
+ public Insets getBorderInsets(Component c, Insets insets) {
+ int size = (int) Math.ceil(this.stroke.getLineWidth());
+ insets.set(size, size, size, size);
+ return insets;
+ }
+
+ /**
+ * Returns the {@link BasicStroke} object used to stroke a shape
+ * during the border rendering.
+ *
+ * @return the {@link BasicStroke} object
+ */
+ public BasicStroke getStroke() {
+ return this.stroke;
+ }
+
+ /**
+ * Returns the {@link Paint} object used to generate a color
+ * during the border rendering.
+ *
+ * @return the {@link Paint} object or {@code null}
+ * if the {@code paint} parameter is not set
+ */
+ public Paint getPaint() {
+ return this.paint;
+ }
+}
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java Sat Nov 13 18:56:50 2010 -0800
@@ -362,6 +362,14 @@
* @since 1.6
*/
public int getBaseline(JComponent c, int width, int height) {
+ if (c == null) {
+ throw new NullPointerException("Component must be non-null");
+ }
+
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Width and height must be >= 0");
+ }
+
JViewport viewport = scrollpane.getViewport();
Insets spInsets = scrollpane.getInsets();
int y = spInsets.top;
--- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java Sat Nov 13 18:56:50 2010 -0800
@@ -115,10 +115,7 @@
return new SynthTabbedPaneUI();
}
- private SynthTabbedPaneUI() {
- }
-
- private boolean scrollableTabLayoutEnabled() {
+ private boolean scrollableTabLayoutEnabled() {
return (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT);
}
--- a/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java Sat Nov 13 18:56:50 2010 -0800
@@ -186,6 +186,9 @@
*/
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
+ if (table == null) {
+ return this;
+ }
Color fg = null;
Color bg = null;
--- a/jdk/src/share/classes/javax/swing/text/DefaultCaret.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/DefaultCaret.java Sat Nov 13 18:56:50 2010 -0800
@@ -1334,13 +1334,13 @@
&& component.getClientProperty("JPasswordField.cutCopyAllowed") !=
Boolean.TRUE) {
//fix for 4793761
- StringBuffer txt = null;
+ StringBuilder txt = null;
char echoChar = ((JPasswordField)component).getEchoChar();
int p0 = Math.min(getDot(), getMark());
int p1 = Math.max(getDot(), getMark());
for (int i = p0; i < p1; i++) {
if (txt == null) {
- txt = new StringBuffer();
+ txt = new StringBuilder();
}
txt.append(echoChar);
}
@@ -1675,7 +1675,6 @@
}
return;
}
- int adjust = 0;
int offset = e.getOffset();
int length = e.getLength();
int newDot = dot;
@@ -1759,7 +1758,6 @@
}
int offs0 = e.getOffset();
int offs1 = offs0 + e.getLength();
- int adjust = 0;
int newDot = dot;
boolean adjustDotBias = false;
int newMark = mark;
--- a/jdk/src/share/classes/javax/swing/text/DefaultStyledDocument.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/DefaultStyledDocument.java Sat Nov 13 18:56:50 2010 -0800
@@ -132,7 +132,7 @@
// install the content
Content c = getContent();
int n = data.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
ElementSpec es = data[i];
if (es.getLength() > 0) {
@@ -191,7 +191,7 @@
// install the content
Content c = getContent();
int n = data.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
ElementSpec es = data[i];
if (es.getLength() > 0) {
--- a/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java Sat Nov 13 18:56:50 2010 -0800
@@ -30,7 +30,6 @@
import java.text.AttributedCharacterIterator.Attribute;
import java.util.*;
import javax.swing.*;
-import javax.swing.text.*;
/**
* <code>InternationalFormatter</code> extends <code>DefaultFormatter</code>,
@@ -875,7 +874,6 @@
(f instanceof AttributedCharacterIterator.Attribute)) {
AttributedCharacterIterator.Attribute field =
(AttributedCharacterIterator.Attribute)f;
- int index = 0;
iterator.first();
while (iterator.getIndex() < start) {
--- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java Sat Nov 13 18:56:50 2010 -0800
@@ -35,10 +35,7 @@
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.*;
@@ -4058,7 +4055,7 @@
private static final Object KEYMAP_TABLE =
new StringBuilder("JTextComponent_KeymapTable");
- private JTextComponent editor;
+
//
// member variables used for on-the-spot input method
// editing style support
@@ -4748,14 +4745,14 @@
processKeyEvent(ke);
}
} else {
- StringBuffer strBuf = new StringBuffer();
+ StringBuilder strBuf = new StringBuilder();
for (char c = text.current(); commitCount > 0;
c = text.next(), commitCount--) {
strBuf.append(c);
}
// map it to an ActionEvent
- mapCommittedTextToAction(new String(strBuf));
+ mapCommittedTextToAction(strBuf.toString());
}
// Remember latest committed text end index
@@ -4801,7 +4798,7 @@
private void createComposedTextAttribute(int composedIndex,
AttributedCharacterIterator text) {
Document doc = getDocument();
- StringBuffer strBuf = new StringBuffer();
+ StringBuilder strBuf = new StringBuilder();
// create attributed string with no attributes
for (char c = text.setIndex(composedIndex);
@@ -4809,7 +4806,7 @@
strBuf.append(c);
}
- composedTextContent = new String(strBuf);
+ composedTextContent = strBuf.toString();
composedTextAttribute = new SimpleAttributeSet();
composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute,
new AttributedString(text, composedIndex, text.getEndIndex()));
--- a/jdk/src/share/classes/javax/swing/text/MaskFormatter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/MaskFormatter.java Sat Nov 13 18:56:50 2010 -0800
@@ -29,7 +29,6 @@
import java.text.*;
import java.util.*;
import javax.swing.*;
-import javax.swing.text.*;
/**
* <code>MaskFormatter</code> is used to format and edit strings. The behavior
@@ -385,7 +384,7 @@
*/
public String valueToString(Object value) throws ParseException {
String sValue = (value == null) ? "" : value.toString();
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
String placeholder = getPlaceholder();
int[] valueCounter = { 0 };
@@ -484,7 +483,7 @@
* Invokes <code>append</code> on the mask characters in
* <code>mask</code>.
*/
- private void append(StringBuffer result, String value, int[] index,
+ private void append(StringBuilder result, String value, int[] index,
String placeholder, MaskCharacter[] mask)
throws ParseException {
for (int counter = 0, maxCounter = mask.length;
@@ -611,13 +610,13 @@
* Removes the literal characters from the passed in string.
*/
private String stripLiteralChars(String string) {
- StringBuffer sb = null;
+ StringBuilder sb = null;
int last = 0;
for (int counter = 0, max = string.length(); counter < max; counter++){
if (isLiteral(counter)) {
if (sb == null) {
- sb = new StringBuffer();
+ sb = new StringBuilder();
if (counter > 0) {
sb.append(string.substring(0, counter));
}
@@ -715,10 +714,10 @@
*/
boolean canReplace(ReplaceHolder rh) {
// This method is rather long, but much of the burden is in
- // maintaining a String and swapping to a StringBuffer only if
+ // maintaining a String and swapping to a StringBuilder only if
// absolutely necessary.
if (!getAllowsInvalid()) {
- StringBuffer replace = null;
+ StringBuilder replace = null;
String text = rh.text;
int tl = (text != null) ? text.length() : 0;
@@ -737,7 +736,7 @@
char aChar = text.charAt(textIndex);
if (aChar != getCharacter(rh.offset + counter, aChar)) {
if (replace == null) {
- replace = new StringBuffer();
+ replace = new StringBuilder();
if (textIndex > 0) {
replace.append(text.substring(0, textIndex));
}
@@ -758,7 +757,7 @@
}
}
else if (textIndex > 0) {
- replace = new StringBuffer(max);
+ replace = new StringBuilder(max);
replace.append(text.substring(0, textIndex));
replace.append(getLiteral(rh.offset + counter));
if (textIndex < tl) {
@@ -780,7 +779,7 @@
else if (textIndex >= tl) {
// placeholder
if (replace == null) {
- replace = new StringBuffer();
+ replace = new StringBuilder();
if (text != null) {
replace.append(text);
}
@@ -863,7 +862,7 @@
* Appends the necessary character in <code>formatting</code> at
* <code>index</code> to <code>buff</code>.
*/
- public void append(StringBuffer buff, String formatting, int[] index,
+ public void append(StringBuilder buff, String formatting, int[] index,
String placeholder)
throws ParseException {
boolean inString = index[0] < formatting.length();
--- a/jdk/src/share/classes/javax/swing/text/NumberFormatter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/NumberFormatter.java Sat Nov 13 18:56:50 2010 -0800
@@ -27,7 +27,6 @@
import java.lang.reflect.*;
import java.text.*;
import java.util.*;
-import javax.swing.text.*;
/**
* <code>NumberFormatter</code> subclasses <code>InternationalFormatter</code>
@@ -132,7 +131,7 @@
DecimalFormatSymbols dfs = getDecimalFormatSymbols();
if (dfs != null) {
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append(dfs.getCurrencySymbol());
sb.append(dfs.getDecimalSeparator());
@@ -240,13 +239,6 @@
}
/**
- */
- private boolean isValidInsertionCharacter(char aChar) {
- return (Character.isDigit(aChar) || specialChars.indexOf(aChar) != -1);
- }
-
-
- /**
* Subclassed to return false if <code>text</code> contains in an invalid
* character to insert, that is, it is not a digit
* (<code>Character.isDigit()</code>) and
@@ -403,28 +395,6 @@
}
/**
- * Returns true if the range offset to length identifies the only
- * integer field.
- */
- private boolean isOnlyIntegerField(int offset, int length) {
- if (isValidMask()) {
- int start = getAttributeStart(NumberFormat.Field.INTEGER);
-
- if (start != -1) {
- AttributedCharacterIterator iterator = getIterator();
-
- iterator.setIndex(start);
- if (offset > start || iterator.getRunLimit(
- NumberFormat.Field.INTEGER) > (offset + length)) {
- return false;
- }
- return true;
- }
- }
- return false;
- }
-
- /**
* Invoked to toggle the sign. For this to work the value class
* must have a single arg constructor that takes a String.
*/
--- a/jdk/src/share/classes/javax/swing/text/PlainDocument.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/PlainDocument.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,7 +25,6 @@
package javax.swing.text;
import java.util.Vector;
-import javax.swing.event.*;
/**
* A plain document that maintains no character attributes. The
@@ -118,7 +117,7 @@
Object filterNewlines = getProperty("filterNewlines");
if ((filterNewlines instanceof Boolean) && filterNewlines.equals(Boolean.TRUE)) {
if ((str != null) && (str.indexOf('\n') >= 0)) {
- StringBuffer filtered = new StringBuffer(str);
+ StringBuilder filtered = new StringBuilder(str);
int n = filtered.length();
for (int i = 0; i < n; i++) {
if (filtered.charAt(i) == '\n') {
@@ -204,11 +203,9 @@
}
}
if (hasBreaks) {
- int rmCount = 1;
removed.addElement(rmCandidate);
if ((offset + length == rmOffs1) && (lastOffset != rmOffs1) &&
((index+1) < lineMap.getElementCount())) {
- rmCount += 1;
Element e = lineMap.getElement(index+1);
removed.addElement(e);
rmOffs1 = e.getEndOffset();
--- a/jdk/src/share/classes/javax/swing/text/TabSet.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/TabSet.java Sat Nov 13 18:56:50 2010 -0800
@@ -199,7 +199,7 @@
*/
public String toString() {
int tabCount = getTabCount();
- StringBuffer buffer = new StringBuffer("[ ");
+ StringBuilder buffer = new StringBuilder("[ ");
for(int counter = 0; counter < tabCount; counter++) {
if(counter > 0)
--- a/jdk/src/share/classes/javax/swing/text/html/FormView.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/html/FormView.java Sat Nov 13 18:56:50 2010 -0800
@@ -362,7 +362,7 @@
*/
public void actionPerformed(ActionEvent evt) {
Element element = getElement();
- StringBuffer dataBuffer = new StringBuffer();
+ StringBuilder dataBuffer = new StringBuilder();
HTMLDocument doc = (HTMLDocument)getDocument();
AttributeSet attr = element.getAttributes();
@@ -508,7 +508,7 @@
*/
protected void imageSubmit(String imageData) {
- StringBuffer dataBuffer = new StringBuffer();
+ StringBuilder dataBuffer = new StringBuilder();
Element elem = getElement();
HTMLDocument hdoc = (HTMLDocument)elem.getDocument();
getFormData(dataBuffer);
@@ -589,7 +589,7 @@
* @param targetElement the element that triggered the
* form submission
*/
- void getFormData(StringBuffer buffer) {
+ private void getFormData(StringBuilder buffer) {
Element formE = getFormElement();
if (formE != null) {
ElementIterator it = new ElementIterator(formE);
@@ -623,7 +623,7 @@
* data is loaded in name/value pairs.
*
*/
- private void loadElementDataIntoBuffer(Element elem, StringBuffer buffer) {
+ private void loadElementDataIntoBuffer(Element elem, StringBuilder buffer) {
AttributeSet attr = elem.getAttributes();
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
@@ -692,29 +692,6 @@
}
if (path != null && path.length() > 0) {
value = path;
-/*
-
- try {
- Reader reader = new BufferedReader(new FileReader(path));
- StringBuffer buffer = new StringBuffer();
- char[] cBuff = new char[1024];
- int read;
-
- try {
- while ((read = reader.read(cBuff)) != -1) {
- buffer.append(cBuff, 0, read);
- }
- } catch (IOException ioe) {
- buffer = null;
- }
- try {
- reader.close();
- } catch (IOException ioe) {}
- if (buffer != null) {
- value = buffer.toString();
- }
- } catch (IOException ioe) {}
-*/
}
}
return value;
@@ -740,7 +717,7 @@
* form element. Basically, only items that are selected
* and have their name attribute set are added to the buffer.
*/
- private void loadSelectData(AttributeSet attr, StringBuffer buffer) {
+ private void loadSelectData(AttributeSet attr, StringBuilder buffer) {
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
if (name == null) {
@@ -771,7 +748,7 @@
* URLEncoder.encode() method before being added to the
* buffer.
*/
- private void appendBuffer(StringBuffer buffer, String name, String value) {
+ private void appendBuffer(StringBuilder buffer, String name, String value) {
if (buffer.length() > 0) {
buffer.append('&');
}
--- a/jdk/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java Sat Nov 13 18:56:50 2010 -0800
@@ -691,11 +691,11 @@
if (styleNameMapping == null) {
return style;
}
- StringBuffer sb = null;
+ StringBuilder sb = null;
for (int counter = style.length() - 1; counter >= 0; counter--) {
if (!isValidCharacter(style.charAt(counter))) {
if (sb == null) {
- sb = new StringBuffer(style);
+ sb = new StringBuilder(style);
}
sb.setCharAt(counter, 'a');
}
--- a/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/html/StyleSheet.java Sat Nov 13 18:56:50 2010 -0800
@@ -998,7 +998,7 @@
void addRule(String[] selector, AttributeSet declaration,
boolean isLinked) {
int n = selector.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append(selector[0]);
for (int counter = 1; counter < n; counter++) {
sb.append(' ');
--- a/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java Sat Nov 13 18:56:50 2010 -0800
@@ -1470,7 +1470,7 @@
*/
public String parseDTDMarkup() throws IOException {
- StringBuffer strBuff = new StringBuffer();
+ StringBuilder strBuff = new StringBuilder();
ch = readCh();
while(true) {
switch (ch) {
--- a/jdk/src/share/classes/javax/swing/text/rtf/AbstractFilter.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/javax/swing/text/rtf/AbstractFilter.java Sat Nov 13 18:56:50 2010 -0800
@@ -160,7 +160,7 @@
public void write(byte[] buf, int off, int len)
throws IOException
{
- StringBuffer accumulator = null;
+ StringBuilder accumulator = null;
while (len > 0) {
short b = (short)buf[off];
@@ -178,7 +178,7 @@
char ch = translationTable[b];
if (ch != (char)0) {
if (accumulator == null)
- accumulator = new StringBuffer();
+ accumulator = new StringBuilder();
accumulator.append(ch);
}
}
--- a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java Sat Nov 13 18:56:50 2010 -0800
@@ -48,8 +48,6 @@
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
// Constructors in this class *must* be package scoped or private.
- // Exception: JavaMethodHandle constructors are protected.
- // (The link between JMH and BMH is temporary.)
/** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static.
@@ -122,55 +120,6 @@
assert(this instanceof JavaMethodHandle);
}
- /** Initialize the current object as a Java method handle.
- */
- protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) {
- super(Access.TOKEN, null);
- MethodHandle entryPoint
- = findJavaMethodHandleEntryPoint(this.getClass(),
- entryPointName, type, matchArity);
- MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1));
- this.argument = this; // kludge; get rid of
- this.vmargslot = this.type().parameterSlotDepth(0);
- initTarget(entryPoint, 0);
- assert(this instanceof JavaMethodHandle);
- }
-
- private static
- MethodHandle findJavaMethodHandleEntryPoint(Class<?> caller,
- String name,
- MethodType type,
- boolean matchArity) {
- if (matchArity) type.getClass(); // elicit NPE
- List<MemberName> methods = IMPL_NAMES.getMethods(caller, true, name, null, caller);
- MethodType foundType = null;
- MemberName foundMethod = null;
- for (MemberName method : methods) {
- if (method.getDeclaringClass() == MethodHandle.class)
- continue; // ignore methods inherited from MH class itself
- MethodType mtype = method.getMethodType();
- if (type != null && type.parameterCount() != mtype.parameterCount())
- continue;
- else if (foundType == null)
- foundType = mtype;
- else if (foundType != mtype)
- throw newIllegalArgumentException("more than one method named "+name+" in "+caller.getName());
- // discard overrides
- if (foundMethod == null)
- foundMethod = method;
- else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass()))
- foundMethod = method;
- }
- if (foundMethod == null)
- throw newIllegalArgumentException("no method named "+name+" in "+caller.getName());
- MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller);
- if (type != null) {
- MethodType epType = type.insertParameterTypes(0, entryPoint.type().parameterType(0));
- entryPoint = MethodHandles.convertArguments(entryPoint, epType);
- }
- return entryPoint;
- }
-
/** Make sure the given {@code argument} can be used as {@code argnum}-th
* parameter of the given method handle {@code mh}, which must be a reference.
* <p>
--- a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java Sat Nov 13 18:56:50 2010 -0800
@@ -26,6 +26,7 @@
package sun.dyn;
import java.dyn.*;
+import static sun.dyn.MemberName.uncaughtException;
/**
* Parts of CallSite known to the JVM.
@@ -49,18 +50,21 @@
}
CallSite site;
try {
- if (bootstrapMethod.type().parameterCount() == 3)
- site = bootstrapMethod.<CallSite>invokeExact(caller, name, type);
- else if (bootstrapMethod.type().parameterCount() == 4)
- site = bootstrapMethod.<CallSite>invokeExact(caller, name, type,
- !(info instanceof java.lang.annotation.Annotation[]) ? null
- : (java.lang.annotation.Annotation[]) info);
+ Object binding;
+ if (false) // switch when invokeGeneric works
+ binding = bootstrapMethod.invokeGeneric(caller, name, type);
else
- throw new InternalError("bad BSM: "+bootstrapMethod);
- if (!(site instanceof CallSite))
- throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
- PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site,
- name, type,
+ binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
+ //System.out.println("BSM for "+name+type+" => "+binding);
+ if (binding instanceof CallSite) {
+ site = (CallSite) binding;
+ } else if (binding instanceof MethodHandleProvider) {
+ MethodHandle target = ((MethodHandleProvider) binding).asMethodHandle();
+ site = new ConstantCallSite(target);
+ } else {
+ throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
+ }
+ PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site, name, type,
callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
@@ -77,11 +81,18 @@
// This method is private in CallSite because it touches private fields in CallSite.
// These private fields (vmmethod, vmindex) are specific to the JVM.
- private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
+ private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
+ static {
+ try {
+ PRIVATE_INITIALIZE_CALL_SITE =
MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM",
MethodType.methodType(void.class,
String.class, MethodType.class,
MemberName.class, int.class));
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
+ }
+ }
public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) {
Access.check(token);
--- a/jdk/src/share/classes/sun/dyn/FilterGeneric.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/FilterGeneric.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,12 +25,8 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodType;
-import java.dyn.NoAccessException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+import java.dyn.*;
+import java.lang.reflect.*;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
@@ -119,7 +115,7 @@
static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) {
FilterGeneric fgen = of(kind, pos, filter.type(), target.type());
- return fgen.makeInstance(kind, pos, filter, target);
+ return fgen.makeInstance(kind, pos, filter, target).asMethodHandle();
}
/** Return the adapter information for this target and filter type. */
--- a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/FilterOneArgument.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,9 +25,8 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodType;
+import java.dyn.*;
+import static sun.dyn.MemberName.uncaughtException;
/**
* Unary function composition, useful for many small plumbing jobs.
@@ -51,8 +50,16 @@
return target.invokeExact(filteredArgument);
}
- private static final MethodHandle INVOKE =
- MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.genericMethodType(1));
+ private static final MethodHandle INVOKE;
+ static {
+ try {
+ INVOKE =
+ MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke",
+ MethodType.genericMethodType(1));
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
+ }
+ }
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
super(INVOKE);
--- a/jdk/src/share/classes/sun/dyn/FromGeneric.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/FromGeneric.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,15 +25,9 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
-import java.dyn.MethodType;
-import java.dyn.NoAccessException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import sun.dyn.util.ValueConversions;
-import sun.dyn.util.Wrapper;
+import java.dyn.*;
+import java.lang.reflect.*;
+import sun.dyn.util.*;
/**
* Adapters which mediate between incoming calls which are generic
--- a/jdk/src/share/classes/sun/dyn/Invokers.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/Invokers.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,10 +25,7 @@
package sun.dyn;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
-import java.dyn.MethodType;
-
+import java.dyn.*;
/**
* Construction and caching of often-used invokers.
@@ -63,8 +60,11 @@
public MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
- invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType);
- if (invoker == null) throw new InternalError("JVM cannot find invoker for "+targetType);
+ try {
+ invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invoke", targetType);
+ } catch (NoAccessException ex) {
+ throw new InternalError("JVM cannot find invoker for "+targetType);
+ }
assert(invokerType(targetType) == invoker.type());
exactInvoker = invoker;
return invoker;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/dyn/JavaMethodHandle.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.dyn;
+
+import java.dyn.*;
+import sun.dyn.Access;
+
+/**
+ * A Java method handle is a deprecated proposal for extending
+ * the basic method handle type with additional
+ * programmer defined methods and fields.
+ * Its behavior as a method handle is determined at instance creation time,
+ * by providing the new instance with an "entry point" method handle
+ * to handle calls. This entry point must accept a leading argument
+ * whose type is the Java method handle itself or a supertype, and the
+ * entry point is always called with the Java method handle itself as
+ * the first argument. This is similar to ordinary virtual methods, which also
+ * accept the receiver object {@code this} as an implicit leading argument.
+ * The {@code MethodType} of the Java method handle is the same as that
+ * of the entry point method handle, with the leading parameter type
+ * omitted.
+ * <p>
+ * Here is an example of usage, creating a hybrid object/functional datum:
+ * <p><blockquote><pre>
+ * class Greeter extends JavaMethodHandle {
+ * private String greeting = "hello";
+ * public void setGreeting(String s) { greeting = s; }
+ * public void run() { System.out.println(greeting+", "+greetee); }
+ * private final String greetee;
+ * Greeter(String greetee) {
+ * super(RUN); // alternatively, super("run")
+ * this.greetee = greetee;
+ * }
+ * // the entry point function is computed once:
+ * private static final MethodHandle RUN
+ * = MethodHandles.lookup().findVirtual(Greeter.class, "run",
+ * MethodType.make(void.class));
+ * }
+ * // class Main { public static void main(String... av) { ...
+ * Greeter greeter = new Greeter("world");
+ * greeter.run(); // prints "hello, world"
+ * // Statically typed method handle invocation (most direct):
+ * MethodHandle mh = greeter;
+ * mh.<void>invokeExact(); // also prints "hello, world"
+ * // Dynamically typed method handle invocation:
+ * MethodHandles.invokeExact(greeter); // also prints "hello, world"
+ * greeter.setGreeting("howdy");
+ * mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
+ * </pre></blockquote>
+ * <p>
+ * In the example of {@code Greeter}, the method {@code run} provides the entry point.
+ * The entry point need not be a constant value; it may be independently
+ * computed in each call to the constructor. The entry point does not
+ * even need to be a method on the {@code Greeter} class, though
+ * that is the typical case.
+ * <p>
+ * The entry point may also be provided symbolically, in which case the the
+ * {@code JavaMethodHandle} constructor performs the lookup of the entry point.
+ * This makes it possible to use {@code JavaMethodHandle} to create an anonymous
+ * inner class:
+ * <p><blockquote><pre>
+ * // We can also do this with symbolic names and/or inner classes:
+ * MethodHandles.invokeExact(new JavaMethodHandle("yow") {
+ * void yow() { System.out.println("yow, world"); }
+ * });
+ * </pre></blockquote>
+ * <p>
+ * Here is similar lower-level code which works in terms of a bound method handle.
+ * <p><blockquote><pre>
+ * class Greeter {
+ * public void run() { System.out.println("hello, "+greetee); }
+ * private final String greetee;
+ * Greeter(String greetee) { this.greetee = greetee; }
+ * // the entry point function is computed once:
+ * private static final MethodHandle RUN
+ * = MethodHandles.findVirtual(Greeter.class, "run",
+ * MethodType.make(void.class));
+ * }
+ * // class Main { public static void main(String... av) { ...
+ * Greeter greeter = new Greeter("world");
+ * greeter.run(); // prints "hello, world"
+ * MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
+ * mh.invokeExact(); // also prints "hello, world"
+ * </pre></blockquote>
+ * Note that the method handle must be separately created as a view on the base object.
+ * This increases footprint, complexity, and dynamic indirections.
+ * <p>
+ * Here is a pure functional value expressed most concisely as an anonymous inner class:
+ * <p><blockquote><pre>
+ * // class Main { public static void main(String... av) { ...
+ * final String greetee = "world";
+ * MethodHandle greeter = new JavaMethodHandle("run") {
+ * private void run() { System.out.println("hello, "+greetee); }
+ * }
+ * greeter.invokeExact(); // prints "hello, world"
+ * </pre></blockquote>
+ * <p>
+ * Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
+ * and instantiated as an anonymous class. The data structure is a handle to 1-D array,
+ * with a specialized index type (long). It is created by inner class, and uses
+ * signature-polymorphic APIs throughout.
+ * <p><blockquote><pre>
+ * abstract class AssignableMethodHandle extends JavaMethodHandle {
+ * private final MethodHandle setter;
+ * public MethodHandle setter() { return setter; }
+ * public AssignableMethodHandle(String get, String set) {
+ * super(get);
+ * MethodType getType = this.type();
+ * MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
+ * this.setter = MethodHandles.publicLookup().bind(this, set, setType);
+ * }
+ * }
+ * // class Main { public static void main(String... av) { ...
+ * final Number[] stuff = { 123, 456 };
+ * AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
+ * public Number get(long i) { return stuff[(int)i]; }
+ * public void set(long i, Object x) { stuff[(int)i] = x; }
+ * }
+ * int x = (Integer) stuffPtr.<Number>invokeExact(1L); // 456
+ * stuffPtr.setter().<void>invokeExact(0L, (Number) 789); // replaces 123 with 789
+ * </pre></blockquote>
+ * @see MethodHandle
+ * @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
+ * an interface-based API for mixing method handle behavior with other classes.
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class JavaMethodHandle
+ // Note: This is an implementation inheritance hack, and will be removed
+ // with a JVM change which moves the required hidden behavior onto this class.
+ extends sun.dyn.BoundMethodHandle
+{
+ private static final Access IMPL_TOKEN = Access.getToken();
+
+ /**
+ * When creating a {@code JavaMethodHandle}, the actual method handle
+ * invocation behavior will be delegated to the specified {@code entryPoint}.
+ * This may be any method handle which can take the newly constructed object
+ * as a leading parameter.
+ * <p>
+ * The method handle type of {@code this} (i.e, the fully constructed object)
+ * will be {@code entryPoint}, minus the leading argument.
+ * The leading argument will be bound to {@code this} on every method
+ * handle invocation.
+ * @param entryPoint the method handle to handle calls
+ */
+ protected JavaMethodHandle(MethodHandle entryPoint) {
+ super(entryPoint);
+ }
+}
--- a/jdk/src/share/classes/sun/dyn/MemberName.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/MemberName.java Sat Nov 13 18:56:50 2010 -0800
@@ -521,6 +521,11 @@
if (lookupClass != null) message += ", from " + lookupClass.getName();
return new NoAccessException(message);
}
+ public static Error uncaughtException(Exception ex) {
+ Error err = new InternalError("uncaught exception");
+ err.initCause(ex);
+ return err;
+ }
/** Actually making a query requires an access check. */
public static Factory getFactory(Access token) {
@@ -641,7 +646,7 @@
* If lookup fails or access is not permitted, a {@linkplain NoAccessException} is thrown.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
- public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass) {
+ public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass) throws NoAccessException {
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
--- a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,11 +25,8 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
+import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
-import java.dyn.MethodType;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.dyn.util.VerifyType;
@@ -46,6 +43,7 @@
import sun.misc.Unsafe;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
+import static sun.dyn.MemberName.uncaughtException;
/**
* Base class for method handles, containing JVM-specific fields and logic.
@@ -173,7 +171,7 @@
*/
public static
MethodHandle findMethod(Access token, MemberName method,
- boolean doDispatch, Class<?> lookupClass) {
+ boolean doDispatch, Class<?> lookupClass) throws NoAccessException {
Access.check(token); // only trusted calls
MethodType mtype = method.getMethodType();
if (!method.isStatic()) {
@@ -320,7 +318,7 @@
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
// Corresponding generic constructor types:
@@ -416,9 +414,7 @@
f = c.getDeclaredField(field.getName());
return unsafe.staticFieldBase(f);
} catch (Exception ee) {
- Error e = new InternalError();
- e.initCause(ee);
- throw e;
+ throw uncaughtException(ee);
}
}
@@ -473,10 +469,8 @@
MethodHandle mh;
try {
mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
- } catch (NoAccessException ee) {
- Error e = new InternalError("name,type="+name+type);
- e.initCause(ee);
- throw e;
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
}
if (evclass != vclass || (!isStatic && ecclass != cclass)) {
MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
@@ -543,10 +537,8 @@
MethodHandle mh;
try {
mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
- } catch (NoAccessException ee) {
- Error e = new InternalError("name,type="+name+type);
- e.initCause(ee);
- throw e;
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
}
if (caclass != null) {
MethodType strongType = FieldAccessor.atype(caclass, isSetter);
@@ -1031,7 +1023,7 @@
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
}
@@ -1167,7 +1159,7 @@
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
}
@@ -1207,9 +1199,16 @@
return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION);
}
- static final MethodHandle THROW_EXCEPTION
+ static final MethodHandle THROW_EXCEPTION;
+ static {
+ try {
+ THROW_EXCEPTION
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
MethodType.methodType(Empty.class, Throwable.class));
+ } catch (NoAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
public static String getNameString(Access token, MethodHandle target) {
--- a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,9 +25,7 @@
package sun.dyn;
-import java.dyn.CallSite;
-import java.dyn.MethodHandle;
-import java.dyn.MethodType;
+import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
@@ -324,18 +322,24 @@
*/
static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
Class<?> defc, String name, Object type) {
- Lookup lookup = IMPL_LOOKUP.in(callerClass);
- switch (refKind) {
- case REF_getField: return lookup.findGetter( defc, name, (Class<?>) type );
- case REF_getStatic: return lookup.findStaticGetter( defc, name, (Class<?>) type );
- case REF_putField: return lookup.findSetter( defc, name, (Class<?>) type );
- case REF_putStatic: return lookup.findStaticSetter( defc, name, (Class<?>) type );
- case REF_invokeVirtual: return lookup.findVirtual( defc, name, (MethodType) type );
- case REF_invokeStatic: return lookup.findStatic( defc, name, (MethodType) type );
- case REF_invokeSpecial: return lookup.findSpecial( defc, name, (MethodType) type, callerClass );
- case REF_newInvokeSpecial: return lookup.findConstructor( defc, (MethodType) type );
- case REF_invokeInterface: return lookup.findVirtual( defc, name, (MethodType) type );
+ try {
+ Lookup lookup = IMPL_LOOKUP.in(callerClass);
+ switch (refKind) {
+ case REF_getField: return lookup.findGetter( defc, name, (Class<?>) type );
+ case REF_getStatic: return lookup.findStaticGetter( defc, name, (Class<?>) type );
+ case REF_putField: return lookup.findSetter( defc, name, (Class<?>) type );
+ case REF_putStatic: return lookup.findStaticSetter( defc, name, (Class<?>) type );
+ case REF_invokeVirtual: return lookup.findVirtual( defc, name, (MethodType) type );
+ case REF_invokeStatic: return lookup.findStatic( defc, name, (MethodType) type );
+ case REF_invokeSpecial: return lookup.findSpecial( defc, name, (MethodType) type, callerClass );
+ case REF_newInvokeSpecial: return lookup.findConstructor( defc, (MethodType) type );
+ case REF_invokeInterface: return lookup.findVirtual( defc, name, (MethodType) type );
+ }
+ throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
+ } catch (NoAccessException ex) {
+ Error err = new IncompatibleClassChangeError();
+ err.initCause(ex);
+ throw err;
}
- throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
}
}
--- a/jdk/src/share/classes/sun/dyn/SpreadGeneric.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/SpreadGeneric.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,11 +25,7 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
-import java.dyn.MethodType;
-import java.dyn.NoAccessException;
+import java.dyn.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
--- a/jdk/src/share/classes/sun/dyn/ToGeneric.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/ToGeneric.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,11 +25,7 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
-import java.dyn.MethodType;
-import java.dyn.NoAccessException;
+import java.dyn.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import sun.dyn.util.ValueConversions;
--- a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/dyn/util/ValueConversions.java Sat Nov 13 18:56:50 2010 -0800
@@ -34,6 +34,7 @@
import sun.dyn.Access;
import sun.dyn.AdapterMethodHandle;
import sun.dyn.MethodHandleImpl;
+import static sun.dyn.MemberName.uncaughtException;
public class ValueConversions {
private static final Access IMPL_TOKEN = Access.getToken();
@@ -148,11 +149,16 @@
// look up the method
String name = "unbox" + wrap.simpleName() + (raw ? "Raw" : "");
MethodType type = unboxType(wrap, raw);
- if (!exact)
- // actually, type is wrong; the Java method takes Object
- mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type.erase());
- else
+ if (!exact) {
+ try {
+ // actually, type is wrong; the Java method takes Object
+ mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type.erase());
+ } catch (NoAccessException ex) {
+ mh = null;
+ }
+ } else {
mh = retype(type, unbox(wrap, !exact, raw));
+ }
if (mh != null) {
cache.put(wrap, mh);
return mh;
@@ -280,10 +286,15 @@
// look up the method
String name = "box" + wrap.simpleName() + (raw ? "Raw" : "");
MethodType type = boxType(wrap, raw);
- if (exact)
- mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
- else
+ if (exact) {
+ try {
+ mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
+ } catch (NoAccessException ex) {
+ mh = null;
+ }
+ } else {
mh = retype(type.erase(), box(wrap, !exact, raw));
+ }
if (mh != null) {
cache.put(wrap, mh);
return mh;
@@ -394,10 +405,15 @@
// look up the method
String name = "reboxRaw" + wrap.simpleName();
MethodType type = reboxType(wrap);
- if (exact)
- mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
- else
+ if (exact) {
+ try {
+ mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
+ } catch (NoAccessException ex) {
+ mh = null;
+ }
+ } else {
mh = retype(IDENTITY.type(), rebox(wrap, !exact));
+ }
if (mh != null) {
cache.put(wrap, mh);
return mh;
@@ -474,7 +490,11 @@
mh = EMPTY;
break;
case INT: case LONG: case FLOAT: case DOUBLE:
- mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "zero"+wrap.simpleName(), type);
+ try {
+ mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "zero"+wrap.simpleName(), type);
+ } catch (NoAccessException ex) {
+ mh = null;
+ }
break;
}
if (mh != null) {
@@ -549,8 +569,8 @@
ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType);
IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1));
- } catch (RuntimeException ex) {
- throw ex;
+ } catch (Exception ex) {
+ throw uncaughtException(ex);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/pisces/Curve.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.pisces;
+
+import java.util.Iterator;
+
+class Curve {
+
+ float ax, ay, bx, by, cx, cy, dx, dy;
+ float dax, day, dbx, dby;
+
+ Curve() {
+ }
+
+ void set(float[] points, int type) {
+ switch(type) {
+ case 8:
+ set(points[0], points[1],
+ points[2], points[3],
+ points[4], points[5],
+ points[6], points[7]);
+ break;
+ case 6:
+ set(points[0], points[1],
+ points[2], points[3],
+ points[4], points[5]);
+ break;
+ default:
+ throw new InternalError("Curves can only be cubic or quadratic");
+ }
+ }
+
+ void set(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ {
+ ax = 3 * (x2 - x3) + x4 - x1;
+ ay = 3 * (y2 - y3) + y4 - y1;
+ bx = 3 * (x1 - 2 * x2 + x3);
+ by = 3 * (y1 - 2 * y2 + y3);
+ cx = 3 * (x2 - x1);
+ cy = 3 * (y2 - y1);
+ dx = x1;
+ dy = y1;
+ dax = 3 * ax; day = 3 * ay;
+ dbx = 2 * bx; dby = 2 * by;
+ }
+
+ void set(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ ax = ay = 0f;
+
+ bx = x1 - 2 * x2 + x3;
+ by = y1 - 2 * y2 + y3;
+ cx = 2 * (x2 - x1);
+ cy = 2 * (y2 - y1);
+ dx = x1;
+ dy = y1;
+ dax = 0; day = 0;
+ dbx = 2 * bx; dby = 2 * by;
+ }
+
+ float xat(float t) {
+ return t * (t * (t * ax + bx) + cx) + dx;
+ }
+ float yat(float t) {
+ return t * (t * (t * ay + by) + cy) + dy;
+ }
+
+ float dxat(float t) {
+ return t * (t * dax + dbx) + cx;
+ }
+
+ float dyat(float t) {
+ return t * (t * day + dby) + cy;
+ }
+
+ private float ddxat(float t) {
+ return 2 * dax * t + dbx;
+ }
+
+ private float ddyat(float t) {
+ return 2 * day * t + dby;
+ }
+
+ int dxRoots(float[] roots, int off) {
+ return Helpers.quadraticRoots(dax, dbx, cx, roots, off);
+ }
+
+ int dyRoots(float[] roots, int off) {
+ return Helpers.quadraticRoots(day, dby, cy, roots, off);
+ }
+
+ int infPoints(float[] pts, int off) {
+ // inflection point at t if -f'(t)x*f''(t)y + f'(t)y*f''(t)x == 0
+ // Fortunately, this turns out to be quadratic, so there are at
+ // most 2 inflection points.
+ final float a = dax * dby - dbx * day;
+ final float b = 2 * (cy * dax - day * cx);
+ final float c = cy * dbx - cx * dby;
+
+ return Helpers.quadraticRoots(a, b, c, pts, off);
+ }
+
+ // finds points where the first and second derivative are
+ // perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
+ // * is a dot product). Unfortunately, we have to solve a cubic.
+ private int perpendiculardfddf(float[] pts, int off, final float err) {
+ assert pts.length >= off + 4;
+
+ // these are the coefficients of g(t):
+ final float a = 2*(dax*dax + day*day);
+ final float b = 3*(dax*dbx + day*dby);
+ final float c = 2*(dax*cx + day*cy) + dbx*dbx + dby*dby;
+ final float d = dbx*cx + dby*cy;
+ // TODO: We might want to divide the polynomial by a to make the
+ // coefficients smaller. This won't change the roots.
+ return Helpers.cubicRootsInAB(a, b, c, d, pts, off, err, 0f, 1f);
+ }
+
+ // Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
+ // a variant of the false position algorithm to find the roots. False
+ // position requires that 2 initial values x0,x1 be given, and that the
+ // function must have opposite signs at those values. To find such
+ // values, we need the local extrema of the ROC function, for which we
+ // need the roots of its derivative; however, it's harder to find the
+ // roots of the derivative in this case than it is to find the roots
+ // of the original function. So, we find all points where this curve's
+ // first and second derivative are perpendicular, and we pretend these
+ // are our local extrema. There are at most 3 of these, so we will check
+ // at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
+ // points, so roc-w can have at least 6 roots. This shouldn't be a
+ // problem for what we're trying to do (draw a nice looking curve).
+ int rootsOfROCMinusW(float[] roots, int off, final float w, final float err) {
+ // no OOB exception, because by now off<=6, and roots.length >= 10
+ assert off <= 6 && roots.length >= 10;
+ int ret = off;
+ int numPerpdfddf = perpendiculardfddf(roots, off, err);
+ float t0 = 0, ft0 = ROCsq(t0) - w*w;
+ roots[off + numPerpdfddf] = 1f; // always check interval end points
+ numPerpdfddf++;
+ for (int i = off; i < off + numPerpdfddf; i++) {
+ float t1 = roots[i], ft1 = ROCsq(t1) - w*w;
+ if (ft0 == 0f) {
+ roots[ret++] = t0;
+ } else if (ft1 * ft0 < 0f) { // have opposite signs
+ // (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
+ // ROC(t) >= 0 for all t.
+ roots[ret++] = falsePositionROCsqMinusX(t0, t1, w*w, err);
+ }
+ t0 = t1;
+ ft0 = ft1;
+ }
+
+ return ret - off;
+ }
+
+ private static float eliminateInf(float x) {
+ return (x == Float.POSITIVE_INFINITY ? Float.MAX_VALUE :
+ (x == Float.NEGATIVE_INFINITY ? Float.MIN_VALUE : x));
+ }
+
+ // A slight modification of the false position algorithm on wikipedia.
+ // This only works for the ROCsq-x functions. It might be nice to have
+ // the function as an argument, but that would be awkward in java6.
+ // It is something to consider for java7, depending on how closures
+ // and function objects turn out. Same goes for the newton's method
+ // algorithm in Helpers.java
+ private float falsePositionROCsqMinusX(float x0, float x1,
+ final float x, final float err)
+ {
+ final int iterLimit = 100;
+ int side = 0;
+ float t = x1, ft = eliminateInf(ROCsq(t) - x);
+ float s = x0, fs = eliminateInf(ROCsq(s) - x);
+ float r = s, fr;
+ for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
+ r = (fs * t - ft * s) / (fs - ft);
+ fr = ROCsq(r) - x;
+ if (fr * ft > 0) {// have the same sign
+ ft = fr; t = r;
+ if (side < 0) {
+ fs /= (1 << (-side));
+ side--;
+ } else {
+ side = -1;
+ }
+ } else if (fr * fs > 0) {
+ fs = fr; s = r;
+ if (side > 0) {
+ ft /= (1 << side);
+ side++;
+ } else {
+ side = 1;
+ }
+ } else {
+ break;
+ }
+ }
+ return r;
+ }
+
+ // returns the radius of curvature squared at t of this curve
+ // see http://en.wikipedia.org/wiki/Radius_of_curvature_(applications)
+ private float ROCsq(final float t) {
+ final float dx = dxat(t);
+ final float dy = dyat(t);
+ final float ddx = ddxat(t);
+ final float ddy = ddyat(t);
+ final float dx2dy2 = dx*dx + dy*dy;
+ final float ddx2ddy2 = ddx*ddx + ddy*ddy;
+ final float ddxdxddydy = ddx*dx + ddy*dy;
+ float ret = ((dx2dy2*dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy*ddxdxddydy))*dx2dy2;
+ return ret;
+ }
+
+ // curve to be broken should be in pts[0]
+ // this will change the contents of both pts and Ts
+ // TODO: There's no reason for Ts to be an array. All we need is a sequence
+ // of t values at which to subdivide. An array statisfies this condition,
+ // but is unnecessarily restrictive. Ts should be an Iterator<Float> instead.
+ // Doing this will also make dashing easier, since we could easily make
+ // LengthIterator an Iterator<Float> and feed it to this function to simplify
+ // the loop in Dasher.somethingTo.
+ static Iterator<float[]> breakPtsAtTs(final float[][] pts, final int type,
+ final float[] Ts, final int numTs)
+ {
+ assert pts.length >= 2 && pts[0].length >= 8 && numTs <= Ts.length;
+ return new Iterator<float[]>() {
+ int nextIdx = 0;
+ int nextCurveIdx = 0;
+ float prevT = 0;
+
+ @Override public boolean hasNext() {
+ return nextCurveIdx < numTs + 1;
+ }
+
+ @Override public float[] next() {
+ float[] ret;
+ if (nextCurveIdx < numTs) {
+ float curT = Ts[nextCurveIdx];
+ float splitT = (curT - prevT) / (1 - prevT);
+ Helpers.subdivideAt(splitT,
+ pts[nextIdx], 0,
+ pts[nextIdx], 0,
+ pts[1-nextIdx], 0, type);
+ updateTs(Ts, Ts[nextCurveIdx], nextCurveIdx + 1, numTs - nextCurveIdx - 1);
+ ret = pts[nextIdx];
+ nextIdx = 1 - nextIdx;
+ } else {
+ ret = pts[nextIdx];
+ }
+ nextCurveIdx++;
+ return ret;
+ }
+
+ @Override public void remove() {}
+ };
+ }
+
+ // precondition: ts[off]...ts[off+len-1] must all be greater than t.
+ private static void updateTs(float[] ts, final float t, final int off, final int len) {
+ for (int i = off; i < off + len; i++) {
+ ts[i] = (ts[i] - t) / (1 - t);
+ }
+ }
+}
+
--- a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,6 +25,8 @@
package sun.java2d.pisces;
+import sun.awt.geom.PathConsumer2D;
+
/**
* The <code>Dasher</code> class takes a series of linear commands
* (<code>moveTo</code>, <code>lineTo</code>, <code>close</code> and
@@ -36,18 +38,16 @@
* semantics are unclear.
*
*/
-public class Dasher implements LineSink {
- private final LineSink output;
+public class Dasher implements sun.awt.geom.PathConsumer2D {
+
+ private final PathConsumer2D out;
private final float[] dash;
private final float startPhase;
private final boolean startDashOn;
private final int startIdx;
- private final float m00, m10, m01, m11;
- private final float det;
-
- private boolean firstDashOn;
private boolean starting;
+ private boolean needsMoveTo;
private int idx;
private boolean dashOn;
@@ -55,28 +55,23 @@
private float sx, sy;
private float x0, y0;
- private float sx1, sy1;
+ // temporary storage for the current curve
+ private float[] curCurvepts;
/**
* Constructs a <code>Dasher</code>.
*
- * @param output an output <code>LineSink</code>.
- * @param dash an array of <code>int</code>s containing the dash pattern
- * @param phase an <code>int</code> containing the dash phase
- * @param transform a <code>Transform4</code> object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to compute dash lengths
- * properly.
+ * @param out an output <code>PathConsumer2D</code>.
+ * @param dash an array of <code>float</code>s containing the dash pattern
+ * @param phase a <code>float</code> containing the dash phase
*/
- public Dasher(LineSink output,
- float[] dash, float phase,
- float a00, float a01, float a10, float a11) {
+ public Dasher(PathConsumer2D out, float[] dash, float phase) {
if (phase < 0) {
throw new IllegalArgumentException("phase < 0 !");
}
- this.output = output;
+ this.out = out;
// Normalize so 0 <= phase < dash[0]
int idx = 0;
@@ -92,16 +87,19 @@
this.startPhase = this.phase = phase;
this.startDashOn = dashOn;
this.startIdx = idx;
+ this.starting = true;
- m00 = a00;
- m01 = a01;
- m10 = a10;
- m11 = a11;
- det = m00 * m11 - m01 * m10;
+ // we need curCurvepts to be able to contain 2 curves because when
+ // dashing curves, we need to subdivide it
+ curCurvepts = new float[8 * 2];
}
public void moveTo(float x0, float y0) {
- output.moveTo(x0, y0);
+ if (firstSegidx > 0) {
+ out.moveTo(sx, sy);
+ emitFirstSegments();
+ }
+ needsMoveTo = true;
this.idx = startIdx;
this.dashOn = this.startDashOn;
this.phase = this.startPhase;
@@ -110,88 +108,108 @@
this.starting = true;
}
- public void lineJoin() {
- output.lineJoin();
+ private void emitSeg(float[] buf, int off, int type) {
+ switch (type) {
+ case 8:
+ out.curveTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3],
+ buf[off+4], buf[off+5]);
+ break;
+ case 6:
+ out.quadTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3]);
+ break;
+ case 4:
+ out.lineTo(buf[off], buf[off+1]);
+ }
}
- private void goTo(float x1, float y1) {
+ private void emitFirstSegments() {
+ for (int i = 0; i < firstSegidx; ) {
+ emitSeg(firstSegmentsBuffer, i+1, (int)firstSegmentsBuffer[i]);
+ i += (((int)firstSegmentsBuffer[i]) - 1);
+ }
+ firstSegidx = 0;
+ }
+
+ // We don't emit the first dash right away. If we did, caps would be
+ // drawn on it, but we need joins to be drawn if there's a closePath()
+ // So, we store the path elements that make up the first dash in the
+ // buffer below.
+ private float[] firstSegmentsBuffer = new float[7];
+ private int firstSegidx = 0;
+ // precondition: pts must be in relative coordinates (relative to x0,y0)
+ // fullCurve is true iff the curve in pts has not been split.
+ private void goTo(float[] pts, int off, final int type) {
+ float x = pts[off + type - 4];
+ float y = pts[off + type - 3];
if (dashOn) {
if (starting) {
- this.sx1 = x1;
- this.sy1 = y1;
- firstDashOn = true;
- starting = false;
+ firstSegmentsBuffer = Helpers.widenArray(firstSegmentsBuffer,
+ firstSegidx, type - 2);
+ firstSegmentsBuffer[firstSegidx++] = type;
+ System.arraycopy(pts, off, firstSegmentsBuffer, firstSegidx, type - 2);
+ firstSegidx += type - 2;
+ } else {
+ if (needsMoveTo) {
+ out.moveTo(x0, y0);
+ needsMoveTo = false;
+ }
+ emitSeg(pts, off, type);
}
- output.lineTo(x1, y1);
} else {
- if (starting) {
- firstDashOn = false;
- starting = false;
- }
- output.moveTo(x1, y1);
+ starting = false;
+ needsMoveTo = true;
}
- this.x0 = x1;
- this.y0 = y1;
+ this.x0 = x;
+ this.y0 = y;
}
public void lineTo(float x1, float y1) {
- // The widened line is squished to a 0 width one, so no drawing is done
- if (det == 0) {
- goTo(x1, y1);
- return;
- }
float dx = x1 - x0;
float dy = y1 - y0;
-
- // Compute segment length in the untransformed
- // coordinate system
+ float len = (float) Math.hypot(dx, dy);
- float la = (dy*m00 - dx*m10)/det;
- float lb = (dy*m01 - dx*m11)/det;
- float origLen = (float) Math.hypot(la, lb);
-
- if (origLen == 0) {
- // Let the output LineSink deal with cases where dx, dy are 0.
- goTo(x1, y1);
+ if (len == 0) {
return;
}
// The scaling factors needed to get the dx and dy of the
// transformed dash segments.
- float cx = dx / origLen;
- float cy = dy / origLen;
+ float cx = dx / len;
+ float cy = dy / len;
while (true) {
float leftInThisDashSegment = dash[idx] - phase;
- if (origLen < leftInThisDashSegment) {
- goTo(x1, y1);
+ if (len <= leftInThisDashSegment) {
+ curCurvepts[0] = x1;
+ curCurvepts[1] = y1;
+ goTo(curCurvepts, 0, 4);
// Advance phase within current dash segment
- phase += origLen;
- return;
- } else if (origLen == leftInThisDashSegment) {
- goTo(x1, y1);
- phase = 0f;
- idx = (idx + 1) % dash.length;
- dashOn = !dashOn;
+ phase += len;
+ if (len == leftInThisDashSegment) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
return;
}
- float dashx, dashy;
float dashdx = dash[idx] * cx;
float dashdy = dash[idx] * cy;
if (phase == 0) {
- dashx = x0 + dashdx;
- dashy = y0 + dashdy;
+ curCurvepts[0] = x0 + dashdx;
+ curCurvepts[1] = y0 + dashdy;
} else {
- float p = (leftInThisDashSegment) / dash[idx];
- dashx = x0 + p * dashdx;
- dashy = y0 + p * dashdy;
+ float p = leftInThisDashSegment / dash[idx];
+ curCurvepts[0] = x0 + p * dashdx;
+ curCurvepts[1] = y0 + p * dashdy;
}
- goTo(dashx, dashy);
+ goTo(curCurvepts, 0, 4);
- origLen -= (dash[idx] - phase);
+ len -= leftInThisDashSegment;
// Advance to next dash segment
idx = (idx + 1) % dash.length;
dashOn = !dashOn;
@@ -199,15 +217,289 @@
}
}
+ private LengthIterator li = null;
- public void close() {
- lineTo(sx, sy);
- if (firstDashOn) {
- output.lineTo(sx1, sy1);
+ // preconditions: curCurvepts must be an array of length at least 2 * type,
+ // that contains the curve we want to dash in the first type elements
+ private void somethingTo(int type) {
+ if (pointCurve(curCurvepts, type)) {
+ return;
+ }
+ if (li == null) {
+ li = new LengthIterator(4, 0.0001f);
+ }
+ li.initializeIterationOnCurve(curCurvepts, type);
+
+ int curCurveoff = 0; // initially the current curve is at curCurvepts[0...type]
+ float lastSplitT = 0;
+ float t = 0;
+ float leftInThisDashSegment = dash[idx] - phase;
+ while ((t = li.next(leftInThisDashSegment)) < 1) {
+ if (t != 0) {
+ Helpers.subdivideAt((t - lastSplitT) / (1 - lastSplitT),
+ curCurvepts, curCurveoff,
+ curCurvepts, 0,
+ curCurvepts, type, type);
+ lastSplitT = t;
+ goTo(curCurvepts, 2, type);
+ curCurveoff = type;
+ }
+ // Advance to next dash segment
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ phase = 0;
+ leftInThisDashSegment = dash[idx];
+ }
+ goTo(curCurvepts, curCurveoff+2, type);
+ phase += li.lastSegLen();
+ if (phase >= dash[idx]) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
}
}
- public void end() {
- output.end();
+ private static boolean pointCurve(float[] curve, int type) {
+ for (int i = 2; i < type; i++) {
+ if (curve[i] != curve[i-2]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Objects of this class are used to iterate through curves. They return
+ // t values where the left side of the curve has a specified length.
+ // It does this by subdividing the input curve until a certain error
+ // condition has been met. A recursive subdivision procedure would
+ // return as many as 1<<limit curves, but this is an iterator and we
+ // don't need all the curves all at once, so what we carry out a
+ // lazy inorder traversal of the recursion tree (meaning we only move
+ // through the tree when we need the next subdivided curve). This saves
+ // us a lot of memory because at any one time we only need to store
+ // limit+1 curves - one for each level of the tree + 1.
+ // NOTE: the way we do things here is not enough to traverse a general
+ // tree; however, the trees we are interested in have the property that
+ // every non leaf node has exactly 2 children
+ private static class LengthIterator {
+ private enum Side {LEFT, RIGHT};
+ // Holds the curves at various levels of the recursion. The root
+ // (i.e. the original curve) is at recCurveStack[0] (but then it
+ // gets subdivided, the left half is put at 1, so most of the time
+ // only the right half of the original curve is at 0)
+ private float[][] recCurveStack;
+ // sides[i] indicates whether the node at level i+1 in the path from
+ // the root to the current leaf is a left or right child of its parent.
+ private Side[] sides;
+ private int curveType;
+ private final int limit;
+ private final float ERR;
+ private final float minTincrement;
+ // lastT and nextT delimit the current leaf.
+ private float nextT;
+ private float lenAtNextT;
+ private float lastT;
+ private float lenAtLastT;
+ private float lenAtLastSplit;
+ private float lastSegLen;
+ // the current level in the recursion tree. 0 is the root. limit
+ // is the deepest possible leaf.
+ private int recLevel;
+ private boolean done;
+
+ public LengthIterator(int reclimit, float err) {
+ this.limit = reclimit;
+ this.minTincrement = 1f / (1 << limit);
+ this.ERR = err;
+ this.recCurveStack = new float[reclimit+1][8];
+ this.sides = new Side[reclimit];
+ // if any methods are called without first initializing this object on
+ // a curve, we want it to fail ASAP.
+ this.nextT = Float.MAX_VALUE;
+ this.lenAtNextT = Float.MAX_VALUE;
+ this.lenAtLastSplit = Float.MIN_VALUE;
+ this.recLevel = Integer.MIN_VALUE;
+ this.lastSegLen = Float.MAX_VALUE;
+ this.done = true;
+ }
+
+ public void initializeIterationOnCurve(float[] pts, int type) {
+ System.arraycopy(pts, 0, recCurveStack[0], 0, type);
+ this.curveType = type;
+ this.recLevel = 0;
+ this.lastT = 0;
+ this.lenAtLastT = 0;
+ this.nextT = 0;
+ this.lenAtNextT = 0;
+ goLeft(); // initializes nextT and lenAtNextT properly
+ this.lenAtLastSplit = 0;
+ if (recLevel > 0) {
+ this.sides[0] = Side.LEFT;
+ this.done = false;
+ } else {
+ // the root of the tree is a leaf so we're done.
+ this.sides[0] = Side.RIGHT;
+ this.done = true;
+ }
+ this.lastSegLen = 0;
+ }
+
+ // returns the t value where the remaining curve should be split in
+ // order for the left subdivided curve to have length len. If len
+ // is >= than the length of the uniterated curve, it returns 1.
+ public float next(float len) {
+ float targetLength = lenAtLastSplit + len;
+ while(lenAtNextT < targetLength) {
+ if (done) {
+ lastSegLen = lenAtNextT - lenAtLastSplit;
+ return 1;
+ }
+ goToNextLeaf();
+ }
+ lenAtLastSplit = targetLength;
+ float t = binSearchForLen(lenAtLastSplit - lenAtLastT,
+ recCurveStack[recLevel], curveType, lenAtNextT - lenAtLastT, ERR);
+ // t is relative to the current leaf, so we must make it a valid parameter
+ // of the original curve.
+ t = t * (nextT - lastT) + lastT;
+ if (t >= 1) {
+ t = 1;
+ done = true;
+ }
+ // even if done = true, if we're here, that means targetLength
+ // is equal to, or very, very close to the total length of the
+ // curve, so lastSegLen won't be too high. In cases where len
+ // overshoots the curve, this method will exit in the while
+ // loop, and lastSegLen will still be set to the right value.
+ lastSegLen = len;
+ return t;
+ }
+
+ public float lastSegLen() {
+ return lastSegLen;
+ }
+
+ // Returns t such that if leaf is subdivided at t the left
+ // curve will have length len. leafLen must be the length of leaf.
+ private static Curve bsc = new Curve();
+ private static float binSearchForLen(float len, float[] leaf, int type,
+ float leafLen, float err)
+ {
+ assert len <= leafLen;
+ bsc.set(leaf, type);
+ float errBound = err*len;
+ float left = 0, right = 1;
+ while (left < right) {
+ float m = (left + right) / 2;
+ if (m == left || m == right) {
+ return m;
+ }
+ float x = bsc.xat(m);
+ float y = bsc.yat(m);
+ float leftLen = Helpers.linelen(leaf[0], leaf[1], x, y);
+ if (Math.abs(leftLen - len) < errBound) {
+ return m;
+ }
+ if (leftLen < len) {
+ left = m;
+ } else {
+ right = m;
+ }
+ }
+ return left;
+ }
+
+ // go to the next leaf (in an inorder traversal) in the recursion tree
+ // preconditions: must be on a leaf, and that leaf must not be the root.
+ private void goToNextLeaf() {
+ // We must go to the first ancestor node that has an unvisited
+ // right child.
+ recLevel--;
+ while(sides[recLevel] == Side.RIGHT) {
+ if (recLevel == 0) {
+ done = true;
+ return;
+ }
+ recLevel--;
+ }
+
+ sides[recLevel] = Side.RIGHT;
+ System.arraycopy(recCurveStack[recLevel], 0, recCurveStack[recLevel+1], 0, curveType);
+ recLevel++;
+ goLeft();
+ }
+
+ // go to the leftmost node from the current node. Return its length.
+ private void goLeft() {
+ float len = onLeaf();
+ if (len >= 0) {
+ lastT = nextT;
+ lenAtLastT = lenAtNextT;
+ nextT += (1 << (limit - recLevel)) * minTincrement;
+ lenAtNextT += len;
+ } else {
+ Helpers.subdivide(recCurveStack[recLevel], 0,
+ recCurveStack[recLevel+1], 0,
+ recCurveStack[recLevel], 0, curveType);
+ sides[recLevel] = Side.LEFT;
+ recLevel++;
+ goLeft();
+ }
+ }
+
+ // this is a bit of a hack. It returns -1 if we're not on a leaf, and
+ // the length of the leaf if we are on a leaf.
+ private float onLeaf() {
+ float polylen = Helpers.polyLineLength(recCurveStack[recLevel], 0, curveType);
+ float linelen = Helpers.linelen(recCurveStack[recLevel][0], recCurveStack[recLevel][1],
+ recCurveStack[recLevel][curveType - 2], recCurveStack[recLevel][curveType - 1]);
+ return (polylen - linelen < ERR || recLevel == limit) ?
+ (polylen + linelen)/2 : -1;
+ }
+ }
+
+ @Override
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ curCurvepts[0] = x0; curCurvepts[1] = y0;
+ curCurvepts[2] = x1; curCurvepts[3] = y1;
+ curCurvepts[4] = x2; curCurvepts[5] = y2;
+ curCurvepts[6] = x3; curCurvepts[7] = y3;
+ somethingTo(8);
+ }
+
+ @Override
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ curCurvepts[0] = x0; curCurvepts[1] = y0;
+ curCurvepts[2] = x1; curCurvepts[3] = y1;
+ curCurvepts[4] = x2; curCurvepts[5] = y2;
+ somethingTo(6);
+ }
+
+ public void closePath() {
+ lineTo(sx, sy);
+ if (firstSegidx > 0) {
+ if (!dashOn || needsMoveTo) {
+ out.moveTo(sx, sy);
+ }
+ emitFirstSegments();
+ }
+ moveTo(sx, sy);
+ }
+
+ public void pathDone() {
+ if (firstSegidx > 0) {
+ out.moveTo(sx, sy);
+ emitFirstSegments();
+ }
+ out.pathDone();
+ }
+
+ @Override
+ public long getNativeConsumer() {
+ throw new InternalError("Dasher does not use a native consumer");
}
}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/pisces/Helpers.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.pisces;
+
+import java.util.Arrays;
+
+final class Helpers {
+ private Helpers() {
+ throw new Error("This is a non instantiable class");
+ }
+
+ static boolean within(final float x, final float y, final float err) {
+ final float d = y - x;
+ return (d <= err && d >= -err);
+ }
+
+ static boolean within(final double x, final double y, final double err) {
+ final double d = y - x;
+ return (d <= err && d >= -err);
+ }
+
+ static int quadraticRoots(final float a, final float b,
+ final float c, float[] zeroes, final int off)
+ {
+ int ret = off;
+ float t;
+ if (a != 0f) {
+ final float dis = b*b - 4*a*c;
+ if (dis > 0) {
+ final float sqrtDis = (float)Math.sqrt(dis);
+ // depending on the sign of b we use a slightly different
+ // algorithm than the traditional one to find one of the roots
+ // so we can avoid adding numbers of different signs (which
+ // might result in loss of precision).
+ if (b >= 0) {
+ zeroes[ret++] = (2 * c) / (-b - sqrtDis);
+ zeroes[ret++] = (-b - sqrtDis) / (2 * a);
+ } else {
+ zeroes[ret++] = (-b + sqrtDis) / (2 * a);
+ zeroes[ret++] = (2 * c) / (-b + sqrtDis);
+ }
+ } else if (dis == 0f) {
+ t = (-b) / (2 * a);
+ zeroes[ret++] = t;
+ }
+ } else {
+ if (b != 0f) {
+ t = (-c) / b;
+ zeroes[ret++] = t;
+ }
+ }
+ return ret - off;
+ }
+
+ // find the roots of g(t) = a*t^3 + b*t^2 + c*t + d in [A,B)
+ // We will not use Cardano's method, since it is complicated and
+ // involves too many square and cubic roots. We will use Newton's method.
+ // TODO: this should probably return ALL roots. Then the user can do
+ // his own filtering of roots outside [A,B).
+ static int cubicRootsInAB(final float a, final float b,
+ final float c, final float d,
+ float[] pts, final int off, final float E,
+ final float A, final float B)
+ {
+ if (a == 0) {
+ return quadraticRoots(b, c, d, pts, off);
+ }
+ // the coefficients of g'(t). no dc variable because dc=c
+ // we use these to get the critical points of g(t), which
+ // we then use to chose starting points for Newton's method. These
+ // should be very close to the actual roots.
+ final float da = 3 * a;
+ final float db = 2 * b;
+ int numCritPts = quadraticRoots(da, db, c, pts, off+1);
+ numCritPts = filterOutNotInAB(pts, off+1, numCritPts, A, B) - off - 1;
+ // need them sorted.
+ if (numCritPts == 2 && pts[off+1] > pts[off+2]) {
+ float tmp = pts[off+1];
+ pts[off+1] = pts[off+2];
+ pts[off+2] = tmp;
+ }
+
+ int ret = off;
+
+ // we don't actually care much about the extrema themselves. We
+ // only use them to ensure that g(t) is monotonic in each
+ // interval [pts[i],pts[i+1] (for i in off...off+numCritPts+1).
+ // This will allow us to determine intervals containing exactly
+ // one root.
+ // The end points of the interval are always local extrema.
+ pts[off] = A;
+ pts[off + numCritPts + 1] = B;
+ numCritPts += 2;
+
+ float x0 = pts[off], fx0 = evalCubic(a, b, c, d, x0);
+ for (int i = off; i < off + numCritPts - 1; i++) {
+ float x1 = pts[i+1], fx1 = evalCubic(a, b, c, d, x1);
+ if (fx0 == 0f) {
+ pts[ret++] = x0;
+ } else if (fx1 * fx0 < 0f) { // have opposite signs
+ pts[ret++] = CubicNewton(a, b, c, d,
+ x0 + fx0 * (x1 - x0) / (fx0 - fx1), E);
+ }
+ x0 = x1;
+ fx0 = fx1;
+ }
+ return ret - off;
+ }
+
+ // precondition: the polynomial to be evaluated must not be 0 at x0.
+ static float CubicNewton(final float a, final float b,
+ final float c, final float d,
+ float x0, final float err)
+ {
+ // considering how this function is used, 10 should be more than enough
+ final int itlimit = 10;
+ float fx0 = evalCubic(a, b, c, d, x0);
+ float x1;
+ int count = 0;
+ while(true) {
+ x1 = x0 - (fx0 / evalCubic(0, 3 * a, 2 * b, c, x0));
+ if (Math.abs(x1 - x0) < err * Math.abs(x1 + x0) || count == itlimit) {
+ break;
+ }
+ x0 = x1;
+ fx0 = evalCubic(a, b, c, d, x0);
+ count++;
+ }
+ return x1;
+ }
+
+ // fills the input array with numbers 0, INC, 2*INC, ...
+ static void fillWithIdxes(final float[] data, final int[] idxes) {
+ if (idxes.length > 0) {
+ idxes[0] = 0;
+ for (int i = 1; i < idxes.length; i++) {
+ idxes[i] = idxes[i-1] + (int)data[idxes[i-1]];
+ }
+ }
+ }
+
+ static void fillWithIdxes(final int[] idxes, final int inc) {
+ if (idxes.length > 0) {
+ idxes[0] = 0;
+ for (int i = 1; i < idxes.length; i++) {
+ idxes[i] = idxes[i-1] + inc;
+ }
+ }
+ }
+
+ // These use a hardcoded factor of 2 for increasing sizes. Perhaps this
+ // should be provided as an argument.
+ static float[] widenArray(float[] in, final int cursize, final int numToAdd) {
+ if (in == null) {
+ return new float[5 * numToAdd];
+ }
+ if (in.length >= cursize + numToAdd) {
+ return in;
+ }
+ return Arrays.copyOf(in, 2 * (cursize + numToAdd));
+ }
+ static int[] widenArray(int[] in, final int cursize, final int numToAdd) {
+ if (in.length >= cursize + numToAdd) {
+ return in;
+ }
+ return Arrays.copyOf(in, 2 * (cursize + numToAdd));
+ }
+
+ static float evalCubic(final float a, final float b,
+ final float c, final float d,
+ final float t)
+ {
+ return t * (t * (t * a + b) + c) + d;
+ }
+
+ static float evalQuad(final float a, final float b,
+ final float c, final float t)
+ {
+ return t * (t * a + b) + c;
+ }
+
+ // returns the index 1 past the last valid element remaining after filtering
+ static int filterOutNotInAB(float[] nums, final int off, final int len,
+ final float a, final float b)
+ {
+ int ret = off;
+ for (int i = off; i < off + len; i++) {
+ if (nums[i] > a && nums[i] < b) {
+ nums[ret++] = nums[i];
+ }
+ }
+ return ret;
+ }
+
+ static float polyLineLength(float[] poly, final int off, final int nCoords) {
+ assert nCoords % 2 == 0 && poly.length >= off + nCoords : "";
+ float acc = 0;
+ for (int i = off + 2; i < off + nCoords; i += 2) {
+ acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]);
+ }
+ return acc;
+ }
+
+ static float linelen(float x1, float y1, float x2, float y2) {
+ return (float)Math.hypot(x2 - x1, y2 - y1);
+ }
+
+ static void subdivide(float[] src, int srcoff, float[] left, int leftoff,
+ float[] right, int rightoff, int type)
+ {
+ switch(type) {
+ case 6:
+ Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
+ break;
+ case 8:
+ Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);
+ break;
+ default:
+ throw new InternalError("Unsupported curve type");
+ }
+ }
+
+ static void isort(float[] a, int off, int len) {
+ for (int i = off + 1; i < off + len; i++) {
+ float ai = a[i];
+ int j = i - 1;
+ for (; j >= off && a[j] > ai; j--) {
+ a[j+1] = a[j];
+ }
+ a[j+1] = ai;
+ }
+ }
+
+ // Most of these are copied from classes in java.awt.geom because we need
+ // float versions of these functions, and Line2D, CubicCurve2D,
+ // QuadCurve2D don't provide them.
+ /**
+ * Subdivides the cubic curve specified by the coordinates
+ * stored in the <code>src</code> array at indices <code>srcoff</code>
+ * through (<code>srcoff</code> + 7) and stores the
+ * resulting two subdivided curves into the two result arrays at the
+ * corresponding indices.
+ * Either or both of the <code>left</code> and <code>right</code>
+ * arrays may be <code>null</code> or a reference to the same array
+ * as the <code>src</code> array.
+ * Note that the last point in the first subdivided curve is the
+ * same as the first point in the second subdivided curve. Thus,
+ * it is possible to pass the same array for <code>left</code>
+ * and <code>right</code> and to use offsets, such as <code>rightoff</code>
+ * equals (<code>leftoff</code> + 6), in order
+ * to avoid allocating extra storage for this common point.
+ * @param src the array holding the coordinates for the source curve
+ * @param srcoff the offset into the array of the beginning of the
+ * the 6 source coordinates
+ * @param left the array for storing the coordinates for the first
+ * half of the subdivided curve
+ * @param leftoff the offset into the array of the beginning of the
+ * the 6 left coordinates
+ * @param right the array for storing the coordinates for the second
+ * half of the subdivided curve
+ * @param rightoff the offset into the array of the beginning of the
+ * the 6 right coordinates
+ * @since 1.7
+ */
+ static void subdivideCubic(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = (x1 + ctrlx1) / 2.0f;
+ y1 = (y1 + ctrly1) / 2.0f;
+ x2 = (x2 + ctrlx2) / 2.0f;
+ y2 = (y2 + ctrly2) / 2.0f;
+ float centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ float centery = (ctrly1 + ctrly2) / 2.0f;
+ ctrlx1 = (x1 + centerx) / 2.0f;
+ ctrly1 = (y1 + centery) / 2.0f;
+ ctrlx2 = (x2 + centerx) / 2.0f;
+ ctrly2 = (y2 + centery) / 2.0f;
+ centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ centery = (ctrly1 + ctrly2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+
+ static void subdivideCubicAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = x1 + t * (ctrlx1 - x1);
+ y1 = y1 + t * (ctrly1 - y1);
+ x2 = ctrlx2 + t * (x2 - ctrlx2);
+ y2 = ctrly2 + t * (y2 - ctrly2);
+ float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ float centery = ctrly1 + t * (ctrly2 - ctrly1);
+ ctrlx1 = x1 + t * (centerx - x1);
+ ctrly1 = y1 + t * (centery - y1);
+ ctrlx2 = centerx + t * (x2 - centerx);
+ ctrly2 = centery + t * (y2 - centery);
+ centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ centery = ctrly1 + t * (ctrly2 - ctrly1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+ static void subdivideQuad(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = (x1 + ctrlx) / 2.0f;
+ y1 = (y1 + ctrly) / 2.0f;
+ x2 = (x2 + ctrlx) / 2.0f;
+ y2 = (y2 + ctrly) / 2.0f;
+ ctrlx = (x1 + x2) / 2.0f;
+ ctrly = (y1 + y2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideQuadAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = x1 + t * (ctrlx - x1);
+ y1 = y1 + t * (ctrly - y1);
+ x2 = ctrlx + t * (x2 - ctrlx);
+ y2 = ctrly + t * (y2 - ctrly);
+ ctrlx = x1 + t * (x2 - x1);
+ ctrly = y1 + t * (y2 - y1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff, int size)
+ {
+ switch(size) {
+ case 8:
+ subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ case 6:
+ subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ }
+ }
+}
--- a/jdk/src/share/classes/sun/java2d/pisces/LineSink.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.java2d.pisces;
-
-/**
- * The <code>LineSink</code> interface accepts a series of line
- * drawing commands: <code>moveTo</code>, <code>lineTo</code>,
- * <code>close</code> (equivalent to a <code>lineTo</code> command
- * with an argument equal to the argument of the last
- * <code>moveTo</code> command), and <code>end</code>.
- *
- * <p> A <code>Flattener</code> may be used to connect a general path
- * source to a <code>LineSink</code>.
- *
- * <p> The <code>Renderer</code> class implements the
- * <code>LineSink</code> interface.
- *
- */
-public interface LineSink {
-
- /**
- * Moves the current drawing position to the point <code>(x0,
- * y0)</code>.
- *
- * @param x0 the X coordinate
- * @param y0 the Y coordinate
- */
- public void moveTo(float x0, float y0);
-
- /**
- * Provides a hint that the current segment should be joined to
- * the following segment using an explicit miter or round join if
- * required.
- *
- * <p> An application-generated path will generally have no need
- * to contain calls to this method; they are typically introduced
- * by a <code>Flattener</code> to mark segment divisions that
- * appear in its input, and consumed by a <code>Stroker</code>
- * that is responsible for emitting the miter or round join
- * segments.
- *
- * <p> Other <code>LineSink</code> classes should simply pass this
- * hint to their output sink as needed.
- */
- public void lineJoin();
-
- /**
- * Draws a line from the current drawing position to the point
- * <code>(x1, y1)</code> and sets the current drawing position to
- * <code>(x1, y1)</code>.
- *
- * @param x1 the X coordinate
- * @param y1 the Y coordinate
- */
- public void lineTo(float x1, float y1);
-
- /**
- * Closes the current path by drawing a line from the current
- * drawing position to the point specified by the moset recent
- * <code>moveTo</code> command.
- */
- public void close();
-
- /**
- * Ends the current path. It may be necessary to end a path in
- * order to allow end caps to be drawn.
- */
- public void end();
-
-}
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesCache.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesCache.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,6 +25,8 @@
package sun.java2d.pisces;
+import java.util.Arrays;
+
/**
* An object used to cache pre-rendered complex paths.
*
@@ -32,115 +34,153 @@
*/
public final class PiscesCache {
- int bboxX0, bboxY0, bboxX1, bboxY1;
+ final int bboxX0, bboxY0, bboxX1, bboxY1;
+
+ // rowAARLE[i] holds the encoding of the pixel row with y = bboxY0+i.
+ // The format of each of the inner arrays is: rowAARLE[i][0,1] = (x0, n)
+ // where x0 is the first x in row i with nonzero alpha, and n is the
+ // number of RLE entries in this row. rowAARLE[i][j,j+1] for j>1 is
+ // (val,runlen)
+ final int[][] rowAARLE;
- byte[] rowAARLE;
- int alphaRLELength;
+ // RLE encodings are added in increasing y rows and then in increasing
+ // x inside those rows. Therefore, at any one time there is a well
+ // defined position (x,y) where a run length is about to be added (or
+ // the row terminated). x0,y0 is this (x,y)-(bboxX0,bboxY0). They
+ // are used to get indices into the current tile.
+ private int x0 = Integer.MIN_VALUE, y0 = Integer.MIN_VALUE;
+
+ // touchedTile[i][j] is the sum of all the alphas in the tile with
+ // y=i*TILE_SIZE+bboxY0 and x=j*TILE_SIZE+bboxX0.
+ private final int[][] touchedTile;
- int[] rowOffsetsRLE;
- int[] minTouched;
- int alphaRows;
+ static final int TILE_SIZE_LG = 5;
+ static final int TILE_SIZE = 1 << TILE_SIZE_LG; // 32
+ private static final int INIT_ROW_SIZE = 8; // enough for 3 run lengths
- private PiscesCache() {}
+ PiscesCache(int minx, int miny, int maxx, int maxy) {
+ assert maxy >= miny && maxx >= minx;
+ bboxX0 = minx;
+ bboxY0 = miny;
+ bboxX1 = maxx + 1;
+ bboxY1 = maxy + 1;
+ // we could just leave the inner arrays as null and allocate them
+ // lazily (which would be beneficial for shapes with gaps), but we
+ // assume there won't be too many of those so we allocate everything
+ // up front (which is better for other cases)
+ rowAARLE = new int[bboxY1 - bboxY0 + 1][INIT_ROW_SIZE];
+ x0 = 0;
+ y0 = -1; // -1 makes the first assert in startRow succeed
+ // the ceiling of (maxy - miny + 1) / TILE_SIZE;
+ int nyTiles = (maxy - miny + TILE_SIZE) >> TILE_SIZE_LG;
+ int nxTiles = (maxx - minx + TILE_SIZE) >> TILE_SIZE_LG;
- public static PiscesCache createInstance() {
- return new PiscesCache();
+ touchedTile = new int[nyTiles][nxTiles];
}
- private static final float ROWAA_RLE_FACTOR = 1.5f;
- private static final float TOUCHED_FACTOR = 1.5f;
- private static final int MIN_TOUCHED_LEN = 64;
-
- private void reallocRowAARLE(int newLength) {
- if (rowAARLE == null) {
- rowAARLE = new byte[newLength];
- } else if (rowAARLE.length < newLength) {
- int len = Math.max(newLength,
- (int)(rowAARLE.length*ROWAA_RLE_FACTOR));
- byte[] newRowAARLE = new byte[len];
- System.arraycopy(rowAARLE, 0, newRowAARLE, 0, rowAARLE.length);
- rowAARLE = newRowAARLE;
- }
- }
-
- private void reallocRowInfo(int newHeight) {
- if (minTouched == null) {
- int len = Math.max(newHeight, MIN_TOUCHED_LEN);
- minTouched = new int[len];
- rowOffsetsRLE = new int[len];
- } else if (minTouched.length < newHeight) {
- int len = Math.max(newHeight,
- (int)(minTouched.length*TOUCHED_FACTOR));
- int[] newMinTouched = new int[len];
- int[] newRowOffsetsRLE = new int[len];
- System.arraycopy(minTouched, 0, newMinTouched, 0,
- alphaRows);
- System.arraycopy(rowOffsetsRLE, 0, newRowOffsetsRLE, 0,
- alphaRows);
- minTouched = newMinTouched;
- rowOffsetsRLE = newRowOffsetsRLE;
+ void addRLERun(int val, int runLen) {
+ if (runLen > 0) {
+ addTupleToRow(y0, val, runLen);
+ if (val != 0) {
+ // the x and y of the current row, minus bboxX0, bboxY0
+ int tx = x0 >> TILE_SIZE_LG;
+ int ty = y0 >> TILE_SIZE_LG;
+ int tx1 = (x0 + runLen - 1) >> TILE_SIZE_LG;
+ // while we forbid rows from starting before bboxx0, our users
+ // can still store rows that go beyond bboxx1 (although this
+ // shouldn't happen), so it's a good idea to check that i
+ // is not going out of bounds in touchedTile[ty]
+ if (tx1 >= touchedTile[ty].length) {
+ tx1 = touchedTile[ty].length - 1;
+ }
+ if (tx <= tx1) {
+ int nextTileXCoord = (tx + 1) << TILE_SIZE_LG;
+ if (nextTileXCoord > x0+runLen) {
+ touchedTile[ty][tx] += val * runLen;
+ } else {
+ touchedTile[ty][tx] += val * (nextTileXCoord - x0);
+ }
+ tx++;
+ }
+ // don't go all the way to tx1 - we need to handle the last
+ // tile as a special case (just like we did with the first
+ for (; tx < tx1; tx++) {
+// try {
+ touchedTile[ty][tx] += (val << TILE_SIZE_LG);
+// } catch (RuntimeException e) {
+// System.out.println("x0, y0: " + x0 + ", " + y0);
+// System.out.printf("tx, ty, tx1: %d, %d, %d %n", tx, ty, tx1);
+// System.out.printf("bboxX/Y0/1: %d, %d, %d, %d %n",
+// bboxX0, bboxY0, bboxX1, bboxY1);
+// throw e;
+// }
+ }
+ // they will be equal unless x0>>TILE_SIZE_LG == tx1
+ if (tx == tx1) {
+ int lastXCoord = Math.min(x0 + runLen, (tx + 1) << TILE_SIZE_LG);
+ int txXCoord = tx << TILE_SIZE_LG;
+ touchedTile[ty][tx] += val * (lastXCoord - txXCoord);
+ }
+ }
+ x0 += runLen;
}
}
- void addRLERun(byte val, int runLen) {
- reallocRowAARLE(alphaRLELength + 2);
- rowAARLE[alphaRLELength++] = val;
- rowAARLE[alphaRLELength++] = (byte)runLen;
+ void startRow(int y, int x) {
+ // rows are supposed to be added by increasing y.
+ assert y - bboxY0 > y0;
+ assert y <= bboxY1; // perhaps this should be < instead of <=
+
+ y0 = y - bboxY0;
+ // this should be a new, uninitialized row.
+ assert rowAARLE[y0][1] == 0;
+
+ x0 = x - bboxX0;
+ assert x0 >= 0 : "Input must not be to the left of bbox bounds";
+
+ // the way addTupleToRow is implemented it would work for this but it's
+ // not a good idea to use it because it is meant for adding
+ // RLE tuples, not the first tuple (which is special).
+ rowAARLE[y0][0] = x;
+ rowAARLE[y0][1] = 2;
}
- void startRow(int y, int x0, int x1) {
- if (alphaRows == 0) {
- bboxY0 = y;
- bboxY1 = y+1;
- bboxX0 = x0;
- bboxX1 = x1+1;
- } else {
- if (bboxX0 > x0) bboxX0 = x0;
- if (bboxX1 < x1 + 1) bboxX1 = x1 + 1;
- while (bboxY1++ < y) {
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = 0;
- // Assuming last 2 entries in rowAARLE are 0,0
- rowOffsetsRLE[alphaRows] = alphaRLELength-2;
- alphaRows++;
- }
- }
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = x0;
- rowOffsetsRLE[alphaRows] = alphaRLELength;
- alphaRows++;
+ int alphaSumInTile(int x, int y) {
+ x -= bboxX0;
+ y -= bboxY0;
+ return touchedTile[y>>TILE_SIZE_LG][x>>TILE_SIZE_LG];
+ }
+
+ int minTouched(int rowidx) {
+ return rowAARLE[rowidx][0];
}
- public synchronized void dispose() {
- rowAARLE = null;
- alphaRLELength = 0;
+ int rowLength(int rowidx) {
+ return rowAARLE[rowidx][1];
+ }
- minTouched = null;
- rowOffsetsRLE = null;
- alphaRows = 0;
-
- bboxX0 = bboxY0 = bboxX1 = bboxY1 = 0;
+ private void addTupleToRow(int row, int a, int b) {
+ int end = rowAARLE[row][1];
+ rowAARLE[row] = Helpers.widenArray(rowAARLE[row], end, 2);
+ rowAARLE[row][end++] = a;
+ rowAARLE[row][end++] = b;
+ rowAARLE[row][1] = end;
}
- public void print(java.io.PrintStream out) {
- synchronized (out) {
- out.println("bbox = ["+
- bboxX0+", "+bboxY0+" => "+
- bboxX1+", "+bboxY1+"]");
-
- out.println("alphRLELength = "+alphaRLELength);
-
- for (int y = bboxY0; y < bboxY1; y++) {
- int i = y-bboxY0;
- out.println("row["+i+"] == {"+
- "minX = "+minTouched[i]+
- ", off = "+rowOffsetsRLE[i]+"}");
+ @Override
+ public String toString() {
+ String ret = "bbox = ["+
+ bboxX0+", "+bboxY0+" => "+
+ bboxX1+", "+bboxY1+"]\n";
+ for (int[] row : rowAARLE) {
+ if (row != null) {
+ ret += ("minTouchedX=" + row[0] +
+ "\tRLE Entries: " + Arrays.toString(
+ Arrays.copyOfRange(row, 2, row[1])) + "\n");
+ } else {
+ ret += "[]\n";
+ }
}
-
- for (int i = 0; i < alphaRLELength; i += 2) {
- out.println("rle["+i+"] = "+
- (rowAARLE[i+1]&0xff)+" of "+(rowAARLE[i]&0xff));
- }
- }
+ return ret;
}
}
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java Sat Nov 13 18:56:50 2010 -0800
@@ -27,7 +27,7 @@
import java.awt.Shape;
import java.awt.BasicStroke;
-import java.awt.geom.FlatteningPathIterator;
+import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Path2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
@@ -38,8 +38,6 @@
import sun.java2d.pipe.AATileGenerator;
public class PiscesRenderingEngine extends RenderingEngine {
- public static double defaultFlat = 0.1;
-
private static enum NormMode {OFF, ON_NO_AA, ON_WITH_AA}
/**
@@ -78,20 +76,29 @@
miterlimit,
dashes,
dashphase,
- new LineSink() {
+ new PathConsumer2D() {
public void moveTo(float x0, float y0) {
p2d.moveTo(x0, y0);
}
- public void lineJoin() {}
public void lineTo(float x1, float y1) {
p2d.lineTo(x1, y1);
}
- public void close() {
+ public void closePath() {
p2d.closePath();
}
- public void end() {}
+ public void pathDone() {}
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3) {
+ p2d.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ p2d.quadTo(x1, y1, x2, y2);
+ }
+ public long getNativeConsumer() {
+ throw new InternalError("Not using a native peer");
+ }
});
-
return p2d;
}
@@ -133,22 +140,7 @@
NormMode norm = (normalize) ?
((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
: NormMode.OFF;
- strokeTo(src, at, bs, thin, norm, antialias,
- new LineSink() {
- public void moveTo(float x0, float y0) {
- consumer.moveTo(x0, y0);
- }
- public void lineJoin() {}
- public void lineTo(float x1, float y1) {
- consumer.lineTo(x1, y1);
- }
- public void close() {
- consumer.closePath();
- }
- public void end() {
- consumer.pathDone();
- }
- });
+ strokeTo(src, at, bs, thin, norm, antialias, consumer);
}
void strokeTo(Shape src,
@@ -157,7 +149,7 @@
boolean thin,
NormMode normalize,
boolean antialias,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
float lw;
if (thin) {
@@ -178,7 +170,7 @@
bs.getMiterLimit(),
bs.getDashArray(),
bs.getDashPhase(),
- lsink);
+ pc2d);
}
private float userSpaceLineWidth(AffineTransform at, float lw) {
@@ -256,28 +248,113 @@
float miterlimit,
float dashes[],
float dashphase,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
- float a00 = 1f, a01 = 0f, a10 = 0f, a11 = 1f;
+ // We use inat and outat so that in Stroker and Dasher we can work only
+ // with the pre-transformation coordinates. This will repeat a lot of
+ // computations done in the path iterator, but the alternative is to
+ // work with transformed paths and compute untransformed coordinates
+ // as needed. This would be faster but I do not think the complexity
+ // of working with both untransformed and transformed coordinates in
+ // the same code is worth it.
+ // However, if a path's width is constant after a transformation,
+ // we can skip all this untransforming.
+
+ // If normalization is off we save some transformations by not
+ // transforming the input to pisces. Instead, we apply the
+ // transformation after the path processing has been done.
+ // We can't do this if normalization is on, because it isn't a good
+ // idea to normalize before the transformation is applied.
+ AffineTransform inat = null;
+ AffineTransform outat = null;
+
+ PathIterator pi = null;
+
if (at != null && !at.isIdentity()) {
- a00 = (float)at.getScaleX();
- a01 = (float)at.getShearX();
- a10 = (float)at.getShearY();
- a11 = (float)at.getScaleY();
+ final double a = at.getScaleX();
+ final double b = at.getShearX();
+ final double c = at.getShearY();
+ final double d = at.getScaleY();
+ final double det = a * d - c * b;
+ if (Math.abs(det) <= 2 * Float.MIN_VALUE) {
+ // this rendering engine takes one dimensional curves and turns
+ // them into 2D shapes by giving them width.
+ // However, if everything is to be passed through a singular
+ // transformation, these 2D shapes will be squashed down to 1D
+ // again so, nothing can be drawn.
+
+ // Every path needs an initial moveTo and a pathDone. If these
+ // aren't there this causes a SIGSEV in libawt.so (at the time
+ // of writing of this comment (September 16, 2010)). Actually,
+ // I'm not sure if the moveTo is necessary to avoid the SIGSEV
+ // but the pathDone is definitely needed.
+ pc2d.moveTo(0, 0);
+ pc2d.pathDone();
+ return;
+ }
+
+ // If the transform is a constant multiple of an orthogonal transformation
+ // then every length is just multiplied by a constant, so we just
+ // need to transform input paths to stroker and tell stroker
+ // the scaled width. This condition is satisfied if
+ // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
+ // leave a bit of room for error.
+ if (nearZero(a*b + c*d, 2) && nearZero(a*a+c*c - (b*b+d*d), 2)) {
+ double scale = Math.sqrt(a*a + c*c);
+ if (dashes != null) {
+ dashes = java.util.Arrays.copyOf(dashes, dashes.length);
+ for (int i = 0; i < dashes.length; i++) {
+ dashes[i] = (float)(scale * dashes[i]);
+ }
+ dashphase = (float)(scale * dashphase);
+ }
+ width = (float)(scale * width);
+ pi = src.getPathIterator(at);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
+ // leave inat and outat null.
+ } else {
+ // We only need the inverse if normalization is on. Otherwise
+ // we just don't transform the input paths, do all the stroking
+ // and then transform out output (instead of making PathIterator
+ // apply the transformation, us applying the inverse, and then
+ // us applying the transform again to our output).
+ outat = at;
+ if (normalize != NormMode.OFF) {
+ try {
+ inat = outat.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ // we made sure this can't happen
+ e.printStackTrace();
+ }
+ pi = src.getPathIterator(at);
+ pi = new NormalizingPathIterator(pi, normalize);
+ } else {
+ pi = src.getPathIterator(null);
+ }
+ }
+ } else {
+ // either at is null or it's the identity. In either case
+ // we don't transform the path.
+ pi = src.getPathIterator(null);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
}
- lsink = new Stroker(lsink, width, caps, join, miterlimit, a00, a01, a10, a11);
+
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, outat);
+ pc2d = new Stroker(pc2d, width, caps, join, miterlimit);
if (dashes != null) {
- lsink = new Dasher(lsink, dashes, dashphase, a00, a01, a10, a11);
+ pc2d = new Dasher(pc2d, dashes, dashphase);
}
- PathIterator pi;
- if (normalize != NormMode.OFF) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(src.getPathIterator(at), normalize),
- defaultFlat);
- } else {
- pi = src.getPathIterator(at, defaultFlat);
- }
- pathTo(pi, lsink);
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, inat);
+
+ pathTo(pi, pc2d);
+ }
+
+ private static boolean nearZero(double num, int nulps) {
+ return Math.abs(num) < nulps * Math.ulp(num);
}
private static class NormalizingPathIterator implements PathIterator {
@@ -337,10 +414,10 @@
}
// normalize endpoint
- float x_adjust = (float)Math.floor(coords[lastCoord] + lval) + rval -
- coords[lastCoord];
- float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) + rval -
- coords[lastCoord + 1];
+ float x_adjust = (float)Math.floor(coords[lastCoord] + lval) +
+ rval - coords[lastCoord];
+ float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) +
+ rval - coords[lastCoord + 1];
coords[lastCoord ] += x_adjust;
coords[lastCoord + 1] += y_adjust;
@@ -393,27 +470,9 @@
}
}
- void pathTo(PathIterator pi, LineSink lsink) {
- float coords[] = new float[2];
- while (!pi.isDone()) {
- switch (pi.currentSegment(coords)) {
- case PathIterator.SEG_MOVETO:
- lsink.moveTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_LINETO:
- lsink.lineJoin();
- lsink.lineTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_CLOSE:
- lsink.lineJoin();
- lsink.close();
- break;
- default:
- throw new InternalError("unknown flattened segment type");
- }
- pi.next();
- }
- lsink.end();
+ static void pathTo(PathIterator pi, PathConsumer2D pc2d) {
+ RenderingEngine.feedConsumer(pi, pc2d);
+ pc2d.pathDone();
}
/**
@@ -471,32 +530,29 @@
boolean normalize,
int bbox[])
{
- PiscesCache pc = PiscesCache.createInstance();
Renderer r;
NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
if (bs == null) {
PathIterator pi;
if (normalize) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(s.getPathIterator(at), norm),
- defaultFlat);
+ pi = new NormalizingPathIterator(s.getPathIterator(at), norm);
} else {
- pi = s.getPathIterator(at, defaultFlat);
+ pi = s.getPathIterator(at);
}
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- pi.getWindingRule(), pc);
+ pi.getWindingRule());
pathTo(pi, r);
} else {
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- PathIterator.WIND_NON_ZERO, pc);
+ PathIterator.WIND_NON_ZERO);
strokeTo(s, at, bs, thin, norm, true, r);
}
r.endRendering();
- PiscesTileGenerator ptg = new PiscesTileGenerator(pc, r.MAX_AA_ALPHA);
+ PiscesTileGenerator ptg = new PiscesTileGenerator(r, r.MAX_AA_ALPHA);
ptg.getBbox(bbox);
return ptg;
}
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,40 +25,54 @@
package sun.java2d.pisces;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import sun.java2d.pipe.AATileGenerator;
-public class PiscesTileGenerator implements AATileGenerator {
- public static final int TILE_SIZE = 32;
+public final class PiscesTileGenerator implements AATileGenerator {
+ public static final int TILE_SIZE = PiscesCache.TILE_SIZE;
+
+ // perhaps we should be using weak references here, but right now
+ // that's not necessary. The way the renderer is, this map will
+ // never contain more than one element - the one with key 64, since
+ // we only do 8x8 supersampling.
+ private static final Map<Integer, byte[]> alphaMapsCache = new
+ ConcurrentHashMap<Integer, byte[]>();
PiscesCache cache;
int x, y;
- int maxalpha;
+ final int maxalpha;
+ private final int maxTileAlphaSum;
+
+ // The alpha map used by this object (taken out of our map cache) to convert
+ // pixel coverage counts gotten from PiscesCache (which are in the range
+ // [0, maxalpha]) into alpha values, which are in [0,256).
byte alphaMap[];
- public PiscesTileGenerator(PiscesCache cache, int maxalpha) {
- this.cache = cache;
+ public PiscesTileGenerator(Renderer r, int maxalpha) {
+ this.cache = r.getCache();
this.x = cache.bboxX0;
this.y = cache.bboxY0;
this.alphaMap = getAlphaMap(maxalpha);
this.maxalpha = maxalpha;
+ this.maxTileAlphaSum = TILE_SIZE*TILE_SIZE*maxalpha;
}
- static int prevMaxAlpha;
- static byte prevAlphaMap[];
+ private static byte[] buildAlphaMap(int maxalpha) {
+ byte[] alMap = new byte[maxalpha+1];
+ int halfmaxalpha = maxalpha>>2;
+ for (int i = 0; i <= maxalpha; i++) {
+ alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
+ }
+ return alMap;
+ }
- public synchronized static byte[] getAlphaMap(int maxalpha) {
- if (maxalpha != prevMaxAlpha) {
- prevAlphaMap = new byte[maxalpha+300];
- int halfmaxalpha = maxalpha>>2;
- for (int i = 0; i <= maxalpha; i++) {
- prevAlphaMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
- }
- for (int i = maxalpha; i < prevAlphaMap.length; i++) {
- prevAlphaMap[i] = (byte) 255;
- }
- prevMaxAlpha = maxalpha;
+ public static byte[] getAlphaMap(int maxalpha) {
+ if (!alphaMapsCache.containsKey(maxalpha)) {
+ alphaMapsCache.put(maxalpha, buildAlphaMap(maxalpha));
}
- return prevAlphaMap;
+ return alphaMapsCache.get(maxalpha);
}
public void getBbox(int bbox[]) {
@@ -96,53 +110,24 @@
* value for partial coverage of the tile
*/
public int getTypicalAlpha() {
- if (true) return 0x80;
- // Decode run-length encoded alpha mask data
- // The data for row j begins at cache.rowOffsetsRLE[j]
- // and is encoded as a set of 2-byte pairs (val, runLen)
- // terminated by a (0, 0) pair.
-
- int x0 = this.x;
- int x1 = x0 + TILE_SIZE;
- int y0 = this.y;
- int y1 = y0 + TILE_SIZE;
- if (x1 > cache.bboxX1) x1 = cache.bboxX1;
- if (y1 > cache.bboxY1) y1 = cache.bboxY1;
- y0 -= cache.bboxY0;
- y1 -= cache.bboxY0;
-
- int ret = -1;
- for (int cy = y0; cy < y1; cy++) {
- int pos = cache.rowOffsetsRLE[cy];
- int cx = cache.minTouched[cy];
-
- if (cx > x0) {
- if (ret > 0) return 0x80;
- ret = 0x00;
- }
- while (cx < x1) {
- int runLen = cache.rowAARLE[pos + 1] & 0xff;
- if (runLen == 0) {
- if (ret > 0) return 0x80;
- ret = 0x00;
- break;
- }
- cx += runLen;
- if (cx > x0) {
- int val = cache.rowAARLE[pos] & 0xff;
- if (ret != val) {
- if (ret < 0) {
- if (val != 0x00 && val != maxalpha) return 0x80;
- ret = val;
- } else {
- return 0x80;
- }
- }
- }
- pos += 2;
- }
- }
- return ret;
+ int al = cache.alphaSumInTile(x, y);
+ // Note: if we have a filled rectangle that doesn't end on a tile
+ // border, we could still return 0xff, even though al!=maxTileAlphaSum
+ // This is because if we return 0xff, our users will fill a rectangle
+ // starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),
+ // and height min(TILE_SIZE,bboxY1-y), which is what should happen.
+ // However, to support this, we would have to use 2 Math.min's
+ // and 2 multiplications per tile, instead of just 2 multiplications
+ // to compute maxTileAlphaSum. The savings offered would probably
+ // not be worth it, considering how rare this case is.
+ // Note: I have not tested this, so in the future if it is determined
+ // that it is worth it, it should be implemented. Perhaps this method's
+ // interface should be changed to take arguments the width and height
+ // of the current tile. This would eliminate the 2 Math.min calls that
+ // would be needed here, since our caller needs to compute these 2
+ // values anyway.
+ return (al == 0x00 ? 0x00 :
+ (al == maxTileAlphaSum ? 0xff : 0x80));
}
/**
@@ -179,22 +164,24 @@
int idx = offset;
for (int cy = y0; cy < y1; cy++) {
- int pos = cache.rowOffsetsRLE[cy];
- int cx = cache.minTouched[cy];
+ int[] row = cache.rowAARLE[cy];
+ assert row != null;
+ int cx = cache.minTouched(cy);
if (cx > x1) cx = x1;
- if (cx > x0) {
- //System.out.println("L["+(cx-x0)+"]");
- for (int i = x0; i < cx; i++) {
- tile[idx++] = 0x00;
- }
+ for (int i = x0; i < cx; i++) {
+ tile[idx++] = 0x00;
}
- while (cx < x1) {
+
+ int pos = 2;
+ while (cx < x1 && pos < row[1]) {
byte val;
int runLen = 0;
+ assert row[1] > 2;
try {
- val = alphaMap[cache.rowAARLE[pos] & 0xff];
- runLen = cache.rowAARLE[pos + 1] & 0xff;
+ val = alphaMap[row[pos]];
+ runLen = row[pos + 1];
+ assert runLen > 0;
} catch (RuntimeException e0) {
System.out.println("maxalpha = "+maxalpha);
System.out.println("tile["+x0+", "+y0+
@@ -202,14 +189,12 @@
System.out.println("cx = "+cx+", cy = "+cy);
System.out.println("idx = "+idx+", pos = "+pos);
System.out.println("len = "+runLen);
- cache.print(System.out);
+ System.out.print(cache.toString());
e0.printStackTrace();
System.exit(1);
return;
}
- if (runLen == 0) {
- break;
- }
+
int rx0 = cx;
cx += runLen;
int rx1 = cx;
@@ -228,7 +213,7 @@
System.out.println("idx = "+idx+", pos = "+pos);
System.out.println("rx0 = "+rx0+", rx1 = "+rx1);
System.out.println("len = "+runLen);
- cache.print(System.out);
+ System.out.print(cache.toString());
e.printStackTrace();
System.exit(1);
return;
@@ -265,4 +250,4 @@
* No further calls will be made on this instance.
*/
public void dispose() {}
-}
+}
\ No newline at end of file
--- a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java Sat Nov 13 18:56:50 2010 -0800
@@ -26,250 +26,552 @@
package sun.java2d.pisces;
import java.util.Arrays;
+import java.util.Iterator;
-public class Renderer implements LineSink {
+import sun.awt.geom.PathConsumer2D;
-///////////////////////////////////////////////////////////////////////////////
-// Scan line iterator and edge crossing data.
-//////////////////////////////////////////////////////////////////////////////
+public class Renderer implements PathConsumer2D {
- private int[] crossings;
+ private class ScanlineIterator {
+
+ private int[] crossings;
- // This is an array of indices into the edge array. It is initialized to
- // [i * SIZEOF_STRUCT_EDGE for i in range(0, edgesSize/SIZEOF_STRUCT_EDGE)]
- // (where range(i, j) is i,i+1,...,j-1 -- just like in python).
- // The reason for keeping this is because we need the edges array sorted
- // by y0, but we don't want to move all that data around, so instead we
- // sort the indices into the edge array, and use edgeIndices to access
- // the edges array. This is meant to simulate a pointer array (hence the name)
- private int[] edgePtrs;
+ // crossing bounds. The bounds are not necessarily tight (the scan line
+ // at minY, for example, might have no crossings). The x bounds will
+ // be accumulated as crossings are computed.
+ private int minY, maxY;
+ private int nextY;
- // crossing bounds. The bounds are not necessarily tight (the scan line
- // at minY, for example, might have no crossings). The x bounds will
- // be accumulated as crossings are computed.
- private int minY, maxY;
- private int minX, maxX;
- private int nextY;
+ // indices into the segment pointer lists. They indicate the "active"
+ // sublist in the segment lists (the portion of the list that contains
+ // all the segments that cross the next scan line).
+ private int elo, ehi;
+ private final int[] edgePtrs;
+ private int qlo, qhi;
+ private final int[] quadPtrs;
+ private int clo, chi;
+ private final int[] curvePtrs;
+
+ private static final int INIT_CROSSINGS_SIZE = 10;
+
+ private ScanlineIterator() {
+ crossings = new int[INIT_CROSSINGS_SIZE];
- // indices into the edge pointer list. They indicate the "active" sublist in
- // the edge list (the portion of the list that contains all the edges that
- // cross the next scan line).
- private int lo, hi;
+ edgePtrs = new int[numEdges];
+ Helpers.fillWithIdxes(edgePtrs, SIZEOF_EDGE);
+ qsort(edges, edgePtrs, YMIN, 0, numEdges - 1);
- private static final int INIT_CROSSINGS_SIZE = 50;
- private void ScanLineItInitialize() {
- crossings = new int[INIT_CROSSINGS_SIZE];
- edgePtrs = new int[edgesSize / SIZEOF_STRUCT_EDGE];
- for (int i = 0; i < edgePtrs.length; i++) {
- edgePtrs[i] = i * SIZEOF_STRUCT_EDGE;
- }
+ quadPtrs = new int[numQuads];
+ Helpers.fillWithIdxes(quadPtrs, SIZEOF_QUAD);
+ qsort(quads, quadPtrs, YMIN, 0, numQuads - 1);
+
+ curvePtrs = new int[numCurves];
+ Helpers.fillWithIdxes(curvePtrs, SIZEOF_CURVE);
+ qsort(curves, curvePtrs, YMIN, 0, numCurves - 1);
- qsort(0, edgePtrs.length - 1);
+ // We don't care if we clip some of the line off with ceil, since
+ // no scan line crossings will be eliminated (in fact, the ceil is
+ // the y of the first scan line crossing).
+ nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
+ maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
- // We don't care if we clip some of the line off with ceil, since
- // no scan line crossings will be eliminated (in fact, the ceil is
- // the y of the first scan line crossing).
- nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
- maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
+ for (elo = 0; elo < numEdges && edges[edgePtrs[elo]+YMAX] <= minY; elo++)
+ ;
+ // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
+ for (ehi = elo; ehi < numEdges && edges[edgePtrs[ehi]+YMIN] <= minY; ehi++)
+ edgeSetCurY(edgePtrs[ehi], minY);// TODO: make minY a float to avoid casts
- for (lo = 0; lo < edgePtrs.length && edges[edgePtrs[lo]+Y1] <= nextY; lo++)
- ;
- for (hi = lo; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++)
- ; // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
- for (int i = lo; i < hi; i++) {
- setCurY(edgePtrs[i], nextY);
+ for (qlo = 0; qlo < numQuads && quads[quadPtrs[qlo]+YMAX] <= minY; qlo++)
+ ;
+ for (qhi = qlo; qhi < numQuads && quads[quadPtrs[qhi]+YMIN] <= minY; qhi++)
+ quadSetCurY(quadPtrs[qhi], minY);
+
+ for (clo = 0; clo < numCurves && curves[curvePtrs[clo]+YMAX] <= minY; clo++)
+ ;
+ for (chi = clo; chi < numCurves && curves[curvePtrs[chi]+YMIN] <= minY; chi++)
+ curveSetCurY(curvePtrs[chi], minY);
}
- // We accumulate X in the iterator because accumulating it in addEdge
- // like we do with Y does not do much good: if there's an edge
- // (0,0)->(1000,10000), and if y gets clipped to 1000, then the x
- // bound should be 100, but the accumulator from addEdge would say 1000,
- // so we'd still have to accumulate the X bounds as we add crossings.
- minX = boundsMinX;
- maxX = boundsMaxX;
- }
+ private int next() {
+ // we go through the active lists and remove segments that don't cross
+ // the nextY scanline.
+ int crossingIdx = 0;
+ for (int i = elo; i < ehi; i++) {
+ if (edges[edgePtrs[i]+YMAX] <= nextY) {
+ edgePtrs[i] = edgePtrs[elo++];
+ }
+ }
+ for (int i = qlo; i < qhi; i++) {
+ if (quads[quadPtrs[i]+YMAX] <= nextY) {
+ quadPtrs[i] = quadPtrs[qlo++];
+ }
+ }
+ for (int i = clo; i < chi; i++) {
+ if (curves[curvePtrs[i]+YMAX] <= nextY) {
+ curvePtrs[i] = curvePtrs[clo++];
+ }
+ }
- private int ScanLineItCurrentY() {
- return nextY - 1;
- }
+ crossings = Helpers.widenArray(crossings, 0, ehi-elo+qhi-qlo+chi-clo);
- private int ScanLineItGoToNextYAndComputeCrossings() {
- // we go through the active list and remove the ones that don't cross
- // the nextY scanline.
- int crossingIdx = 0;
- for (int i = lo; i < hi; i++) {
- if (edges[edgePtrs[i]+Y1] <= nextY) {
- edgePtrs[i] = edgePtrs[lo++];
+ // Now every edge between lo and hi crosses nextY. Compute it's
+ // crossing and put it in the crossings array.
+ for (int i = elo; i < ehi; i++) {
+ int ptr = edgePtrs[i];
+ addCrossing(nextY, (int)edges[ptr+CURX], edges[ptr+OR], crossingIdx);
+ edgeGoToNextY(ptr);
+ crossingIdx++;
+ }
+ for (int i = qlo; i < qhi; i++) {
+ int ptr = quadPtrs[i];
+ addCrossing(nextY, (int)quads[ptr+CURX], quads[ptr+OR], crossingIdx);
+ quadGoToNextY(ptr);
+ crossingIdx++;
}
- }
- if (hi - lo > crossings.length) {
- int newSize = Math.max(hi - lo, crossings.length * 2);
- crossings = Arrays.copyOf(crossings, newSize);
- }
- // Now every edge between lo and hi crosses nextY. Compute it's
- // crossing and put it in the crossings array.
- for (int i = lo; i < hi; i++) {
- addCrossing(nextY, getCurCrossing(edgePtrs[i]), (int)edges[edgePtrs[i]+OR], crossingIdx);
- gotoNextY(edgePtrs[i]);
- crossingIdx++;
+ for (int i = clo; i < chi; i++) {
+ int ptr = curvePtrs[i];
+ addCrossing(nextY, (int)curves[ptr+CURX], curves[ptr+OR], crossingIdx);
+ curveGoToNextY(ptr);
+ crossingIdx++;
+ }
+
+ nextY++;
+ // Expand active lists to include new edges.
+ for (; ehi < numEdges && edges[edgePtrs[ehi]+YMIN] <= nextY; ehi++) {
+ edgeSetCurY(edgePtrs[ehi], nextY);
+ }
+ for (; qhi < numQuads && quads[quadPtrs[qhi]+YMIN] <= nextY; qhi++) {
+ quadSetCurY(quadPtrs[qhi], nextY);
+ }
+ for (; chi < numCurves && curves[curvePtrs[chi]+YMIN] <= nextY; chi++) {
+ curveSetCurY(curvePtrs[chi], nextY);
+ }
+ Arrays.sort(crossings, 0, crossingIdx);
+ return crossingIdx;
}
- nextY++;
- // Expand active list to include new edges.
- for (; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++) {
- setCurY(edgePtrs[hi], nextY);
+ private boolean hasNext() {
+ return nextY < maxY;
}
- Arrays.sort(crossings, 0, crossingIdx);
- return crossingIdx;
- }
-
- private boolean ScanLineItHasNext() {
- return nextY < maxY;
- }
+ private int curY() {
+ return nextY - 1;
+ }
- private void addCrossing(int y, int x, int or, int idx) {
- if (x < minX) {
- minX = x;
+ private void addCrossing(int y, int x, float or, int idx) {
+ x <<= 1;
+ crossings[idx] = ((or > 0) ? (x | 0x1) : x);
}
- if (x > maxX) {
- maxX = x;
- }
- x <<= 1;
- crossings[idx] = ((or == 1) ? (x | 0x1) : x);
}
-
-
// quicksort implementation for sorting the edge indices ("pointers")
// by increasing y0. first, last are indices into the "pointer" array
// It sorts the pointer array from first (inclusive) to last (inclusive)
- private void qsort(int first, int last) {
+ private static void qsort(final float[] data, final int[] ptrs,
+ final int fieldForCmp, int first, int last)
+ {
if (last > first) {
- int p = partition(first, last);
+ int p = partition(data, ptrs, fieldForCmp, first, last);
if (first < p - 1) {
- qsort(first, p - 1);
+ qsort(data, ptrs, fieldForCmp, first, p - 1);
}
if (p < last) {
- qsort(p, last);
+ qsort(data, ptrs, fieldForCmp, p, last);
}
}
}
// i, j are indices into edgePtrs.
- private int partition(int i, int j) {
- int pivotVal = edgePtrs[i];
+ private static int partition(final float[] data, final int[] ptrs,
+ final int fieldForCmp, int i, int j)
+ {
+ int pivotValFieldForCmp = ptrs[i]+fieldForCmp;
while (i <= j) {
// edges[edgePtrs[i]+1] is equivalent to (*(edgePtrs[i])).y0 in C
- while (edges[edgePtrs[i]+CURY] < edges[pivotVal+CURY]) { i++; }
- while (edges[edgePtrs[j]+CURY] > edges[pivotVal+CURY]) { j--; }
+ while (data[ptrs[i]+fieldForCmp] < data[pivotValFieldForCmp])
+ i++;
+ while (data[ptrs[j]+fieldForCmp] > data[pivotValFieldForCmp])
+ j--;
if (i <= j) {
- int tmp = edgePtrs[i];
- edgePtrs[i] = edgePtrs[j];
- edgePtrs[j] = tmp;
+ int tmp = ptrs[i];
+ ptrs[i] = ptrs[j];
+ ptrs[j] = tmp;
i++;
j--;
}
}
return i;
}
-
//============================================================================
//////////////////////////////////////////////////////////////////////////////
// EDGE LIST
//////////////////////////////////////////////////////////////////////////////
+// TODO(maybe): very tempting to use fixed point here. A lot of opportunities
+// for shifts and just removing certain operations altogether.
+// TODO: it might be worth it to make an EdgeList class. It would probably
+// clean things up a bit and not impact performance much.
- private static final int INIT_NUM_EDGES = 1000;
- private static final int SIZEOF_STRUCT_EDGE = 5;
+ // common to all types of input path segments.
+ private static final int YMIN = 0;
+ private static final int YMAX = 1;
+ private static final int CURX = 2;
+ // this and OR are meant to be indeces into "int" fields, but arrays must
+ // be homogenous, so every field is a float. However floats can represent
+ // exactly up to 26 bit ints, so we're ok.
+ private static final int CURY = 3;
+ private static final int OR = 4;
+
+ // for straight lines only:
+ private static final int SLOPE = 5;
+
+ // for quads and cubics:
+ private static final int X0 = 5;
+ private static final int Y0 = 6;
+ private static final int XL = 7;
+ private static final int COUNT = 8;
+ private static final int CURSLOPE = 9;
+ private static final int DX = 10;
+ private static final int DY = 11;
+ private static final int DDX = 12;
+ private static final int DDY = 13;
+
+ // for cubics only
+ private static final int DDDX = 14;
+ private static final int DDDY = 15;
+
+ private float edgeMinY = Float.POSITIVE_INFINITY;
+ private float edgeMaxY = Float.NEGATIVE_INFINITY;
+ private float edgeMinX = Float.POSITIVE_INFINITY;
+ private float edgeMaxX = Float.NEGATIVE_INFINITY;
+
+ private static final int SIZEOF_EDGE = 6;
+ private float[] edges = null;
+ private int numEdges;
+ // these are static because we need them to be usable from ScanlineIterator
+ private void edgeSetCurY(final int idx, int y) {
+ edges[idx+CURX] += (y - edges[idx+CURY]) * edges[idx+SLOPE];
+ edges[idx+CURY] = y;
+ }
+ private void edgeGoToNextY(final int idx) {
+ edges[idx+CURY] += 1;
+ edges[idx+CURX] += edges[idx+SLOPE];
+ }
+
+
+ private static final int SIZEOF_QUAD = 14;
+ private float[] quads = null;
+ private int numQuads;
+ // This function should be called exactly once, to set the first scanline
+ // of the curve. Before it is called, the curve should think its first
+ // scanline is CEIL(YMIN).
+ private void quadSetCurY(final int idx, final int y) {
+ assert y < quads[idx+YMAX];
+ assert (quads[idx+CURY] > y);
+ assert (quads[idx+CURY] == Math.ceil(quads[idx+CURY]));
- // The following array is a poor man's struct array:
- // it simulates a struct array by having
- // edges[SIZEOF_STRUCT_EDGE * i + j] be the jth field in the ith element
- // of an array of edge structs.
- private float[] edges;
- private int edgesSize; // size of the edge list.
- private static final int Y1 = 0;
- private static final int SLOPE = 1;
- private static final int OR = 2; // the orientation. This can be -1 or 1.
- // -1 means up, 1 means down.
- private static final int CURY = 3; // j = 5 corresponds to the "current Y".
- // Each edge keeps track of the last scanline
- // crossing it computed, and this is the y coord of
- // that scanline.
- private static final int CURX = 4; //the x coord of the current crossing.
+ while (quads[idx+CURY] < ((float)y)) {
+ quadGoToNextY(idx);
+ }
+ }
+ private void quadGoToNextY(final int idx) {
+ quads[idx+CURY] += 1;
+ // this will get overriden if the while executes.
+ quads[idx+CURX] += quads[idx+CURSLOPE];
+ int count = (int)quads[idx+COUNT];
+ // this loop should never execute more than once because our
+ // curve is monotonic in Y. Still we put it in because you can
+ // never be too sure when dealing with floating point.
+ while(quads[idx+CURY] >= quads[idx+Y0] && count > 0) {
+ float x0 = quads[idx+X0], y0 = quads[idx+Y0];
+ count = executeQuadAFDIteration(idx);
+ float x1 = quads[idx+X0], y1 = quads[idx+Y0];
+ // our quads are monotonic, so this shouldn't happen, but
+ // it is conceivable that for very flat quads with different
+ // y values at their endpoints AFD might give us a horizontal
+ // segment.
+ if (y1 == y0) {
+ continue;
+ }
+ quads[idx+CURSLOPE] = (x1 - x0) / (y1 - y0);
+ quads[idx+CURX] = x0 + (quads[idx+CURY] - y0) * quads[idx+CURSLOPE];
+ }
+ }
+
- // Note that while the array is declared as a float[] not all of it's
- // elements should be floats. currentY and Orientation should be ints (or int and
- // byte respectively), but they all need to be the same type. This isn't
- // really a problem because floats can represent exactly all 23 bit integers,
- // which should be more than enough.
- // Note, also, that we only need x1 for slope computation, so we don't need
- // to store it. x0, y0 don't need to be stored either. They can be put into
- // curx, cury, and it's ok if they're lost when curx and cury are changed.
- // We take this undeniably ugly and error prone approach (instead of simply
- // making an Edge class) for performance reasons. Also, it would probably be nicer
- // to have one array for each field, but that would defeat the purpose because
- // it would make poor use of the processor cache, since we tend to access
- // all the fields for one edge at a time.
+ private static final int SIZEOF_CURVE = 16;
+ private float[] curves = null;
+ private int numCurves;
+ private void curveSetCurY(final int idx, final int y) {
+ assert y < curves[idx+YMAX];
+ assert (curves[idx+CURY] > y);
+ assert (curves[idx+CURY] == Math.ceil(curves[idx+CURY]));
- private float edgeMinY;
- private float edgeMaxY;
+ while (curves[idx+CURY] < ((float)y)) {
+ curveGoToNextY(idx);
+ }
+ }
+ private void curveGoToNextY(final int idx) {
+ curves[idx+CURY] += 1;
+ // this will get overriden if the while executes.
+ curves[idx+CURX] += curves[idx+CURSLOPE];
+ int count = (int)curves[idx+COUNT];
+ // this loop should never execute more than once because our
+ // curve is monotonic in Y. Still we put it in because you can
+ // never be too sure when dealing with floating point.
+ while(curves[idx+CURY] >= curves[idx+Y0] && count > 0) {
+ float x0 = curves[idx+X0], y0 = curves[idx+Y0];
+ count = executeCurveAFDIteration(idx);
+ float x1 = curves[idx+X0], y1 = curves[idx+Y0];
+ // our curves are monotonic, so this shouldn't happen, but
+ // it is conceivable that for very flat curves with different
+ // y values at their endpoints AFD might give us a horizontal
+ // segment.
+ if (y1 == y0) {
+ continue;
+ }
+ curves[idx+CURSLOPE] = (x1 - x0) / (y1 - y0);
+ curves[idx+CURX] = x0 + (curves[idx+CURY] - y0) * curves[idx+CURSLOPE];
+ }
+ }
- private void addEdge(float x0, float y0, float x1, float y1) {
- float or = (y0 < y1) ? 1f : -1f; // orientation: 1 = UP; -1 = DOWN
- if (or == -1) {
- float tmp = y0;
- y0 = y1;
- y1 = tmp;
- tmp = x0;
- x0 = x1;
- x1 = tmp;
+ private static final float DEC_BND = 20f;
+ private static final float INC_BND = 8f;
+ // Flattens using adaptive forward differencing. This only carries out
+ // one iteration of the AFD loop. All it does is update AFD variables (i.e.
+ // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
+ private int executeQuadAFDIteration(int idx) {
+ int count = (int)quads[idx+COUNT];
+ float ddx = quads[idx+DDX];
+ float ddy = quads[idx+DDY];
+ float dx = quads[idx+DX];
+ float dy = quads[idx+DY];
+
+ while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
+ ddx = ddx / 4;
+ ddy = ddy / 4;
+ dx = (dx - ddx) / 2;
+ dy = (dy - ddy) / 2;
+ count <<= 1;
+ }
+ // can only do this on even "count" values, because we must divide count by 2
+ while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
+ dx = 2 * dx + ddx;
+ dy = 2 * dy + ddy;
+ ddx = 4 * ddx;
+ ddy = 4 * ddy;
+ count >>= 1;
+ }
+ count--;
+ if (count > 0) {
+ quads[idx+X0] += dx;
+ dx += ddx;
+ quads[idx+Y0] += dy;
+ dy += ddy;
+ } else {
+ quads[idx+X0] = quads[idx+XL];
+ quads[idx+Y0] = quads[idx+YMAX];
+ }
+ quads[idx+COUNT] = count;
+ quads[idx+DDX] = ddx;
+ quads[idx+DDY] = ddy;
+ quads[idx+DX] = dx;
+ quads[idx+DY] = dy;
+ return count;
+ }
+ private int executeCurveAFDIteration(int idx) {
+ int count = (int)curves[idx+COUNT];
+ float ddx = curves[idx+DDX];
+ float ddy = curves[idx+DDY];
+ float dx = curves[idx+DX];
+ float dy = curves[idx+DY];
+ float dddx = curves[idx+DDDX];
+ float dddy = curves[idx+DDDY];
+
+ while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
+ dddx /= 8;
+ dddy /= 8;
+ ddx = ddx/4 - dddx;
+ ddy = ddy/4 - dddy;
+ dx = (dx - ddx) / 2;
+ dy = (dy - ddy) / 2;
+ count <<= 1;
+ }
+ // can only do this on even "count" values, because we must divide count by 2
+ while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
+ dx = 2 * dx + ddx;
+ dy = 2 * dy + ddy;
+ ddx = 4 * (ddx + dddx);
+ ddy = 4 * (ddy + dddy);
+ dddx = 8 * dddx;
+ dddy = 8 * dddy;
+ count >>= 1;
+ }
+ count--;
+ if (count > 0) {
+ curves[idx+X0] += dx;
+ dx += ddx;
+ ddx += dddx;
+ curves[idx+Y0] += dy;
+ dy += ddy;
+ ddy += dddy;
+ } else {
+ curves[idx+X0] = curves[idx+XL];
+ curves[idx+Y0] = curves[idx+YMAX];
}
- // skip edges that don't cross a scanline
- if (Math.ceil(y0) >= Math.ceil(y1)) {
+ curves[idx+COUNT] = count;
+ curves[idx+DDDX] = dddx;
+ curves[idx+DDDY] = dddy;
+ curves[idx+DDX] = ddx;
+ curves[idx+DDY] = ddy;
+ curves[idx+DX] = dx;
+ curves[idx+DY] = dy;
+ return count;
+ }
+
+
+ private void initLine(final int idx, float[] pts, int or) {
+ edges[idx+SLOPE] = (pts[2] - pts[0]) / (pts[3] - pts[1]);
+ edges[idx+CURX] = pts[0] + (edges[idx+CURY] - pts[1]) * edges[idx+SLOPE];
+ }
+
+ private void initQuad(final int idx, float[] points, int or) {
+ final int countlg = 3;
+ final int count = 1 << countlg;
+
+ // the dx and dy refer to forward differencing variables, not the last
+ // coefficients of the "points" polynomial
+ final float ddx, ddy, dx, dy;
+ c.set(points, 6);
+
+ ddx = c.dbx / (1 << (2 * countlg));
+ ddy = c.dby / (1 << (2 * countlg));
+ dx = c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
+ dy = c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
+
+ quads[idx+DDX] = ddx;
+ quads[idx+DDY] = ddy;
+ quads[idx+DX] = dx;
+ quads[idx+DY] = dy;
+ quads[idx+COUNT] = count;
+ quads[idx+XL] = points[4];
+ quads[idx+X0] = points[0];
+ quads[idx+Y0] = points[1];
+ executeQuadAFDIteration(idx);
+ float x1 = quads[idx+X0], y1 = quads[idx+Y0];
+ quads[idx+CURSLOPE] = (x1 - points[0]) / (y1 - points[1]);
+ quads[idx+CURX] = points[0] + (quads[idx+CURY] - points[1])*quads[idx+CURSLOPE];
+ }
+
+ private void initCurve(final int idx, float[] points, int or) {
+ final int countlg = 3;
+ final int count = 1 << countlg;
+
+ // the dx and dy refer to forward differencing variables, not the last
+ // coefficients of the "points" polynomial
+ final float dddx, dddy, ddx, ddy, dx, dy;
+ c.set(points, 8);
+ dddx = 2f * c.dax / (1 << (3 * countlg));
+ dddy = 2f * c.day / (1 << (3 * countlg));
+
+ ddx = dddx + c.dbx / (1 << (2 * countlg));
+ ddy = dddy + c.dby / (1 << (2 * countlg));
+ dx = c.ax / (1 << (3 * countlg)) + c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
+ dy = c.ay / (1 << (3 * countlg)) + c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
+
+ curves[idx+DDDX] = dddx;
+ curves[idx+DDDY] = dddy;
+ curves[idx+DDX] = ddx;
+ curves[idx+DDY] = ddy;
+ curves[idx+DX] = dx;
+ curves[idx+DY] = dy;
+ curves[idx+COUNT] = count;
+ curves[idx+XL] = points[6];
+ curves[idx+X0] = points[0];
+ curves[idx+Y0] = points[1];
+ executeCurveAFDIteration(idx);
+ float x1 = curves[idx+X0], y1 = curves[idx+Y0];
+ curves[idx+CURSLOPE] = (x1 - points[0]) / (y1 - points[1]);
+ curves[idx+CURX] = points[0] + (curves[idx+CURY] - points[1])*curves[idx+CURSLOPE];
+ }
+
+ private void addPathSegment(float[] pts, final int type, final int or) {
+ int idx;
+ float[] addTo;
+ switch (type) {
+ case 4:
+ idx = numEdges * SIZEOF_EDGE;
+ addTo = edges = Helpers.widenArray(edges, numEdges*SIZEOF_EDGE, SIZEOF_EDGE);
+ numEdges++;
+ break;
+ case 6:
+ idx = numQuads * SIZEOF_QUAD;
+ addTo = quads = Helpers.widenArray(quads, numQuads*SIZEOF_QUAD, SIZEOF_QUAD);
+ numQuads++;
+ break;
+ case 8:
+ idx = numCurves * SIZEOF_CURVE;
+ addTo = curves = Helpers.widenArray(curves, numCurves*SIZEOF_CURVE, SIZEOF_CURVE);
+ numCurves++;
+ break;
+ default:
+ throw new InternalError();
+ }
+ // set the common fields, except CURX, for which we must know the kind
+ // of curve. NOTE: this must be done before the type specific fields
+ // are initialized, because those depend on the common ones.
+ addTo[idx+YMIN] = pts[1];
+ addTo[idx+YMAX] = pts[type-1];
+ addTo[idx+OR] = or;
+ addTo[idx+CURY] = (float)Math.ceil(pts[1]);
+ switch (type) {
+ case 4:
+ initLine(idx, pts, or);
+ break;
+ case 6:
+ initQuad(idx, pts, or);
+ break;
+ case 8:
+ initCurve(idx, pts, or);
+ break;
+ default:
+ throw new InternalError();
+ }
+ }
+
+ // precondition: the curve in pts must be monotonic and increasing in y.
+ private void somethingTo(float[] pts, final int type, final int or) {
+ // NOTE: it's very important that we check for or >= 0 below (as
+ // opposed to or == 1, or or > 0, or anything else). That's
+ // because if we check for or==1, when the curve being added
+ // is a horizontal line, or will be 0 so or==1 will be false and
+ // x0 and y0 will be updated to pts[0] and pts[1] instead of pts[type-2]
+ // and pts[type-1], which is the correct thing to do.
+ this.x0 = or >= 0 ? pts[type - 2] : pts[0];
+ this.y0 = or >= 0 ? pts[type - 1] : pts[1];
+
+ float minY = pts[1], maxY = pts[type - 1];
+ if (Math.ceil(minY) >= Math.ceil(maxY) ||
+ Math.ceil(minY) >= boundsMaxY || maxY < boundsMinY)
+ {
return;
}
- int newSize = edgesSize + SIZEOF_STRUCT_EDGE;
- if (edges.length < newSize) {
- edges = Arrays.copyOf(edges, newSize * 2);
- }
- edges[edgesSize+CURX] = x0;
- edges[edgesSize+CURY] = y0;
- edges[edgesSize+Y1] = y1;
- edges[edgesSize+SLOPE] = (x1 - x0) / (y1 - y0);
- edges[edgesSize+OR] = or;
- // the crossing values can't be initialized meaningfully yet. This
- // will have to wait until setCurY is called
- edgesSize += SIZEOF_STRUCT_EDGE;
+ if (minY < edgeMinY) { edgeMinY = minY; }
+ if (maxY > edgeMaxY) { edgeMaxY = maxY; }
- // Accumulate edgeMinY and edgeMaxY
- if (y0 < edgeMinY) { edgeMinY = y0; }
- if (y1 > edgeMaxY) { edgeMaxY = y1; }
+ int minXidx = (pts[0] < pts[type-2] ? 0 : type - 2);
+ float minX = pts[minXidx];
+ float maxX = pts[type - 2 - minXidx];
+ if (minX < edgeMinX) { edgeMinX = minX; }
+ if (maxX > edgeMaxX) { edgeMaxX = maxX; }
+ addPathSegment(pts, type, or);
}
- // As far as the following methods care, this edges extends to infinity.
- // They can compute the x intersect of any horizontal line.
- // precondition: idx is the index to the start of the desired edge.
- // So, if the ith edge is wanted, idx should be SIZEOF_STRUCT_EDGE * i
- private void setCurY(int idx, int y) {
- // compute the x crossing of edge at idx and horizontal line y
- // currentXCrossing = (y - y0)*slope + x0
- edges[idx + CURX] = (y - edges[idx + CURY]) * edges[idx + SLOPE] + edges[idx+CURX];
- edges[idx + CURY] = (float)y;
- }
+// END EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
- private void gotoNextY(int idx) {
- edges[idx + CURY] += 1f; // i.e. curY += 1
- edges[idx + CURX] += edges[idx + SLOPE]; // i.e. curXCrossing += slope
- }
-
- private int getCurCrossing(int idx) {
- return (int)edges[idx + CURX];
- }
-//====================================================================================
public static final int WIND_EVEN_ODD = 0;
public static final int WIND_NON_ZERO = 1;
@@ -284,16 +586,13 @@
final int MAX_AA_ALPHA;
// Cache to store RLE-encoded coverage mask of the current primitive
- final PiscesCache cache;
+ PiscesCache cache;
// Bounds of the drawing region, at subpixel precision.
- final private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
-
- // Pixel bounding box for current primitive
- private int pix_bboxX0, pix_bboxY0, pix_bboxX1, pix_bboxY1;
+ private final int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
// Current winding rule
- final private int windingRule;
+ private final int windingRule;
// Current drawing position, i.e., final point of last segment
private float x0, y0;
@@ -304,8 +603,8 @@
public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY,
int pix_boundsX, int pix_boundsY,
int pix_boundsWidth, int pix_boundsHeight,
- int windingRule,
- PiscesCache cache) {
+ int windingRule)
+ {
this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX;
this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY;
this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
@@ -314,23 +613,12 @@
this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
- this.edges = new float[SIZEOF_STRUCT_EDGE * INIT_NUM_EDGES];
- edgeMinY = Float.POSITIVE_INFINITY;
- edgeMaxY = Float.NEGATIVE_INFINITY;
- edgesSize = 0;
-
this.windingRule = windingRule;
- this.cache = cache;
this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X;
this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y;
this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
-
- this.pix_bboxX0 = pix_boundsX;
- this.pix_bboxY0 = pix_boundsY;
- this.pix_bboxX1 = pix_boundsX + pix_boundsWidth;
- this.pix_bboxY1 = pix_boundsY + pix_boundsHeight;
}
private float tosubpixx(float pix_x) {
@@ -341,7 +629,7 @@
}
public void moveTo(float pix_x0, float pix_y0) {
- close();
+ closePath();
this.pix_sx0 = pix_x0;
this.pix_sy0 = pix_y0;
this.y0 = tosubpixy(pix_y0);
@@ -350,39 +638,102 @@
public void lineJoin() { /* do nothing */ }
- public void lineTo(float pix_x1, float pix_y1) {
- float x1 = tosubpixx(pix_x1);
- float y1 = tosubpixy(pix_y1);
+ private final float[][] pts = new float[2][8];
+ private final float[] ts = new float[4];
+
+ private static void invertPolyPoints(float[] pts, int off, int type) {
+ for (int i = off, j = off + type - 2; i < j; i += 2, j -= 2) {
+ float tmp = pts[i];
+ pts[i] = pts[j];
+ pts[j] = tmp;
+ tmp = pts[i+1];
+ pts[i+1] = pts[j+1];
+ pts[j+1] = tmp;
+ }
+ }
- // Ignore horizontal lines
- if (y0 == y1) {
- this.x0 = x1;
- return;
+ // return orientation before making the curve upright.
+ private static int makeMonotonicCurveUpright(float[] pts, int off, int type) {
+ float y0 = pts[off + 1];
+ float y1 = pts[off + type - 1];
+ if (y0 > y1) {
+ invertPolyPoints(pts, off, type);
+ return -1;
+ } else if (y0 < y1) {
+ return 1;
}
-
- addEdge(x0, y0, x1, y1);
+ return 0;
+ }
- this.x0 = x1;
- this.y0 = y1;
+ public void lineTo(float pix_x1, float pix_y1) {
+ pts[0][0] = x0; pts[0][1] = y0;
+ pts[0][2] = tosubpixx(pix_x1); pts[0][3] = tosubpixy(pix_y1);
+ int or = makeMonotonicCurveUpright(pts[0], 0, 4);
+ somethingTo(pts[0], 4, or);
}
- public void close() {
+ Curve c = new Curve();
+ private void curveOrQuadTo(int type) {
+ c.set(pts[0], type);
+ int numTs = c.dxRoots(ts, 0);
+ numTs += c.dyRoots(ts, numTs);
+ numTs = Helpers.filterOutNotInAB(ts, 0, numTs, 0, 1);
+ Helpers.isort(ts, 0, numTs);
+
+ Iterator<float[]> it = Curve.breakPtsAtTs(pts, type, ts, numTs);
+ while(it.hasNext()) {
+ float[] curCurve = it.next();
+ int or = makeMonotonicCurveUpright(curCurve, 0, type);
+ somethingTo(curCurve, type, or);
+ }
+ }
+
+ @Override public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ pts[0][0] = x0; pts[0][1] = y0;
+ pts[0][2] = tosubpixx(x1); pts[0][3] = tosubpixy(y1);
+ pts[0][4] = tosubpixx(x2); pts[0][5] = tosubpixy(y2);
+ pts[0][6] = tosubpixx(x3); pts[0][7] = tosubpixy(y3);
+ curveOrQuadTo(8);
+ }
+
+ @Override public void quadTo(float x1, float y1, float x2, float y2) {
+ pts[0][0] = x0; pts[0][1] = y0;
+ pts[0][2] = tosubpixx(x1); pts[0][3] = tosubpixy(y1);
+ pts[0][4] = tosubpixx(x2); pts[0][5] = tosubpixy(y2);
+ curveOrQuadTo(6);
+ }
+
+ public void closePath() {
// lineTo expects its input in pixel coordinates.
lineTo(pix_sx0, pix_sy0);
}
- public void end() {
- close();
+ public void pathDone() {
+ closePath();
}
- private void _endRendering() {
+
+ @Override
+ public long getNativeConsumer() {
+ throw new InternalError("Renderer does not use a native consumer.");
+ }
+
+ private void _endRendering(final int pix_bboxx0, final int pix_bboxy0,
+ final int pix_bboxx1, final int pix_bboxy1)
+ {
// Mask to determine the relevant bit of the crossing sum
// 0x1 if EVEN_ODD, all bits if NON_ZERO
int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
// add 1 to better deal with the last pixel in a pixel row.
- int width = ((boundsMaxX - boundsMinX) >> SUBPIXEL_LG_POSITIONS_X) + 1;
- byte[] alpha = new byte[width+1];
+ int width = pix_bboxx1 - pix_bboxx0 + 1;
+ int[] alpha = new int[width+1];
+
+ int bboxx0 = pix_bboxx0 << SUBPIXEL_LG_POSITIONS_X;
+ int bboxx1 = pix_bboxx1 << SUBPIXEL_LG_POSITIONS_X;
// Now we iterate through the scanlines. We must tell emitRow the coord
// of the first non-transparent pixel, so we must keep accumulators for
@@ -394,33 +745,34 @@
int pix_minX = Integer.MAX_VALUE;
int y = boundsMinY; // needs to be declared here so we emit the last row properly.
- ScanLineItInitialize();
- for ( ; ScanLineItHasNext(); ) {
- int numCrossings = ScanLineItGoToNextYAndComputeCrossings();
- y = ScanLineItCurrentY();
+ ScanlineIterator it = this.new ScanlineIterator();
+ for ( ; it.hasNext(); ) {
+ int numCrossings = it.next();
+ int[] crossings = it.crossings;
+ y = it.curY();
if (numCrossings > 0) {
int lowx = crossings[0] >> 1;
int highx = crossings[numCrossings - 1] >> 1;
- int x0 = Math.max(lowx, boundsMinX);
- int x1 = Math.min(highx, boundsMaxX);
+ int x0 = Math.max(lowx, bboxx0);
+ int x1 = Math.min(highx, bboxx1);
pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
}
int sum = 0;
- int prev = boundsMinX;
+ int prev = bboxx0;
for (int i = 0; i < numCrossings; i++) {
int curxo = crossings[i];
int curx = curxo >> 1;
int crorientation = ((curxo & 0x1) == 0x1) ? 1 : -1;
if ((sum & mask) != 0) {
- int x0 = Math.max(prev, boundsMinX);
- int x1 = Math.min(curx, boundsMaxX);
+ int x0 = Math.max(prev, bboxx0);
+ int x1 = Math.min(curx, bboxx1);
if (x0 < x1) {
- x0 -= boundsMinX; // turn x0, x1 from coords to indeces
- x1 -= boundsMinX; // in the alpha array.
+ x0 -= bboxx0; // turn x0, x1 from coords to indeces
+ x1 -= bboxx0; // in the alpha array.
int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X;
int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
@@ -442,6 +794,9 @@
prev = curx;
}
+ // even if this last row had no crossings, alpha will be zeroed
+ // from the last emitRow call. But this doesn't matter because
+ // maxX < minX, so no row will be emitted to the cache.
if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) {
emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
pix_minX = Integer.MAX_VALUE;
@@ -453,47 +808,53 @@
if (pix_maxX >= pix_minX) {
emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
}
- pix_bboxX0 = minX >> SUBPIXEL_LG_POSITIONS_X;
- pix_bboxX1 = maxX >> SUBPIXEL_LG_POSITIONS_X;
- pix_bboxY0 = minY >> SUBPIXEL_LG_POSITIONS_Y;
- pix_bboxY1 = maxY >> SUBPIXEL_LG_POSITIONS_Y;
}
-
public void endRendering() {
- // Set up the cache to accumulate the bounding box
- if (cache != null) {
- cache.bboxX0 = Integer.MAX_VALUE;
- cache.bboxY0 = Integer.MAX_VALUE;
- cache.bboxX1 = Integer.MIN_VALUE;
- cache.bboxY1 = Integer.MIN_VALUE;
+ final int bminx = boundsMinX >> SUBPIXEL_LG_POSITIONS_X;
+ final int bmaxx = boundsMaxX >> SUBPIXEL_LG_POSITIONS_X;
+ final int bminy = boundsMinY >> SUBPIXEL_LG_POSITIONS_Y;
+ final int bmaxy = boundsMaxY >> SUBPIXEL_LG_POSITIONS_Y;
+ final int eminx = ((int)Math.floor(edgeMinX)) >> SUBPIXEL_LG_POSITIONS_X;
+ final int emaxx = ((int)Math.ceil(edgeMaxX)) >> SUBPIXEL_LG_POSITIONS_X;
+ final int eminy = ((int)Math.floor(edgeMinY)) >> SUBPIXEL_LG_POSITIONS_Y;
+ final int emaxy = ((int)Math.ceil(edgeMaxY)) >> SUBPIXEL_LG_POSITIONS_Y;
+
+ final int minX = Math.max(bminx, eminx);
+ final int maxX = Math.min(bmaxx, emaxx);
+ final int minY = Math.max(bminy, eminy);
+ final int maxY = Math.min(bmaxy, emaxy);
+ if (minX > maxX || minY > maxY) {
+ this.cache = new PiscesCache(bminx, bminy, bmaxx, bmaxy);
+ return;
}
- _endRendering();
+ this.cache = new PiscesCache(minX, minY, maxX, maxY);
+ _endRendering(minX, minY, maxX, maxY);
}
- public void getBoundingBox(int[] pix_bbox) {
- pix_bbox[0] = pix_bboxX0;
- pix_bbox[1] = pix_bboxY0;
- pix_bbox[2] = pix_bboxX1 - pix_bboxX0;
- pix_bbox[3] = pix_bboxY1 - pix_bboxY0;
+ public PiscesCache getCache() {
+ if (cache == null) {
+ throw new InternalError("cache not yet initialized");
+ }
+ return cache;
}
- private void emitRow(byte[] alphaRow, int pix_y, int pix_from, int pix_to) {
+ private void emitRow(int[] alphaRow, int pix_y, int pix_from, int pix_to) {
// Copy rowAA data into the cache if one is present
if (cache != null) {
if (pix_to >= pix_from) {
- cache.startRow(pix_y, pix_from, pix_to);
+ cache.startRow(pix_y, pix_from);
// Perform run-length encoding and store results in the cache
- int from = pix_from - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
- int to = pix_to - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
+ int from = pix_from - cache.bboxX0;
+ int to = pix_to - cache.bboxX0;
int runLen = 1;
- byte startVal = alphaRow[from];
+ int startVal = alphaRow[from];
for (int i = from + 1; i <= to; i++) {
- byte nextVal = (byte)(startVal + alphaRow[i]);
- if (nextVal == startVal && runLen < 255) {
+ int nextVal = startVal + alphaRow[i];
+ if (nextVal == startVal) {
runLen++;
} else {
cache.addRLERun(startVal, runLen);
@@ -502,9 +863,8 @@
}
}
cache.addRLERun(startVal, runLen);
- cache.addRLERun((byte)0, 0);
}
}
- java.util.Arrays.fill(alphaRow, (byte)0);
+ java.util.Arrays.fill(alphaRow, 0);
}
}
--- a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,10 +25,18 @@
package sun.java2d.pisces;
-public class Stroker implements LineSink {
+import java.util.Arrays;
+import java.util.Iterator;
+
+import sun.awt.geom.PathConsumer2D;
+
+// TODO: some of the arithmetic here is too verbose and prone to hard to
+// debug typos. We should consider making a small Point/Vector class that
+// has methods like plus(Point), minus(Point), dot(Point), cross(Point)and such
+public class Stroker implements PathConsumer2D {
private static final int MOVE_TO = 0;
- private static final int LINE_TO = 1;
+ private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
private static final int CLOSE = 2;
/**
@@ -61,57 +69,37 @@
*/
public static final int CAP_SQUARE = 2;
- private final LineSink output;
+ private final PathConsumer2D out;
private final int capStyle;
private final int joinStyle;
- private final float m00, m01, m10, m11, det;
-
private final float lineWidth2;
- private final float scaledLineWidth2;
- // For any pen offset (pen_dx, pen_dy) that does not depend on
- // the line orientation, the pen should be transformed so that:
- //
- // pen_dx' = m00*pen_dx + m01*pen_dy
- // pen_dy' = m10*pen_dx + m11*pen_dy
- //
- // For a round pen, this means:
- //
- // pen_dx(r, theta) = r*cos(theta)
- // pen_dy(r, theta) = r*sin(theta)
- //
- // pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
- // pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
- private int numPenSegments;
- private final float[] pen_dx;
- private final float[] pen_dy;
- private boolean[] penIncluded;
- private final float[] join;
-
- private final float[] offset = new float[2];
- private float[] reverse = new float[100];
+ private final float[][] offset = new float[3][2];
private final float[] miter = new float[2];
private final float miterLimitSq;
private int prev;
- private int rindex;
- private boolean started;
- private boolean lineToOrigin;
- private boolean joinToOrigin;
- private float sx0, sy0, sx1, sy1, x0, y0, px0, py0;
- private float mx0, my0, omx, omy;
+ // The starting point of the path, and the slope there.
+ private float sx0, sy0, sdx, sdy;
+ // the current point and the slope there.
+ private float cx0, cy0, cdx, cdy; // c stands for current
+ // vectors that when added to (sx0,sy0) and (cx0,cy0) respectively yield the
+ // first and last points on the left parallel path. Since this path is
+ // parallel, it's slope at any point is parallel to the slope of the
+ // original path (thought they may have different directions), so these
+ // could be computed from sdx,sdy and cdx,cdy (and vice versa), but that
+ // would be error prone and hard to read, so we keep these anyway.
+ private float smx, smy, cmx, cmy;
- private float m00_2_m01_2;
- private float m10_2_m11_2;
- private float m00_m10_m01_m11;
+ private final PolyStack reverse = new PolyStack();
/**
* Constructs a <code>Stroker</code>.
*
- * @param output an output <code>LineSink</code>.
+ * @param pc2d an output <code>PathConsumer2D</code>.
* @param lineWidth the desired line width in pixels
* @param capStyle the desired end cap style, one of
* <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
@@ -120,183 +108,61 @@
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
* @param miterLimit the desired miter limit
- * @param transform a <code>Transform4</code> object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to produce consistently
- * shaped end caps and joins.
*/
- public Stroker(LineSink output,
+ public Stroker(PathConsumer2D pc2d,
float lineWidth,
int capStyle,
int joinStyle,
- float miterLimit,
- float m00, float m01, float m10, float m11) {
- this.output = output;
+ float miterLimit)
+ {
+ this.out = pc2d;
this.lineWidth2 = lineWidth / 2;
- this.scaledLineWidth2 = m00 * lineWidth2;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
- m00_2_m01_2 = m00*m00 + m01*m01;
- m10_2_m11_2 = m10*m10 + m11*m11;
- m00_m10_m01_m11 = m00*m10 + m01*m11;
-
- this.m00 = m00;
- this.m01 = m01;
- this.m10 = m10;
- this.m11 = m11;
- det = m00*m11 - m01*m10;
-
- float limit = miterLimit * lineWidth2 * det;
+ float limit = miterLimit * lineWidth2;
this.miterLimitSq = limit*limit;
- this.numPenSegments = (int)(3.14159f * lineWidth);
- this.pen_dx = new float[numPenSegments];
- this.pen_dy = new float[numPenSegments];
- this.penIncluded = new boolean[numPenSegments];
- this.join = new float[2*numPenSegments];
-
- for (int i = 0; i < numPenSegments; i++) {
- double theta = (i * 2.0 * Math.PI)/numPenSegments;
-
- double cos = Math.cos(theta);
- double sin = Math.sin(theta);
- pen_dx[i] = (float)(lineWidth2 * (m00*cos + m01*sin));
- pen_dy[i] = (float)(lineWidth2 * (m10*cos + m11*sin));
- }
-
- prev = CLOSE;
- rindex = 0;
- started = false;
- lineToOrigin = false;
+ this.prev = CLOSE;
}
- private void computeOffset(float x0, float y0,
- float x1, float y1, float[] m) {
- float lx = x1 - x0;
- float ly = y1 - y0;
-
- float dx, dy;
- if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) {
- float ilen = (float)Math.hypot(lx, ly);
- if (ilen == 0) {
- dx = dy = 0;
- } else {
- dx = (ly * scaledLineWidth2)/ilen;
- dy = -(lx * scaledLineWidth2)/ilen;
- }
+ private static void computeOffset(final float lx, final float ly,
+ final float w, final float[] m)
+ {
+ final float len = (float)Math.hypot(lx, ly);
+ if (len == 0) {
+ m[0] = m[1] = 0;
} else {
- int sdet = (det > 0) ? 1 : -1;
- float a = ly * m00 - lx * m10;
- float b = ly * m01 - lx * m11;
- float dh = (float)Math.hypot(a, b);
- float div = sdet * lineWidth2/dh;
-
- float ddx = ly * m00_2_m01_2 - lx * m00_m10_m01_m11;
- float ddy = ly * m00_m10_m01_m11 - lx * m10_2_m11_2;
- dx = ddx*div;
- dy = ddy*div;
- }
-
- m[0] = dx;
- m[1] = dy;
- }
-
- private void ensureCapacity(int newrindex) {
- if (reverse.length < newrindex) {
- reverse = java.util.Arrays.copyOf(reverse, 6*reverse.length/5);
+ m[0] = (ly * w)/len;
+ m[1] = -(lx * w)/len;
}
}
- private boolean isCCW(float x0, float y0,
- float x1, float y1,
- float x2, float y2) {
- return (x1 - x0) * (y2 - y1) < (y1 - y0) * (x2 - x1);
- }
-
- private boolean side(float x, float y,
- float x0, float y0,
- float x1, float y1) {
- return (y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0) > 0;
- }
-
- private int computeRoundJoin(float cx, float cy,
- float xa, float ya,
- float xb, float yb,
- int side,
- boolean flip,
- float[] join) {
- float px, py;
- int ncoords = 0;
-
- boolean centerSide;
- if (side == 0) {
- centerSide = side(cx, cy, xa, ya, xb, yb);
- } else {
- centerSide = (side == 1);
- }
- for (int i = 0; i < numPenSegments; i++) {
- px = cx + pen_dx[i];
- py = cy + pen_dy[i];
-
- boolean penSide = side(px, py, xa, ya, xb, yb);
- penIncluded[i] = (penSide != centerSide);
- }
-
- int start = -1, end = -1;
- for (int i = 0; i < numPenSegments; i++) {
- if (penIncluded[i] &&
- !penIncluded[(i + numPenSegments - 1) % numPenSegments]) {
- start = i;
- }
- if (penIncluded[i] &&
- !penIncluded[(i + 1) % numPenSegments]) {
- end = i;
- }
- }
-
- if (end < start) {
- end += numPenSegments;
- }
-
- if (start != -1 && end != -1) {
- float dxa = cx + pen_dx[start] - xa;
- float dya = cy + pen_dy[start] - ya;
- float dxb = cx + pen_dx[start] - xb;
- float dyb = cy + pen_dy[start] - yb;
-
- boolean rev = (dxa*dxa + dya*dya > dxb*dxb + dyb*dyb);
- int i = rev ? end : start;
- int incr = rev ? -1 : 1;
- while (true) {
- int idx = i % numPenSegments;
- px = cx + pen_dx[idx];
- py = cy + pen_dy[idx];
- join[ncoords++] = px;
- join[ncoords++] = py;
- if (i == (rev ? start : end)) {
- break;
- }
- i += incr;
- }
- }
-
- return ncoords/2;
+ // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
+ // clockwise (if dx1,dy1 needs to be rotated clockwise to close
+ // the smallest angle between it and dx2,dy2).
+ // This is equivalent to detecting whether a point q is on the right side
+ // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
+ // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
+ // clockwise order.
+ // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
+ private static boolean isCW(final float dx1, final float dy1,
+ final float dx2, final float dy2)
+ {
+ return dx1 * dy2 <= dy1 * dx2;
}
// pisces used to use fixed point arithmetic with 16 decimal digits. I
- // didn't want to change the values of the constants below when I converted
+ // didn't want to change the values of the constant below when I converted
// it to floating point, so that's why the divisions by 2^16 are there.
private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
- private static final float ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000/65536f;
private void drawRoundJoin(float x, float y,
float omx, float omy, float mx, float my,
- int side,
- boolean flip,
boolean rev,
- float threshold) {
+ float threshold)
+ {
if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) {
return;
}
@@ -314,54 +180,148 @@
mx = -mx;
my = -my;
}
+ drawRoundJoin(x, y, omx, omy, mx, my, rev);
+ }
- float bx0 = x + omx;
- float by0 = y + omy;
- float bx1 = x + mx;
- float by1 = y + my;
+ private void drawRoundJoin(float cx, float cy,
+ float omx, float omy,
+ float mx, float my,
+ boolean rev)
+ {
+ // The sign of the dot product of mx,my and omx,omy is equal to the
+ // the sign of the cosine of ext
+ // (ext is the angle between omx,omy and mx,my).
+ double cosext = omx * mx + omy * my;
+ // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
+ // need 1 curve to approximate the circle section that joins omx,omy
+ // and mx,my.
+ final int numCurves = cosext >= 0 ? 1 : 2;
- int npoints = computeRoundJoin(x, y,
- bx0, by0, bx1, by1, side, flip,
- join);
- for (int i = 0; i < npoints; i++) {
- emitLineTo(join[2*i], join[2*i + 1], rev);
+ switch (numCurves) {
+ case 1:
+ drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
+ break;
+ case 2:
+ // we need to split the arc into 2 arcs spanning the same angle.
+ // The point we want will be one of the 2 intersections of the
+ // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
+ // circle. We could find this by scaling the vector
+ // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
+ // on the circle), but that can have numerical problems when the angle
+ // between omx,omy and mx,my is close to 180 degrees. So we compute a
+ // normal of (omx,omy)-(mx,my). This will be the direction of the
+ // perpendicular bisector. To get one of the intersections, we just scale
+ // this vector that its length is lineWidth2 (this works because the
+ // perpendicular bisector goes through the origin). This scaling doesn't
+ // have numerical problems because we know that lineWidth2 divided by
+ // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
+ // we know the angle of the arc is > 90 degrees).
+ float nx = my - omy, ny = omx - mx;
+ float nlen = (float)Math.sqrt(nx*nx + ny*ny);
+ float scale = lineWidth2/nlen;
+ float mmx = nx * scale, mmy = ny * scale;
+
+ // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
+ // computed the wrong intersection so we get the other one.
+ // The test above is equivalent to if (rev).
+ if (rev) {
+ mmx = -mmx;
+ mmy = -mmy;
+ }
+ drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
+ drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
+ break;
}
}
- // Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
- // and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
- private void computeMiter(float x0, float y0, float x1, float y1,
- float x0p, float y0p, float x1p, float y1p,
- float[] m) {
+ // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
+ private void drawBezApproxForArc(final float cx, final float cy,
+ final float omx, final float omy,
+ final float mx, final float my,
+ boolean rev)
+ {
+ float cosext2 = (omx * mx + omy * my) / (2 * lineWidth2 * lineWidth2);
+ // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
+ // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
+ // define the bezier curve we're computing.
+ // It is computed using the constraints that P1-P0 and P3-P2 are parallel
+ // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
+ float cv = (float)((4.0 / 3.0) * Math.sqrt(0.5-cosext2) /
+ (1.0 + Math.sqrt(cosext2+0.5)));
+ // if clockwise, we need to negate cv.
+ if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
+ cv = -cv;
+ }
+ final float x1 = cx + omx;
+ final float y1 = cy + omy;
+ final float x2 = x1 - cv * omy;
+ final float y2 = y1 + cv * omx;
+
+ final float x4 = cx + mx;
+ final float y4 = cy + my;
+ final float x3 = x4 + cv * my;
+ final float y3 = y4 - cv * mx;
+
+ emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
+ }
+
+ private void drawRoundCap(float cx, float cy, float mx, float my) {
+ final float C = 0.5522847498307933f;
+ // the first and second arguments of the following two calls
+ // are really will be ignored by emitCurveTo (because of the false),
+ // but we put them in anyway, as opposed to just giving it 4 zeroes,
+ // because it's just 4 additions and it's not good to rely on this
+ // sort of assumption (right now it's true, but that may change).
+ emitCurveTo(cx+mx, cy+my,
+ cx+mx-C*my, cy+my+C*mx,
+ cx-my+C*mx, cy+mx+C*my,
+ cx-my, cy+mx,
+ false);
+ emitCurveTo(cx-my, cy+mx,
+ cx-my-C*mx, cy+mx-C*my,
+ cx-mx-C*my, cy-my+C*mx,
+ cx-mx, cy-my,
+ false);
+ }
+
+ // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+ // and (x0p, y0p) -> (x1p, y1p) in m[0] and m[1]
+ private void computeMiter(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x0p, final float y0p,
+ final float x1p, final float y1p,
+ final float[] m, int off)
+ {
float x10 = x1 - x0;
float y10 = y1 - y0;
float x10p = x1p - x0p;
float y10p = y1p - y0p;
+ // if this is 0, the lines are parallel. If they go in the
+ // same direction, there is no intersection so m[off] and
+ // m[off+1] will contain infinity, so no miter will be drawn.
+ // If they go in the same direction that means that the start of the
+ // current segment and the end of the previous segment have the same
+ // tangent, in which case this method won't even be involved in
+ // miter drawing because it won't be called by drawMiter (because
+ // (mx == omx && my == omy) will be true, and drawMiter will return
+ // immediately).
float den = x10*y10p - x10p*y10;
- if (den == 0) {
- m[0] = x0;
- m[1] = y0;
- return;
- }
-
- float t = x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0);
- m[0] = x0 + (t*x10)/den;
- m[1] = y0 + (t*y10)/den;
+ float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ t /= den;
+ m[off++] = x0 + t*x10;
+ m[off] = y0 + t*y10;
}
- private void drawMiter(float px0, float py0,
- float x0, float y0,
- float x1, float y1,
+ private void drawMiter(final float pdx, final float pdy,
+ final float x0, final float y0,
+ final float dx, final float dy,
float omx, float omy, float mx, float my,
- boolean rev) {
- if (mx == omx && my == omy) {
- return;
- }
- if (px0 == x0 && py0 == y0) {
- return;
- }
- if (x0 == x1 && y0 == y1) {
+ boolean rev)
+ {
+ if ((mx == omx && my == omy) ||
+ (pdx == 0 && pdy == 0) ||
+ (dx == 0 && dy == 0)) {
return;
}
@@ -372,297 +332,734 @@
my = -my;
}
- computeMiter(px0 + omx, py0 + omy, x0 + omx, y0 + omy,
- x0 + mx, y0 + my, x1 + mx, y1 + my,
- miter);
+ computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+ (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
+ miter, 0);
- // Compute miter length in untransformed coordinates
- float dx = miter[0] - x0;
- float dy = miter[1] - y0;
- float a = dy*m00 - dx*m10;
- float b = dy*m01 - dx*m11;
- float lenSq = a*a + b*b;
+ float lenSq = (miter[0]-x0)*(miter[0]-x0) + (miter[1]-y0)*(miter[1]-y0);
if (lenSq < miterLimitSq) {
emitLineTo(miter[0], miter[1], rev);
}
}
-
public void moveTo(float x0, float y0) {
- // System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
-
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- }
-
- if (prev == LINE_TO) {
+ if (prev == DRAWING_OP_TO) {
finish();
}
-
- this.sx0 = this.x0 = x0;
- this.sy0 = this.y0 = y0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
+ this.sx0 = this.cx0 = x0;
+ this.sy0 = this.cy0 = y0;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
this.prev = MOVE_TO;
}
- boolean joinSegment = false;
-
- public void lineJoin() {
- // System.out.println("Stroker.lineJoin()");
- this.joinSegment = true;
- }
-
public void lineTo(float x1, float y1) {
- // System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
+ float dx = x1 - cx0;
+ float dy = y1 - cy0;
+ if (dx == 0f && dy == 0f) {
+ dx = 1;
+ }
+ computeOffset(dx, dy, lineWidth2, offset[0]);
+ float mx = offset[0][0];
+ float my = offset[0][1];
- if (lineToOrigin) {
- if (x1 == sx0 && y1 == sy0) {
- // staying in the starting point
- return;
- }
+ drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my);
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- } else if (x1 == x0 && y1 == y0) {
- return;
- } else if (x1 == sx0 && y1 == sy0) {
- lineToOrigin = true;
- joinToOrigin = joinSegment;
- joinSegment = false;
- return;
- }
+ emitLineTo(cx0 + mx, cy0 + my);
+ emitLineTo(x1 + mx, y1 + my);
+
+ emitLineTo(cx0 - mx, cy0 - my, true);
+ emitLineTo(x1 - mx, y1 - my, true);
- lineToImpl(x1, y1, joinSegment);
- joinSegment = false;
+ this.cmx = mx;
+ this.cmy = my;
+ this.cdx = dx;
+ this.cdy = dy;
+ this.cx0 = x1;
+ this.cy0 = y1;
+ this.prev = DRAWING_OP_TO;
}
- private void lineToImpl(float x1, float y1, boolean joinSegment) {
- computeOffset(x0, y0, x1, y1, offset);
- float mx = offset[0];
- float my = offset[1];
-
- if (!started) {
- emitMoveTo(x0 + mx, y0 + my);
- this.sx1 = x1;
- this.sy1 = y1;
- this.mx0 = mx;
- this.my0 = my;
- started = true;
- } else {
- boolean ccw = isCCW(px0, py0, x0, y0, x1, y1);
- if (joinSegment) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, x1, y1, omx, omy, mx, my,
- ccw);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_THRESHOLD);
- }
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
+ public void closePath() {
+ if (prev != DRAWING_OP_TO) {
+ if (prev == CLOSE) {
+ return;
}
-
- emitLineTo(x0, y0, !ccw);
- }
-
- emitLineTo(x0 + mx, y0 + my, false);
- emitLineTo(x1 + mx, y1 + my, false);
-
- emitLineTo(x0 - mx, y0 - my, true);
- emitLineTo(x1 - mx, y1 - my, true);
-
- this.omx = mx;
- this.omy = my;
- this.px0 = x0;
- this.py0 = y0;
- this.x0 = x1;
- this.y0 = y1;
- this.prev = LINE_TO;
- }
-
- public void close() {
- // System.out.println("Stroker.close()");
-
- if (lineToOrigin) {
- // ignore the previous lineTo
- lineToOrigin = false;
- }
-
- if (!started) {
+ emitMoveTo(cx0, cy0 - lineWidth2);
+ this.cmx = this.smx = 0;
+ this.cmy = this.smy = -lineWidth2;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
finish();
return;
}
- computeOffset(x0, y0, sx0, sy0, offset);
- float mx = offset[0];
- float my = offset[1];
-
- // Draw penultimate join
- boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0);
- if (joinSegment) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, sx0, sy0, omx, omy, mx, my, ccw);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
- ROUND_JOIN_THRESHOLD);
- }
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
+ if (cx0 != sx0 || cy0 != sy0) {
+ lineTo(sx0, sy0);
}
- emitLineTo(x0 + mx, y0 + my);
- emitLineTo(sx0 + mx, sy0 + my);
-
- ccw = isCCW(x0, y0, sx0, sy0, sx1, sy1);
+ drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy);
- // Draw final join on the outside
- if (!ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- mx, my, mx0, my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, mx, my, mx0, my0, 0, false, false,
- ROUND_JOIN_THRESHOLD);
- }
- }
-
- emitLineTo(sx0 + mx0, sy0 + my0);
- emitLineTo(sx0 - mx0, sy0 - my0); // same as reverse[0], reverse[1]
+ emitLineTo(sx0 + smx, sy0 + smy);
- // Draw final join on the inside
- if (ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- -mx, -my, -mx0, -my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, -mx, -my, -mx0, -my0, 0,
- true, false,
- ROUND_JOIN_THRESHOLD);
- }
- }
+ emitMoveTo(sx0 - smx, sy0 - smy);
+ emitReverse();
- emitLineTo(sx0 - mx, sy0 - my);
- emitLineTo(x0 - mx, y0 - my);
- for (int i = rindex - 2; i >= 0; i -= 2) {
- emitLineTo(reverse[i], reverse[i + 1]);
- }
-
- this.x0 = this.sx0;
- this.y0 = this.sy0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
this.prev = CLOSE;
emitClose();
}
- public void end() {
- // System.out.println("Stroker.end()");
+ private void emitReverse() {
+ while(!reverse.isEmpty()) {
+ reverse.pop(out);
+ }
+ }
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- }
-
- if (prev == LINE_TO) {
+ public void pathDone() {
+ if (prev == DRAWING_OP_TO) {
finish();
}
- output.end();
- this.joinSegment = false;
- this.prev = MOVE_TO;
- }
-
- double userSpaceLineLength(double dx, double dy) {
- double a = (dy*m00 - dx*m10)/det;
- double b = (dy*m01 - dx*m11)/det;
- return Math.hypot(a, b);
+ out.pathDone();
+ // this shouldn't matter since this object won't be used
+ // after the call to this method.
+ this.prev = CLOSE;
}
private void finish() {
if (capStyle == CAP_ROUND) {
- drawRoundJoin(x0, y0,
- omx, omy, -omx, -omy, 1, false, false,
- ROUND_JOIN_THRESHOLD);
+ drawRoundCap(cx0, cy0, cmx, cmy);
} else if (capStyle == CAP_SQUARE) {
- float dx = px0 - x0;
- float dy = py0 - y0;
- float len = (float)userSpaceLineLength(dx, dy);
- float s = lineWidth2/len;
-
- float capx = x0 - dx*s;
- float capy = y0 - dy*s;
-
- emitLineTo(capx + omx, capy + omy);
- emitLineTo(capx - omx, capy - omy);
+ emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+ emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
}
- for (int i = rindex - 2; i >= 0; i -= 2) {
- emitLineTo(reverse[i], reverse[i + 1]);
- }
- this.rindex = 0;
+ emitReverse();
if (capStyle == CAP_ROUND) {
- drawRoundJoin(sx0, sy0,
- -mx0, -my0, mx0, my0, 1, false, false,
- ROUND_JOIN_THRESHOLD);
+ drawRoundCap(sx0, sy0, -smx, -smy);
} else if (capStyle == CAP_SQUARE) {
- float dx = sx1 - sx0;
- float dy = sy1 - sy0;
- float len = (float)userSpaceLineLength(dx, dy);
- float s = lineWidth2/len;
-
- float capx = sx0 - dx*s;
- float capy = sy0 - dy*s;
-
- emitLineTo(capx - mx0, capy - my0);
- emitLineTo(capx + mx0, capy + my0);
+ emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+ emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
}
emitClose();
- this.joinSegment = false;
}
- private void emitMoveTo(float x0, float y0) {
- // System.out.println("Stroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
- output.moveTo(x0, y0);
+ private void emitMoveTo(final float x0, final float y0) {
+ out.moveTo(x0, y0);
}
- private void emitLineTo(float x1, float y1) {
- // System.out.println("Stroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
- output.lineTo(x1, y1);
+ private void emitLineTo(final float x1, final float y1) {
+ out.lineTo(x1, y1);
}
- private void emitLineTo(float x1, float y1, boolean rev) {
+ private void emitLineTo(final float x1, final float y1,
+ final boolean rev)
+ {
if (rev) {
- ensureCapacity(rindex + 2);
- reverse[rindex++] = x1;
- reverse[rindex++] = y1;
+ reverse.pushLine(x1, y1);
} else {
emitLineTo(x1, y1);
}
}
+ private void emitQuadTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushQuad(x0, y0, x1, y1);
+ } else {
+ out.quadTo(x1, y1, x2, y2);
+ }
+ }
+
+ private void emitCurveTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2,
+ final float x3, final float y3, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+ } else {
+ out.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ }
+
private void emitClose() {
- // System.out.println("Stroker.emitClose()");
- output.close();
+ out.closePath();
+ }
+
+ private void drawJoin(float pdx, float pdy,
+ float x0, float y0,
+ float dx, float dy,
+ float omx, float omy,
+ float mx, float my)
+ {
+ if (prev != DRAWING_OP_TO) {
+ emitMoveTo(x0 + mx, y0 + my);
+ this.sdx = dx;
+ this.sdy = dy;
+ this.smx = mx;
+ this.smy = my;
+ } else {
+ boolean cw = isCW(pdx, pdy, dx, dy);
+ if (joinStyle == JOIN_MITER) {
+ drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
+ } else if (joinStyle == JOIN_ROUND) {
+ drawRoundJoin(x0, y0,
+ omx, omy,
+ mx, my, cw,
+ ROUND_JOIN_THRESHOLD);
+ }
+ emitLineTo(x0, y0, !cw);
+ }
+ prev = DRAWING_OP_TO;
+ }
+
+ private static boolean within(final float x1, final float y1,
+ final float x2, final float y2,
+ final float ERR)
+ {
+ assert ERR > 0 : "";
+ // compare taxicab distance. ERR will always be small, so using
+ // true distance won't give much benefit
+ return (Helpers.within(x1, x2, ERR) && // we want to avoid calling Math.abs
+ Helpers.within(y1, y2, ERR)); // this is just as good.
+ }
+
+ private void getLineOffsets(float x1, float y1,
+ float x2, float y2,
+ float[] left, float[] right) {
+ computeOffset(x2 - x1, y2 - y1, lineWidth2, offset[0]);
+ left[0] = x1 + offset[0][0];
+ left[1] = y1 + offset[0][1];
+ left[2] = x2 + offset[0][0];
+ left[3] = y2 + offset[0][1];
+ right[0] = x1 - offset[0][0];
+ right[1] = y1 - offset[0][1];
+ right[2] = x2 - offset[0][0];
+ right[3] = y2 - offset[0][1];
+ }
+
+ private int computeOffsetCubic(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+ final float x4 = pts[off + 6], y4 = pts[off + 7];
+
+ float dx4 = x4 - x3;
+ float dy4 = y4 - y3;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore if p1 == p2
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p3eqp4 = within(x3,y3,x4,y4, 6 * Math.ulp(y4));
+ if (p1eqp2 && p3eqp4) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ } else if (p1eqp2) {
+ dx1 = x3 - x1;
+ dy1 = y3 - y1;
+ } else if (p3eqp4) {
+ dx4 = x4 - x2;
+ dy4 = y4 - y2;
+ }
+
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx4 + dy1 * dy4);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+ if (Helpers.within(dotsq, l1sq * l4sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ }
+
+// What we're trying to do in this function is to approximate an ideal
+// offset curve (call it I) of the input curve B using a bezier curve Bp.
+// The constraints I use to get the equations are:
+//
+// 1. The computed curve Bp should go through I(0) and I(1). These are
+// x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
+// 4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
+//
+// 2. Bp should have slope equal in absolute value to I at the endpoints. So,
+// (by the way, the operator || in the comments below means "aligned with".
+// It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
+// vectors I'(0) and Bp'(0) are aligned, which is the same as saying
+// that the tangent lines of I and Bp at 0 are parallel. Mathematically
+// this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
+// nonzero constant.)
+// I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
+// I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
+// We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
+// is true for any bezier curve; therefore, we get the equations
+// (1) p2p = c1 * (p2-p1) + p1p
+// (2) p3p = c2 * (p4-p3) + p4p
+// We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
+// of unknowns from 4 to 2 (i.e. just c1 and c2).
+// To eliminate these 2 unknowns we use the following constraint:
+//
+// 3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
+// that I(0.5) is *the only* reason for computing dxm,dym. This gives us
+// (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
+// (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
+// We can substitute (1) and (2) from above into (4) and we get:
+// (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
+// which is equivalent to
+// (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
+//
+// The right side of this is a 2D vector, and we know I(0.5), which gives us
+// Bp(0.5), which gives us the value of the right side.
+// The left side is just a matrix vector multiplication in disguise. It is
+//
+// [x2-x1, x4-x3][c1]
+// [y2-y1, y4-y3][c2]
+// which, is equal to
+// [dx1, dx4][c1]
+// [dy1, dy4][c2]
+// At this point we are left with a simple linear system and we solve it by
+// getting the inverse of the matrix above. Then we use [c1,c2] to compute
+// p2p and p3p.
+
+ float x = 0.125f * (x1 + 3 * (x2 + x3) + x4);
+ float y = 0.125f * (y1 + 3 * (y2 + y3) + y4);
+ // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
+ // c*B'(0.5) for some constant c.
+ float dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
+
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dxm, dym, lineWidth2, offset[1]);
+ computeOffset(dx4, dy4, lineWidth2, offset[2]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float xi = x + offset[1][0]; // interpolation
+ float yi = y + offset[1][1]; // point
+ float x4p = x4 + offset[2][0]; // end
+ float y4p = y4 + offset[2][1]; // point
+
+ float invdet43 = 4f / (3f * (dx1 * dy4 - dy1 * dx4));
+
+ float two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ float two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ float x2p, y2p, x3p, y3p;
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[2] = x2p; leftOff[3] = y2p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ leftOff[6] = x4p; leftOff[7] = y4p;
+
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ xi = xi - 2 * offset[1][0]; yi = yi - 2 * offset[1][1];
+ x4p = x4 - offset[2][0]; y4p = y4 - offset[2][1];
+
+ two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[2] = x2p; rightOff[3] = y2p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ rightOff[6] = x4p; rightOff[7] = y4p;
+ return 8;
+ }
+
+ // compute offset curves using bezier spline through t=0.5 (i.e.
+ // ComputedCurve(0.5) == IdealParallelCurve(0.5))
+ // return the kind of curve in the right and left arrays.
+ private int computeOffsetQuad(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+
+ float dx3 = x3 - x2;
+ float dy3 = y3 - y2;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore.
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p2eqp3 = within(x2,y2,x3,y3, 6 * Math.ulp(y3));
+ if (p1eqp2 || p2eqp3) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
+ }
+
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx3 + dy1 * dy3);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+ if (Helpers.within(dotsq, l1sq * l3sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
+ }
+
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dx3, dy3, lineWidth2, offset[1]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float x3p = x3 + offset[1][0]; // end
+ float y3p = y3 + offset[1][1]; // point
+
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ x3p = x3 - offset[1][0]; y3p = y3 - offset[1][1];
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ return 6;
+ }
+
+ // This is where the curve to be processed is put. We give it
+ // enough room to store 2 curves: one for the current subdivision, the
+ // other for the rest of the curve.
+ private float[][] middle = new float[2][8];
+ private float[] lp = new float[8];
+ private float[] rp = new float[8];
+ private static final int MAX_N_CURVES = 11;
+ private float[] subdivTs = new float[MAX_N_CURVES - 1];
+
+ private void somethingTo(final int type) {
+ // need these so we can update the state at the end of this method
+ final float xf = middle[0][type-2], yf = middle[0][type-1];
+ float dxs = middle[0][2] - middle[0][0];
+ float dys = middle[0][3] - middle[0][1];
+ float dxf = middle[0][type - 2] - middle[0][type - 4];
+ float dyf = middle[0][type - 1] - middle[0][type - 3];
+ switch(type) {
+ case 6:
+ if ((dxs == 0f && dys == 0f) ||
+ (dxf == 0f && dyf == 0f)) {
+ dxs = dxf = middle[0][4] - middle[0][0];
+ dys = dyf = middle[0][5] - middle[0][1];
+ }
+ break;
+ case 8:
+ boolean p1eqp2 = (dxs == 0f && dys == 0f);
+ boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+ if (p1eqp2) {
+ dxs = middle[0][4] - middle[0][0];
+ dys = middle[0][5] - middle[0][1];
+ if (dxs == 0f && dys == 0f) {
+ dxs = middle[0][6] - middle[0][0];
+ dys = middle[0][7] - middle[0][1];
+ }
+ }
+ if (p3eqp4) {
+ dxf = middle[0][6] - middle[0][2];
+ dyf = middle[0][7] - middle[0][3];
+ if (dxf == 0f && dyf == 0f) {
+ dxf = middle[0][6] - middle[0][0];
+ dyf = middle[0][7] - middle[0][1];
+ }
+ }
+ }
+ if (dxs == 0f && dys == 0f) {
+ // this happens iff the "curve" is just a point
+ lineTo(middle[0][0], middle[0][1]);
+ return;
+ }
+ // if these vectors are too small, normalize them, to avoid future
+ // precision problems.
+ if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+ double len = Math.hypot(dxs, dys);
+ dxs = (float)(dxs / len);
+ dys = (float)(dys / len);
+ }
+ if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+ double len = Math.hypot(dxf, dyf);
+ dxf = (float)(dxf / len);
+ dyf = (float)(dyf / len);
+ }
+
+ computeOffset(dxs, dys, lineWidth2, offset[0]);
+ final float mx = offset[0][0];
+ final float my = offset[0][1];
+ drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+ int nSplits = findSubdivPoints(middle[0], subdivTs, type,lineWidth2);
+
+ int kind = 0;
+ Iterator<float[]> it = Curve.breakPtsAtTs(middle, type, subdivTs, nSplits);
+ while(it.hasNext()) {
+ float[] curCurve = it.next();
+
+ kind = 0;
+ switch (type) {
+ case 8:
+ kind = computeOffsetCubic(curCurve, 0, lp, rp);
+ break;
+ case 6:
+ kind = computeOffsetQuad(curCurve, 0, lp, rp);
+ break;
+ }
+ if (kind != 0) {
+ emitLineTo(lp[0], lp[1]);
+ switch(kind) {
+ case 8:
+ emitCurveTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], lp[6], lp[7], false);
+ emitCurveTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7], true);
+ break;
+ case 6:
+ emitQuadTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], false);
+ emitQuadTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], true);
+ break;
+ case 4:
+ emitLineTo(lp[2], lp[3]);
+ emitLineTo(rp[0], rp[1], true);
+ break;
+ }
+ emitLineTo(rp[kind - 2], rp[kind - 1], true);
+ }
+ }
+
+ this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
+ this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
+ this.cdx = dxf;
+ this.cdy = dyf;
+ this.cx0 = xf;
+ this.cy0 = yf;
+ this.prev = DRAWING_OP_TO;
+ }
+
+ // finds values of t where the curve in pts should be subdivided in order
+ // to get good offset curves a distance of w away from the middle curve.
+ // Stores the points in ts, and returns how many of them there were.
+ private static Curve c = new Curve();
+ private static int findSubdivPoints(float[] pts, float[] ts,
+ final int type, final float w)
+ {
+ final float x12 = pts[2] - pts[0];
+ final float y12 = pts[3] - pts[1];
+ // if the curve is already parallel to either axis we gain nothing
+ // from rotating it.
+ if (y12 != 0f && x12 != 0f) {
+ // we rotate it so that the first vector in the control polygon is
+ // parallel to the x-axis. This will ensure that rotated quarter
+ // circles won't be subdivided.
+ final float hypot = (float)Math.sqrt(x12 * x12 + y12 * y12);
+ final float cos = x12 / hypot;
+ final float sin = y12 / hypot;
+ final float x1 = cos * pts[0] + sin * pts[1];
+ final float y1 = cos * pts[1] - sin * pts[0];
+ final float x2 = cos * pts[2] + sin * pts[3];
+ final float y2 = cos * pts[3] - sin * pts[2];
+ final float x3 = cos * pts[4] + sin * pts[5];
+ final float y3 = cos * pts[5] - sin * pts[4];
+ switch(type) {
+ case 8:
+ final float x4 = cos * pts[6] + sin * pts[7];
+ final float y4 = cos * pts[7] - sin * pts[6];
+ c.set(x1, y1, x2, y2, x3, y3, x4, y4);
+ break;
+ case 6:
+ c.set(x1, y1, x2, y2, x3, y3);
+ break;
+ }
+ } else {
+ c.set(pts, type);
+ }
+
+ int ret = 0;
+ // we subdivide at values of t such that the remaining rotated
+ // curves are monotonic in x and y.
+ ret += c.dxRoots(ts, ret);
+ ret += c.dyRoots(ts, ret);
+ // subdivide at inflection points.
+ if (type == 8) {
+ // quadratic curves can't have inflection points
+ ret += c.infPoints(ts, ret);
+ }
+
+ // now we must subdivide at points where one of the offset curves will have
+ // a cusp. This happens at ts where the radius of curvature is equal to w.
+ ret += c.rootsOfROCMinusW(ts, ret, w, 0.0001f);
+ ret = Helpers.filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
+ Helpers.isort(ts, 0, ret);
+ return ret;
+ }
+
+ @Override public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ middle[0][0] = cx0; middle[0][1] = cy0;
+ middle[0][2] = x1; middle[0][3] = y1;
+ middle[0][4] = x2; middle[0][5] = y2;
+ middle[0][6] = x3; middle[0][7] = y3;
+ somethingTo(8);
+ }
+
+ @Override public long getNativeConsumer() {
+ throw new InternalError("Stroker doesn't use a native consumer");
+ }
+
+ @Override public void quadTo(float x1, float y1, float x2, float y2) {
+ middle[0][0] = cx0; middle[0][1] = cy0;
+ middle[0][2] = x1; middle[0][3] = y1;
+ middle[0][4] = x2; middle[0][5] = y2;
+ somethingTo(6);
+ }
+
+ // a stack of polynomial curves where each curve shares endpoints with
+ // adjacent ones.
+ private static final class PolyStack {
+ float[] curves;
+ int end;
+ int[] curveTypes;
+ int numCurves;
+
+ private static final int INIT_SIZE = 50;
+
+ PolyStack() {
+ curves = new float[8 * INIT_SIZE];
+ curveTypes = new int[INIT_SIZE];
+ end = 0;
+ numCurves = 0;
+ }
+
+ public boolean isEmpty() {
+ return numCurves == 0;
+ }
+
+ private void ensureSpace(int n) {
+ if (end + n >= curves.length) {
+ int newSize = (end + n) * 2;
+ curves = Arrays.copyOf(curves, newSize);
+ }
+ if (numCurves >= curveTypes.length) {
+ int newSize = numCurves * 2;
+ curveTypes = Arrays.copyOf(curveTypes, newSize);
+ }
+ }
+
+ public void pushCubic(float x0, float y0,
+ float x1, float y1,
+ float x2, float y2)
+ {
+ ensureSpace(6);
+ curveTypes[numCurves++] = 8;
+ // assert(x0 == lastX && y0 == lastY)
+
+ // we reverse the coordinate order to make popping easier
+ curves[end++] = x2; curves[end++] = y2;
+ curves[end++] = x1; curves[end++] = y1;
+ curves[end++] = x0; curves[end++] = y0;
+ }
+
+ public void pushQuad(float x0, float y0,
+ float x1, float y1)
+ {
+ ensureSpace(4);
+ curveTypes[numCurves++] = 6;
+ // assert(x0 == lastX && y0 == lastY)
+ curves[end++] = x1; curves[end++] = y1;
+ curves[end++] = x0; curves[end++] = y0;
+ }
+
+ public void pushLine(float x, float y) {
+ ensureSpace(2);
+ curveTypes[numCurves++] = 4;
+ // assert(x0 == lastX && y0 == lastY)
+ curves[end++] = x; curves[end++] = y;
+ }
+
+ @SuppressWarnings("unused")
+ public int pop(float[] pts) {
+ int ret = curveTypes[numCurves - 1];
+ numCurves--;
+ end -= (ret - 2);
+ System.arraycopy(curves, end, pts, 0, ret - 2);
+ return ret;
+ }
+
+ public void pop(PathConsumer2D io) {
+ numCurves--;
+ int type = curveTypes[numCurves];
+ end -= (type - 2);
+ switch(type) {
+ case 8:
+ io.curveTo(curves[end+0], curves[end+1],
+ curves[end+2], curves[end+3],
+ curves[end+4], curves[end+5]);
+ break;
+ case 6:
+ io.quadTo(curves[end+0], curves[end+1],
+ curves[end+2], curves[end+3]);
+ break;
+ case 4:
+ io.lineTo(curves[end], curves[end+1]);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String ret = "";
+ int nc = numCurves;
+ int end = this.end;
+ while (nc > 0) {
+ nc--;
+ int type = curveTypes[numCurves];
+ end -= (type - 2);
+ switch(type) {
+ case 8:
+ ret += "cubic: ";
+ break;
+ case 6:
+ ret += "quad: ";
+ break;
+ case 4:
+ ret += "line: ";
+ break;
+ }
+ ret += Arrays.toString(Arrays.copyOfRange(curves, end, end+type-2)) + "\n";
+ }
+ return ret;
+ }
}
}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/pisces/TransformingPathConsumer2D.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.pisces;
+
+import sun.awt.geom.PathConsumer2D;
+import java.awt.geom.AffineTransform;
+
+public class TransformingPathConsumer2D {
+ public static PathConsumer2D
+ transformConsumer(PathConsumer2D out,
+ AffineTransform at)
+ {
+ if (at == null) {
+ return out;
+ }
+ float Mxx = (float) at.getScaleX();
+ float Mxy = (float) at.getShearX();
+ float Mxt = (float) at.getTranslateX();
+ float Myx = (float) at.getShearY();
+ float Myy = (float) at.getScaleY();
+ float Myt = (float) at.getTranslateY();
+ if (Mxy == 0f && Myx == 0f) {
+ if (Mxx == 1f && Myy == 1f) {
+ if (Mxt == 0f && Myt == 0f) {
+ return out;
+ } else {
+ return new TranslateFilter(out, Mxt, Myt);
+ }
+ } else {
+ return new ScaleFilter(out, Mxx, Myy, Mxt, Myt);
+ }
+ } else {
+ return new TransformFilter(out, Mxx, Mxy, Mxt, Myx, Myy, Myt);
+ }
+ }
+
+ static class TranslateFilter implements PathConsumer2D {
+ PathConsumer2D out;
+ float tx;
+ float ty;
+
+ TranslateFilter(PathConsumer2D out,
+ float tx, float ty)
+ {
+ this.out = out;
+ this.tx = tx;
+ this.ty = ty;
+ }
+
+ public void moveTo(float x0, float y0) {
+ out.moveTo(x0 + tx, y0 + ty);
+ }
+
+ public void lineTo(float x1, float y1) {
+ out.lineTo(x1 + tx, y1 + ty);
+ }
+
+ public void quadTo(float x1, float y1,
+ float x2, float y2)
+ {
+ out.quadTo(x1 + tx, y1 + ty,
+ x2 + tx, y2 + ty);
+ }
+
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ out.curveTo(x1 + tx, y1 + ty,
+ x2 + tx, y2 + ty,
+ x3 + tx, y3 + ty);
+ }
+
+ public void closePath() {
+ out.closePath();
+ }
+
+ public void pathDone() {
+ out.pathDone();
+ }
+
+ public long getNativeConsumer() {
+ return 0;
+ }
+ }
+
+ static class ScaleFilter implements PathConsumer2D {
+ PathConsumer2D out;
+ float sx;
+ float sy;
+ float tx;
+ float ty;
+
+ ScaleFilter(PathConsumer2D out,
+ float sx, float sy, float tx, float ty)
+ {
+ this.out = out;
+ this.sx = sx;
+ this.sy = sy;
+ this.tx = tx;
+ this.ty = ty;
+ }
+
+ public void moveTo(float x0, float y0) {
+ out.moveTo(x0 * sx + tx, y0 * sy + ty);
+ }
+
+ public void lineTo(float x1, float y1) {
+ out.lineTo(x1 * sx + tx, y1 * sy + ty);
+ }
+
+ public void quadTo(float x1, float y1,
+ float x2, float y2)
+ {
+ out.quadTo(x1 * sx + tx, y1 * sy + ty,
+ x2 * sx + tx, y2 * sy + ty);
+ }
+
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ out.curveTo(x1 * sx + tx, y1 * sy + ty,
+ x2 * sx + tx, y2 * sy + ty,
+ x3 * sx + tx, y3 * sy + ty);
+ }
+
+ public void closePath() {
+ out.closePath();
+ }
+
+ public void pathDone() {
+ out.pathDone();
+ }
+
+ public long getNativeConsumer() {
+ return 0;
+ }
+ }
+
+ static class TransformFilter implements PathConsumer2D {
+ PathConsumer2D out;
+ float Mxx;
+ float Mxy;
+ float Mxt;
+ float Myx;
+ float Myy;
+ float Myt;
+
+ TransformFilter(PathConsumer2D out,
+ float Mxx, float Mxy, float Mxt,
+ float Myx, float Myy, float Myt)
+ {
+ this.out = out;
+ this.Mxx = Mxx;
+ this.Mxy = Mxy;
+ this.Mxt = Mxt;
+ this.Myx = Myx;
+ this.Myy = Myy;
+ this.Myt = Myt;
+ }
+
+ public void moveTo(float x0, float y0) {
+ out.moveTo(x0 * Mxx + y0 * Mxy + Mxt,
+ x0 * Myx + y0 * Myy + Myt);
+ }
+
+ public void lineTo(float x1, float y1) {
+ out.lineTo(x1 * Mxx + y1 * Mxy + Mxt,
+ x1 * Myx + y1 * Myy + Myt);
+ }
+
+ public void quadTo(float x1, float y1,
+ float x2, float y2)
+ {
+ out.quadTo(x1 * Mxx + y1 * Mxy + Mxt,
+ x1 * Myx + y1 * Myy + Myt,
+ x2 * Mxx + y2 * Mxy + Mxt,
+ x2 * Myx + y2 * Myy + Myt);
+ }
+
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ out.curveTo(x1 * Mxx + y1 * Mxy + Mxt,
+ x1 * Myx + y1 * Myy + Myt,
+ x2 * Mxx + y2 * Mxy + Mxt,
+ x2 * Myx + y2 * Myy + Myt,
+ x3 * Mxx + y3 * Mxy + Mxt,
+ x3 * Myx + y3 * Myy + Myt);
+ }
+
+ public void closePath() {
+ out.closePath();
+ }
+
+ public void pathDone() {
+ out.pathDone();
+ }
+
+ public long getNativeConsumer() {
+ return 0;
+ }
+ }
+}
--- a/jdk/src/share/classes/sun/text/resources/FormatData_fr.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_fr.java Sat Nov 13 18:56:50 2010 -0800
@@ -145,7 +145,7 @@
"{1} {0}" // date-time pattern
}
},
- { "DateTimePatternChars", "GaMjkHmsSEDFwWahKzZ" },
+ { "DateTimePatternChars", "GaMjkHmsSEDFwWxhKzZ" },
};
}
}
--- a/jdk/src/share/classes/sun/text/resources/FormatData_fr_BE.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_fr_BE.java Sat Nov 13 18:56:50 2010 -0800
@@ -76,7 +76,7 @@
"{1} {0}" // date-time pattern
}
},
- { "DateTimePatternChars", "GaMjkHmsSEDFwWahKzZ" },
+ { "DateTimePatternChars", "GaMjkHmsSEDFwWxhKzZ" },
};
}
}
--- a/jdk/src/share/classes/sun/text/resources/FormatData_fr_CA.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_fr_CA.java Sat Nov 13 18:56:50 2010 -0800
@@ -68,7 +68,7 @@
"{1} {0}" // date-time pattern
}
},
- { "DateTimePatternChars", "GaMjkHmsSEDFwWahKzZ" },
+ { "DateTimePatternChars", "GaMjkHmsSEDFwWxhKzZ" },
};
}
}
--- a/jdk/src/share/classes/sun/text/resources/FormatData_fr_CH.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_fr_CH.java Sat Nov 13 18:56:50 2010 -0800
@@ -83,7 +83,7 @@
"{1} {0}" // date-time pattern
}
},
- { "DateTimePatternChars", "GaMjkHmsSEDFwWahKzZ" },
+ { "DateTimePatternChars", "GaMjkHmsSEDFwWxhKzZ" },
};
}
}
--- a/jdk/src/share/classes/sun/util/resources/LocaleNames.properties Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/classes/sun/util/resources/LocaleNames.properties Sat Nov 13 18:56:50 2010 -0800
@@ -1,4 +1,4 @@
-#
+#
# Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
@@ -21,7 +21,7 @@
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
-#
+#
# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
@@ -228,6 +228,492 @@
zh=Chinese
zu=Zulu
+# key is ISO 639.2 language code
+aar=Afar
+abk=Abkhazian
+ace=Achinese
+ach=Acoli
+ada=Adangme
+ady=Adyghe
+afa=Afro-Asiatic
+afh=Afrihili
+afr=Afrikaans
+ain=Ainu
+aka=Akan
+akk=Akkadian
+alb=Albanian
+ale=Aleut
+alg=Algonquian
+alt=Southern Altai
+amh=Amharic
+ang=English, Old (ca.450-1100)
+anp=Angika
+apa=Apache
+ara=Arabic
+arc=Official Aramaic (700-300 BCE)
+arg=Aragonese
+arm=Armenian
+arn=Mapudungun
+arp=Arapaho
+art=Artificial
+arw=Arawak
+asm=Assamese
+ast=Asturian
+ath=Athapascan
+aus=Australian
+ava=Avaric
+ave=Avestan
+awa=Awadhi
+aym=Aymara
+aze=Azerbaijani
+bad=Banda
+bai=Bamileke
+bak=Bashkir
+bal=Baluchi
+bam=Bambara
+ban=Balinese
+baq=Basque
+bas=Basa
+bat=Baltic
+bej=Beja
+bel=Belarusian
+bem=Bemba
+ben=Bengali
+ber=Berber
+bho=Bhojpuri
+bih=Bihari
+bik=Bikol
+bin=Bini
+bis=Bislama
+bla=Siksika
+bnt=Bantu
+bos=Bosnian
+bra=Braj
+bre=Breton
+btk=Batak
+bua=Buriat
+bug=Buginese
+bul=Bulgarian
+bur=Burmese
+byn=Blin
+cad=Caddo
+cai=Central American Indian
+car=Galibi Carib
+cat=Catalan
+cau=Caucasian
+ceb=Cebuano
+cel=Celtic
+cha=Chamorro
+chb=Chibcha
+che=Chechen
+chg=Chagatai
+chi=Chinese
+chk=Chuukese
+chm=Mari
+chn=Chinook jargon
+cho=Choctaw
+chp=Chipewyan
+chr=Cherokee
+chu=Church Slavic
+chv=Chuvash
+chy=Cheyenne
+cmc=Chamic
+cop=Coptic
+cor=Cornish
+cos=Corsican
+cpe=Creoles and pidgins, English based
+cpf=Creoles and pidgins, French-based
+cpp=Creoles and pidgins, Portuguese-based
+cre=Cree
+crh=Crimean Tatar
+crp=Creoles and pidgins
+csb=Kashubian
+cus=Cushitic
+cze=Czech
+dak=Dakota
+dan=Danish
+dar=Dargwa
+day=Land Dayak
+del=Delaware
+den=Slave (Athapascan)
+dgr=Dogrib
+din=Dinka
+div=Divehi
+doi=Dogri
+dra=Dravidian
+dsb=Lower Sorbian
+dua=Duala
+dum=Dutch, Middle (ca.1050-1350)
+dut=Dutch
+dyu=Dyula
+dzo=Dzongkha
+efi=Efik
+egy=Egyptian (Ancient)
+eka=Ekajuk
+elx=Elamite
+eng=English
+enm=English, Middle (1100-1500)
+epo=Esperanto
+est=Estonian
+ewe=Ewe
+ewo=Ewondo
+fan=Fang
+fao=Faroese
+fat=Fanti
+fij=Fijian
+fil=Filipino
+fin=Finnish
+fiu=Finno-Ugrian
+fon=Fon
+fre=French
+frm=French, Middle (ca.1400-1600)
+fro=French, Old (842-ca.1400)
+frr=Northern Frisian
+frs=Eastern Frisian
+fry=Western Frisian
+ful=Fulah
+fur=Friulian
+gaa=Ga
+gay=Gayo
+gba=Gbaya
+gem=Germanic
+geo=Georgian
+ger=German
+gez=Geez
+gil=Gilbertese
+gla=Gaelic
+gle=Irish
+glg=Galician
+glv=Manx
+gmh=German, Middle High (ca.1050-1500)
+goh=German, Old High (ca.750-1050)
+gon=Gondi
+gor=Gorontalo
+got=Gothic
+grb=Grebo
+grc=Greek, Ancient (to 1453)
+gre=Greek, Modern (1453-)
+grn=Guarani
+gsw=Swiss German
+guj=Gujarati
+gwi=Gwich'in
+hai=Haida
+hat=Haitian
+hau=Hausa
+haw=Hawaiian
+heb=Hebrew
+her=Herero
+hil=Hiligaynon
+him=Himachali
+hin=Hindi
+hit=Hittite
+hmn=Hmong
+hmo=Hiri Motu
+hrv=Croatian
+hsb=Upper Sorbian
+hun=Hungarian
+hup=Hupa
+iba=Iban
+ibo=Igbo
+ice=Icelandic
+ido=Ido
+iii=Sichuan Yi
+ijo=Ijo
+iku=Inuktitut
+ile=Interlingue
+ilo=Iloko
+ina=Interlingua (International Auxiliary Language Association)
+inc=Indic
+ind=Indonesian
+ine=Indo-European
+inh=Ingush
+ipk=Inupiaq
+ira=Iranian
+iro=Iroquoian
+ita=Italian
+jav=Javanese
+jbo=Lojban
+jpn=Japanese
+jpr=Judeo-Persian
+jrb=Judeo-Arabic
+kaa=Kara-Kalpak
+kab=Kabyle
+kac=Kachin
+kal=Kalaallisut
+kam=Kamba
+kan=Kannada
+kar=Karen
+kas=Kashmiri
+kau=Kanuri
+kaw=Kawi
+kaz=Kazakh
+kbd=Kabardian
+kha=Khasi
+khi=Khoisan
+khm=Central Khmer
+kho=Khotanese
+kik=Kikuyu
+kin=Kinyarwanda
+kir=Kirghiz
+kmb=Kimbundu
+kok=Konkani
+kom=Komi
+kon=Kongo
+kor=Korean
+kos=Kosraean
+kpe=Kpelle
+krc=Karachay-Balkar
+krl=Karelian
+kro=Kru
+kru=Kurukh
+kua=Kuanyama
+kum=Kumyk
+kur=Kurdish
+kut=Kutenai
+lad=Ladino
+lah=Lahnda
+lam=Lamba
+lao=Lao
+lat=Latin
+lav=Latvian
+lez=Lezghian
+lim=Limburgan
+lin=Lingala
+lit=Lithuanian
+lol=Mongo
+loz=Lozi
+ltz=Luxembourgish
+lua=Luba-Lulua
+lub=Luba-Katanga
+lug=Ganda
+lui=Luiseno
+lun=Lunda
+luo=Luo (Kenya and Tanzania)
+lus=Lushai
+mac=Macedonian
+mad=Madurese
+mag=Magahi
+mah=Marshallese
+mai=Maithili
+mak=Makasar
+mal=Malayalam
+man=Mandingo
+mao=Maori
+map=Austronesian
+mar=Marathi
+mas=Masai
+may=Malay
+mdf=Moksha
+mdr=Mandar
+men=Mende
+mga=Irish, Middle (900-1200)
+mic=Mi'kmaq
+min=Minangkabau
+mis=Uncoded
+mkh=Mon-Khmer
+mlg=Malagasy
+mlt=Maltese
+mnc=Manchu
+mni=Manipuri
+mno=Manobo
+moh=Mohawk
+mon=Mongolian
+mos=Mossi
+mul=Multiple
+mun=Munda
+mus=Creek
+mwl=Mirandese
+mwr=Marwari
+myn=Mayan
+myv=Erzya
+nah=Nahuatl
+nai=North American Indian
+nap=Neapolitan
+nau=Nauru
+nav=Navajo
+nbl=Ndebele, South
+nde=Ndebele, North
+ndo=Ndonga
+nds=Low German
+nep=Nepali
+new=Nepal Bhasa
+nia=Nias
+nic=Niger-Kordofanian
+niu=Niuean
+nno=Norwegian Nynorsk
+nob=Bokm\u00e5l, Norwegian
+nog=Nogai
+non=Norse, Old
+nor=Norwegian
+nqo=N'Ko
+nso=Pedi
+nub=Nubian
+nwc=Classical Newari
+nya=Chichewa
+nym=Nyamwezi
+nyn=Nyankole
+nyo=Nyoro
+nzi=Nzima
+oci=Occitan (post 1500)
+oji=Ojibwa
+ori=Oriya
+orm=Oromo
+osa=Osage
+oss=Ossetian
+ota=Turkish, Ottoman (1500-1928)
+oto=Otomian
+paa=Papuan
+pag=Pangasinan
+pal=Pahlavi
+pam=Pampanga
+pan=Panjabi
+pap=Papiamento
+pau=Palauan
+peo=Persian, Old (ca.600-400 B.C.)
+per=Persian
+phi=Philippine
+phn=Phoenician
+pli=Pali
+pol=Polish
+pon=Pohnpeian
+por=Portuguese
+pra=Prakrit
+pro=Proven\u00e7al, Old (to 1500)
+pus=Pushto; Pashto
+que=Quechua
+raj=Rajasthani
+rap=Rapanui
+rar=Rarotongan
+roa=Romance
+roh=Romansh
+rom=Romany
+rum=Romanian
+run=Rundi
+rup=Aromanian
+rus=Russian
+sad=Sandawe
+sag=Sango
+sah=Yakut
+sai=South American Indian
+sal=Salishan
+sam=Samaritan Aramaic
+san=Sanskrit
+sas=Sasak
+sat=Santali
+scn=Sicilian
+sco=Scots
+sel=Selkup
+sem=Semitic
+sga=Irish, Old (to 900)
+sgn=Sign
+shn=Shan
+sid=Sidamo
+sin=Sinhala
+sio=Siouan
+sit=Sino-Tibetan
+sla=Slavic
+slo=Slovak
+slv=Slovenian
+sma=Southern Sami
+sme=Northern Sami
+smi=Sami
+smj=Lule Sami
+smn=Inari Sami
+smo=Samoan
+sms=Skolt Sami
+sna=Shona
+snd=Sindhi
+snk=Soninke
+sog=Sogdian
+som=Somali
+son=Songhai
+sot=Sotho, Southern
+spa=Spanish
+srd=Sardinian
+srn=Sranan Tongo
+srp=Serbian
+srr=Serer
+ssa=Nilo-Saharan
+ssw=Swati
+suk=Sukuma
+sun=Sundanese
+sus=Susu
+sux=Sumerian
+swa=Swahili
+swe=Swedish
+syc=Classical Syriac
+syr=Syriac
+tah=Tahitian
+tai=Tai
+tam=Tamil
+tat=Tatar
+tel=Telugu
+tem=Timne
+ter=Tereno
+tet=Tetum
+tgk=Tajik
+tgl=Tagalog
+tha=Thai
+tib=Tibetan
+tig=Tigre
+tir=Tigrinya
+tiv=Tiv
+tkl=Tokelau
+tlh=Klingon
+tli=Tlingit
+tmh=Tamashek
+tog=Tonga (Nyasa)
+ton=Tonga (Tonga Islands)
+tpi=Tok Pisin
+tsi=Tsimshian
+tsn=Tswana
+tso=Tsonga
+tuk=Turkmen
+tum=Tumbuka
+tup=Tupi
+tur=Turkish
+tut=Altaic
+tvl=Tuvalu
+twi=Twi
+tyv=Tuvinian
+udm=Udmurt
+uga=Ugaritic
+uig=Uighur
+ukr=Ukrainian
+umb=Umbundu
+und=Undetermined
+urd=Urdu
+uzb=Uzbek
+vai=Vai
+ven=Venda
+vie=Vietnamese
+vol=Volap\u00fck
+vot=Votic
+wak=Wakashan
+wal=Wolaitta
+war=Waray
+was=Washo
+wel=Welsh
+wen=Sorbian
+wln=Walloon
+wol=Wolof
+xal=Kalmyk
+xho=Xhosa
+yao=Yao
+yap=Yapese
+yid=Yiddish
+yor=Yoruba
+ypk=Yupik
+zap=Zapotec
+zbl=Blissymbols
+zen=Zenaga
+zha=Zhuang
+znd=Zande
+zul=Zulu
+zun=Zuni
+zxx=No linguistic content
+zza=Zaza
+
# script names
# key is ISO 15924 script code
--- a/jdk/src/share/native/java/lang/System.c Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/native/java/lang/System.c Sat Nov 13 18:56:50 2010 -0800
@@ -219,11 +219,14 @@
/*
* user.language
- * user.country, user.variant (if user's environment specifies them)
+ * user.script, user.country, user.variant (if user's environment specifies them)
* file.encoding
* file.encoding.pkg
*/
PUTPROP(props, "user.language", sprops->language);
+ if (sprops->script) {
+ PUTPROP(props, "user.script", sprops->script);
+ }
if (sprops->country) {
PUTPROP(props, "user.country", sprops->country);
}
@@ -305,11 +308,12 @@
}
/*
- * unset "user.language", "user.country", and "user.variant"
+ * unset "user.language", "user.script", "user.country", and "user.variant"
* in order to tell whether the command line option "-DXXXX=YYYY" is
* specified or not. They will be reset in fillI18nProps() below.
*/
REMOVEPROP(props, "user.language");
+ REMOVEPROP(props, "user.script");
REMOVEPROP(props, "user.country");
REMOVEPROP(props, "user.variant");
REMOVEPROP(props, "file.encoding");
@@ -328,6 +332,8 @@
/* reconstruct i18n related properties */
fillI18nProps(env, props, "user.language", sprops->display_language,
sprops->format_language, putID, getPropID);
+ fillI18nProps(env, props, "user.script",
+ sprops->display_script, sprops->format_script, putID, getPropID);
fillI18nProps(env, props, "user.country",
sprops->display_country, sprops->format_country, putID, getPropID);
fillI18nProps(env, props, "user.variant",
--- a/jdk/src/share/native/java/lang/java_props.h Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/native/java/lang/java_props.h Sat Nov 13 18:56:50 2010 -0800
@@ -55,6 +55,9 @@
char *language;
char *format_language;
char *display_language;
+ char *script;
+ char *format_script;
+ char *display_script;
char *country;
char *format_country;
char *display_country;
--- a/jdk/src/share/native/sun/java2d/loops/ProcessPath.c Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/share/native/sun/java2d/loops/ProcessPath.c Sat Nov 13 18:56:50 2010 -0800
@@ -116,14 +116,26 @@
jint Y0 = (fY0) >> MDP_PREC; \
jint X1 = (fX1) >> MDP_PREC; \
jint Y1 = (fY1) >> MDP_PREC; \
- /* Handling lines having just one pixel */\
+ jint res; \
+ \
+ /* Checking bounds and clipping if necessary */ \
+ if (checkBounds) { \
+ TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y0, X0, Y1, X1, \
+ jint, res); \
+ if (res == CRES_INVISIBLE) break; \
+ TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y1, X1, Y0, X0, \
+ jint, res); \
+ if (res == CRES_INVISIBLE) break; \
+ TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X0, Y0, X1, Y1, \
+ jint, res); \
+ if (res == CRES_INVISIBLE) break; \
+ TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X1, Y1, X0, Y0, \
+ jint, res); \
+ if (res == CRES_INVISIBLE) break; \
+ } \
+ \
+ /* Handling lines having just one pixel */ \
if (((X0^X1) | (Y0^Y1)) == 0) { \
- if (checkBounds && \
- (hnd->dhnd->yMin > Y0 || \
- hnd->dhnd->yMax <= Y0 || \
- hnd->dhnd->xMin > X0 || \
- hnd->dhnd->xMax <= X0)) break; \
- \
if (pixelInfo[0] == 0) { \
pixelInfo[0] = 1; \
pixelInfo[1] = X0; \
@@ -140,18 +152,11 @@
break; \
} \
\
- if (!checkBounds || \
- (hnd->dhnd->yMin <= Y0 && \
- hnd->dhnd->yMax > Y0 && \
- hnd->dhnd->xMin <= X0 && \
- hnd->dhnd->xMax > X0)) \
+ if (pixelInfo[0] && \
+ ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || \
+ (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) \
{ \
- if (pixelInfo[0] && \
- ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || \
- (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) \
- { \
- hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \
- } \
+ hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \
} \
\
hnd->dhnd->pDrawLine(hnd->dhnd, X0, Y0, X1, Y1); \
@@ -170,14 +175,6 @@
if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || \
(pixelInfo[3] == X1 && pixelInfo[4] == Y1)) \
{ \
- if (checkBounds && \
- (hnd->dhnd->yMin > Y1 || \
- hnd->dhnd->yMax <= Y1 || \
- hnd->dhnd->xMin > X1 || \
- hnd->dhnd->xMax <= X1)) { \
- break; \
- } \
- \
hnd->dhnd->pDrawPixel(hnd->dhnd, X1, Y1); \
} \
pixelInfo[3] = X1; \
--- a/jdk/src/solaris/native/java/lang/java_props_md.c Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/solaris/native/java/lang/java_props_md.c Sat Nov 13 18:56:50 2010 -0800
@@ -117,7 +117,8 @@
#define P_tmpdir "/var/tmp"
#endif
-static int ParseLocale(int cat, char ** std_language, char ** std_country, char ** std_variant, char ** std_encoding) {
+static int ParseLocale(int cat, char ** std_language, char ** std_script,
+ char ** std_country, char ** std_variant, char ** std_encoding) {
char temp[64];
char *language = NULL, *country = NULL, *variant = NULL,
*encoding = NULL;
@@ -181,14 +182,22 @@
strcpy(encoding_variant, p); /* Copy the leading '.' */
*p = '\0';
} else if ((p = strchr(temp, '@')) != NULL) {
- strcpy(encoding_variant, p); /* Copy the leading '@' */
- *p = '\0';
+ strcpy(encoding_variant, p); /* Copy the leading '@' */
+ *p = '\0';
} else {
*encoding_variant = '\0';
}
if (mapLookup(locale_aliases, temp, &p)) {
strcpy(temp, p);
+ // check the "encoding_variant" again, if any.
+ if ((p = strchr(temp, '.')) != NULL) {
+ strcpy(encoding_variant, p); /* Copy the leading '.' */
+ *p = '\0';
+ } else if ((p = strchr(temp, '@')) != NULL) {
+ strcpy(encoding_variant, p); /* Copy the leading '@' */
+ *p = '\0';
+ }
}
language = temp;
@@ -219,10 +228,17 @@
mapLookup(country_names, country, std_country);
}
- /* Normalize the variant name. Note that we only use
- * variants listed in the mapping array; others are ignored. */
- if (std_variant != NULL && variant != NULL) {
- mapLookup(variant_names, variant, std_variant);
+ /* Normalize the script and variant name. Note that we only use
+ * variants listed in the mapping array; others are ignored.
+ */
+ if (variant != NULL) {
+ if (std_script != NULL) {
+ mapLookup(script_names, variant, std_script);
+ }
+
+ if (std_variant != NULL) {
+ mapLookup(variant_names, variant, std_variant);
+ }
}
/* Normalize the encoding name. Note that we IGNORE the string
@@ -358,11 +374,13 @@
setlocale(LC_ALL, "");
if (ParseLocale(LC_CTYPE,
&(sprops.format_language),
+ &(sprops.format_script),
&(sprops.format_country),
&(sprops.format_variant),
&(sprops.encoding))) {
ParseLocale(LC_MESSAGES,
&(sprops.language),
+ &(sprops.script),
&(sprops.country),
&(sprops.variant),
NULL);
@@ -371,6 +389,7 @@
sprops.encoding = "ISO8859-1";
}
sprops.display_language = sprops.language;
+ sprops.display_script = sprops.script;
sprops.display_country = sprops.country;
sprops.display_variant = sprops.variant;
sprops.sun_jnu_encoding = sprops.encoding;
--- a/jdk/src/solaris/native/java/lang/locale_str.h Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/solaris/native/java/lang/locale_str.h Sat Nov 13 18:56:50 2010 -0800
@@ -86,6 +86,8 @@
"wa", "wa_BE",
"zh", "zh_CN",
#ifdef __linux__
+ "bokmal", "nb_NO",
+ "bokm\u00e5l", "nb_NO",
"catalan", "ca_ES",
"croatian", "hr_HR",
"czech", "cs_CZ",
@@ -93,9 +95,13 @@
"dansk", "da_DK",
"deutsch", "de_DE",
"dutch", "nl_NL",
+ "eesti", "et_EE",
+ "estonian", "et_EE",
"finnish", "fi_FI",
"fran\xE7\x61is", "fr_FR",
"french", "fr_FR",
+ "galego", "gl_ES",
+ "galician", "gl_ES",
"german", "de_DE",
"greek", "el_GR",
"hebrew", "iw_IL",
@@ -104,7 +110,10 @@
"icelandic", "is_IS",
"italian", "it_IT",
"japanese", "ja_JP",
+ "korean", "ko_KR",
+ "lithuanian", "lt_LT",
"norwegian", "no_NO",
+ "nynorsk", "nn_NO",
"polish", "pl_PL",
"portuguese", "pt_PT",
"romanian", "ro_RO",
@@ -114,11 +123,16 @@
"slovenian", "sl_SI",
"spanish", "es_ES",
"swedish", "sv_SE",
+ "thai", "th_TH",
"turkish", "tr_TR",
#else
"big5", "zh_TW.Big5",
"chinese", "zh_CN",
+ "iso_8859_1", "en_US.ISO8859-1",
+ "iso_8859_15", "en_US.ISO8859-15",
"japanese", "ja_JP",
+ "no_NY", "no_NO@nynorsk",
+ "sr_SP", "sr_YU",
"tchinese", "zh_TW",
#endif
""
@@ -361,6 +375,506 @@
"japanese", "ja",
"korean", "ko",
#endif
+
+ /* ISO 639.2 codes */
+ "aar", "aar",
+ "abk", "abk",
+ "ace", "ace",
+ "ach", "ach",
+ "ada", "ada",
+ "ady", "ady",
+ "afa", "afa",
+ "afh", "afh",
+ "afr", "afr",
+ "ain", "ain",
+ "aka", "aka",
+ "akk", "akk",
+ "alb", "alb",
+ "ale", "ale",
+ "alg", "alg",
+ "alt", "alt",
+ "amh", "amh",
+ "ang", "ang",
+ "anp", "anp",
+ "apa", "apa",
+ "ara", "ara",
+ "arc", "arc",
+ "arg", "arg",
+ "arm", "arm",
+ "arn", "arn",
+ "arp", "arp",
+ "art", "art",
+ "arw", "arw",
+ "asm", "asm",
+ "ast", "ast",
+ "ath", "ath",
+ "aus", "aus",
+ "ava", "ava",
+ "ave", "ave",
+ "awa", "awa",
+ "aym", "aym",
+ "aze", "aze",
+ "bad", "bad",
+ "bai", "bai",
+ "bak", "bak",
+ "bal", "bal",
+ "bam", "bam",
+ "ban", "ban",
+ "baq", "baq",
+ "bas", "bas",
+ "bat", "bat",
+ "bej", "bej",
+ "bel", "bel",
+ "bem", "bem",
+ "ben", "ben",
+ "ber", "ber",
+ "bho", "bho",
+ "bih", "bih",
+ "bik", "bik",
+ "bin", "bin",
+ "bis", "bis",
+ "bla", "bla",
+ "bnt", "bnt",
+ "bos", "bos",
+ "bra", "bra",
+ "bre", "bre",
+ "btk", "btk",
+ "bua", "bua",
+ "bug", "bug",
+ "bul", "bul",
+ "bur", "bur",
+ "byn", "byn",
+ "cad", "cad",
+ "cai", "cai",
+ "car", "car",
+ "cat", "cat",
+ "cau", "cau",
+ "ceb", "ceb",
+ "cel", "cel",
+ "cha", "cha",
+ "chb", "chb",
+ "che", "che",
+ "chg", "chg",
+ "chi", "chi",
+ "chk", "chk",
+ "chm", "chm",
+ "chn", "chn",
+ "cho", "cho",
+ "chp", "chp",
+ "chr", "chr",
+ "chu", "chu",
+ "chv", "chv",
+ "chy", "chy",
+ "cmc", "cmc",
+ "cop", "cop",
+ "cor", "cor",
+ "cos", "cos",
+ "cpe", "cpe",
+ "cpf", "cpf",
+ "cpp", "cpp",
+ "cre", "cre",
+ "crh", "crh",
+ "crp", "crp",
+ "csb", "csb",
+ "cus", "cus",
+ "cze", "cze",
+ "dak", "dak",
+ "dan", "dan",
+ "dar", "dar",
+ "day", "day",
+ "del", "del",
+ "den", "den",
+ "dgr", "dgr",
+ "din", "din",
+ "div", "div",
+ "doi", "doi",
+ "dra", "dra",
+ "dsb", "dsb",
+ "dua", "dua",
+ "dum", "dum",
+ "dut", "dut",
+ "dyu", "dyu",
+ "dzo", "dzo",
+ "efi", "efi",
+ "egy", "egy",
+ "eka", "eka",
+ "elx", "elx",
+ "eng", "eng",
+ "enm", "enm",
+ "epo", "epo",
+ "est", "est",
+ "ewe", "ewe",
+ "ewo", "ewo",
+ "fan", "fan",
+ "fao", "fao",
+ "fat", "fat",
+ "fij", "fij",
+ "fil", "fil",
+ "fin", "fin",
+ "fiu", "fiu",
+ "fon", "fon",
+ "fre", "fre",
+ "frm", "frm",
+ "fro", "fro",
+ "frr", "frr",
+ "frs", "frs",
+ "fry", "fry",
+ "ful", "ful",
+ "fur", "fur",
+ "gaa", "gaa",
+ "gay", "gay",
+ "gba", "gba",
+ "gem", "gem",
+ "geo", "geo",
+ "ger", "ger",
+ "gez", "gez",
+ "gil", "gil",
+ "gla", "gla",
+ "gle", "gle",
+ "glg", "glg",
+ "glv", "glv",
+ "gmh", "gmh",
+ "goh", "goh",
+ "gon", "gon",
+ "gor", "gor",
+ "got", "got",
+ "grb", "grb",
+ "grc", "grc",
+ "gre", "gre",
+ "grn", "grn",
+ "gsw", "gsw",
+ "guj", "guj",
+ "gwi", "gwi",
+ "hai", "hai",
+ "hat", "hat",
+ "hau", "hau",
+ "haw", "haw",
+ "heb", "heb",
+ "her", "her",
+ "hil", "hil",
+ "him", "him",
+ "hin", "hin",
+ "hit", "hit",
+ "hmn", "hmn",
+ "hmo", "hmo",
+ "hrv", "hrv",
+ "hsb", "hsb",
+ "hun", "hun",
+ "hup", "hup",
+ "iba", "iba",
+ "ibo", "ibo",
+ "ice", "ice",
+ "ido", "ido",
+ "iii", "iii",
+ "ijo", "ijo",
+ "iku", "iku",
+ "ile", "ile",
+ "ilo", "ilo",
+ "ina", "ina",
+ "inc", "inc",
+ "ind", "ind",
+ "ine", "ine",
+ "inh", "inh",
+ "ipk", "ipk",
+ "ira", "ira",
+ "iro", "iro",
+ "ita", "ita",
+ "jav", "jav",
+ "jbo", "jbo",
+ "jpn", "jpn",
+ "jpr", "jpr",
+ "jrb", "jrb",
+ "kaa", "kaa",
+ "kab", "kab",
+ "kac", "kac",
+ "kal", "kal",
+ "kam", "kam",
+ "kan", "kan",
+ "kar", "kar",
+ "kas", "kas",
+ "kau", "kau",
+ "kaw", "kaw",
+ "kaz", "kaz",
+ "kbd", "kbd",
+ "kha", "kha",
+ "khi", "khi",
+ "khm", "khm",
+ "kho", "kho",
+ "kik", "kik",
+ "kin", "kin",
+ "kir", "kir",
+ "kmb", "kmb",
+ "kok", "kok",
+ "kom", "kom",
+ "kon", "kon",
+ "kor", "kor",
+ "kos", "kos",
+ "kpe", "kpe",
+ "krc", "krc",
+ "krl", "krl",
+ "kro", "kro",
+ "kru", "kru",
+ "kua", "kua",
+ "kum", "kum",
+ "kur", "kur",
+ "kut", "kut",
+ "lad", "lad",
+ "lah", "lah",
+ "lam", "lam",
+ "lao", "lao",
+ "lat", "lat",
+ "lav", "lav",
+ "lez", "lez",
+ "lim", "lim",
+ "lin", "lin",
+ "lit", "lit",
+ "lol", "lol",
+ "loz", "loz",
+ "ltz", "ltz",
+ "lua", "lua",
+ "lub", "lub",
+ "lug", "lug",
+ "lui", "lui",
+ "lun", "lun",
+ "luo", "luo",
+ "lus", "lus",
+ "mac", "mac",
+ "mad", "mad",
+ "mag", "mag",
+ "mah", "mah",
+ "mai", "mai",
+ "mak", "mak",
+ "mal", "mal",
+ "man", "man",
+ "mao", "mao",
+ "map", "map",
+ "mar", "mar",
+ "mas", "mas",
+ "may", "may",
+ "mdf", "mdf",
+ "mdr", "mdr",
+ "men", "men",
+ "mga", "mga",
+ "mic", "mic",
+ "min", "min",
+ "mis", "mis",
+ "mkh", "mkh",
+ "mlg", "mlg",
+ "mlt", "mlt",
+ "mnc", "mnc",
+ "mni", "mni",
+ "mno", "mno",
+ "moh", "moh",
+ "mon", "mon",
+ "mos", "mos",
+ "mul", "mul",
+ "mun", "mun",
+ "mus", "mus",
+ "mwl", "mwl",
+ "mwr", "mwr",
+ "myn", "myn",
+ "myv", "myv",
+ "nah", "nah",
+ "nai", "nai",
+ "nap", "nap",
+ "nau", "nau",
+ "nav", "nav",
+ "nbl", "nbl",
+ "nde", "nde",
+ "ndo", "ndo",
+ "nds", "nds",
+ "nep", "nep",
+ "new", "new",
+ "nia", "nia",
+ "nic", "nic",
+ "niu", "niu",
+ "nno", "nno",
+ "nob", "nob",
+ "nog", "nog",
+ "non", "non",
+ "nor", "nor",
+ "nqo", "nqo",
+ "nso", "nso",
+ "nub", "nub",
+ "nwc", "nwc",
+ "nya", "nya",
+ "nym", "nym",
+ "nyn", "nyn",
+ "nyo", "nyo",
+ "nzi", "nzi",
+ "oci", "oci",
+ "oji", "oji",
+ "ori", "ori",
+ "orm", "orm",
+ "osa", "osa",
+ "oss", "oss",
+ "ota", "ota",
+ "oto", "oto",
+ "paa", "paa",
+ "pag", "pag",
+ "pal", "pal",
+ "pam", "pam",
+ "pan", "pan",
+ "pap", "pap",
+ "pau", "pau",
+ "peo", "peo",
+ "per", "per",
+ "phi", "phi",
+ "phn", "phn",
+ "pli", "pli",
+ "pol", "pol",
+ "pon", "pon",
+ "por", "por",
+ "pra", "pra",
+ "pro", "pro",
+ "pus", "pus",
+ "que", "que",
+ "raj", "raj",
+ "rap", "rap",
+ "rar", "rar",
+ "roa", "roa",
+ "roh", "roh",
+ "rom", "rom",
+ "rum", "rum",
+ "run", "run",
+ "rup", "rup",
+ "rus", "rus",
+ "sad", "sad",
+ "sag", "sag",
+ "sah", "sah",
+ "sai", "sai",
+ "sal", "sal",
+ "sam", "sam",
+ "san", "san",
+ "sas", "sas",
+ "sat", "sat",
+ "scn", "scn",
+ "sco", "sco",
+ "sel", "sel",
+ "sem", "sem",
+ "sga", "sga",
+ "sgn", "sgn",
+ "shn", "shn",
+ "sid", "sid",
+ "sin", "sin",
+ "sio", "sio",
+ "sit", "sit",
+ "sla", "sla",
+ "slo", "slo",
+ "slv", "slv",
+ "sma", "sma",
+ "sme", "sme",
+ "smi", "smi",
+ "smj", "smj",
+ "smn", "smn",
+ "smo", "smo",
+ "sms", "sms",
+ "sna", "sna",
+ "snd", "snd",
+ "snk", "snk",
+ "sog", "sog",
+ "som", "som",
+ "son", "son",
+ "sot", "sot",
+ "spa", "spa",
+ "srd", "srd",
+ "srn", "srn",
+ "srp", "srp",
+ "srr", "srr",
+ "ssa", "ssa",
+ "ssw", "ssw",
+ "suk", "suk",
+ "sun", "sun",
+ "sus", "sus",
+ "sux", "sux",
+ "swa", "swa",
+ "swe", "swe",
+ "syc", "syc",
+ "syr", "syr",
+ "tah", "tah",
+ "tai", "tai",
+ "tam", "tam",
+ "tat", "tat",
+ "tel", "tel",
+ "tem", "tem",
+ "ter", "ter",
+ "tet", "tet",
+ "tgk", "tgk",
+ "tgl", "tgl",
+ "tha", "tha",
+ "tib", "tib",
+ "tig", "tig",
+ "tir", "tir",
+ "tiv", "tiv",
+ "tkl", "tkl",
+ "tlh", "tlh",
+ "tli", "tli",
+ "tmh", "tmh",
+ "tog", "tog",
+ "ton", "ton",
+ "tpi", "tpi",
+ "tsi", "tsi",
+ "tsn", "tsn",
+ "tso", "tso",
+ "tuk", "tuk",
+ "tum", "tum",
+ "tup", "tup",
+ "tur", "tur",
+ "tut", "tut",
+ "tvl", "tvl",
+ "twi", "twi",
+ "tyv", "tyv",
+ "udm", "udm",
+ "uga", "uga",
+ "uig", "uig",
+ "ukr", "ukr",
+ "umb", "umb",
+ "und", "und",
+ "urd", "urd",
+ "uzb", "uzb",
+ "vai", "vai",
+ "ven", "ven",
+ "vie", "vie",
+ "vol", "vol",
+ "vot", "vot",
+ "wak", "wak",
+ "wal", "wal",
+ "war", "war",
+ "was", "was",
+ "wel", "wel",
+ "wen", "wen",
+ "wln", "wln",
+ "wol", "wol",
+ "xal", "xal",
+ "xho", "xho",
+ "yao", "yao",
+ "yap", "yap",
+ "yid", "yid",
+ "yor", "yor",
+ "ypk", "ypk",
+ "zap", "zap",
+ "zbl", "zbl",
+ "zen", "zen",
+ "zha", "zha",
+ "znd", "znd",
+ "zul", "zul",
+ "zun", "zun",
+ "zxx", "zxx",
+ "zza", "zza",
+
+ "",
+};
+
+/*
+ * Linux/Solaris script string to Java script name mapping table.
+ */
+static char *script_names[] = {
+#ifdef __linux__
+ "cyrillic", "Cyrl",
+ "devanagari", "Deva",
+ "iqtelif", "Latn",
+ "latin", "Latn",
+#endif
"",
};
@@ -503,6 +1017,7 @@
"MA", "MA",
"MC", "MC",
"MD", "MD",
+ "ME", "ME",
"MG", "MG",
"MH", "MH",
"MK", "MK",
@@ -554,6 +1069,7 @@
"RN", "US", // used on Linux, not clear what it stands for
#endif
"RO", "RO",
+ "RS", "RS",
"RU", "RU",
"RW", "RW",
"SA", "SA",
--- a/jdk/src/windows/bin/java_md.c Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/bin/java_md.c Sat Nov 13 18:56:50 2010 -0800
@@ -51,6 +51,92 @@
static jboolean GetJREPath(char *path, jint pathsize);
static void EnsureJreInstallation(const char *jrepath);
+/* We supports warmup for UI stack that is performed in parallel
+ * to VM initialization.
+ * This helps to improve startup of UI application as warmup phase
+ * might be long due to initialization of OS or hardware resources.
+ * It is not CPU bound and therefore it does not interfere with VM init.
+ * Obviously such warmup only has sense for UI apps and therefore it needs
+ * to be explicitly requested by passing -Dsun.awt.warmup=true property
+ * (this is always the case for plugin/javaws).
+ *
+ * Implementation launches new thread after VM starts and use it to perform
+ * warmup code (platform dependent).
+ * This thread is later reused as AWT toolkit thread as graphics toolkit
+ * often assume that they are used from the same thread they were launched on.
+ *
+ * At the moment we only support warmup for D3D. It only possible on windows
+ * and only if other flags do not prohibit this (e.g. OpenGL support requested).
+ */
+#undef ENABLE_AWT_PRELOAD
+#ifndef JAVA_ARGS /* turn off AWT preloading for javac, jar, etc */
+ #define ENABLE_AWT_PRELOAD
+#endif
+
+#ifdef ENABLE_AWT_PRELOAD
+/* "AWT was preloaded" flag;
+ * turned on by AWTPreload().
+ */
+int awtPreloaded = 0;
+
+/* Calls a function with the name specified
+ * the function must be int(*fn)(void).
+ */
+int AWTPreload(const char *funcName);
+/* stops AWT preloading */
+void AWTPreloadStop();
+
+/* D3D preloading */
+/* -1: not initialized; 0: OFF, 1: ON */
+int awtPreloadD3D = -1;
+/* command line parameter to swith D3D preloading on */
+#define PARAM_PRELOAD_D3D "-Dsun.awt.warmup"
+/* D3D/OpenGL management parameters */
+#define PARAM_NODDRAW "-Dsun.java2d.noddraw"
+#define PARAM_D3D "-Dsun.java2d.d3d"
+#define PARAM_OPENGL "-Dsun.java2d.opengl"
+/* funtion in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */
+#define D3D_PRELOAD_FUNC "preloadD3D"
+
+
+/* Extracts value of a parameter with the specified name
+ * from command line argument (returns pointer in the argument).
+ * Returns NULL if the argument does not contains the parameter.
+ * e.g.:
+ * GetParamValue("theParam", "theParam=value") returns pointer to "value".
+ */
+const char * GetParamValue(const char *paramName, const char *arg) {
+ int nameLen = JLI_StrLen(paramName);
+ if (JLI_StrNCmp(paramName, arg, nameLen) == 0) {
+ /* arg[nameLen] is valid (may contain final NULL) */
+ if (arg[nameLen] == '=') {
+ return arg + nameLen + 1;
+ }
+ }
+ return NULL;
+}
+
+/* Checks if commandline argument contains property specified
+ * and analyze it as boolean property (true/false).
+ * Returns -1 if the argument does not contain the parameter;
+ * Returns 1 if the argument contains the parameter and its value is "true";
+ * Returns 0 if the argument contains the parameter and its value is "false".
+ */
+int GetBoolParamValue(const char *paramName, const char *arg) {
+ const char * paramValue = GetParamValue(paramName, arg);
+ if (paramValue != NULL) {
+ if (JLI_StrCaseCmp(paramValue, "true") == 0) {
+ return 1;
+ }
+ if (JLI_StrCaseCmp(paramValue, "false") == 0) {
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif /* ENABLE_AWT_PRELOAD */
+
+
static jboolean _isjavaw = JNI_FALSE;
@@ -132,6 +218,30 @@
exit(4);
}
/* If we got here, jvmpath has been correctly initialized. */
+
+ /* Check if we need preload AWT */
+#ifdef ENABLE_AWT_PRELOAD
+ argv = *pargv;
+ for (i = 0; i < *pargc ; i++) {
+ /* Tests the "turn on" parameter only if not set yet. */
+ if (awtPreloadD3D < 0) {
+ if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) {
+ awtPreloadD3D = 1;
+ }
+ }
+ /* Test parameters which can disable preloading if not already disabled. */
+ if (awtPreloadD3D != 0) {
+ if (GetBoolParamValue(PARAM_NODDRAW, argv[i]) == 1
+ || GetBoolParamValue(PARAM_D3D, argv[i]) == 0
+ || GetBoolParamValue(PARAM_OPENGL, argv[i]) == 1)
+ {
+ awtPreloadD3D = 0;
+ /* no need to test the rest of the parameters */
+ break;
+ }
+ }
+ }
+#endif /* ENABLE_AWT_PRELOAD */
}
@@ -1086,6 +1196,40 @@
0,
&thread_id);
}
+
+ /* AWT preloading (AFTER main thread start) */
+#ifdef ENABLE_AWT_PRELOAD
+ /* D3D preloading */
+ if (awtPreloadD3D != 0) {
+ char *envValue;
+ /* D3D routines checks env.var J2D_D3D if no appropriate
+ * command line params was specified
+ */
+ envValue = getenv("J2D_D3D");
+ if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) {
+ awtPreloadD3D = 0;
+ }
+ /* Test that AWT preloading isn't disabled by J2D_D3D_PRELOAD env.var */
+ envValue = getenv("J2D_D3D_PRELOAD");
+ if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) {
+ awtPreloadD3D = 0;
+ }
+ if (awtPreloadD3D < 0) {
+ /* If awtPreloadD3D is still undefined (-1), test
+ * if it is turned on by J2D_D3D_PRELOAD env.var.
+ * By default it's turned OFF.
+ */
+ awtPreloadD3D = 0;
+ if (envValue != NULL && JLI_StrCaseCmp(envValue, "true") == 0) {
+ awtPreloadD3D = 1;
+ }
+ }
+ }
+ if (awtPreloadD3D) {
+ AWTPreload(D3D_PRELOAD_FUNC);
+ }
+#endif /* ENABLE_AWT_PRELOAD */
+
if (thread_handle) {
WaitForSingleObject(thread_handle, INFINITE);
GetExitCodeThread(thread_handle, &rslt);
@@ -1093,6 +1237,13 @@
} else {
rslt = continuation(args);
}
+
+#ifdef ENABLE_AWT_PRELOAD
+ if (awtPreloaded) {
+ AWTPreloadStop();
+ }
+#endif /* ENABLE_AWT_PRELOAD */
+
return rslt;
}
@@ -1139,3 +1290,98 @@
_isjavaw = javaw;
JLI_SetTraceLauncher();
}
+
+
+/* ============================== */
+/* AWT preloading */
+#ifdef ENABLE_AWT_PRELOAD
+
+typedef int FnPreloadStart(void);
+typedef void FnPreloadStop(void);
+static FnPreloadStop *fnPreloadStop = NULL;
+static HMODULE hPreloadAwt = NULL;
+
+/*
+ * Starts AWT preloading
+ */
+int AWTPreload(const char *funcName)
+{
+ int result = -1;
+ /* load AWT library once (if several preload function should be called) */
+ if (hPreloadAwt == NULL) {
+ /* awt.dll is not loaded yet */
+ char libraryPath[MAXPATHLEN];
+ int jrePathLen = 0;
+ HMODULE hJava = NULL;
+ HMODULE hVerify = NULL;
+
+ while (1) {
+ /* awt.dll depends on jvm.dll & java.dll;
+ * jvm.dll is already loaded, so we need only java.dll;
+ * java.dll depends on MSVCRT lib & verify.dll.
+ */
+ if (!GetJREPath(libraryPath, MAXPATHLEN)) {
+ break;
+ }
+
+ /* save path length */
+ jrePathLen = JLI_StrLen(libraryPath);
+
+ /* load msvcrt 1st */
+ LoadMSVCRT();
+
+ /* load verify.dll */
+ JLI_StrCat(libraryPath, "\\bin\\verify.dll");
+ hVerify = LoadLibrary(libraryPath);
+ if (hVerify == NULL) {
+ break;
+ }
+
+ /* restore jrePath */
+ libraryPath[jrePathLen] = 0;
+ /* load java.dll */
+ JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL);
+ hJava = LoadLibrary(libraryPath);
+ if (hJava == NULL) {
+ break;
+ }
+
+ /* restore jrePath */
+ libraryPath[jrePathLen] = 0;
+ /* load awt.dll */
+ JLI_StrCat(libraryPath, "\\bin\\awt.dll");
+ hPreloadAwt = LoadLibrary(libraryPath);
+ if (hPreloadAwt == NULL) {
+ break;
+ }
+
+ /* get "preloadStop" func ptr */
+ fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop");
+
+ break;
+ }
+ }
+
+ if (hPreloadAwt != NULL) {
+ FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName);
+ if (fnInit != NULL) {
+ /* don't forget to stop preloading */
+ awtPreloaded = 1;
+
+ result = fnInit();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Terminates AWT preloading
+ */
+void AWTPreloadStop() {
+ if (fnPreloadStop != NULL) {
+ fnPreloadStop();
+ }
+}
+
+#endif /* ENABLE_AWT_PRELOAD */
--- a/jdk/src/windows/classes/sun/awt/windows/WInputMethod.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/classes/sun/awt/windows/WInputMethod.java Sat Nov 13 18:56:50 2010 -0800
@@ -169,7 +169,7 @@
locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) ||
locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) {
if (isActive) {
- setNativeLocale(locale.toString(), onActivate);
+ setNativeLocale(locale.toLanguageTag(), onActivate);
}
currentLocale = locale;
return true;
--- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Sat Nov 13 18:56:50 2010 -0800
@@ -218,6 +218,8 @@
private static native void postDispose();
+ private static native boolean startToolkitThread(Runnable thread);
+
public WToolkit() {
// Startup toolkit threads
if (PerformanceLogger.loggingEnabled()) {
@@ -231,9 +233,6 @@
// where notifyAll can be called before
// the "AWT-Windows" thread's parent thread is
// waiting, resulting in a deadlock on startup.
- Thread toolkitThread = new Thread(this, "AWT-Windows");
- toolkitThread.setDaemon(true);
- toolkitThread.setPriority(Thread.NORM_PRIORITY+1);
/*
* Fix for 4701990.
@@ -242,7 +241,11 @@
*/
AWTAutoShutdown.notifyToolkitThreadBusy();
- toolkitThread.start();
+ if (!startToolkitThread(this)) {
+ Thread toolkitThread = new Thread(this, "AWT-Windows");
+ toolkitThread.setDaemon(true);
+ toolkitThread.start();
+ }
try {
wait();
@@ -263,6 +266,7 @@
}
public void run() {
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY+1);
boolean startPump = init();
if (startPump) {
--- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Sat Nov 13 18:56:50 2010 -0800
@@ -600,6 +600,7 @@
}
private native void setOpacity(int iOpacity);
+ private float opacity = 1.0f;
public void setOpacity(float opacity) {
if (!((SunToolkit)((Window)target).getToolkit()).
@@ -608,7 +609,21 @@
return;
}
- replaceSurfaceDataRecursively((Component)getTarget());
+ if (opacity < 0.0f || opacity > 1.0f) {
+ throw new IllegalArgumentException(
+ "The value of opacity should be in the range [0.0f .. 1.0f].");
+ }
+
+ if (((this.opacity == 1.0f && opacity < 1.0f) ||
+ (this.opacity < 1.0f && opacity == 1.0f)) &&
+ !Win32GraphicsEnvironment.isVistaOS())
+ {
+ // non-Vista OS: only replace the surface data if opacity status
+ // changed (see WComponentPeer.isAccelCapable() for more)
+ replaceSurfaceDataRecursively((Component)getTarget());
+ }
+
+ this.opacity = opacity;
final int maxOpacity = 0xff;
int iOpacity = (int)(opacity * maxOpacity);
@@ -650,7 +665,7 @@
boolean isVistaOS = Win32GraphicsEnvironment.isVistaOS();
- if (!isVistaOS) {
+ if (this.isOpaque != isOpaque && !isVistaOS) {
// non-Vista OS: only replace the surface data if the opacity
// status changed (see WComponentPeer.isAccelCapable() for more)
replaceSurfaceDataRecursively(target);
--- a/jdk/src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_DirectSound.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_DirectSound.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -476,6 +476,7 @@
DWORD WINAPI __stdcall DS_StartBufferHelper::ThreadProc(void *param)
{
+ ::CoInitialize(NULL);
while (1) {
// wait for something to do
::WaitForSingleObject(data.startEvent, INFINITE);
@@ -492,6 +493,7 @@
}
::SetEvent(data.startedEvent);
}
+ ::CoUninitialize();
return 0;
}
--- a/jdk/src/windows/native/java/lang/java_props_md.c Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/java/lang/java_props_md.c Sat Nov 13 18:56:50 2010 -0800
@@ -43,11 +43,14 @@
#endif
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
-static void SetupI18nProps(LCID lcid, char** language, char** country,
+static void SetupI18nProps(LCID lcid, char** language, char** script, char** country,
char** variant, char** encoding);
#define SHELL_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
+#define PROPSIZE 9 // eight-letter + null terminator
+#define SNAMESIZE 86 // max number of chars for LOCALE_SNAME is 85
+
static char *
getEncodingInternal(LCID lcid)
{
@@ -127,30 +130,31 @@
return getEncodingInternal(MAKELCID(langID, SORT_DEFAULT));
}
+// Returns BCP47 Language Tag
DllExport const char *
getJavaIDFromLangID(LANGID langID)
{
- char * lang;
- char * ctry;
- char * vrnt;
- char * enc;
- char * ret = malloc(16);
+ char * elems[5]; // lang, script, ctry, variant, encoding
+ char * ret = malloc(SNAMESIZE);
+ int index;
+
+ SetupI18nProps(MAKELCID(langID, SORT_DEFAULT),
+ &(elems[0]), &(elems[1]), &(elems[2]), &(elems[3]), &(elems[4]));
- SetupI18nProps(MAKELCID(langID, SORT_DEFAULT), &lang, &ctry, &vrnt, &enc);
- if (ctry[0] != '\0') {
- if (vrnt[0] != '\0') {
- sprintf(ret, "%s_%s_%s", lang, ctry, vrnt);
- } else {
- sprintf(ret, "%s_%s", lang, ctry);
+ // there always is the "language" tag
+ strcpy(ret, elems[0]);
+
+ // append other elements, if any
+ for (index = 1; index < 4; index++) {
+ if ((elems[index])[0] != '\0') {
+ strcat(ret, "-");
+ strcat(ret, elems[index]);
}
- } else {
- strcpy(ret, lang);
}
- free(lang);
- free(ctry);
- free(vrnt);
- free(enc);
+ for (index = 0; index < 5; index++) {
+ free(elems[index]);
+ }
return ret;
}
@@ -289,39 +293,38 @@
return NULL;
}
-#define PROPSIZE 3 // two-letter + null terminator
static void
-SetupI18nProps(LCID lcid, char** language, char** country,
+SetupI18nProps(LCID lcid, char** language, char** script, char** country,
char** variant, char** encoding) {
+ /* script */
+ char tmp[SNAMESIZE];
+ *script = malloc(PROPSIZE);
+ if (GetLocaleInfo(lcid,
+ LOCALE_SNAME, tmp, SNAMESIZE) == 0 ||
+ sscanf(tmp, "%*[a-z\\-]%1[A-Z]%[a-z]", *script, &((*script)[1])) == 0 ||
+ strlen(*script) != 4) {
+ (*script)[0] = '\0';
+ }
+
/* country */
*country = malloc(PROPSIZE);
if (GetLocaleInfo(lcid,
- LOCALE_SISO3166CTRYNAME, *country, PROPSIZE) == 0) {
+ LOCALE_SISO3166CTRYNAME, *country, PROPSIZE) == 0 &&
+ GetLocaleInfo(lcid,
+ LOCALE_SISO3166CTRYNAME2, *country, PROPSIZE) == 0) {
(*country)[0] = '\0';
}
/* language */
*language = malloc(PROPSIZE);
- if (lcid == 0x46c) {
- /* Windows returns non-existent language code "ns" for Northern Sotho.
- * Defaults to en_US
- */
- strcpy(*language, "en");
- strcpy(*country, "US");
- } else if (GetLocaleInfo(lcid,
- LOCALE_SISO639LANGNAME, *language, PROPSIZE) == 0) {
- if (lcid == 0x465) {
- /* for some reason, Windows returns "div" for this Divehi LCID, even though
- * there is a two letter language code "dv". Tweak it here.
- */
- strcpy(*language, "dv");
- strcpy(*country, "MV");
- } else {
+ if (GetLocaleInfo(lcid,
+ LOCALE_SISO639LANGNAME, *language, PROPSIZE) == 0 &&
+ GetLocaleInfo(lcid,
+ LOCALE_SISO639LANGNAME2, *language, PROPSIZE) == 0) {
/* defaults to en_US */
strcpy(*language, "en");
strcpy(*country, "US");
}
- }
/* variant */
*variant = malloc(PROPSIZE);
@@ -564,7 +567,7 @@
/*
* user.language
- * user.country, user.variant (if user's environment specifies them)
+ * user.script, user.country, user.variant (if user's environment specifies them)
* file.encoding
* file.encoding.pkg
*/
@@ -582,16 +585,19 @@
SetupI18nProps(userDefaultUILang,
&sprops.language,
+ &sprops.script,
&sprops.country,
&sprops.variant,
&display_encoding);
SetupI18nProps(userDefaultLCID,
&sprops.format_language,
+ &sprops.format_script,
&sprops.format_country,
&sprops.format_variant,
&sprops.encoding);
SetupI18nProps(userDefaultUILang,
&sprops.display_language,
+ &sprops.display_script,
&sprops.display_country,
&sprops.display_variant,
&display_encoding);
--- a/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -36,22 +36,6 @@
extern void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
jint height, jint bitDepth, jint refreshRate);
-void InitD3D(void *pReturn)
-{
- J2dTraceLn(J2D_TRACE_INFO, "InitD3D");
-
- jboolean *pRet = (jboolean *)pReturn;
-
- D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance();
- if (pMgr == NULL) {
- J2dTraceLn(J2D_TRACE_ERROR, "InitD3D: could not create or init d3d");
- *pRet = JNI_FALSE;
- } else {
- J2dTraceLn(J2D_TRACE_INFO, "InitD3D: successfully initialized d3d");
- *pRet = JNI_TRUE;
- }
-}
-
extern "C" {
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
@@ -63,8 +47,8 @@
{
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_initD3D");
- jboolean result = JNI_FALSE;
- AwtToolkit::GetInstance().InvokeFunction(InitD3D, &result);
+ jboolean result = D3DInitializer::GetInstance().EnsureInited()
+ ? JNI_TRUE : JNI_FALSE;
J2dTraceLn1(J2D_TRACE_INFO, "D3DGD_initD3D: result=%x", result);
return result;
}
--- a/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -40,6 +40,7 @@
D3DPipelineManager *D3DPipelineManager::pMgr = NULL;
+
D3DPipelineManager * D3DPipelineManager::CreateInstance(void)
{
if (!IsD3DEnabled() ||
@@ -179,6 +180,12 @@
HMONITOR hMon;
int gdiScreen;
D3DPipelineManager *pMgr;
+
+ // fix for 6946559: if d3d preloading fails jmv may be NULL
+ if (jvm == NULL) {
+ return;
+ }
+
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
pMgr = D3DPipelineManager::GetInstance();
@@ -934,3 +941,87 @@
*ppd3dContext = pAdapters[adapterOrdinal].pd3dContext;
return res;
}
+
+
+//==============================================================
+// D3DInitializer
+//==============================================================
+
+D3DInitializer D3DInitializer::theInstance;
+
+D3DInitializer::D3DInitializer()
+ : bComInitialized(false), pAdapterIniters(NULL)
+{
+}
+
+D3DInitializer::~D3DInitializer()
+{
+ if (pAdapterIniters) {
+ delete[] pAdapterIniters;
+ }
+}
+
+void D3DInitializer::InitImpl()
+{
+ J2dRlsTraceLn(J2D_TRACE_INFO, "D3DInitializer::InitImpl");
+ if (SUCCEEDED(::CoInitialize(NULL))) {
+ bComInitialized = true;
+ }
+ D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance();
+ if (pMgr != NULL) {
+ UINT adapterCount = pMgr->adapterCount;
+
+ pAdapterIniters = new D3DAdapterInitializer[adapterCount];
+ for (UINT i=0; i<adapterCount; i++) {
+ pAdapterIniters[i].setAdapter(i);
+ AwtToolkit::GetInstance().GetPreloadThread().AddAction(&pAdapterIniters[i]);
+ }
+ }
+}
+
+void D3DInitializer::CleanImpl(bool reInit)
+{
+ J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DInitializer::CleanImpl (%s)",
+ reInit ? "RELAUNCH" : "normal");
+ D3DPipelineManager::DeleteInstance();
+ if (bComInitialized) {
+ CoUninitialize();
+ }
+}
+
+
+void D3DInitializer::D3DAdapterInitializer::InitImpl()
+{
+ J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) started", adapter);
+
+ D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance();
+ if (pMgr == NULL) {
+ return;
+ }
+
+ D3DContext *pd3dContext;
+ pMgr->GetD3DContext(adapter, &pd3dContext);
+
+ J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) finished", adapter);
+}
+
+void D3DInitializer::D3DAdapterInitializer::CleanImpl(bool reInit)
+{
+ // nothing to do - D3DPipelineManager cleans adapters
+}
+
+
+extern "C" {
+/*
+ * Export function to start D3D preloading
+ * (called from java/javaw - see src/windows/bin/java-md.c)
+ */
+__declspec(dllexport) int preloadD3D()
+{
+ J2dRlsTraceLn(J2D_TRACE_INFO, "AWT warmup: preloadD3D");
+ AwtToolkit::GetInstance().GetPreloadThread().AddAction(&D3DInitializer::GetInstance());
+ return 1;
+}
+
+}
+
--- a/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h Sat Nov 13 18:56:50 2010 -0800
@@ -26,6 +26,7 @@
#include "D3DPipeline.h"
#include "D3DContext.h"
+#include "awt_Toolkit.h"
typedef class D3DPipelineManager *LPD3DPIPELINEMANAGER;
@@ -38,11 +39,15 @@
class D3DPIPELINE_API D3DPipelineManager
{
-public:
+ friend class D3DInitializer;
+private:
// creates and initializes instance of D3DPipelineManager, may return NULL
static D3DPipelineManager* CreateInstance(void);
+
// deletes the single instance of the manager
static void DeleteInstance();
+
+public:
// returns the single instance of the manager, may return NULL
static D3DPipelineManager* GetInstance(void);
@@ -143,3 +148,40 @@
#define OS_ALL (OS_VISTA|OS_WINSERV_2008|OS_WINXP|OS_WINXP_64|OS_WINSERV_2003)
#define OS_UNKNOWN (~OS_ALL)
BOOL D3DPPLM_OsVersionMatches(USHORT osInfo);
+
+
+class D3DInitializer : public AwtToolkit::PreloadAction {
+private:
+ D3DInitializer();
+ ~D3DInitializer();
+
+protected:
+ // PreloadAction overrides
+ virtual void InitImpl();
+ virtual void CleanImpl(bool reInit);
+
+public:
+ static D3DInitializer& GetInstance() { return theInstance; }
+
+private:
+ // single instance
+ static D3DInitializer theInstance;
+
+ // adapter initializer class
+ class D3DAdapterInitializer : public AwtToolkit::PreloadAction {
+ public:
+ void setAdapter(UINT adapter) { this->adapter = adapter; }
+ protected:
+ // PreloadAction overrides
+ virtual void InitImpl();
+ virtual void CleanImpl(bool reInit);
+ private:
+ UINT adapter;
+ };
+
+ // the flag indicates success of COM initialization
+ bool bComInitialized;
+ D3DAdapterInitializer *pAdapterIniters;
+
+};
+
--- a/jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -28,7 +28,8 @@
#include "WindowsFlags.h"
BOOL accelReset; // reset registry 2d acceleration settings
-BOOL useD3D; // d3d enabled flag
+BOOL useD3D = TRUE; // d3d enabled flag
+ // initially is TRUE to allow D3D preloading
BOOL forceD3DUsage; // force d3d on or off
jboolean g_offscreenSharing; // JAWT accelerated surface sharing
BOOL checkRegistry; // Diagnostic tool: outputs 2d registry settings
--- a/jdk/src/windows/native/sun/windows/awt_InputMethod.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/windows/awt_InputMethod.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -540,34 +540,15 @@
{
TRY;
- // get language, country, variant information
- char * language = (char *)safe_Malloc(strlen(name) + 1);
- char * country;
- char * variant;
- DASSERT(!safe_ExceptionOccurred(env));
- strcpy(language, name);
- for (country = language; *country != '_' && *country != '\0'; country++);
- if (*country == '_') {
- *country++ = '\0';
- for (variant = country; *variant != '_' && *variant != '\0'; variant++);
- if (*variant == '_') {
- *variant++ = '\0';
- }
- } else {
- variant = country;
- }
-
// create Locale object
- jobject langObj = env->NewStringUTF(language);
- jobject ctryObj = env->NewStringUTF(country);
- jobject vrntObj = env->NewStringUTF(variant);
- jobject localeObj = JNU_NewObjectByName(env, "java/util/Locale",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
- langObj, ctryObj, vrntObj);
- free(language);
- env->DeleteLocalRef(langObj);
- env->DeleteLocalRef(ctryObj);
- env->DeleteLocalRef(vrntObj);
+ jobject langtagObj = env->NewStringUTF(name);
+ jobject localeObj = JNU_CallStaticMethodByName(env,
+ NULL,
+ "java/util/Locale",
+ "forLanguageTag",
+ "(Ljava/lang/String;)Ljava/util/Locale;",
+ langtagObj).l;
+ env->DeleteLocalRef(langtagObj);
return localeObj;
--- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Sat Nov 13 18:56:50 2010 -0800
@@ -28,6 +28,7 @@
#include "awt.h"
#include <signal.h>
#include <windowsx.h>
+#include <process.h>
#include "awt_DrawingSurface.h"
#include "awt_AWTEvent.h"
@@ -88,7 +89,7 @@
/* Initialize the Java VM instance variable when the library is
first loaded */
-JavaVM *jvm;
+JavaVM *jvm = NULL;
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
@@ -358,6 +359,95 @@
return hwnd;
}
+
+struct ToolkitThreadProc_Data {
+ bool result;
+ HANDLE hCompleted;
+
+ jobject thread;
+};
+
+void ToolkitThreadProc(void *param)
+{
+ ToolkitThreadProc_Data *data = (ToolkitThreadProc_Data *)param;
+
+ bool bNotified = false;
+
+ JNIEnv *env;
+ JavaVMAttachArgs attachArgs;
+ attachArgs.version = JNI_VERSION_1_2;
+ attachArgs.name = "AWT-Windows";
+ attachArgs.group = NULL;
+
+ jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs);
+ if (res < 0) {
+ return;
+ }
+
+ jobject thread = env->NewGlobalRef(data->thread);
+ if (thread != NULL) {
+ jclass cls = env->GetObjectClass(thread);
+ if (cls != NULL) {
+ jmethodID runId = env->GetMethodID(cls, "run", "()V");
+ if (runId != NULL) {
+ data->result = true;
+ ::SetEvent(data->hCompleted);
+ bNotified = true;
+
+ env->CallVoidMethod(thread, runId);
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ // TODO: handle
+ }
+ }
+ env->DeleteLocalRef(cls);
+ }
+ env->DeleteGlobalRef(thread);
+ }
+ if (!bNotified) {
+ ::SetEvent(data->hCompleted);
+ }
+
+ jvm->DetachCurrentThread();
+}
+
+/*
+ * Class: sun_awt_windows_WToolkit
+ * Method: startToolkitThread
+ * Signature: (Ljava/lang/Runnable;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread)
+{
+ AwtToolkit& tk = AwtToolkit::GetInstance();
+
+ ToolkitThreadProc_Data data;
+ data.result = false;
+ data.thread = env->NewGlobalRef(thread);
+ if (data.thread == NULL) {
+ return JNI_FALSE;
+ }
+ data.hCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ bool result = tk.GetPreloadThread()
+ .InvokeAndTerminate(ToolkitThreadProc, &data);
+
+ if (result) {
+ ::WaitForSingleObject(data.hCompleted, INFINITE);
+ result = data.result;
+ } else {
+ // no awt preloading
+ // return back to the usual toolkit way
+ }
+ ::CloseHandle(data.hCompleted);
+
+ env->DeleteGlobalRef(data.thread);
+
+ return result ? JNI_TRUE : JNI_FALSE;
+}
+
BOOL AwtToolkit::Initialize(BOOL localPump) {
AwtToolkit& tk = AwtToolkit::GetInstance();
@@ -371,6 +461,11 @@
// ComCtl32Util was constructed but not disposed
ComCtl32Util::GetInstance().InitLibraries();
+ if (!localPump) {
+ // if preload thread was run, terminate it
+ preloadThread.Terminate(true);
+ }
+
/* Register this toolkit's helper window */
VERIFY(tk.RegisterClass() != NULL);
@@ -439,7 +534,7 @@
// dispose Direct3D-related resources. This should be done
// before AwtObjectList::Cleanup() as the d3d will attempt to
// shutdown when the last of its windows is disposed of
- D3DPipelineManager::DeleteInstance();
+ D3DInitializer::GetInstance().Clean();
AwtObjectList::Cleanup();
AwtFont::Cleanup();
@@ -1635,6 +1730,270 @@
::GetWindowRect(hWnd, lpRect);
}
+
+/************************************************************************
+ * AWT preloading support
+ */
+bool AwtToolkit::PreloadAction::EnsureInited()
+{
+ DWORD _initThreadId = GetInitThreadID();
+ if (_initThreadId != 0) {
+ // already inited
+ // ensure the action is inited on correct thread
+ PreloadThread &preloadThread
+ = AwtToolkit::GetInstance().GetPreloadThread();
+ if (_initThreadId == preloadThread.GetThreadId()) {
+ if (!preloadThread.IsWrongThread()) {
+ return true;
+ }
+ // inited on preloadThread (wrongThread), not cleaned yet
+ // have to wait cleanup completion
+ preloadThread.Wait4Finish();
+ } else {
+ // inited on other thread (Toolkit thread?)
+ // consider as correctly inited
+ return true;
+ }
+ }
+
+ // init on Toolkit thread
+ AwtToolkit::GetInstance().InvokeFunction(InitWrapper, this);
+
+ return true;
+}
+
+DWORD AwtToolkit::PreloadAction::GetInitThreadID()
+{
+ CriticalSection::Lock lock(initLock);
+ return initThreadId;
+}
+
+bool AwtToolkit::PreloadAction::Clean()
+{
+ DWORD _initThreadId = GetInitThreadID();
+ if (_initThreadId == ::GetCurrentThreadId()) {
+ // inited on this thread
+ Clean(false);
+ return true;
+ }
+ return false;
+}
+
+/*static*/
+void AwtToolkit::PreloadAction::InitWrapper(void *param)
+{
+ PreloadAction *pThis = (PreloadAction *)param;
+ pThis->Init();
+}
+
+void AwtToolkit::PreloadAction::Init()
+{
+ CriticalSection::Lock lock(initLock);
+ if (initThreadId == 0) {
+ initThreadId = ::GetCurrentThreadId();
+ InitImpl();
+ }
+}
+
+void AwtToolkit::PreloadAction::Clean(bool reInit) {
+ CriticalSection::Lock lock(initLock);
+ if (initThreadId != 0) {
+ //ASSERT(initThreadId == ::GetCurrentThreadId());
+ CleanImpl(reInit);
+ initThreadId = 0;
+ }
+}
+
+// PreloadThread implementation
+AwtToolkit::PreloadThread::PreloadThread()
+ : status(None), wrongThread(false), threadId(0),
+ pActionChain(NULL), pLastProcessedAction(NULL),
+ execFunc(NULL), execParam(NULL)
+{
+ hFinished = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ hAwake = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+AwtToolkit::PreloadThread::~PreloadThread()
+{
+ //Terminate(false);
+ ::CloseHandle(hFinished);
+ ::CloseHandle(hAwake);
+}
+
+bool AwtToolkit::PreloadThread::AddAction(AwtToolkit::PreloadAction *pAction)
+{
+ CriticalSection::Lock lock(threadLock);
+
+ if (status > Preloading) {
+ // too late - the thread already terminated or run as toolkit thread
+ return false;
+ }
+
+ if (pActionChain == NULL) {
+ // 1st action
+ pActionChain = pAction;
+ } else {
+ // add the action to the chain
+ PreloadAction *pChain = pActionChain;
+ while (true) {
+ PreloadAction *pNext = pChain->GetNext();
+ if (pNext == NULL) {
+ break;
+ }
+ pChain = pNext;
+ }
+ pChain->SetNext(pAction);
+ }
+
+ if (status > None) {
+ // the thread is already running (status == Preloading)
+ AwakeThread();
+ return true;
+ }
+
+ // need to start thread
+ ::ResetEvent(hAwake);
+ ::ResetEvent(hFinished);
+
+ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0x100000, StaticThreadProc,
+ this, 0, &threadId);
+
+ if (hThread == 0) {
+ threadId = 0;
+ return false;
+ }
+
+ status = Preloading;
+
+ ::CloseHandle(hThread);
+
+ return true;
+}
+
+bool AwtToolkit::PreloadThread::Terminate(bool wrongThread)
+{
+ CriticalSection::Lock lock(threadLock);
+
+ if (status != Preloading) {
+ return false;
+ }
+
+ execFunc = NULL;
+ execParam = NULL;
+ this->wrongThread = wrongThread;
+ status = Cleaning;
+ AwakeThread();
+
+ return true;
+}
+
+bool AwtToolkit::PreloadThread::InvokeAndTerminate(void(_cdecl *fn)(void *), void *param)
+{
+ CriticalSection::Lock lock(threadLock);
+
+ if (status != Preloading) {
+ return false;
+ }
+
+ execFunc = fn;
+ execParam = param;
+ status = fn == NULL ? Cleaning : RunningToolkit;
+ AwakeThread();
+
+ return true;
+}
+
+/*static*/
+unsigned WINAPI AwtToolkit::PreloadThread::StaticThreadProc(void *param)
+{
+ AwtToolkit::PreloadThread *pThis = (AwtToolkit::PreloadThread *)param;
+ return pThis->ThreadProc();
+}
+
+unsigned AwtToolkit::PreloadThread::ThreadProc()
+{
+ void(_cdecl *_execFunc)(void *) = NULL;
+ void *_execParam = NULL;
+ bool _wrongThread = false;
+
+ // initialization
+ while (true) {
+ PreloadAction *pAction;
+ {
+ CriticalSection::Lock lock(threadLock);
+ if (status != Preloading) {
+ // get invoke parameters
+ _execFunc = execFunc;
+ _execParam = execParam;
+ _wrongThread = wrongThread;
+ break;
+ }
+ pAction = GetNextAction();
+ }
+ if (pAction != NULL) {
+ pAction->Init();
+ } else {
+ ::WaitForSingleObject(hAwake, INFINITE);
+ }
+ }
+
+ // call a function from InvokeAndTerminate
+ if (_execFunc != NULL) {
+ _execFunc(_execParam);
+ } else {
+ // time to terminate..
+ }
+
+ // cleanup
+ {
+ CriticalSection::Lock lock(threadLock);
+ pLastProcessedAction = NULL; // goto 1st action in the chain
+ status = Cleaning;
+ }
+ for (PreloadAction *pAction = GetNextAction(); pAction != NULL;
+ pAction = GetNextAction()) {
+ pAction->Clean(_wrongThread);
+ }
+
+ // don't clear threadId! it is used by PreloadAction::EnsureInited
+
+ {
+ CriticalSection::Lock lock(threadLock);
+ status = Finished;
+ }
+ ::SetEvent(hFinished);
+ return 0;
+}
+
+AwtToolkit::PreloadAction* AwtToolkit::PreloadThread::GetNextAction()
+{
+ CriticalSection::Lock lock(threadLock);
+ PreloadAction *pAction = (pLastProcessedAction == NULL)
+ ? pActionChain
+ : pLastProcessedAction->GetNext();
+ if (pAction != NULL) {
+ pLastProcessedAction = pAction;
+ }
+
+ return pAction;
+}
+
+
+extern "C" {
+
+/* Terminates preload thread (if it's still alive
+ * - it may occur if the application doesn't use AWT).
+ * The function is called from launcher after completion main java thread.
+ */
+__declspec(dllexport) void preloadStop()
+{
+ AwtToolkit::GetInstance().GetPreloadThread().Terminate(false);
+}
+
+}
+
+
/************************************************************************
* Toolkit native methods
*/
--- a/jdk/src/windows/native/sun/windows/awt_Toolkit.h Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.h Sat Nov 13 18:56:50 2010 -0800
@@ -465,6 +465,151 @@
void InstallMouseLowLevelHook();
void UninstallMouseLowLevelHook();
+
+
+/* AWT preloading (early Toolkit thread start)
+ */
+public:
+ /* Toolkit preload action class.
+ * Preload actions should be registered with
+ * AwtToolkit::getInstance().GetPreloadThread().AddAction().
+ * AwtToolkit thread calls InitImpl method at the beghining
+ * and CleanImpl(false) before exiting for all registered actions.
+ * If an application provides own Toolkit thread
+ * (sun.awt.windows.WToolkit.embeddedInit), the thread calls Clean(true)
+ * for each action.
+ */
+ class PreloadThread; // forward declaration
+ class PreloadAction {
+ friend class PreloadThread;
+ public:
+ PreloadAction() : initThreadId(0), pNext(NULL) {}
+ virtual ~PreloadAction() {}
+
+ protected:
+ // called by PreloadThread or as result
+ // of EnsureInited() call (on Toolkit thread!).
+ virtual void InitImpl() = 0;
+
+ // called by PreloadThread (before exiting).
+ // reInit == false: normal shutdown;
+ // reInit == true: PreloadThread is shutting down due external
+ // Toolkit thread was provided.
+ virtual void CleanImpl(bool reInit) = 0;
+
+ public:
+ // Initialized the action on the Toolkit thread if not yet initialized.
+ bool EnsureInited();
+
+ // returns thread ID which the action was inited on (0 if not inited)
+ DWORD GetInitThreadID();
+
+ // Allows to deinitialize action earlier.
+ // The method must be called on the Toolkit thread only.
+ // returns true on success,
+ // false if the action was inited on other thread.
+ bool Clean();
+
+ private:
+ unsigned initThreadId;
+ // lock for Init/Clean
+ CriticalSection initLock;
+
+ // Chain support (for PreloadThread)
+ PreloadAction *pNext; // for action chain used by PreloadThread
+ void SetNext(PreloadAction *pNext) { this->pNext = pNext; }
+ PreloadAction *GetNext() { return pNext; }
+
+ // wrapper for AwtToolkit::InvokeFunction
+ static void InitWrapper(void *param);
+
+ void Init();
+ void Clean(bool reInit);
+
+ };
+
+ /** Toolkit preload thread class.
+ */
+ class PreloadThread {
+ public:
+ PreloadThread();
+ ~PreloadThread();
+
+ // adds action & start the thread if not yet started
+ bool AddAction(PreloadAction *pAction);
+
+ // sets termination flag; returns true if the thread is running.
+ // wrongThread specifies cause of the termination:
+ // false means termination on the application shutdown;
+ // wrongThread is used as reInit parameter for action cleanup.
+ bool Terminate(bool wrongThread);
+ bool InvokeAndTerminate(void(_cdecl *fn)(void *), void *param);
+
+ // waits for the the thread completion;
+ // use the method after Terminate() only if Terminate() returned true
+ INLINE void Wait4Finish() {
+ ::WaitForSingleObject(hFinished, INFINITE);
+ }
+
+ INLINE unsigned GetThreadId() {
+ CriticalSection::Lock lock(threadLock);
+ return threadId;
+ }
+ INLINE bool IsWrongThread() {
+ CriticalSection::Lock lock(threadLock);
+ return wrongThread;
+ }
+
+ private:
+ // data access lock
+ CriticalSection threadLock;
+
+ // the thread status
+ enum Status {
+ None = -1, // initial
+ Preloading = 0, // preloading in progress
+ RunningToolkit, // Running as Toolkit thread
+ Cleaning, // exited from Toolkit thread proc, cleaning
+ Finished //
+ } status;
+
+ // "wrong thread" flag
+ bool wrongThread;
+
+ // thread proc (calls (this)param->ThreadProc())
+ static unsigned WINAPI StaticThreadProc(void *param);
+ unsigned ThreadProc();
+
+ INLINE void AwakeThread() {
+ ::SetEvent(hAwake);
+ }
+
+ // if threadId != 0 -> we are running
+ unsigned threadId;
+ // ThreadProc sets the event on exit
+ HANDLE hFinished;
+ // ThreadProc waits on the event for NewAction/Terminate/InvokeAndTerminate
+ HANDLE hAwake;
+
+ // function/param to invoke (InvokeAndTerminate)
+ // if execFunc == NULL => just terminate
+ void(_cdecl *execFunc)(void *);
+ void *execParam;
+
+ // action chain
+ PreloadAction *pActionChain;
+ PreloadAction *pLastProcessedAction;
+
+ // returns next action in the list (NULL if no more actions)
+ PreloadAction* GetNextAction();
+
+ };
+
+ INLINE PreloadThread& GetPreloadThread() { return preloadThread; }
+
+private:
+ PreloadThread preloadThread;
+
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_BasicStroke.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests BasicStroke encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.BasicStroke;
+
+public final class java_awt_BasicStroke extends AbstractTest<BasicStroke> {
+ public static void main(String[] args) {
+ new java_awt_BasicStroke().test(true);
+ }
+
+ protected BasicStroke getObject() {
+ return new BasicStroke();
+ }
+
+ protected BasicStroke getAnotherObject() {
+ float[] f = {1.0f, 2.0f, 3.0f, 4.0f};
+ return new BasicStroke(f[1], BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, f[2], f, f[3]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_GradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests GradientPaint encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+
+public final class java_awt_GradientPaint extends AbstractTest<GradientPaint> {
+ public static void main(String[] args) {
+ new java_awt_GradientPaint().test(true);
+ }
+
+ protected GradientPaint getObject() {
+ return new GradientPaint(0.1f, 0.2f, Color.BLACK, 0.3f, 0.4f, Color.WHITE, true);
+ }
+
+ protected GradientPaint getAnotherObject() {
+ return null; /* TODO: could not update property
+ return new GradientPaint(0.4f, 0.3f, Color.WHITE, 0.2f, 0.1f, Color.BLACK, false);*/
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_LinearGradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests LinearGradientPaint encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.Color;
+import java.awt.LinearGradientPaint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+import static java.awt.MultipleGradientPaint.ColorSpaceType.LINEAR_RGB;
+import static java.awt.MultipleGradientPaint.CycleMethod.REFLECT;
+
+public final class java_awt_LinearGradientPaint extends AbstractTest<LinearGradientPaint> {
+ public static void main(String[] args) {
+ new java_awt_LinearGradientPaint().test(true);
+ }
+
+ protected LinearGradientPaint getObject() {
+ float[] f = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f };
+ Color[] c = { Color.BLUE, Color.GREEN, Color.RED, Color.BLUE, Color.GREEN, Color.RED };
+ return new LinearGradientPaint(f[0], f[1], f[2], f[3], f, c);
+ }
+
+ protected LinearGradientPaint getAnotherObject() {
+ return null; /* TODO: could not update property
+ float[] f = { 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f };
+ Color[] c = { Color.RED, Color.GREEN, Color.BLUE, Color.RED, Color.GREEN, Color.BLUE };
+ return new LinearGradientPaint(
+ new Point2D.Float(f[0], f[1]),
+ new Point2D.Float(f[2], f[3]),
+ f, c, REFLECT, LINEAR_RGB,
+ new AffineTransform(f));*/
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_RadialGradientPaint.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests RadialGradientPaint encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.Color;
+import java.awt.RadialGradientPaint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+import static java.awt.MultipleGradientPaint.ColorSpaceType.LINEAR_RGB;
+import static java.awt.MultipleGradientPaint.CycleMethod.REFLECT;
+
+public final class java_awt_RadialGradientPaint extends AbstractTest<RadialGradientPaint> {
+ public static void main(String[] args) {
+ new java_awt_RadialGradientPaint().test(true);
+ }
+
+ protected RadialGradientPaint getObject() {
+ float[] f = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f };
+ Color[] c = { Color.BLUE, Color.GREEN, Color.RED, Color.BLUE, Color.GREEN, Color.RED };
+ return new RadialGradientPaint(f[0], f[1], f[2], f, c);
+ }
+
+ protected RadialGradientPaint getAnotherObject() {
+ return null; /* TODO: could not update property
+ float[] f = { 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f };
+ Color[] c = { Color.RED, Color.GREEN, Color.BLUE, Color.RED, Color.GREEN, Color.BLUE };
+ return new RadialGradientPaint(
+ new Point2D.Float(f[0], f[1]), 100.0f,
+ new Point2D.Float(f[2], f[3]),
+ f, c, REFLECT, LINEAR_RGB,
+ new AffineTransform(f));*/
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_geom_AffineTransform.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests AffineTransform encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.geom.AffineTransform;
+
+public final class java_awt_geom_AffineTransform extends AbstractTest<AffineTransform> {
+ public static void main(String[] args) {
+ new java_awt_geom_AffineTransform().test(true);
+ }
+
+ protected AffineTransform getObject() {
+ return new AffineTransform(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f);
+ }
+
+ protected AffineTransform getAnotherObject() {
+ return new AffineTransform(0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/javax_swing_border_StrokeBorder.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4358979
+ * @summary Tests StrokeBorder encoding
+ * @author Sergey Malenkov
+ */
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import javax.swing.border.StrokeBorder;
+
+public final class javax_swing_border_StrokeBorder extends AbstractTest<StrokeBorder> {
+ public static void main(String[] args) {
+ new javax_swing_border_StrokeBorder().test(true);
+ }
+
+ protected StrokeBorder getObject() {
+ return new StrokeBorder(new BasicStroke(0), Color.WHITE);
+ }
+
+ protected StrokeBorder getAnotherObject() {
+ return null; // TODO: could not update property
+ //return new StrokeBorder(new BasicStroke(1));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/dyn/ClassValueTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @summary tests for class-specific values
+ * @compile ClassValueTest.java
+ * @run junit/othervm test.java.dyn.ClassValueTest
+ */
+
+/*
+ Manually:
+ $ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/dyn/ClassValueTest.java
+ $ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.dyn.ClassValueTest
+ Output: .testAdd => 1000 : Integer
+ */
+
+package test.java.dyn;
+
+import java.util.*;
+
+import java.dyn.*;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+/**
+ * @author jrose
+ */
+public class ClassValueTest {
+ static String nameForCV1(Class<?> type) {
+ return "CV1:" + type.getName();
+ }
+ static int countForCV1;
+ static final ClassValue<String> CV1 = new ClassValue<String>() {
+ protected String computeValue(Class<?> type) {
+ countForCV1++;
+ return nameForCV1(type);
+ }
+ };
+
+ static final Class[] CLASSES = {
+ String.class,
+ Integer.class,
+ int.class,
+ boolean[].class,
+ char[][].class,
+ ClassValueTest.class
+ };
+
+ @Test
+ public void testGet() {
+ countForCV1 = 0;
+ for (Class c : CLASSES) {
+ assertEquals(nameForCV1(c), CV1.get(c));
+ }
+ assertEquals(CLASSES.length, countForCV1);
+ for (Class c : CLASSES) {
+ assertEquals(nameForCV1(c), CV1.get(c));
+ }
+ assertEquals(CLASSES.length, countForCV1);
+ }
+
+ @Test
+ public void testRemove() {
+ for (Class c : CLASSES) {
+ CV1.get(c);
+ }
+ countForCV1 = 0;
+ int REMCOUNT = 3;
+ for (int i = 0; i < REMCOUNT; i++) {
+ CV1.remove(CLASSES[i]);
+ }
+ assertEquals(0, countForCV1); // no change
+ for (Class c : CLASSES) {
+ assertEquals(nameForCV1(c), CV1.get(c));
+ }
+ assertEquals(REMCOUNT, countForCV1);
+ }
+
+ static String nameForCVN(Class<?> type, int n) {
+ return "CV[" + n + "]" + type.getName();
+ }
+ static int countForCVN;
+ static class CVN extends ClassValue<String> {
+ final int n;
+ CVN(int n) { this.n = n; }
+ protected String computeValue(Class<?> type) {
+ countForCVN++;
+ return nameForCVN(type, n);
+ }
+ };
+
+ @Test
+ public void testGetMany() {
+ int CVN_COUNT1 = 100, CVN_COUNT2 = 100;
+ CVN cvns[] = new CVN[CVN_COUNT1 * CVN_COUNT2];
+ for (int n = 0; n < cvns.length; n++) {
+ cvns[n] = new CVN(n);
+ }
+ countForCVN = 0;
+ for (int pass = 0; pass <= 2; pass++) {
+ for (int i1 = 0; i1 < CVN_COUNT1; i1++) {
+ eachClass:
+ for (Class c : CLASSES) {
+ for (int i2 = 0; i2 < CVN_COUNT2; i2++) {
+ int n = i1*CVN_COUNT2 + i2;
+ assertEquals(0, countForCVN);
+ assertEquals(nameForCVN(c, n), cvns[n].get(c));
+ cvns[n].get(c); //get it again
+ //System.out.println("getting "+n+":"+cvns[n].get(c));
+ boolean doremove = (((i1 + i2) & 3) == 0);
+ switch (pass) {
+ case 0:
+ assertEquals(1, countForCVN);
+ break;
+ case 1:
+ // remove on middle pass
+ assertEquals(0, countForCVN);
+ if (doremove) {
+ //System.out.println("removing "+n+":"+cvns[n].get(c));
+ cvns[n].remove(c);
+ assertEquals(0, countForCVN);
+ }
+ break;
+ case 2:
+ assertEquals(doremove ? 1 : 0, countForCVN);
+ break;
+ }
+ countForCVN = 0;
+ if (i1 > i2 && i1 < i2+5) continue eachClass; // leave diagonal gap
+ }
+ }
+ }
+ }
+ assertEquals(countForCVN, 0);
+ for (int n = 0; n < cvns.length; n++) {
+ for (Class c : CLASSES) {
+ assertEquals(nameForCVN(c, n), cvns[n].get(c));
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/dyn/JavaDocExamples.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @summary example code used in javadoc for java.dyn API
+ * @compile -XDallowTransitionalJSR292=no JavaDocExamples.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
+ */
+
+/*
+---- To run outside jtreg:
+$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
+ $DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples.java
+$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
+ -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
+ -Dtest.java.dyn.JavaDocExamples.verbosity=1 \
+ test.java.dyn.JavaDocExamples
+----
+*/
+
+package test.java.dyn;
+
+import java.dyn.*;
+import static java.dyn.MethodHandles.*;
+import static java.dyn.MethodType.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+
+/**
+ * @author jrose
+ */
+public class JavaDocExamples {
+ /** Wrapper for running the JUnit tests in this module.
+ * Put JUnit on the classpath!
+ */
+ public static void main(String... ignore) {
+ org.junit.runner.JUnitCore.runClasses(JavaDocExamples.class);
+ }
+ // How much output?
+ static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamples.verbosity", 0);
+
+{}
+static final private Lookup LOOKUP = lookup();
+// static final private MethodHandle CONCAT_1 = LOOKUP.findVirtual(String.class,
+// "concat", methodType(String.class, String.class));
+// static final private MethodHandle HASHCODE_1 = LOOKUP.findVirtual(Object.class,
+// "hashCode", methodType(int.class));
+
+// form required if NoAccessException is intercepted:
+static final private MethodHandle CONCAT_2, HASHCODE_2;
+static {
+ try {
+ CONCAT_2 = LOOKUP.findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+ HASHCODE_2 = LOOKUP.findVirtual(Object.class,
+ "hashCode", methodType(int.class));
+ } catch (NoAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+}
+{}
+
+ @Test public void testFindVirtual() throws Throwable {
+{}
+MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class,
+ "hashCode", methodType(int.class));
+//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));
+assertEquals("xy", (String) CONCAT_2.<String>invokeExact("x", "y"));
+assertEquals("xy", (String) CONCAT_3.<String>invokeExact("x", "y"));
+//assertEquals("xy".hashCode(), (int) HASHCODE_1.<int>invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) HASHCODE_2.<int>invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) HASHCODE_3.<int>invokeExact((Object)"xy"));
+{}
+ }
+ @Test public void testDropArguments() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+cat = cat.asType(methodType(Object.class, String.class, String.class)); /*(String)*/
+assertEquals("xy", /*(String)*/ cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", /*(String)*/ d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", /*(String)*/ d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", /*(String)*/ d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
+ }}
+ }
+
+ static void assertEquals(Object exp, Object act) {
+ if (verbosity > 0)
+ System.out.println("result: "+act);
+ Assert.assertEquals(exp, act);
+ }
+}
--- a/jdk/test/java/dyn/MethodHandlesTest.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/dyn/MethodHandlesTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -265,6 +265,12 @@
// wrap = Wrapper.forWrapperType(dst);
// if (wrap != Wrapper.OBJECT)
// return wrap.wrap(nextArg++);
+ if (param.isInterface()) {
+ for (Class<?> c : param.getClasses()) {
+ if (param.isAssignableFrom(c) && !c.isInterface())
+ { param = c; break; }
+ }
+ }
if (param.isInterface() || param.isAssignableFrom(String.class))
return "#"+nextArg();
else
@@ -380,7 +386,7 @@
}
public static interface IntExample {
public void v0();
- static class Impl implements IntExample {
+ public static class Impl implements IntExample {
public void v0() { called("Int/v0", this); }
final String name;
public Impl() { name = "Impl#"+nextArg(); }
@@ -449,7 +455,7 @@
countTest(positive);
MethodType type = MethodType.methodType(ret, params);
MethodHandle target = null;
- RuntimeException noAccess = null;
+ Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findStatic(defc, name, type);
@@ -513,7 +519,7 @@
String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
MethodType type = MethodType.methodType(ret, params);
MethodHandle target = null;
- RuntimeException noAccess = null;
+ Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findVirtual(defc, methodName, type);
@@ -567,7 +573,7 @@
countTest(positive);
MethodType type = MethodType.methodType(ret, params);
MethodHandle target = null;
- RuntimeException noAccess = null;
+ Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.findSpecial(defc, name, type, specialCaller);
@@ -623,7 +629,7 @@
MethodType type = MethodType.methodType(ret, params);
Object receiver = randomArg(defc);
MethodHandle target = null;
- RuntimeException noAccess = null;
+ Exception noAccess = null;
try {
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
target = lookup.bind(receiver, methodName, type);
@@ -688,7 +694,7 @@
MethodType type = MethodType.methodType(ret, params);
Method rmethod = null;
MethodHandle target = null;
- RuntimeException noAccess = null;
+ Exception noAccess = null;
try {
rmethod = defc.getDeclaredMethod(name, params);
} catch (NoSuchMethodException ex) {
@@ -1088,7 +1094,11 @@
if (rtype != Object.class)
pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
String name = pfx+"id";
- return PRIVATE.findStatic(Callee.class, name, type);
+ try {
+ return PRIVATE.findStatic(Callee.class, name, type);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
}
}
@@ -1327,7 +1337,8 @@
MethodHandle result = MethodHandles.spreadArguments(target2, newType);
Object[] returnValue;
if (pos == 0) {
- returnValue = (Object[]) result.invokeExact(args);
+ Object rawRetVal = result.invokeExact(args);
+ returnValue = (Object[]) rawRetVal;
} else {
Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
args1[pos] = Arrays.copyOfRange(args, pos, args.length);
@@ -1817,8 +1828,13 @@
testCastFailure("unbox/return", 11000);
}
- static class Surprise extends JavaMethodHandle {
- Surprise() { super("value"); }
+ static class Surprise implements MethodHandleProvider {
+ public MethodHandle asMethodHandle() {
+ return VALUE.bindTo(this);
+ }
+ public MethodHandle asMethodHandle(MethodType type) {
+ return asMethodHandle().asType(type);
+ }
Object value(Object x) {
trace("value", x);
if (boo != null) return boo;
@@ -1833,22 +1849,32 @@
static Object refIdentity(Object x) { trace("ref.x", x); return x; }
static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }
static int intIdentity(int x) { trace("int.x", x); return x; }
- static MethodHandle REF_IDENTITY = PRIVATE.findStatic(
- Surprise.class, "refIdentity",
- MethodType.methodType(Object.class, Object.class));
- static MethodHandle BOX_IDENTITY = PRIVATE.findStatic(
- Surprise.class, "boxIdentity",
- MethodType.methodType(Integer.class, Integer.class));
- static MethodHandle INT_IDENTITY = PRIVATE.findStatic(
- Surprise.class, "intIdentity",
- MethodType.methodType(int.class, int.class));
+ static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY;
+ static {
+ try {
+ VALUE = PRIVATE.findVirtual(
+ Surprise.class, "value",
+ MethodType.methodType(Object.class, Object.class));
+ REF_IDENTITY = PRIVATE.findStatic(
+ Surprise.class, "refIdentity",
+ MethodType.methodType(Object.class, Object.class));
+ BOX_IDENTITY = PRIVATE.findStatic(
+ Surprise.class, "boxIdentity",
+ MethodType.methodType(Integer.class, Integer.class));
+ INT_IDENTITY = PRIVATE.findStatic(
+ Surprise.class, "intIdentity",
+ MethodType.methodType(int.class, int.class));
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
void testCastFailure(String mode, int okCount) throws Throwable {
countTest(false);
if (verbosity > 2) System.out.println("mode="+mode);
Surprise boo = new Surprise();
- MethodHandle identity = Surprise.REF_IDENTITY, surprise = boo;
+ MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0;
if (mode.endsWith("/return")) {
if (mode.equals("unbox/return")) {
// fail on return to ((Integer)surprise).intValue
@@ -1874,7 +1900,7 @@
identity = MethodHandles.filterArguments(callee, identity);
}
}
- assertNotSame(mode, surprise, boo);
+ assertNotSame(mode, surprise, surprise0);
identity = MethodHandles.convertArguments(identity, MethodType.genericMethodType(1));
surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1));
Object x = 42;
@@ -1936,6 +1962,107 @@
mh.invokeVarargs(args);
assertCalled(name, args);
}
+
+ static void runForRunnable() {
+ called("runForRunnable");
+ }
+ private interface Fooable {
+ Object foo(Fooable x, Object y);
+ // this is for randomArg:
+ public class Impl implements Fooable {
+ public Object foo(Fooable x, Object y) {
+ throw new RuntimeException("do not call");
+ }
+ final String name;
+ public Impl() { name = "Fooable#"+nextArg(); }
+ @Override public String toString() { return name; }
+ }
+ }
+ static Object fooForFooable(Fooable x, Object y) {
+ return called("fooForFooable", x, y);
+ }
+ private static class MyCheckedException extends Exception {
+ }
+ private interface WillThrow {
+ void willThrow() throws MyCheckedException;
+ }
+
+ @Test
+ public void testAsInstance() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ Lookup lookup = MethodHandles.lookup();
+ {
+ MethodType mt = MethodType.methodType(void.class);
+ MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
+ Runnable proxy = MethodHandles.asInstance(mh, Runnable.class);
+ proxy.run();
+ assertCalled("runForRunnable");
+ }
+ {
+ MethodType mt = MethodType.methodType(Object.class, Fooable.class, Object.class);
+ MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", mt);
+ Fooable proxy = MethodHandles.asInstance(mh, Fooable.class);
+ Object[] args = randomArgs(mt.parameterArray());
+ Object result = proxy.foo((Fooable) args[0], args[1]);
+ assertCalled("fooForFooable", args);
+ assertEquals(result, logEntry("fooForFooable", args));
+ }
+ for (Throwable ex : new Throwable[] { new NullPointerException("ok"),
+ new InternalError("ok"),
+ new Throwable("fail"),
+ new Exception("fail"),
+ new MyCheckedException()
+ }) {
+ MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
+ mh = MethodHandles.insertArguments(mh, 0, ex);
+ WillThrow proxy = MethodHandles.asInstance(mh, WillThrow.class);
+ try {
+ proxy.willThrow();
+ System.out.println("Failed to throw: "+ex);
+ assertTrue(false);
+ } catch (Throwable ex1) {
+ if (verbosity > 2) {
+ System.out.println("throw "+ex);
+ System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));
+ }
+ if (ex instanceof RuntimeException ||
+ ex instanceof Error) {
+ assertSame("must pass unchecked exception out without wrapping", ex, ex1);
+ } else if (ex instanceof MyCheckedException) {
+ assertSame("must pass declared exception out without wrapping", ex, ex1);
+ } else {
+ assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);
+ UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;
+ assertSame(ex, utex.getCause());
+ }
+ }
+ }
+ // Test error checking:
+ MethodHandle genericMH = ValueConversions.varargsArray(0);
+ genericMH = MethodHandles.convertArguments(genericMH, genericMH.type().generic());
+ for (Class<?> sam : new Class[] { Runnable.class,
+ Fooable.class,
+ Iterable.class }) {
+ try {
+ // Must throw, because none of these guys has generic type.
+ MethodHandles.asInstance(genericMH, sam);
+ System.out.println("Failed to throw");
+ assertTrue(false);
+ } catch (IllegalArgumentException ex) {
+ }
+ }
+ for (Class<?> nonSAM : new Class[] { Object.class,
+ String.class,
+ CharSequence.class,
+ Example.class }) {
+ try {
+ MethodHandles.asInstance(ValueConversions.varargsArray(0), nonSAM);
+ System.out.println("Failed to throw");
+ assertTrue(false);
+ } catch (IllegalArgumentException ex) {
+ }
+ }
+ }
}
// Local abbreviated copy of sun.dyn.util.ValueConversions
class ValueConversions {
--- a/jdk/test/java/util/Locale/LocaleCategory.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/LocaleCategory.java Sat Nov 13 18:56:50 2010 -0800
@@ -29,15 +29,28 @@
private static String enc = null;
public static void main(String[] args) {
- base = new Locale(System.getProperty("user.language", ""),
- System.getProperty("user.country", ""),
- System.getProperty("user.variant", ""));
- disp = new Locale(System.getProperty("user.language.display", ""),
- System.getProperty("user.country.display", ""),
- System.getProperty("user.variant.display", ""));
- fmt = new Locale(System.getProperty("user.language.format", ""),
- System.getProperty("user.country.format", ""),
- System.getProperty("user.variant.format", ""));
+ Locale.Builder builder = new Locale.Builder();
+
+ base = builder.setLanguage(System.getProperty("user.language", ""))
+ .setScript(System.getProperty("user.script", ""))
+ .setRegion(System.getProperty("user.country", ""))
+ .setVariant(System.getProperty("user.variant", "")).build();
+ disp = builder.setLanguage(System.getProperty("user.language.display",
+ Locale.getDefault().getLanguage()))
+ .setScript(System.getProperty("user.script.display",
+ Locale.getDefault().getScript()))
+ .setRegion(System.getProperty("user.country.display",
+ Locale.getDefault().getCountry()))
+ .setVariant(System.getProperty("user.variant.display",
+ Locale.getDefault().getVariant())).build();
+ fmt = builder.setLanguage(System.getProperty("user.language.format",
+ Locale.getDefault().getLanguage()))
+ .setScript(System.getProperty("user.script.format",
+ Locale.getDefault().getScript()))
+ .setRegion(System.getProperty("user.country.format",
+ Locale.getDefault().getCountry()))
+ .setVariant(System.getProperty("user.variant.format",
+ Locale.getDefault().getVariant())).build();
checkDefault();
testGetSetDefault();
}
--- a/jdk/test/java/util/Locale/LocaleCategory.sh Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/LocaleCategory.sh Sat Nov 13 18:56:50 2010 -0800
@@ -1,7 +1,7 @@
#!/bin/sh
#
# @test
-# @bug 4700857
+# @bug 4700857 6997928
# @summary tests for Locale.getDefault(Locale.Category) and
# Locale.setDefault(Locale.Category, Locale)
# @build LocaleCategory
--- a/jdk/test/java/util/Locale/data/deflocale.rhel5 Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.rhel5 Sat Nov 13 18:56:50 2010 -0800
@@ -465,15 +465,15 @@
default charset: UTF-8
OS Locale: be_BY.utf8@latin
-default locale: ID: be_BY, Name: Belarusian (Belarus)
-display locale: ID: be_BY, Name: Belarusian (Belarus)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
+default locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+display locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+format locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
default charset: UTF-8
OS Locale: be_BY@latin
-default locale: ID: be_BY, Name: Belarusian (Belarus)
-display locale: ID: be_BY, Name: Belarusian (Belarus)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
+default locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+display locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+format locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
default charset: UTF-8
OS Locale: bg_BG
@@ -518,18 +518,18 @@
format locale: ID: bn_IN, Name: Bengali (India)
default charset: UTF-8
+OS Locale: bokmal
+default locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+display locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+format locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+default charset: ISO-8859-1
+
OS Locale: bokmål
default locale: ID: en, Name: English
display locale: ID: en, Name: English
format locale: ID: en, Name: English
default charset: ISO-8859-1
-OS Locale: bokmal
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
-default charset: ISO-8859-1
-
OS Locale: br_FR
default locale: ID: br_FR, Name: Breton (France)
display locale: ID: br_FR, Name: Breton (France)
@@ -579,15 +579,15 @@
default charset: UTF-8
OS Locale: byn_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: byn_ER, Name: Blin (Eritrea)
+display locale: ID: byn_ER, Name: Blin (Eritrea)
+format locale: ID: byn_ER, Name: Blin (Eritrea)
default charset: UTF-8
OS Locale: byn_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: byn_ER, Name: Blin (Eritrea)
+display locale: ID: byn_ER, Name: Blin (Eritrea)
+format locale: ID: byn_ER, Name: Blin (Eritrea)
default charset: UTF-8
OS Locale: ca_AD
@@ -705,15 +705,15 @@
default charset: UTF-8
OS Locale: csb_PL
-default locale: ID: en_PL, Name: English (Poland)
-display locale: ID: en_PL, Name: English (Poland)
-format locale: ID: en_PL, Name: English (Poland)
+default locale: ID: csb_PL, Name: Kashubian (Poland)
+display locale: ID: csb_PL, Name: Kashubian (Poland)
+format locale: ID: csb_PL, Name: Kashubian (Poland)
default charset: UTF-8
OS Locale: csb_PL.utf8
-default locale: ID: en_PL, Name: English (Poland)
-display locale: ID: en_PL, Name: English (Poland)
-format locale: ID: en_PL, Name: English (Poland)
+default locale: ID: csb_PL, Name: Kashubian (Poland)
+display locale: ID: csb_PL, Name: Kashubian (Poland)
+format locale: ID: csb_PL, Name: Kashubian (Poland)
default charset: UTF-8
OS Locale: cy_GB
@@ -939,9 +939,9 @@
default charset: UTF-8
OS Locale: eesti
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: et_EE, Name: Estonian (Estonia)
+display locale: ID: et_EE, Name: Estonian (Estonia)
+format locale: ID: et_EE, Name: Estonian (Estonia)
default charset: ISO-8859-1
OS Locale: el_CY
@@ -1623,9 +1623,9 @@
default charset: UTF-8
OS Locale: estonian
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: et_EE, Name: Estonian (Estonia)
+display locale: ID: et_EE, Name: Estonian (Estonia)
+format locale: ID: et_EE, Name: Estonian (Estonia)
default charset: ISO-8859-1
OS Locale: et_EE
@@ -1929,15 +1929,15 @@
default charset: ISO-8859-15
OS Locale: galego
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: gl_ES, Name: Gallegan (Spain)
+display locale: ID: gl_ES, Name: Gallegan (Spain)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
default charset: ISO-8859-1
OS Locale: galician
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: gl_ES, Name: Gallegan (Spain)
+display locale: ID: gl_ES, Name: Gallegan (Spain)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
default charset: ISO-8859-1
OS Locale: gd_GB
@@ -1965,51 +1965,51 @@
default charset: ISO-8859-1
OS Locale: gez_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER.utf8@abegede
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER@abegede
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ET
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET.utf8
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET.utf8@abegede
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET@abegede
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gl_ES
@@ -2139,21 +2139,21 @@
default charset: ISO-8859-2
OS Locale: hsb_DE
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: ISO-8859-2
OS Locale: hsb_DE.iso88592
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: ISO-8859-2
OS Locale: hsb_DE.utf8
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: UTF-8
OS Locale: hu_HU
@@ -2445,15 +2445,15 @@
default charset: UTF-8
OS Locale: korean
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: ko_KR, Name: Korean (South Korea)
+display locale: ID: ko_KR, Name: Korean (South Korea)
+format locale: ID: ko_KR, Name: Korean (South Korea)
default charset: EUC-KR
OS Locale: korean.euc
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: ko_KR, Name: Korean (South Korea)
+display locale: ID: ko_KR, Name: Korean (South Korea)
+format locale: ID: ko_KR, Name: Korean (South Korea)
default charset: EUC-KR
OS Locale: ku_TR
@@ -2523,9 +2523,9 @@
default charset: UTF-8
OS Locale: lithuanian
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+display locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
default charset: ISO-8859-13
OS Locale: lo_LA
@@ -2577,15 +2577,15 @@
default charset: UTF-8
OS Locale: mai_IN
-default locale: ID: en_IN, Name: English (India)
-display locale: ID: en_IN, Name: English (India)
-format locale: ID: en_IN, Name: English (India)
+default locale: ID: mai_IN, Name: Maithili (India)
+display locale: ID: mai_IN, Name: Maithili (India)
+format locale: ID: mai_IN, Name: Maithili (India)
default charset: UTF-8
OS Locale: mai_IN.utf8
-default locale: ID: en_IN, Name: English (India)
-display locale: ID: en_IN, Name: English (India)
-format locale: ID: en_IN, Name: English (India)
+default locale: ID: mai_IN, Name: Maithili (India)
+display locale: ID: mai_IN, Name: Maithili (India)
+format locale: ID: mai_IN, Name: Maithili (India)
default charset: UTF-8
OS Locale: mg_MG
@@ -2859,21 +2859,21 @@
default charset: UTF-8
OS Locale: nso_ZA
-default locale: ID: en_ZA, Name: English (South Africa)
-display locale: ID: en_ZA, Name: English (South Africa)
-format locale: ID: en_ZA, Name: English (South Africa)
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: nso_ZA, Name: Pedi (South Africa)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
default charset: UTF-8
OS Locale: nso_ZA.utf8
-default locale: ID: en_ZA, Name: English (South Africa)
-display locale: ID: en_ZA, Name: English (South Africa)
-format locale: ID: en_ZA, Name: English (South Africa)
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: nso_ZA, Name: Pedi (South Africa)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
default charset: UTF-8
OS Locale: nynorsk
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
+display locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
+format locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
default charset: ISO-8859-1
OS Locale: oc_FR
@@ -3147,15 +3147,15 @@
default charset: UTF-8
OS Locale: sid_ET
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+display locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+format locale: ID: sid_ET, Name: Sidamo (Ethiopia)
default charset: UTF-8
OS Locale: sid_ET.utf8
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+display locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+format locale: ID: sid_ET, Name: Sidamo (Ethiopia)
default charset: UTF-8
OS Locale: sk_SK
@@ -3321,39 +3321,39 @@
default charset: UTF-8
OS Locale: sr_ME
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_ME, Name: Serbian (Montenegro)
+display locale: ID: sr_ME, Name: Serbian (Montenegro)
+format locale: ID: sr_ME, Name: Serbian (Montenegro)
default charset: UTF-8
OS Locale: sr_ME.utf8
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_ME, Name: Serbian (Montenegro)
+display locale: ID: sr_ME, Name: Serbian (Montenegro)
+format locale: ID: sr_ME, Name: Serbian (Montenegro)
default charset: UTF-8
OS Locale: sr_RS
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS, Name: Serbian (Serbia)
+display locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS, Name: Serbian (Serbia)
default charset: UTF-8
OS Locale: sr_RS.utf8
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS, Name: Serbian (Serbia)
+display locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS, Name: Serbian (Serbia)
default charset: UTF-8
OS Locale: sr_RS.utf8@latin
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
default charset: UTF-8
OS Locale: sr_RS@latin
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
default charset: UTF-8
OS Locale: ss_ZA
@@ -3507,9 +3507,9 @@
default charset: UTF-8
OS Locale: thai
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: th_TH, Name: Thai (Thailand)
+display locale: ID: th_TH, Name: Thai (Thailand)
+format locale: ID: th_TH, Name: Thai (Thailand)
default charset: TIS-620
OS Locale: ti_ER
@@ -3537,15 +3537,15 @@
default charset: UTF-8
OS Locale: tig_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: tig_ER, Name: Tigre (Eritrea)
+display locale: ID: tig_ER, Name: Tigre (Eritrea)
+format locale: ID: tig_ER, Name: Tigre (Eritrea)
default charset: UTF-8
OS Locale: tig_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: tig_ER, Name: Tigre (Eritrea)
+display locale: ID: tig_ER, Name: Tigre (Eritrea)
+format locale: ID: tig_ER, Name: Tigre (Eritrea)
default charset: UTF-8
OS Locale: tl_PH
@@ -3681,15 +3681,15 @@
default charset: ISO-8859-1
OS Locale: uz_UZ.utf8@cyrillic
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+display locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: UTF-8
OS Locale: uz_UZ@cyrillic
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+display locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: UTF-8
OS Locale: ve_ZA
--- a/jdk/test/java/util/Locale/data/deflocale.rhel5.fmtasdefault Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.rhel5.fmtasdefault Sat Nov 13 18:56:50 2010 -0800
@@ -465,15 +465,15 @@
default charset: UTF-8
OS Locale: be_BY.utf8@latin
-default locale: ID: be_BY, Name: Belarusian (Belarus)
-display locale: ID: be_BY, Name: Belarusian (Belarus)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
+default locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+display locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+format locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
default charset: UTF-8
OS Locale: be_BY@latin
-default locale: ID: be_BY, Name: Belarusian (Belarus)
-display locale: ID: be_BY, Name: Belarusian (Belarus)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
+default locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+display locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
+format locale: ID: be_BY_#Latn, Name: Belarusian (Latin,Belarus)
default charset: UTF-8
OS Locale: bg_BG
@@ -518,18 +518,18 @@
format locale: ID: bn_IN, Name: Bengali (India)
default charset: UTF-8
+OS Locale: bokmal
+default locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+display locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+format locale: ID: nb_NO, Name: Norwegian Bokmål (Norway)
+default charset: ISO-8859-1
+
OS Locale: bokmål
default locale: ID: en, Name: English
display locale: ID: en, Name: English
format locale: ID: en, Name: English
default charset: ISO-8859-1
-OS Locale: bokmal
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
-default charset: ISO-8859-1
-
OS Locale: br_FR
default locale: ID: br_FR, Name: Breton (France)
display locale: ID: br_FR, Name: Breton (France)
@@ -579,15 +579,15 @@
default charset: UTF-8
OS Locale: byn_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: byn_ER, Name: Blin (Eritrea)
+display locale: ID: byn_ER, Name: Blin (Eritrea)
+format locale: ID: byn_ER, Name: Blin (Eritrea)
default charset: UTF-8
OS Locale: byn_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: byn_ER, Name: Blin (Eritrea)
+display locale: ID: byn_ER, Name: Blin (Eritrea)
+format locale: ID: byn_ER, Name: Blin (Eritrea)
default charset: UTF-8
OS Locale: ca_AD
@@ -705,15 +705,15 @@
default charset: UTF-8
OS Locale: csb_PL
-default locale: ID: en_PL, Name: English (Poland)
-display locale: ID: en_PL, Name: English (Poland)
-format locale: ID: en_PL, Name: English (Poland)
+default locale: ID: csb_PL, Name: Kashubian (Poland)
+display locale: ID: csb_PL, Name: Kashubian (Poland)
+format locale: ID: csb_PL, Name: Kashubian (Poland)
default charset: UTF-8
OS Locale: csb_PL.utf8
-default locale: ID: en_PL, Name: English (Poland)
-display locale: ID: en_PL, Name: English (Poland)
-format locale: ID: en_PL, Name: English (Poland)
+default locale: ID: csb_PL, Name: Kashubian (Poland)
+display locale: ID: csb_PL, Name: Kashubian (Poland)
+format locale: ID: csb_PL, Name: Kashubian (Poland)
default charset: UTF-8
OS Locale: cy_GB
@@ -939,9 +939,9 @@
default charset: UTF-8
OS Locale: eesti
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: et_EE, Name: Estonian (Estonia)
+display locale: ID: et_EE, Name: Estonian (Estonia)
+format locale: ID: et_EE, Name: Estonian (Estonia)
default charset: ISO-8859-1
OS Locale: el_CY
@@ -1623,9 +1623,9 @@
default charset: UTF-8
OS Locale: estonian
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: et_EE, Name: Estonian (Estonia)
+display locale: ID: et_EE, Name: Estonian (Estonia)
+format locale: ID: et_EE, Name: Estonian (Estonia)
default charset: ISO-8859-1
OS Locale: et_EE
@@ -1929,15 +1929,15 @@
default charset: ISO-8859-15
OS Locale: galego
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: gl_ES, Name: Gallegan (Spain)
+display locale: ID: gl_ES, Name: Gallegan (Spain)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
default charset: ISO-8859-1
OS Locale: galician
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: gl_ES, Name: Gallegan (Spain)
+display locale: ID: gl_ES, Name: Gallegan (Spain)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
default charset: ISO-8859-1
OS Locale: gd_GB
@@ -1965,51 +1965,51 @@
default charset: ISO-8859-1
OS Locale: gez_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER.utf8@abegede
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ER@abegede
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: gez_ER, Name: Geez (Eritrea)
+display locale: ID: gez_ER, Name: Geez (Eritrea)
+format locale: ID: gez_ER, Name: Geez (Eritrea)
default charset: UTF-8
OS Locale: gez_ET
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET.utf8
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET.utf8@abegede
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gez_ET@abegede
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: gez_ET, Name: Geez (Ethiopia)
+display locale: ID: gez_ET, Name: Geez (Ethiopia)
+format locale: ID: gez_ET, Name: Geez (Ethiopia)
default charset: UTF-8
OS Locale: gl_ES
@@ -2139,21 +2139,21 @@
default charset: ISO-8859-2
OS Locale: hsb_DE
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: ISO-8859-2
OS Locale: hsb_DE.iso88592
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: ISO-8859-2
OS Locale: hsb_DE.utf8
-default locale: ID: en_DE, Name: English (Germany)
-display locale: ID: en_DE, Name: English (Germany)
-format locale: ID: en_DE, Name: English (Germany)
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
default charset: UTF-8
OS Locale: hu_HU
@@ -2445,15 +2445,15 @@
default charset: UTF-8
OS Locale: korean
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: ko_KR, Name: Korean (South Korea)
+display locale: ID: ko_KR, Name: Korean (South Korea)
+format locale: ID: ko_KR, Name: Korean (South Korea)
default charset: EUC-KR
OS Locale: korean.euc
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: ko_KR, Name: Korean (South Korea)
+display locale: ID: ko_KR, Name: Korean (South Korea)
+format locale: ID: ko_KR, Name: Korean (South Korea)
default charset: EUC-KR
OS Locale: ku_TR
@@ -2523,9 +2523,9 @@
default charset: UTF-8
OS Locale: lithuanian
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+display locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
default charset: ISO-8859-13
OS Locale: lo_LA
@@ -2577,15 +2577,15 @@
default charset: UTF-8
OS Locale: mai_IN
-default locale: ID: en_IN, Name: English (India)
-display locale: ID: en_IN, Name: English (India)
-format locale: ID: en_IN, Name: English (India)
+default locale: ID: mai_IN, Name: Maithili (India)
+display locale: ID: mai_IN, Name: Maithili (India)
+format locale: ID: mai_IN, Name: Maithili (India)
default charset: UTF-8
OS Locale: mai_IN.utf8
-default locale: ID: en_IN, Name: English (India)
-display locale: ID: en_IN, Name: English (India)
-format locale: ID: en_IN, Name: English (India)
+default locale: ID: mai_IN, Name: Maithili (India)
+display locale: ID: mai_IN, Name: Maithili (India)
+format locale: ID: mai_IN, Name: Maithili (India)
default charset: UTF-8
OS Locale: mg_MG
@@ -2859,21 +2859,21 @@
default charset: UTF-8
OS Locale: nso_ZA
-default locale: ID: en_ZA, Name: English (South Africa)
-display locale: ID: en_ZA, Name: English (South Africa)
-format locale: ID: en_ZA, Name: English (South Africa)
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: nso_ZA, Name: Pedi (South Africa)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
default charset: UTF-8
OS Locale: nso_ZA.utf8
-default locale: ID: en_ZA, Name: English (South Africa)
-display locale: ID: en_ZA, Name: English (South Africa)
-format locale: ID: en_ZA, Name: English (South Africa)
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: nso_ZA, Name: Pedi (South Africa)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
default charset: UTF-8
OS Locale: nynorsk
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
+display locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
+format locale: ID: nn_NO, Name: Norwegian Nynorsk (Norway)
default charset: ISO-8859-1
OS Locale: oc_FR
@@ -3147,15 +3147,15 @@
default charset: UTF-8
OS Locale: sid_ET
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+display locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+format locale: ID: sid_ET, Name: Sidamo (Ethiopia)
default charset: UTF-8
OS Locale: sid_ET.utf8
-default locale: ID: en_ET, Name: English (Ethiopia)
-display locale: ID: en_ET, Name: English (Ethiopia)
-format locale: ID: en_ET, Name: English (Ethiopia)
+default locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+display locale: ID: sid_ET, Name: Sidamo (Ethiopia)
+format locale: ID: sid_ET, Name: Sidamo (Ethiopia)
default charset: UTF-8
OS Locale: sk_SK
@@ -3321,39 +3321,39 @@
default charset: UTF-8
OS Locale: sr_ME
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_ME, Name: Serbian (Montenegro)
+display locale: ID: sr_ME, Name: Serbian (Montenegro)
+format locale: ID: sr_ME, Name: Serbian (Montenegro)
default charset: UTF-8
OS Locale: sr_ME.utf8
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_ME, Name: Serbian (Montenegro)
+display locale: ID: sr_ME, Name: Serbian (Montenegro)
+format locale: ID: sr_ME, Name: Serbian (Montenegro)
default charset: UTF-8
OS Locale: sr_RS
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS, Name: Serbian (Serbia)
+display locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS, Name: Serbian (Serbia)
default charset: UTF-8
OS Locale: sr_RS.utf8
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS, Name: Serbian (Serbia)
+display locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS, Name: Serbian (Serbia)
default charset: UTF-8
OS Locale: sr_RS.utf8@latin
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
default charset: UTF-8
OS Locale: sr_RS@latin
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
default charset: UTF-8
OS Locale: ss_ZA
@@ -3507,9 +3507,9 @@
default charset: UTF-8
OS Locale: thai
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+default locale: ID: th_TH, Name: Thai (Thailand)
+display locale: ID: th_TH, Name: Thai (Thailand)
+format locale: ID: th_TH, Name: Thai (Thailand)
default charset: TIS-620
OS Locale: ti_ER
@@ -3537,15 +3537,15 @@
default charset: UTF-8
OS Locale: tig_ER
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: tig_ER, Name: Tigre (Eritrea)
+display locale: ID: tig_ER, Name: Tigre (Eritrea)
+format locale: ID: tig_ER, Name: Tigre (Eritrea)
default charset: UTF-8
OS Locale: tig_ER.utf8
-default locale: ID: en_ER, Name: English (Eritrea)
-display locale: ID: en_ER, Name: English (Eritrea)
-format locale: ID: en_ER, Name: English (Eritrea)
+default locale: ID: tig_ER, Name: Tigre (Eritrea)
+display locale: ID: tig_ER, Name: Tigre (Eritrea)
+format locale: ID: tig_ER, Name: Tigre (Eritrea)
default charset: UTF-8
OS Locale: tl_PH
@@ -3681,15 +3681,15 @@
default charset: ISO-8859-1
OS Locale: uz_UZ.utf8@cyrillic
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+display locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: UTF-8
OS Locale: uz_UZ@cyrillic
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+display locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: UTF-8
OS Locale: ve_ZA
--- a/jdk/test/java/util/Locale/data/deflocale.sol10 Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.sol10 Sat Nov 13 18:56:50 2010 -0800
@@ -1128,9 +1128,9 @@
default charset: ISO-8859-1
OS Locale: no_NY
-default locale: ID: no_, Name: Norwegian ()
-display locale: ID: no_, Name: Norwegian ()
-format locale: ID: no_, Name: Norwegian ()
+default locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
+display locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
+format locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
default charset: ISO-8859-1
OS Locale: nr
@@ -1332,9 +1332,9 @@
default charset: ISO-8859-2
OS Locale: sr_SP
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+display locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
default charset: ISO-8859-5
OS Locale: sr_YU
@@ -1721,5 +1721,5 @@
OS Locale (LC_CTYPE: C, LC_MESSAGES: zh_CN.UTF-8)
default locale: ID: zh_CN, Name: Chinese (China)
display locale: ID: zh_CN, Name: Chinese (China)
-format locale: ID: en, Name: English
+format locale: ID: en_CN, Name: English (China)
default charset: US-ASCII
--- a/jdk/test/java/util/Locale/data/deflocale.sol10.fmtasdefault Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.sol10.fmtasdefault Sat Nov 13 18:56:50 2010 -0800
@@ -1128,9 +1128,9 @@
default charset: ISO-8859-1
OS Locale: no_NY
-default locale: ID: no_, Name: Norwegian ()
-display locale: ID: no_, Name: Norwegian ()
-format locale: ID: no_, Name: Norwegian ()
+default locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
+display locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
+format locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
default charset: ISO-8859-1
OS Locale: nr
@@ -1332,9 +1332,9 @@
default charset: ISO-8859-2
OS Locale: sr_SP
-default locale: ID: sr, Name: Serbian
-display locale: ID: sr, Name: Serbian
-format locale: ID: sr, Name: Serbian
+default locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+display locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
default charset: ISO-8859-5
OS Locale: sr_YU
--- a/jdk/test/java/util/Locale/data/deflocale.win7 Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.win7 Sat Nov 13 18:56:50 2010 -0800
@@ -1,1493 +1,1493 @@
-# OSVersionInfo
-# MajorVersion: 6
-# MinorVersion: 1
-# BuildNumber: 7600
-# CSDVersion:
-
-
-OS Locale (lcid: 7f, name: ): Invariant Language (Invariant Country) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 401, name: ar-SA): Arabic (Saudi Arabia) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
-default charset: windows-1252
-
-OS Locale (lcid: 402, name: bg-BG): Bulgarian (Bulgaria) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
-default charset: windows-1252
-
-OS Locale (lcid: 403, name: ca-ES): Catalan (Spain) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ca_ES, Name: Catalan (Spain)
-default charset: windows-1252
-
-OS Locale (lcid: 404, name: zh-TW): Chinese (Traditional) (Taiwan) - 950
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: zh_TW, Name: Chinese (Taiwan)
-default charset: windows-1252
-
-OS Locale (lcid: 405, name: cs-CZ): Czech (Czech Republic) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: cs_CZ, Name: Czech (Czech Republic)
-default charset: windows-1252
-
-OS Locale (lcid: 406, name: da-DK): Danish (Denmark) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: da_DK, Name: Danish (Denmark)
-default charset: windows-1252
-
-OS Locale (lcid: 407, name: de-DE): German (Germany) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: de_DE, Name: German (Germany)
-default charset: windows-1252
-
-OS Locale (lcid: 408, name: el-GR): Greek (Greece) - 1253
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: el_GR, Name: Greek (Greece)
-default charset: windows-1252
-
-OS Locale (lcid: 409, name: en-US): English (United States) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 40b, name: fi-FI): Finnish (Finland) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fi_FI, Name: Finnish (Finland)
-default charset: windows-1252
-
-OS Locale (lcid: 40c, name: fr-FR): French (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fr_FR, Name: French (France)
-default charset: windows-1252
-
-OS Locale (lcid: 40d, name: he-IL): Hebrew (Israel) - 1255
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iw_IL, Name: Hebrew (Israel)
-default charset: windows-1252
-
-OS Locale (lcid: 40e, name: hu-HU): Hungarian (Hungary) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hu_HU, Name: Hungarian (Hungary)
-default charset: windows-1252
-
-OS Locale (lcid: 40f, name: is-IS): Icelandic (Iceland) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: is_IS, Name: Icelandic (Iceland)
-default charset: windows-1252
-
-OS Locale (lcid: 410, name: it-IT): Italian (Italy) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: it_IT, Name: Italian (Italy)
-default charset: windows-1252
-
-OS Locale (lcid: 411, name: ja-JP): Japanese (Japan) - 932
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ja_JP, Name: Japanese (Japan)
-default charset: windows-1252
-
-OS Locale (lcid: 412, name: ko-KR): Korean (Korea) - 949
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ko_KR, Name: Korean (South Korea)
-default charset: windows-1252
-
-OS Locale (lcid: 413, name: nl-NL): Dutch (Netherlands) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: nl_NL, Name: Dutch (Netherlands)
-default charset: windows-1252
-
-OS Locale (lcid: 414, name: nb-NO): Norwegian (Bokmål) (Norway) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: no_NO, Name: Norwegian (Norway)
-default charset: windows-1252
-
-OS Locale (lcid: 415, name: pl-PL): Polish (Poland) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pl_PL, Name: Polish (Poland)
-default charset: windows-1252
-
-OS Locale (lcid: 416, name: pt-BR): Portuguese (Brazil) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pt_BR, Name: Portuguese (Brazil)
-default charset: windows-1252
-
-OS Locale (lcid: 417, name: rm-CH): Romansh (Switzerland) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
-default charset: windows-1252
-
-OS Locale (lcid: 418, name: ro-RO): Romanian (Romania) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ro_RO, Name: Romanian (Romania)
-default charset: windows-1252
-
-OS Locale (lcid: 419, name: ru-RU): Russian (Russia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ru_RU, Name: Russian (Russia)
-default charset: windows-1252
-
-OS Locale (lcid: 41a, name: hr-HR): Croatian (Croatia) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hr_HR, Name: Croatian (Croatia)
-default charset: windows-1252
-
-OS Locale (lcid: 41b, name: sk-SK): Slovak (Slovakia) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sk_SK, Name: Slovak (Slovakia)
-default charset: windows-1252
-
-OS Locale (lcid: 41c, name: sq-AL): Albanian (Albania) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sq_AL, Name: Albanian (Albania)
-default charset: windows-1252
-
-OS Locale (lcid: 41d, name: sv-SE): Swedish (Sweden) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sv_SE, Name: Swedish (Sweden)
-default charset: windows-1252
-
-OS Locale (lcid: 41e, name: th-TH): Thai (Thailand) - 874
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: th_TH, Name: Thai (Thailand)
-default charset: windows-1252
-
-OS Locale (lcid: 41f, name: tr-TR): Turkish (Turkey) - 1254
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tr_TR, Name: Turkish (Turkey)
-default charset: windows-1252
-
-OS Locale (lcid: 420, name: ur-PK): Urdu (Islamic Republic of Pakistan) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ur_PK, Name: Urdu (Pakistan)
-default charset: windows-1252
-
-OS Locale (lcid: 421, name: id-ID): Indonesian (Indonesia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: in_ID, Name: Indonesian (Indonesia)
-default charset: windows-1252
-
-OS Locale (lcid: 422, name: uk-UA): Ukrainian (Ukraine) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uk_UA, Name: Ukrainian (Ukraine)
-default charset: windows-1252
-
-OS Locale (lcid: 423, name: be-BY): Belarusian (Belarus) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
-default charset: windows-1252
-
-OS Locale (lcid: 424, name: sl-SI): Slovenian (Slovenia) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sl_SI, Name: Slovenian (Slovenia)
-default charset: windows-1252
-
-OS Locale (lcid: 425, name: et-EE): Estonian (Estonia) - 1257
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: et_EE, Name: Estonian (Estonia)
-default charset: windows-1252
-
-OS Locale (lcid: 426, name: lv-LV): Latvian (Latvia) - 1257
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lv_LV, Name: Latvian (Latvia)
-default charset: windows-1252
-
-OS Locale (lcid: 427, name: lt-LT): Lithuanian (Lithuania) - 1257
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
-default charset: windows-1252
-
-OS Locale (lcid: 428, name: tg-Cyrl-TJ): Tajik (Cyrillic) (Tajikistan) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-default charset: windows-1252
-
-OS Locale (lcid: 428, name: tg-Cyrl): Tajik (Cyrillic) (Tajikistan) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-default charset: windows-1252
-
-OS Locale (lcid: 429, name: fa-IR): Persian (Iran) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fa_IR, Name: Persian (Iran)
-default charset: windows-1252
-
-OS Locale (lcid: 42a, name: vi-VN): Vietnamese (Vietnam) - 1258
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: vi_VN, Name: Vietnamese (Vietnam)
-default charset: windows-1252
-
-OS Locale (lcid: 42b, name: hy-AM): Armenian (Armenia) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hy_AM, Name: Armenian (Armenia)
-default charset: windows-1252
-
-OS Locale (lcid: 42c, name: az-Latn-AZ): Azeri (Latin) (Azerbaijan) - 1254
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-default charset: windows-1252
-
-OS Locale (lcid: 42c, name: az-Latn): Azeri (Latin) (Azerbaijan) - 1254
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-default charset: windows-1252
-
-OS Locale (lcid: 42d, name: eu-ES): Basque (Spain) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: eu_ES, Name: Basque (Spain)
-default charset: windows-1252
-
-OS Locale (lcid: 42e, name: hsb-DE): Upper Sorbian (Germany) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 42e, name: hsb): Upper Sorbian (Germany) - 1252
+# OSVersionInfo
+# MajorVersion: 6
+# MinorVersion: 1
+# BuildNumber: 7600
+# CSDVersion:
+
+
+OS Locale (lcid: 7f, name: ): Invariant Language (Invariant Country) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 42f, name: mk-MK): Macedonian (FYROM) (Macedonia (FYROM)) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mk_MK, Name: Macedonian (Macedonia)
-default charset: windows-1252
-
-OS Locale (lcid: 432, name: tn-ZA): Setswana (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tn_ZA, Name: Tswana (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 434, name: xh-ZA): isiXhosa (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: xh_ZA, Name: Xhosa (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 435, name: zu-ZA): isiZulu (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: zu_ZA, Name: Zulu (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 436, name: af-ZA): Afrikaans (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: af_ZA, Name: Afrikaans (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 437, name: ka-GE): Georgian (Georgia) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ka_GE, Name: Georgian (Georgia)
-default charset: windows-1252
-
-OS Locale (lcid: 438, name: fo-FO): Faroese (Faroe Islands) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fo_FO, Name: Faroese (Faroe Islands)
-default charset: windows-1252
-
-OS Locale (lcid: 439, name: hi-IN): Hindi (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hi_IN, Name: Hindi (India)
-default charset: windows-1252
-
-OS Locale (lcid: 43a, name: mt-MT): Maltese (Malta) - 0
+
+OS Locale (lcid: 401, name: ar-SA): Arabic (Saudi Arabia) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mt_MT, Name: Maltese (Malta)
-default charset: windows-1252
-
-OS Locale (lcid: 43b, name: se-NO): Sami (Northern) (Norway) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: se_NO, Name: Northern Sami (Norway)
-default charset: windows-1252
-
-OS Locale (lcid: 43e, name: ms-MY): Malay (Malaysia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ms_MY, Name: Malay (Malaysia)
-default charset: windows-1252
-
-OS Locale (lcid: 43f, name: kk-KZ): Kazakh (Kazakhstan) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
-default charset: windows-1252
-
-OS Locale (lcid: 440, name: ky-KG): Kyrgyz (Kyrgyzstan) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
+format locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
default charset: windows-1252
-
-OS Locale (lcid: 441, name: sw-KE): Kiswahili (Kenya) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sw_KE, Name: Swahili (Kenya)
-default charset: windows-1252
-
-OS Locale (lcid: 442, name: tk-TM): Turkmen (Turkmenistan) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
-default charset: windows-1252
-
-OS Locale (lcid: 443, name: uz-Latn): Uzbek (Latin) (Uzbekistan) - 1254
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-default charset: windows-1252
-
-OS Locale (lcid: 443, name: uz-Latn-UZ): Uzbek (Latin) (Uzbekistan) - 1254
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-default charset: windows-1252
-
-OS Locale (lcid: 444, name: tt-RU): Tatar (Russia) - 1251
+
+OS Locale (lcid: 402, name: bg-BG): Bulgarian (Bulgaria) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: tt_RU, Name: Tatar (Russia)
-default charset: windows-1252
-
-OS Locale (lcid: 445, name: bn-IN): Bengali (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bn_IN, Name: Bengali (India)
-default charset: windows-1252
-
-OS Locale (lcid: 446, name: pa-IN): Punjabi (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pa_IN, Name: Panjabi (India)
-default charset: windows-1252
-
-OS Locale (lcid: 447, name: gu-IN): Gujarati (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: gu_IN, Name: Gujarati (India)
-default charset: windows-1252
-
-OS Locale (lcid: 448, name: or-IN): Oriya (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: or_IN, Name: Oriya (India)
+format locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
default charset: windows-1252
-
-OS Locale (lcid: 449, name: ta-IN): Tamil (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ta_IN, Name: Tamil (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44a, name: te-IN): Telugu (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: te_IN, Name: Telugu (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44b, name: kn-IN): Kannada (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kn_IN, Name: Kannada (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44c, name: ml-IN): Malayalam (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ml_IN, Name: Malayalam (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44d, name: as-IN): Assamese (India) - 0
+
+OS Locale (lcid: 403, name: ca-ES): Catalan (Spain) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: as_IN, Name: Assamese (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44e, name: mr-IN): Marathi (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mr_IN, Name: Marathi (India)
-default charset: windows-1252
-
-OS Locale (lcid: 44f, name: sa-IN): Sanskrit (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sa_IN, Name: Sanskrit (India)
-default charset: windows-1252
-
-OS Locale (lcid: 450, name: mn-MN): Mongolian (Cyrillic) (Mongolia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_MN, Name: Mongolian (Mongolia)
-default charset: windows-1252
-
-OS Locale (lcid: 450, name: mn-Cyrl): Mongolian (Cyrillic) (Mongolia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_MN, Name: Mongolian (Mongolia)
+format locale: ID: ca_ES, Name: Catalan (Spain)
default charset: windows-1252
-
-OS Locale (lcid: 451, name: bo-CN): Tibetan (People's Republic of China) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bo_CN, Name: Tibetan (China)
-default charset: windows-1252
-
-OS Locale (lcid: 452, name: cy-GB): Welsh (United Kingdom) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: cy_GB, Name: Welsh (United Kingdom)
-default charset: windows-1252
-
-OS Locale (lcid: 453, name: km-KH): Khmer (Cambodia) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: km_KH, Name: Khmer (Cambodia)
-default charset: windows-1252
-
-OS Locale (lcid: 454, name: lo-LA): Lao (Lao P.D.R.) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lo_LA, Name: Lao (Laos)
-default charset: windows-1252
-
-OS Locale (lcid: 456, name: gl-ES): Galician (Spain) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: gl_ES, Name: Gallegan (Spain)
-default charset: windows-1252
-
-OS Locale (lcid: 457, name: kok-IN): Konkani (India) - 0
+
+OS Locale (lcid: 404, name: zh-TW): Chinese (Traditional) (Taiwan) - 950
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 457, name: kok): Konkani (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 45a, name: syr): Syriac (Syria) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 45a, name: syr-SY): Syriac (Syria) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: zh_TW, Name: Chinese (Taiwan)
default charset: windows-1252
-
-OS Locale (lcid: 45b, name: si-LK): Sinhala (Sri Lanka) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
-default charset: windows-1252
-
-OS Locale (lcid: 45d, name: iu-Cans-CA): Inuktitut (Syllabics) (Canada) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
-default charset: windows-1252
-
-OS Locale (lcid: 45d, name: iu-Cans): Inuktitut (Syllabics) (Canada) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
-default charset: windows-1252
-
-OS Locale (lcid: 45e, name: am-ET): Amharic (Ethiopia) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: am_ET, Name: Amharic (Ethiopia)
-default charset: windows-1252
-
-OS Locale (lcid: 461, name: ne-NP): Nepali (Nepal) - 0
+
+OS Locale (lcid: 405, name: cs-CZ): Czech (Czech Republic) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ne_NP, Name: Nepali (Nepal)
-default charset: windows-1252
-
-OS Locale (lcid: 462, name: fy-NL): Frisian (Netherlands) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fy_NL, Name: Frisian (Netherlands)
-default charset: windows-1252
-
-OS Locale (lcid: 463, name: ps-AF): Pashto (Afghanistan) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ps_AF, Name: Pushto (Afghanistan)
-default charset: windows-1252
-
-OS Locale (lcid: 464, name: fil-PH): Filipino (Philippines) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 464, name: fil): Filipino (Philippines) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: cs_CZ, Name: Czech (Czech Republic)
default charset: windows-1252
-
-OS Locale (lcid: 465, name: dv-MV): Divehi (Maldives) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: dv_MV, Name: Divehi (Maldives)
-default charset: windows-1252
-
-OS Locale (lcid: 468, name: ha-Latn-NG): Hausa (Latin) (Nigeria) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ha_NG, Name: Hausa (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 468, name: ha-Latn): Hausa (Latin) (Nigeria) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ha_NG, Name: Hausa (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 46a, name: yo-NG): Yoruba (Nigeria) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: yo_NG, Name: Yoruba (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 46b, name: quz): Quechua (Bolivia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46b, name: quz-BO): Quechua (Bolivia) - 1252
+
+OS Locale (lcid: 406, name: da-DK): Danish (Denmark) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46c, name: nso): Sesotho sa Leboa (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46c, name: nso-ZA): Sesotho sa Leboa (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46d, name: ba-RU): Bashkir (Russia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ba_RU, Name: Bashkir (Russia)
-default charset: windows-1252
-
-OS Locale (lcid: 46e, name: lb-LU): Luxembourgish (Luxembourg) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
+format locale: ID: da_DK, Name: Danish (Denmark)
default charset: windows-1252
-
-OS Locale (lcid: 46f, name: kl-GL): Greenlandic (Greenland) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kl_GL, Name: Greenlandic (Greenland)
-default charset: windows-1252
-
-OS Locale (lcid: 470, name: ig-NG): Igbo (Nigeria) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ig_NG, Name: Igbo (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 478, name: ii-CN): Yi (People's Republic of China) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ii_CN, Name: Sichuan Yi (China)
-default charset: windows-1252
-
-OS Locale (lcid: 47a, name: arn): Mapudungun (Chile) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47a, name: arn-CL): Mapudungun (Chile) - 1252
+
+OS Locale (lcid: 407, name: de-DE): German (Germany) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47c, name: moh): Mohawk (Canada) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: de_DE, Name: German (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 47c, name: moh-CA): Mohawk (Canada) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47e, name: br-FR): Breton (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: br_FR, Name: Breton (France)
-default charset: windows-1252
-
-OS Locale (lcid: 480, name: ug-CN): Uyghur (People's Republic of China) - 1256
+
+OS Locale (lcid: 408, name: el-GR): Greek (Greece) - 1253
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ug_CN, Name: Uighur (China)
-default charset: windows-1252
-
-OS Locale (lcid: 481, name: mi-NZ): Maori (New Zealand) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mi_NZ, Name: Maori (New Zealand)
-default charset: windows-1252
-
-OS Locale (lcid: 482, name: oc-FR): Occitan (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: oc_FR, Name: Occitan (France)
+format locale: ID: el_GR, Name: Greek (Greece)
default charset: windows-1252
-
-OS Locale (lcid: 483, name: co-FR): Corsican (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: co_FR, Name: Corsican (France)
-default charset: windows-1252
-
-OS Locale (lcid: 484, name: gsw): Alsatian (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 484, name: gsw-FR): Alsatian (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 485, name: sah): Yakut (Russia) - 1251
+
+OS Locale (lcid: 409, name: en-US): English (United States) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 485, name: sah-RU): Yakut (Russia) - 1251
+
+OS Locale (lcid: 40b, name: fi-FI): Finnish (Finland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fi_FI, Name: Finnish (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 40c, name: fr-FR): French (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fr_FR, Name: French (France)
+default charset: windows-1252
+
+OS Locale (lcid: 40d, name: he-IL): Hebrew (Israel) - 1255
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iw_IL, Name: Hebrew (Israel)
+default charset: windows-1252
+
+OS Locale (lcid: 40e, name: hu-HU): Hungarian (Hungary) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hu_HU, Name: Hungarian (Hungary)
+default charset: windows-1252
+
+OS Locale (lcid: 40f, name: is-IS): Icelandic (Iceland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: is_IS, Name: Icelandic (Iceland)
+default charset: windows-1252
+
+OS Locale (lcid: 410, name: it-IT): Italian (Italy) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: it_IT, Name: Italian (Italy)
+default charset: windows-1252
+
+OS Locale (lcid: 411, name: ja-JP): Japanese (Japan) - 932
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ja_JP, Name: Japanese (Japan)
+default charset: windows-1252
+
+OS Locale (lcid: 412, name: ko-KR): Korean (Korea) - 949
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ko_KR, Name: Korean (South Korea)
+default charset: windows-1252
+
+OS Locale (lcid: 413, name: nl-NL): Dutch (Netherlands) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nl_NL, Name: Dutch (Netherlands)
+default charset: windows-1252
+
+OS Locale (lcid: 414, name: nb-NO): Norwegian (Bokm…l) (Norway) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: no_NO, Name: Norwegian (Norway)
+default charset: windows-1252
+
+OS Locale (lcid: 415, name: pl-PL): Polish (Poland) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: pl_PL, Name: Polish (Poland)
+default charset: windows-1252
+
+OS Locale (lcid: 416, name: pt-BR): Portuguese (Brazil) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: pt_BR, Name: Portuguese (Brazil)
+default charset: windows-1252
+
+OS Locale (lcid: 417, name: rm-CH): Romansh (Switzerland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
+default charset: windows-1252
+
+OS Locale (lcid: 418, name: ro-RO): Romanian (Romania) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ro_RO, Name: Romanian (Romania)
+default charset: windows-1252
+
+OS Locale (lcid: 419, name: ru-RU): Russian (Russia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ru_RU, Name: Russian (Russia)
+default charset: windows-1252
+
+OS Locale (lcid: 41a, name: hr-HR): Croatian (Croatia) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hr_HR, Name: Croatian (Croatia)
+default charset: windows-1252
+
+OS Locale (lcid: 41b, name: sk-SK): Slovak (Slovakia) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sk_SK, Name: Slovak (Slovakia)
+default charset: windows-1252
+
+OS Locale (lcid: 41c, name: sq-AL): Albanian (Albania) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sq_AL, Name: Albanian (Albania)
+default charset: windows-1252
+
+OS Locale (lcid: 41d, name: sv-SE): Swedish (Sweden) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sv_SE, Name: Swedish (Sweden)
+default charset: windows-1252
+
+OS Locale (lcid: 41e, name: th-TH): Thai (Thailand) - 874
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: th_TH, Name: Thai (Thailand)
+default charset: windows-1252
+
+OS Locale (lcid: 41f, name: tr-TR): Turkish (Turkey) - 1254
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tr_TR, Name: Turkish (Turkey)
+default charset: windows-1252
+
+OS Locale (lcid: 420, name: ur-PK): Urdu (Islamic Republic of Pakistan) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ur_PK, Name: Urdu (Pakistan)
+default charset: windows-1252
+
+OS Locale (lcid: 421, name: id-ID): Indonesian (Indonesia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: in_ID, Name: Indonesian (Indonesia)
+default charset: windows-1252
+
+OS Locale (lcid: 422, name: uk-UA): Ukrainian (Ukraine) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uk_UA, Name: Ukrainian (Ukraine)
+default charset: windows-1252
+
+OS Locale (lcid: 423, name: be-BY): Belarusian (Belarus) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: be_BY, Name: Belarusian (Belarus)
+default charset: windows-1252
+
+OS Locale (lcid: 424, name: sl-SI): Slovenian (Slovenia) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sl_SI, Name: Slovenian (Slovenia)
+default charset: windows-1252
+
+OS Locale (lcid: 425, name: et-EE): Estonian (Estonia) - 1257
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: et_EE, Name: Estonian (Estonia)
+default charset: windows-1252
+
+OS Locale (lcid: 426, name: lv-LV): Latvian (Latvia) - 1257
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lv_LV, Name: Latvian (Latvia)
+default charset: windows-1252
+
+OS Locale (lcid: 427, name: lt-LT): Lithuanian (Lithuania) - 1257
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+default charset: windows-1252
+
+OS Locale (lcid: 428, name: tg-Cyrl-TJ): Tajik (Cyrillic) (Tajikistan) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+default charset: windows-1252
+
+OS Locale (lcid: 428, name: tg-Cyrl): Tajik (Cyrillic) (Tajikistan) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+default charset: windows-1252
+
+OS Locale (lcid: 429, name: fa-IR): Persian (Iran) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fa_IR, Name: Persian (Iran)
+default charset: windows-1252
+
+OS Locale (lcid: 42a, name: vi-VN): Vietnamese (Vietnam) - 1258
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: vi_VN, Name: Vietnamese (Vietnam)
+default charset: windows-1252
+
+OS Locale (lcid: 42b, name: hy-AM): Armenian (Armenia) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hy_AM, Name: Armenian (Armenia)
+default charset: windows-1252
+
+OS Locale (lcid: 42c, name: az-Latn-AZ): Azeri (Latin) (Azerbaijan) - 1254
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+default charset: windows-1252
+
+OS Locale (lcid: 42c, name: az-Latn): Azeri (Latin) (Azerbaijan) - 1254
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+default charset: windows-1252
+
+OS Locale (lcid: 42d, name: eu-ES): Basque (Spain) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: eu_ES, Name: Basque (Spain)
+default charset: windows-1252
+
+OS Locale (lcid: 42e, name: hsb-DE): Upper Sorbian (Germany) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+default charset: windows-1252
+
+OS Locale (lcid: 42e, name: hsb): Upper Sorbian (Germany) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+default charset: windows-1252
+
+OS Locale (lcid: 42f, name: mk-MK): Macedonian (FYROM) (Macedonia (FYROM)) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mk_MK, Name: Macedonian (Macedonia)
+default charset: windows-1252
+
+OS Locale (lcid: 432, name: tn-ZA): Setswana (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tn_ZA, Name: Tswana (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 434, name: xh-ZA): isiXhosa (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: xh_ZA, Name: Xhosa (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 435, name: zu-ZA): isiZulu (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: zu_ZA, Name: Zulu (South Africa)
default charset: windows-1252
-
-OS Locale (lcid: 486, name: qut): K'iche (Guatemala) - 1252
+
+OS Locale (lcid: 436, name: af-ZA): Afrikaans (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: af_ZA, Name: Afrikaans (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 437, name: ka-GE): Georgian (Georgia) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ka_GE, Name: Georgian (Georgia)
+default charset: windows-1252
+
+OS Locale (lcid: 438, name: fo-FO): Faroese (Faroe Islands) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fo_FO, Name: Faroese (Faroe Islands)
+default charset: windows-1252
+
+OS Locale (lcid: 439, name: hi-IN): Hindi (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hi_IN, Name: Hindi (India)
+default charset: windows-1252
+
+OS Locale (lcid: 43a, name: mt-MT): Maltese (Malta) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mt_MT, Name: Maltese (Malta)
+default charset: windows-1252
+
+OS Locale (lcid: 43b, name: se-NO): Sami (Northern) (Norway) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: se_NO, Name: Northern Sami (Norway)
+default charset: windows-1252
+
+OS Locale (lcid: 43e, name: ms-MY): Malay (Malaysia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ms_MY, Name: Malay (Malaysia)
+default charset: windows-1252
+
+OS Locale (lcid: 43f, name: kk-KZ): Kazakh (Kazakhstan) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
+default charset: windows-1252
+
+OS Locale (lcid: 440, name: ky-KG): Kyrgyz (Kyrgyzstan) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
+default charset: windows-1252
+
+OS Locale (lcid: 441, name: sw-KE): Kiswahili (Kenya) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sw_KE, Name: Swahili (Kenya)
+default charset: windows-1252
+
+OS Locale (lcid: 442, name: tk-TM): Turkmen (Turkmenistan) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
+default charset: windows-1252
+
+OS Locale (lcid: 443, name: uz-Latn): Uzbek (Latin) (Uzbekistan) - 1254
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+default charset: windows-1252
+
+OS Locale (lcid: 443, name: uz-Latn-UZ): Uzbek (Latin) (Uzbekistan) - 1254
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+default charset: windows-1252
+
+OS Locale (lcid: 444, name: tt-RU): Tatar (Russia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tt_RU, Name: Tatar (Russia)
+default charset: windows-1252
+
+OS Locale (lcid: 445, name: bn-IN): Bengali (India) - 0
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: bn_IN, Name: Bengali (India)
+default charset: windows-1252
+
+OS Locale (lcid: 446, name: pa-IN): Punjabi (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: pa_IN, Name: Panjabi (India)
+default charset: windows-1252
+
+OS Locale (lcid: 447, name: gu-IN): Gujarati (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gu_IN, Name: Gujarati (India)
+default charset: windows-1252
+
+OS Locale (lcid: 448, name: or-IN): Oriya (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: or_IN, Name: Oriya (India)
+default charset: windows-1252
+
+OS Locale (lcid: 449, name: ta-IN): Tamil (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ta_IN, Name: Tamil (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44a, name: te-IN): Telugu (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: te_IN, Name: Telugu (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44b, name: kn-IN): Kannada (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kn_IN, Name: Kannada (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44c, name: ml-IN): Malayalam (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ml_IN, Name: Malayalam (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44d, name: as-IN): Assamese (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: as_IN, Name: Assamese (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44e, name: mr-IN): Marathi (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mr_IN, Name: Marathi (India)
+default charset: windows-1252
+
+OS Locale (lcid: 44f, name: sa-IN): Sanskrit (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sa_IN, Name: Sanskrit (India)
+default charset: windows-1252
+
+OS Locale (lcid: 450, name: mn-MN): Mongolian (Cyrillic) (Mongolia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mn_MN, Name: Mongolian (Mongolia)
+default charset: windows-1252
+
+OS Locale (lcid: 450, name: mn-Cyrl): Mongolian (Cyrillic) (Mongolia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mn_MN, Name: Mongolian (Mongolia)
+default charset: windows-1252
+
+OS Locale (lcid: 451, name: bo-CN): Tibetan (People's Republic of China) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: bo_CN, Name: Tibetan (China)
+default charset: windows-1252
+
+OS Locale (lcid: 452, name: cy-GB): Welsh (United Kingdom) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: cy_GB, Name: Welsh (United Kingdom)
default charset: windows-1252
-
-OS Locale (lcid: 486, name: qut-GT): K'iche (Guatemala) - 1252
+
+OS Locale (lcid: 453, name: km-KH): Khmer (Cambodia) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: km_KH, Name: Khmer (Cambodia)
+default charset: windows-1252
+
+OS Locale (lcid: 454, name: lo-LA): Lao (Lao P.D.R.) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lo_LA, Name: Lao (Laos)
+default charset: windows-1252
+
+OS Locale (lcid: 456, name: gl-ES): Galician (Spain) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
+default charset: windows-1252
+
+OS Locale (lcid: 457, name: kok-IN): Konkani (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kok_IN, Name: Konkani (India)
+default charset: windows-1252
+
+OS Locale (lcid: 457, name: kok): Konkani (India) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kok_IN, Name: Konkani (India)
+default charset: windows-1252
+
+OS Locale (lcid: 45a, name: syr): Syriac (Syria) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: syr_SY, Name: Syriac (Syria)
+default charset: windows-1252
+
+OS Locale (lcid: 45a, name: syr-SY): Syriac (Syria) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: syr_SY, Name: Syriac (Syria)
+default charset: windows-1252
+
+OS Locale (lcid: 45b, name: si-LK): Sinhala (Sri Lanka) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
+default charset: windows-1252
+
+OS Locale (lcid: 45d, name: iu-Cans-CA): Inuktitut (Syllabics) (Canada) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 45d, name: iu-Cans): Inuktitut (Syllabics) (Canada) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 45e, name: am-ET): Amharic (Ethiopia) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: am_ET, Name: Amharic (Ethiopia)
+default charset: windows-1252
+
+OS Locale (lcid: 461, name: ne-NP): Nepali (Nepal) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ne_NP, Name: Nepali (Nepal)
+default charset: windows-1252
+
+OS Locale (lcid: 462, name: fy-NL): Frisian (Netherlands) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fy_NL, Name: Frisian (Netherlands)
+default charset: windows-1252
+
+OS Locale (lcid: 463, name: ps-AF): Pashto (Afghanistan) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ps_AF, Name: Pushto (Afghanistan)
+default charset: windows-1252
+
+OS Locale (lcid: 464, name: fil-PH): Filipino (Philippines) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: fil_PH, Name: Filipino (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 464, name: fil): Filipino (Philippines) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fil_PH, Name: Filipino (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 465, name: dv-MV): Divehi (Maldives) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: dv_MV, Name: Divehi (Maldives)
+default charset: windows-1252
+
+OS Locale (lcid: 468, name: ha-Latn-NG): Hausa (Latin) (Nigeria) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 468, name: ha-Latn): Hausa (Latin) (Nigeria) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 46a, name: yo-NG): Yoruba (Nigeria) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: yo_NG, Name: Yoruba (Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 46b, name: quz): Quechua (Bolivia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_BO, Name: quz (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 46b, name: quz-BO): Quechua (Bolivia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_BO, Name: quz (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 46c, name: nso): Sesotho sa Leboa (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 46c, name: nso-ZA): Sesotho sa Leboa (South Africa) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 46d, name: ba-RU): Bashkir (Russia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ba_RU, Name: Bashkir (Russia)
+default charset: windows-1252
+
+OS Locale (lcid: 46e, name: lb-LU): Luxembourgish (Luxembourg) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
+default charset: windows-1252
+
+OS Locale (lcid: 46f, name: kl-GL): Greenlandic (Greenland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kl_GL, Name: Greenlandic (Greenland)
+default charset: windows-1252
+
+OS Locale (lcid: 470, name: ig-NG): Igbo (Nigeria) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ig_NG, Name: Igbo (Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 478, name: ii-CN): Yi (People's Republic of China) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ii_CN, Name: Sichuan Yi (China)
default charset: windows-1252
-
-OS Locale (lcid: 487, name: rw-RW): Kinyarwanda (Rwanda) - 1252
+
+OS Locale (lcid: 47a, name: arn): Mapudungun (Chile) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: arn_CL, Name: Mapudungun (Chile)
+default charset: windows-1252
+
+OS Locale (lcid: 47a, name: arn-CL): Mapudungun (Chile) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: arn_CL, Name: Mapudungun (Chile)
+default charset: windows-1252
+
+OS Locale (lcid: 47c, name: moh): Mohawk (Canada) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: moh_CA, Name: Mohawk (Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 47c, name: moh-CA): Mohawk (Canada) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: moh_CA, Name: Mohawk (Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 47e, name: br-FR): Breton (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: br_FR, Name: Breton (France)
+default charset: windows-1252
+
+OS Locale (lcid: 480, name: ug-CN): Uyghur (People's Republic of China) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ug_CN, Name: Uighur (China)
+default charset: windows-1252
+
+OS Locale (lcid: 481, name: mi-NZ): Maori (New Zealand) - 0
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mi_NZ, Name: Maori (New Zealand)
+default charset: windows-1252
+
+OS Locale (lcid: 482, name: oc-FR): Occitan (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: oc_FR, Name: Occitan (France)
+default charset: windows-1252
+
+OS Locale (lcid: 483, name: co-FR): Corsican (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: co_FR, Name: Corsican (France)
+default charset: windows-1252
+
+OS Locale (lcid: 484, name: gsw): Alsatian (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gsw_FR, Name: Swiss German (France)
+default charset: windows-1252
+
+OS Locale (lcid: 484, name: gsw-FR): Alsatian (France) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gsw_FR, Name: Swiss German (France)
+default charset: windows-1252
+
+OS Locale (lcid: 485, name: sah): Yakut (Russia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sah_RU, Name: Yakut (Russia)
+default charset: windows-1252
+
+OS Locale (lcid: 485, name: sah-RU): Yakut (Russia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sah_RU, Name: Yakut (Russia)
+default charset: windows-1252
+
+OS Locale (lcid: 486, name: qut): K'iche (Guatemala) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: qut_GT, Name: qut (Guatemala)
+default charset: windows-1252
+
+OS Locale (lcid: 486, name: qut-GT): K'iche (Guatemala) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: qut_GT, Name: qut (Guatemala)
+default charset: windows-1252
+
+OS Locale (lcid: 487, name: rw-RW): Kinyarwanda (Rwanda) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: rw_RW, Name: Kinyarwanda (Rwanda)
default charset: windows-1252
-
-OS Locale (lcid: 488, name: wo-SN): Wolof (Senegal) - 1252
+
+OS Locale (lcid: 488, name: wo-SN): Wolof (Senegal) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: wo_SN, Name: Wolof (Senegal)
default charset: windows-1252
-
-OS Locale (lcid: 48c, name: prs): Dari (Afghanistan) - 1256
+
+OS Locale (lcid: 48c, name: prs): Dari (Afghanistan) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: prs_AF, Name: prs (Afghanistan)
default charset: windows-1252
-
-OS Locale (lcid: 48c, name: prs-AF): Dari (Afghanistan) - 1256
+
+OS Locale (lcid: 48c, name: prs-AF): Dari (Afghanistan) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: prs_AF, Name: prs (Afghanistan)
default charset: windows-1252
-
-OS Locale (lcid: 491, name: gd-GB): Scottish Gaelic (United Kingdom) - 1252
+
+OS Locale (lcid: 491, name: gd-GB): Scottish Gaelic (United Kingdom) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: gd_GB, Name: Scottish Gaelic (United Kingdom)
default charset: windows-1252
-
-OS Locale (lcid: 801, name: ar-IQ): Arabic (Iraq) - 1256
+
+OS Locale (lcid: 801, name: ar-IQ): Arabic (Iraq) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_IQ, Name: Arabic (Iraq)
default charset: windows-1252
-
-OS Locale (lcid: 804, name: zh-Hans): Chinese (Simplified) (People's Republic of China) - 936
+
+OS Locale (lcid: 804, name: zh-Hans): Chinese (Simplified) (People's Republic of China) - 936
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_CN, Name: Chinese (China)
default charset: windows-1252
-
-OS Locale (lcid: 804, name: zh-CN): Chinese (Simplified) (People's Republic of China) - 936
+
+OS Locale (lcid: 804, name: zh-CN): Chinese (Simplified) (People's Republic of China) - 936
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_CN, Name: Chinese (China)
default charset: windows-1252
-
-OS Locale (lcid: 807, name: de-CH): German (Switzerland) - 1252
+
+OS Locale (lcid: 807, name: de-CH): German (Switzerland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_CH, Name: German (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 809, name: en-GB): English (United Kingdom) - 1252
+
+OS Locale (lcid: 809, name: en-GB): English (United Kingdom) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_GB, Name: English (United Kingdom)
default charset: windows-1252
-
-OS Locale (lcid: 80a, name: es-MX): Spanish (Mexico) - 1252
+
+OS Locale (lcid: 80a, name: es-MX): Spanish (Mexico) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_MX, Name: Spanish (Mexico)
default charset: windows-1252
-
-OS Locale (lcid: 80c, name: fr-BE): French (Belgium) - 1252
+
+OS Locale (lcid: 80c, name: fr-BE): French (Belgium) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_BE, Name: French (Belgium)
default charset: windows-1252
-
-OS Locale (lcid: 810, name: it-CH): Italian (Switzerland) - 1252
+
+OS Locale (lcid: 810, name: it-CH): Italian (Switzerland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: it_CH, Name: Italian (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 813, name: nl-BE): Dutch (Belgium) - 1252
+
+OS Locale (lcid: 813, name: nl-BE): Dutch (Belgium) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: nl_BE, Name: Dutch (Belgium)
default charset: windows-1252
-
-OS Locale (lcid: 814, name: nn-NO): Norwegian (Nynorsk) (Norway) - 1252
+
+OS Locale (lcid: 814, name: nn-NO): Norwegian (Nynorsk) (Norway) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
default charset: windows-1252
-
-OS Locale (lcid: 816, name: pt-PT): Portuguese (Portugal) - 1252
+
+OS Locale (lcid: 816, name: pt-PT): Portuguese (Portugal) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: pt_PT, Name: Portuguese (Portugal)
default charset: windows-1252
-
-OS Locale (lcid: 81a, name: sr-Latn-CS): Serbian (Latin) (Serbia and Montenegro (Former)) - 1250
+
+OS Locale (lcid: 81a, name: sr-Latn-CS): Serbian (Latin) (Serbia and Montenegro (Former)) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS_#Latn, Name: Serbian (Latin,Serbia and Montenegro)
default charset: windows-1252
-
-OS Locale (lcid: 81d, name: sv-FI): Swedish (Finland) - 1252
+
+OS Locale (lcid: 81d, name: sv-FI): Swedish (Finland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: sv_FI, Name: Swedish (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 82c, name: az-Cyrl-AZ): Azeri (Cyrillic) (Azerbaijan) - 1251
+
+OS Locale (lcid: 82c, name: az-Cyrl-AZ): Azeri (Cyrillic) (Azerbaijan) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+format locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
default charset: windows-1252
-
-OS Locale (lcid: 82c, name: az-Cyrl): Azeri (Cyrillic) (Azerbaijan) - 1251
+
+OS Locale (lcid: 82c, name: az-Cyrl): Azeri (Cyrillic) (Azerbaijan) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+format locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
default charset: windows-1252
-
-OS Locale (lcid: 82e, name: dsb): Lower Sorbian (Germany) - 1252
+
+OS Locale (lcid: 82e, name: dsb): Lower Sorbian (Germany) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 82e, name: dsb-DE): Lower Sorbian (Germany) - 1252
+
+OS Locale (lcid: 82e, name: dsb-DE): Lower Sorbian (Germany) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 83b, name: se-SE): Sami (Northern) (Sweden) - 1252
+
+OS Locale (lcid: 83b, name: se-SE): Sami (Northern) (Sweden) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: se_SE, Name: Northern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 83c, name: ga-IE): Irish (Ireland) - 1252
+
+OS Locale (lcid: 83c, name: ga-IE): Irish (Ireland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ga_IE, Name: Irish (Ireland)
default charset: windows-1252
-
-OS Locale (lcid: 83e, name: ms-BN): Malay (Brunei Darussalam) - 1252
+
+OS Locale (lcid: 83e, name: ms-BN): Malay (Brunei Darussalam) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ms_BN, Name: Malay (Brunei)
default charset: windows-1252
-
-OS Locale (lcid: 843, name: uz-Cyrl-UZ): Uzbek (Cyrillic) (Uzbekistan) - 1251
+
+OS Locale (lcid: 843, name: uz-Cyrl-UZ): Uzbek (Cyrillic) (Uzbekistan) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: windows-1252
-
-OS Locale (lcid: 843, name: uz-Cyrl): Uzbek (Cyrillic) (Uzbekistan) - 1251
+
+OS Locale (lcid: 843, name: uz-Cyrl): Uzbek (Cyrillic) (Uzbekistan) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: windows-1252
-
-OS Locale (lcid: 845, name: bn-BD): Bengali (Bangladesh) - 0
+
+OS Locale (lcid: 845, name: bn-BD): Bengali (Bangladesh) - 0
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: bn_BD, Name: Bengali (Bangladesh)
default charset: windows-1252
-
-OS Locale (lcid: 850, name: mn-Mong-CN): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
+
+OS Locale (lcid: 850, name: mn-Mong-CN): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_CN, Name: Mongolian (China)
+format locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
default charset: windows-1252
-
-OS Locale (lcid: 850, name: mn-Mong): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
+
+OS Locale (lcid: 850, name: mn-Mong): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_CN, Name: Mongolian (China)
+format locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
default charset: windows-1252
-
-OS Locale (lcid: 85d, name: iu-Latn): Inuktitut (Latin) (Canada) - 1252
+
+OS Locale (lcid: 85d, name: iu-Latn): Inuktitut (Latin) (Canada) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
+format locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
default charset: windows-1252
-
-OS Locale (lcid: 85d, name: iu-Latn-CA): Inuktitut (Latin) (Canada) - 1252
+
+OS Locale (lcid: 85d, name: iu-Latn-CA): Inuktitut (Latin) (Canada) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
+format locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm): Tamazight (Latin) (Algeria) - 1252
+
+OS Locale (lcid: 85f, name: tzm): Tamazight (Latin) (Algeria) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm-Latn-DZ): Tamazight (Latin) (Algeria) - 1252
+
+OS Locale (lcid: 85f, name: tzm-Latn-DZ): Tamazight (Latin) (Algeria) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm-Latn): Tamazight (Latin) (Algeria) - 1252
+
+OS Locale (lcid: 85f, name: tzm-Latn): Tamazight (Latin) (Algeria) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 86b, name: quz-EC): Quechua (Ecuador) - 1252
+
+OS Locale (lcid: 86b, name: quz-EC): Quechua (Ecuador) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_EC, Name: quz (Ecuador)
default charset: windows-1252
-
-OS Locale (lcid: c01, name: ar-EG): Arabic (Egypt) - 1256
+
+OS Locale (lcid: c01, name: ar-EG): Arabic (Egypt) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_EG, Name: Arabic (Egypt)
default charset: windows-1252
-
-OS Locale (lcid: c04, name: zh-HK): Chinese (Traditional) (Hong Kong S.A.R.) - 950
+
+OS Locale (lcid: c04, name: zh-HK): Chinese (Traditional) (Hong Kong S.A.R.) - 950
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_HK, Name: Chinese (Hong Kong)
default charset: x-MS950-HKSCS
-
-OS Locale (lcid: c04, name: zh-Hant): Chinese (Traditional) (Hong Kong S.A.R.) - 950
+
+OS Locale (lcid: c04, name: zh-Hant): Chinese (Traditional) (Hong Kong S.A.R.) - 950
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_HK, Name: Chinese (Hong Kong)
default charset: windows-1252
-
-OS Locale (lcid: c07, name: de-AT): German (Austria) - 1252
+
+OS Locale (lcid: c07, name: de-AT): German (Austria) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_AT, Name: German (Austria)
default charset: windows-1252
-
-OS Locale (lcid: c09, name: en-AU): English (Australia) - 1252
+
+OS Locale (lcid: c09, name: en-AU): English (Australia) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_AU, Name: English (Australia)
default charset: windows-1252
-
-OS Locale (lcid: c0a, name: es-ES): Spanish (Spain) - 1252
+
+OS Locale (lcid: c0a, name: es-ES): Spanish (Spain) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_ES, Name: Spanish (Spain)
default charset: windows-1252
-
-OS Locale (lcid: c0c, name: fr-CA): French (Canada) - 1252
+
+OS Locale (lcid: c0c, name: fr-CA): French (Canada) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_CA, Name: French (Canada)
default charset: windows-1252
-
-OS Locale (lcid: c1a, name: sr-Cyrl-CS): Serbian (Cyrillic) (Serbia and Montenegro (Former)) - 1251
+
+OS Locale (lcid: c1a, name: sr-Cyrl-CS): Serbian (Cyrillic) (Serbia and Montenegro (Former)) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS_#Cyrl, Name: Serbian (Cyrillic,Serbia and Montenegro)
default charset: windows-1252
-
-OS Locale (lcid: c3b, name: se-FI): Sami (Northern) (Finland) - 1252
+
+OS Locale (lcid: c3b, name: se-FI): Sami (Northern) (Finland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: se_FI, Name: Northern Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: c6b, name: quz-PE): Quechua (Peru) - 1252
+
+OS Locale (lcid: c6b, name: quz-PE): Quechua (Peru) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_PE, Name: quz (Peru)
default charset: windows-1252
-
-OS Locale (lcid: 1001, name: ar-LY): Arabic (Libya) - 1256
+
+OS Locale (lcid: 1001, name: ar-LY): Arabic (Libya) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_LY, Name: Arabic (Libya)
default charset: windows-1252
-
-OS Locale (lcid: 1004, name: zh-SG): Chinese (Simplified) (Singapore) - 936
+
+OS Locale (lcid: 1004, name: zh-SG): Chinese (Simplified) (Singapore) - 936
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_SG, Name: Chinese (Singapore)
default charset: windows-1252
-
-OS Locale (lcid: 1007, name: de-LU): German (Luxembourg) - 1252
+
+OS Locale (lcid: 1007, name: de-LU): German (Luxembourg) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_LU, Name: German (Luxembourg)
default charset: windows-1252
-
-OS Locale (lcid: 1009, name: en-CA): English (Canada) - 1252
+
+OS Locale (lcid: 1009, name: en-CA): English (Canada) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_CA, Name: English (Canada)
default charset: windows-1252
-
-OS Locale (lcid: 100a, name: es-GT): Spanish (Guatemala) - 1252
+
+OS Locale (lcid: 100a, name: es-GT): Spanish (Guatemala) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_GT, Name: Spanish (Guatemala)
default charset: windows-1252
-
-OS Locale (lcid: 100c, name: fr-CH): French (Switzerland) - 1252
+
+OS Locale (lcid: 100c, name: fr-CH): French (Switzerland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_CH, Name: French (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 101a, name: hr-BA): Croatian (Latin) (Bosnia and Herzegovina) - 1250
+
+OS Locale (lcid: 101a, name: hr-BA): Croatian (Latin) (Bosnia and Herzegovina) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: hr_BA, Name: Croatian (Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 103b, name: smj-NO): Sami (Lule) (Norway) - 1252
+
+OS Locale (lcid: 103b, name: smj-NO): Sami (Lule) (Norway) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_NO, Name: Lule Sami (Norway)
default charset: windows-1252
-
-OS Locale (lcid: 1401, name: ar-DZ): Arabic (Algeria) - 1256
+
+OS Locale (lcid: 1401, name: ar-DZ): Arabic (Algeria) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_DZ, Name: Arabic (Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 1404, name: zh-MO): Chinese (Traditional) (Macao S.A.R.) - 950
+
+OS Locale (lcid: 1404, name: zh-MO): Chinese (Traditional) (Macao S.A.R.) - 950
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_MO, Name: Chinese (Macao)
default charset: windows-1252
-
-OS Locale (lcid: 1407, name: de-LI): German (Liechtenstein) - 1252
+
+OS Locale (lcid: 1407, name: de-LI): German (Liechtenstein) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_LI, Name: German (Liechtenstein)
default charset: windows-1252
-
-OS Locale (lcid: 1409, name: en-NZ): English (New Zealand) - 1252
+
+OS Locale (lcid: 1409, name: en-NZ): English (New Zealand) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_NZ, Name: English (New Zealand)
default charset: windows-1252
-
-OS Locale (lcid: 140a, name: es-CR): Spanish (Costa Rica) - 1252
+
+OS Locale (lcid: 140a, name: es-CR): Spanish (Costa Rica) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_CR, Name: Spanish (Costa Rica)
default charset: windows-1252
-
-OS Locale (lcid: 140c, name: fr-LU): French (Luxembourg) - 1252
+
+OS Locale (lcid: 140c, name: fr-LU): French (Luxembourg) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_LU, Name: French (Luxembourg)
default charset: windows-1252
-
-OS Locale (lcid: 141a, name: bs-Latn): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
+
+OS Locale (lcid: 141a, name: bs-Latn): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 141a, name: bs-Latn-BA): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
+
+OS Locale (lcid: 141a, name: bs-Latn-BA): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 143b, name: smj-SE): Sami (Lule) (Sweden) - 1252
+
+OS Locale (lcid: 143b, name: smj-SE): Sami (Lule) (Sweden) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_SE, Name: Lule Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 143b, name: smj): Sami (Lule) (Sweden) - 1252
+
+OS Locale (lcid: 143b, name: smj): Sami (Lule) (Sweden) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_SE, Name: Lule Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 1801, name: ar-MA): Arabic (Morocco) - 1256
+
+OS Locale (lcid: 1801, name: ar-MA): Arabic (Morocco) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_MA, Name: Arabic (Morocco)
default charset: windows-1252
-
-OS Locale (lcid: 1809, name: en-IE): English (Ireland) - 1252
+
+OS Locale (lcid: 1809, name: en-IE): English (Ireland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_IE, Name: English (Ireland)
default charset: windows-1252
-
-OS Locale (lcid: 180a, name: es-PA): Spanish (Panama) - 1252
+
+OS Locale (lcid: 180a, name: es-PA): Spanish (Panama) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_PA, Name: Spanish (Panama)
default charset: windows-1252
-
-OS Locale (lcid: 180c, name: fr-MC): French (Principality of Monaco) - 1252
+
+OS Locale (lcid: 180c, name: fr-MC): French (Principality of Monaco) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_MC, Name: French (Monaco)
default charset: windows-1252
-
-OS Locale (lcid: 181a, name: sr-Latn-BA): Serbian (Latin) (Bosnia and Herzegovina) - 1250
+
+OS Locale (lcid: 181a, name: sr-Latn-BA): Serbian (Latin) (Bosnia and Herzegovina) - 1250
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+format locale: ID: sr_BA_#Latn, Name: Serbian (Latin,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 183b, name: sma-NO): Sami (Southern) (Norway) - 1252
+
+OS Locale (lcid: 183b, name: sma-NO): Sami (Southern) (Norway) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_NO, Name: Southern Sami (Norway)
default charset: windows-1252
-
-OS Locale (lcid: 1c01, name: ar-TN): Arabic (Tunisia) - 1256
+
+OS Locale (lcid: 1c01, name: ar-TN): Arabic (Tunisia) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_TN, Name: Arabic (Tunisia)
default charset: windows-1252
-
-OS Locale (lcid: 1c09, name: en-ZA): English (South Africa) - 1252
+
+OS Locale (lcid: 1c09, name: en-ZA): English (South Africa) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_ZA, Name: English (South Africa)
default charset: windows-1252
-
-OS Locale (lcid: 1c0a, name: es-DO): Spanish (Dominican Republic) - 1252
+
+OS Locale (lcid: 1c0a, name: es-DO): Spanish (Dominican Republic) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_DO, Name: Spanish (Dominican Republic)
default charset: windows-1252
-
-OS Locale (lcid: 1c1a, name: sr-Cyrl-BA): Serbian (Cyrillic) (Bosnia and Herzegovina) - 1251
+
+OS Locale (lcid: 1c1a, name: sr-Cyrl-BA): Serbian (Cyrillic) (Bosnia and Herzegovina) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+format locale: ID: sr_BA_#Cyrl, Name: Serbian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 1c3b, name: sma): Sami (Southern) (Sweden) - 1252
+
+OS Locale (lcid: 1c3b, name: sma): Sami (Southern) (Sweden) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_SE, Name: Southern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 1c3b, name: sma-SE): Sami (Southern) (Sweden) - 1252
+
+OS Locale (lcid: 1c3b, name: sma-SE): Sami (Southern) (Sweden) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_SE, Name: Southern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 2001, name: ar-OM): Arabic (Oman) - 1256
+
+OS Locale (lcid: 2001, name: ar-OM): Arabic (Oman) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_OM, Name: Arabic (Oman)
default charset: windows-1252
-
-OS Locale (lcid: 2009, name: en-JM): English (Jamaica) - 1252
+
+OS Locale (lcid: 2009, name: en-JM): English (Jamaica) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_JM, Name: English (Jamaica)
default charset: windows-1252
-
-OS Locale (lcid: 200a, name: es-VE): Spanish (Bolivarian Republic of Venezuela) - 1252
+
+OS Locale (lcid: 200a, name: es-VE): Spanish (Bolivarian Republic of Venezuela) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_VE, Name: Spanish (Venezuela)
default charset: windows-1252
-
-OS Locale (lcid: 201a, name: bs-Cyrl-BA): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
+
+OS Locale (lcid: 201a, name: bs-Cyrl-BA): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 201a, name: bs-Cyrl): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
+
+OS Locale (lcid: 201a, name: bs-Cyrl): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1252
-
-OS Locale (lcid: 203b, name: sms-FI): Sami (Skolt) (Finland) - 1252
+
+OS Locale (lcid: 203b, name: sms-FI): Sami (Skolt) (Finland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sms_FI, Name: Skolt Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 203b, name: sms): Sami (Skolt) (Finland) - 1252
+
+OS Locale (lcid: 203b, name: sms): Sami (Skolt) (Finland) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sms_FI, Name: Skolt Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 2401, name: ar-YE): Arabic (Yemen) - 1256
+
+OS Locale (lcid: 2401, name: ar-YE): Arabic (Yemen) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_YE, Name: Arabic (Yemen)
default charset: windows-1252
-
-OS Locale (lcid: 2409, name: en-029): English (Caribbean) - 1252
+
+OS Locale (lcid: 2409, name: en-029): English (Caribbean) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: en_029, Name: English (Caribbean)
default charset: windows-1252
-
-OS Locale (lcid: 240a, name: es-CO): Spanish (Colombia) - 1252
+
+OS Locale (lcid: 240a, name: es-CO): Spanish (Colombia) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_CO, Name: Spanish (Colombia)
default charset: windows-1252
-
-OS Locale (lcid: 241a, name: sr-Latn-RS): Serbian (Latin) (Serbia) - 1250
+
+OS Locale (lcid: 241a, name: sr-Latn-RS): Serbian (Latin) (Serbia) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+default charset: windows-1252
+
+OS Locale (lcid: 241a, name: sr-Latn): Serbian (Latin) (Serbia) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+default charset: windows-1252
+
+OS Locale (lcid: 243b, name: smn): Sami (Inari) (Finland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: smn_FI, Name: Inari Sami (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 243b, name: smn-FI): Sami (Inari) (Finland) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: smn_FI, Name: Inari Sami (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 2801, name: ar-SY): Arabic (Syria) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_SY, Name: Arabic (Syria)
+default charset: windows-1252
+
+OS Locale (lcid: 2809, name: en-BZ): English (Belize) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_BZ, Name: English (Belize)
+default charset: windows-1252
+
+OS Locale (lcid: 280a, name: es-PE): Spanish (Peru) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PE, Name: Spanish (Peru)
+default charset: windows-1252
+
+OS Locale (lcid: 281a, name: sr-Cyrl-RS): Serbian (Cyrillic) (Serbia) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
+default charset: windows-1252
+
+OS Locale (lcid: 281a, name: sr-Cyrl): Serbian (Cyrillic) (Serbia) - 1251
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
+default charset: windows-1252
+
+OS Locale (lcid: 2c01, name: ar-JO): Arabic (Jordan) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_JO, Name: Arabic (Jordan)
+default charset: windows-1252
+
+OS Locale (lcid: 2c09, name: en-TT): English (Trinidad and Tobago) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_TT, Name: English (Trinidad and Tobago)
+default charset: windows-1252
+
+OS Locale (lcid: 2c0a, name: es-AR): Spanish (Argentina) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_AR, Name: Spanish (Argentina)
default charset: windows-1252
-
-OS Locale (lcid: 241a, name: sr-Latn): Serbian (Latin) (Serbia) - 1250
+
+OS Locale (lcid: 2c1a, name: sr-Latn-ME): Serbian (Latin) (Montenegro) - 1250
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_ME_#Latn, Name: Serbian (Latin,Montenegro)
+default charset: windows-1252
+
+OS Locale (lcid: 3001, name: ar-LB): Arabic (Lebanon) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_LB, Name: Arabic (Lebanon)
+default charset: windows-1252
+
+OS Locale (lcid: 3009, name: en-ZW): English (Zimbabwe) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_ZW, Name: English (Zimbabwe)
+default charset: windows-1252
+
+OS Locale (lcid: 300a, name: es-EC): Spanish (Ecuador) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_EC, Name: Spanish (Ecuador)
+default charset: windows-1252
+
+OS Locale (lcid: 301a, name: sr-Cyrl-ME): Serbian (Cyrillic) (Montenegro) - 1251
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_ME_#Cyrl, Name: Serbian (Cyrillic,Montenegro)
+default charset: windows-1252
+
+OS Locale (lcid: 3401, name: ar-KW): Arabic (Kuwait) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_KW, Name: Arabic (Kuwait)
+default charset: windows-1252
+
+OS Locale (lcid: 3409, name: en-PH): English (Republic of the Philippines) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_PH, Name: English (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 340a, name: es-CL): Spanish (Chile) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_CL, Name: Spanish (Chile)
default charset: windows-1252
-
-OS Locale (lcid: 243b, name: smn): Sami (Inari) (Finland) - 1252
+
+OS Locale (lcid: 3801, name: ar-AE): Arabic (U.A.E.) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
+default charset: windows-1252
+
+OS Locale (lcid: 380a, name: es-UY): Spanish (Uruguay) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_UY, Name: Spanish (Uruguay)
+default charset: windows-1252
+
+OS Locale (lcid: 3c01, name: ar-BH): Arabic (Bahrain) - 1256
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_BH, Name: Arabic (Bahrain)
+default charset: windows-1252
+
+OS Locale (lcid: 3c0a, name: es-PY): Spanish (Paraguay) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PY, Name: Spanish (Paraguay)
+default charset: windows-1252
+
+OS Locale (lcid: 4001, name: ar-QA): Arabic (Qatar) - 1256
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_QA, Name: Arabic (Qatar)
+default charset: windows-1252
+
+OS Locale (lcid: 4009, name: en-IN): English (India) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_IN, Name: English (India)
+default charset: windows-1252
+
+OS Locale (lcid: 400a, name: es-BO): Spanish (Bolivia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_BO, Name: Spanish (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 4409, name: en-MY): English (Malaysia) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_MY, Name: English (Malaysia)
+default charset: windows-1252
+
+OS Locale (lcid: 440a, name: es-SV): Spanish (El Salvador) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_SV, Name: Spanish (El Salvador)
default charset: windows-1252
-
-OS Locale (lcid: 243b, name: smn-FI): Sami (Inari) (Finland) - 1252
+
+OS Locale (lcid: 4809, name: en-SG): English (Singapore) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_SG, Name: English (Singapore)
+default charset: windows-1252
+
+OS Locale (lcid: 480a, name: es-HN): Spanish (Honduras) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_HN, Name: Spanish (Honduras)
+default charset: windows-1252
+
+OS Locale (lcid: 4c0a, name: es-NI): Spanish (Nicaragua) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_NI, Name: Spanish (Nicaragua)
+default charset: windows-1252
+
+OS Locale (lcid: 500a, name: es-PR): Spanish (Puerto Rico) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PR, Name: Spanish (Puerto Rico)
+default charset: windows-1252
+
+OS Locale (lcid: 540a, name: es-US): Spanish (United States) - 1252
+default locale: ID: en_US, Name: English (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_US, Name: Spanish (United States)
+default charset: windows-1252
+
+OS UI Language (name: en-US)
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 2801, name: ar-SY): Arabic (Syria) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_SY, Name: Arabic (Syria)
-default charset: windows-1252
-
-OS Locale (lcid: 2809, name: en-BZ): English (Belize) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 280a, name: es-PE): Spanish (Peru) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PE, Name: Spanish (Peru)
-default charset: windows-1252
-
-OS Locale (lcid: 281a, name: sr-Cyrl-RS): Serbian (Cyrillic) (Serbia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
-default charset: windows-1252
-
-OS Locale (lcid: 281a, name: sr-Cyrl): Serbian (Cyrillic) (Serbia) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
-default charset: windows-1252
-
-OS Locale (lcid: 2c01, name: ar-JO): Arabic (Jordan) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_JO, Name: Arabic (Jordan)
-default charset: windows-1252
-
-OS Locale (lcid: 2c09, name: en-TT): English (Trinidad and Tobago) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 2c0a, name: es-AR): Spanish (Argentina) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_AR, Name: Spanish (Argentina)
-default charset: windows-1252
-
-OS Locale (lcid: 2c1a, name: sr-Latn-ME): Serbian (Latin) (Montenegro) - 1250
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_ME, Name: Serbian (Montenegro)
-default charset: windows-1252
-
-OS Locale (lcid: 3001, name: ar-LB): Arabic (Lebanon) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_LB, Name: Arabic (Lebanon)
-default charset: windows-1252
-
-OS Locale (lcid: 3009, name: en-ZW): English (Zimbabwe) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 300a, name: es-EC): Spanish (Ecuador) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_EC, Name: Spanish (Ecuador)
-default charset: windows-1252
-
-OS Locale (lcid: 301a, name: sr-Cyrl-ME): Serbian (Cyrillic) (Montenegro) - 1251
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_ME, Name: Serbian (Montenegro)
-default charset: windows-1252
-
-OS Locale (lcid: 3401, name: ar-KW): Arabic (Kuwait) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_KW, Name: Arabic (Kuwait)
-default charset: windows-1252
-
-OS Locale (lcid: 3409, name: en-PH): English (Republic of the Philippines) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 340a, name: es-CL): Spanish (Chile) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_CL, Name: Spanish (Chile)
-default charset: windows-1252
-
-OS Locale (lcid: 3801, name: ar-AE): Arabic (U.A.E.) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
-default charset: windows-1252
-
-OS Locale (lcid: 380a, name: es-UY): Spanish (Uruguay) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_UY, Name: Spanish (Uruguay)
-default charset: windows-1252
-
-OS Locale (lcid: 3c01, name: ar-BH): Arabic (Bahrain) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_BH, Name: Arabic (Bahrain)
-default charset: windows-1252
-
-OS Locale (lcid: 3c0a, name: es-PY): Spanish (Paraguay) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PY, Name: Spanish (Paraguay)
-default charset: windows-1252
-
-OS Locale (lcid: 4001, name: ar-QA): Arabic (Qatar) - 1256
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_QA, Name: Arabic (Qatar)
-default charset: windows-1252
-
-OS Locale (lcid: 4009, name: en-IN): English (India) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 400a, name: es-BO): Spanish (Bolivia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_BO, Name: Spanish (Bolivia)
-default charset: windows-1252
-
-OS Locale (lcid: 4409, name: en-MY): English (Malaysia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 440a, name: es-SV): Spanish (El Salvador) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_SV, Name: Spanish (El Salvador)
-default charset: windows-1252
-
-OS Locale (lcid: 4809, name: en-SG): English (Singapore) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 480a, name: es-HN): Spanish (Honduras) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_HN, Name: Spanish (Honduras)
-default charset: windows-1252
-
-OS Locale (lcid: 4c0a, name: es-NI): Spanish (Nicaragua) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_NI, Name: Spanish (Nicaragua)
-default charset: windows-1252
-
-OS Locale (lcid: 500a, name: es-PR): Spanish (Puerto Rico) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PR, Name: Spanish (Puerto Rico)
-default charset: windows-1252
-
-OS Locale (lcid: 540a, name: es-US): Spanish (United States) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es, Name: Spanish
-default charset: windows-1252
-
-OS UI Language (name: en-US)
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS UI Language (name: ja-JP)
+
+OS UI Language (name: ja-JP)
default locale: ID: ja_JP, Name: Japanese (Japan)
display locale: ID: ja_JP, Name: Japanese (Japan)
format locale: ID: en_US, Name: English (United States)
--- a/jdk/test/java/util/Locale/data/deflocale.win7.fmtasdefault Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/Locale/data/deflocale.win7.fmtasdefault Sat Nov 13 18:56:50 2010 -0800
@@ -1,1493 +1,1493 @@
-# OSVersionInfo
-# MajorVersion: 6
-# MinorVersion: 1
-# BuildNumber: 7600
-# CSDVersion:
-
-
-OS Locale (lcid: 7f, name: ): Invariant Language (Invariant Country) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 401, name: ar-SA): Arabic (Saudi Arabia) - 1256
-default locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
-default charset: windows-1256
-
-OS Locale (lcid: 402, name: bg-BG): Bulgarian (Bulgaria) - 1251
-default locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
-default charset: windows-1251
-
-OS Locale (lcid: 403, name: ca-ES): Catalan (Spain) - 1252
-default locale: ID: ca_ES, Name: Catalan (Spain)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ca_ES, Name: Catalan (Spain)
-default charset: windows-1252
-
-OS Locale (lcid: 404, name: zh-TW): Chinese (Traditional) (Taiwan) - 950
-default locale: ID: zh_TW, Name: Chinese (Taiwan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: zh_TW, Name: Chinese (Taiwan)
-default charset: x-windows-950
-
-OS Locale (lcid: 405, name: cs-CZ): Czech (Czech Republic) - 1250
-default locale: ID: cs_CZ, Name: Czech (Czech Republic)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: cs_CZ, Name: Czech (Czech Republic)
-default charset: windows-1250
-
-OS Locale (lcid: 406, name: da-DK): Danish (Denmark) - 1252
-default locale: ID: da_DK, Name: Danish (Denmark)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: da_DK, Name: Danish (Denmark)
-default charset: windows-1252
-
-OS Locale (lcid: 407, name: de-DE): German (Germany) - 1252
-default locale: ID: de_DE, Name: German (Germany)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: de_DE, Name: German (Germany)
-default charset: windows-1252
-
-OS Locale (lcid: 408, name: el-GR): Greek (Greece) - 1253
-default locale: ID: el_GR, Name: Greek (Greece)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: el_GR, Name: Greek (Greece)
-default charset: windows-1253
-
-OS Locale (lcid: 409, name: en-US): English (United States) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 40b, name: fi-FI): Finnish (Finland) - 1252
-default locale: ID: fi_FI, Name: Finnish (Finland)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fi_FI, Name: Finnish (Finland)
-default charset: windows-1252
-
-OS Locale (lcid: 40c, name: fr-FR): French (France) - 1252
-default locale: ID: fr_FR, Name: French (France)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fr_FR, Name: French (France)
-default charset: windows-1252
-
-OS Locale (lcid: 40d, name: he-IL): Hebrew (Israel) - 1255
-default locale: ID: iw_IL, Name: Hebrew (Israel)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iw_IL, Name: Hebrew (Israel)
-default charset: windows-1255
-
-OS Locale (lcid: 40e, name: hu-HU): Hungarian (Hungary) - 1250
-default locale: ID: hu_HU, Name: Hungarian (Hungary)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hu_HU, Name: Hungarian (Hungary)
-default charset: windows-1250
-
-OS Locale (lcid: 40f, name: is-IS): Icelandic (Iceland) - 1252
-default locale: ID: is_IS, Name: Icelandic (Iceland)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: is_IS, Name: Icelandic (Iceland)
-default charset: windows-1252
-
-OS Locale (lcid: 410, name: it-IT): Italian (Italy) - 1252
-default locale: ID: it_IT, Name: Italian (Italy)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: it_IT, Name: Italian (Italy)
-default charset: windows-1252
-
-OS Locale (lcid: 411, name: ja-JP): Japanese (Japan) - 932
-default locale: ID: ja_JP, Name: Japanese (Japan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ja_JP, Name: Japanese (Japan)
-default charset: windows-31j
-
-OS Locale (lcid: 412, name: ko-KR): Korean (Korea) - 949
-default locale: ID: ko_KR, Name: Korean (South Korea)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ko_KR, Name: Korean (South Korea)
-default charset: x-windows-949
-
-OS Locale (lcid: 413, name: nl-NL): Dutch (Netherlands) - 1252
-default locale: ID: nl_NL, Name: Dutch (Netherlands)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: nl_NL, Name: Dutch (Netherlands)
-default charset: windows-1252
-
-OS Locale (lcid: 414, name: nb-NO): Norwegian (Bokmål) (Norway) - 1252
-default locale: ID: no_NO, Name: Norwegian (Norway)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: no_NO, Name: Norwegian (Norway)
-default charset: windows-1252
-
-OS Locale (lcid: 415, name: pl-PL): Polish (Poland) - 1250
-default locale: ID: pl_PL, Name: Polish (Poland)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pl_PL, Name: Polish (Poland)
-default charset: windows-1250
-
-OS Locale (lcid: 416, name: pt-BR): Portuguese (Brazil) - 1252
-default locale: ID: pt_BR, Name: Portuguese (Brazil)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pt_BR, Name: Portuguese (Brazil)
-default charset: windows-1252
-
-OS Locale (lcid: 417, name: rm-CH): Romansh (Switzerland) - 1252
-default locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
-default charset: windows-1252
-
-OS Locale (lcid: 418, name: ro-RO): Romanian (Romania) - 1250
-default locale: ID: ro_RO, Name: Romanian (Romania)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ro_RO, Name: Romanian (Romania)
-default charset: windows-1250
-
-OS Locale (lcid: 419, name: ru-RU): Russian (Russia) - 1251
-default locale: ID: ru_RU, Name: Russian (Russia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ru_RU, Name: Russian (Russia)
-default charset: windows-1251
-
-OS Locale (lcid: 41a, name: hr-HR): Croatian (Croatia) - 1250
-default locale: ID: hr_HR, Name: Croatian (Croatia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hr_HR, Name: Croatian (Croatia)
-default charset: windows-1250
-
-OS Locale (lcid: 41b, name: sk-SK): Slovak (Slovakia) - 1250
-default locale: ID: sk_SK, Name: Slovak (Slovakia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sk_SK, Name: Slovak (Slovakia)
-default charset: windows-1250
-
-OS Locale (lcid: 41c, name: sq-AL): Albanian (Albania) - 1250
-default locale: ID: sq_AL, Name: Albanian (Albania)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sq_AL, Name: Albanian (Albania)
-default charset: windows-1250
-
-OS Locale (lcid: 41d, name: sv-SE): Swedish (Sweden) - 1252
-default locale: ID: sv_SE, Name: Swedish (Sweden)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sv_SE, Name: Swedish (Sweden)
-default charset: windows-1252
-
-OS Locale (lcid: 41e, name: th-TH): Thai (Thailand) - 874
-default locale: ID: th_TH, Name: Thai (Thailand)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: th_TH, Name: Thai (Thailand)
-default charset: x-windows-874
-
-OS Locale (lcid: 41f, name: tr-TR): Turkish (Turkey) - 1254
-default locale: ID: tr_TR, Name: Turkish (Turkey)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tr_TR, Name: Turkish (Turkey)
-default charset: windows-1254
-
-OS Locale (lcid: 420, name: ur-PK): Urdu (Islamic Republic of Pakistan) - 1256
-default locale: ID: ur_PK, Name: Urdu (Pakistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ur_PK, Name: Urdu (Pakistan)
-default charset: windows-1256
-
-OS Locale (lcid: 421, name: id-ID): Indonesian (Indonesia) - 1252
-default locale: ID: in_ID, Name: Indonesian (Indonesia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: in_ID, Name: Indonesian (Indonesia)
-default charset: windows-1252
-
-OS Locale (lcid: 422, name: uk-UA): Ukrainian (Ukraine) - 1251
-default locale: ID: uk_UA, Name: Ukrainian (Ukraine)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uk_UA, Name: Ukrainian (Ukraine)
-default charset: windows-1251
-
-OS Locale (lcid: 423, name: be-BY): Belarusian (Belarus) - 1251
-default locale: ID: be_BY, Name: Belarusian (Belarus)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: be_BY, Name: Belarusian (Belarus)
-default charset: windows-1251
-
-OS Locale (lcid: 424, name: sl-SI): Slovenian (Slovenia) - 1250
-default locale: ID: sl_SI, Name: Slovenian (Slovenia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sl_SI, Name: Slovenian (Slovenia)
-default charset: windows-1250
-
-OS Locale (lcid: 425, name: et-EE): Estonian (Estonia) - 1257
-default locale: ID: et_EE, Name: Estonian (Estonia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: et_EE, Name: Estonian (Estonia)
-default charset: windows-1257
-
-OS Locale (lcid: 426, name: lv-LV): Latvian (Latvia) - 1257
-default locale: ID: lv_LV, Name: Latvian (Latvia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lv_LV, Name: Latvian (Latvia)
-default charset: windows-1257
-
-OS Locale (lcid: 427, name: lt-LT): Lithuanian (Lithuania) - 1257
-default locale: ID: lt_LT, Name: Lithuanian (Lithuania)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
-default charset: windows-1257
-
-OS Locale (lcid: 428, name: tg-Cyrl-TJ): Tajik (Cyrillic) (Tajikistan) - 1251
-default locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-default charset: windows-1251
-
-OS Locale (lcid: 428, name: tg-Cyrl): Tajik (Cyrillic) (Tajikistan) - 1251
-default locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tg_TJ, Name: Tajik (Tajikistan)
-default charset: windows-1251
-
-OS Locale (lcid: 429, name: fa-IR): Persian (Iran) - 1256
-default locale: ID: fa_IR, Name: Persian (Iran)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fa_IR, Name: Persian (Iran)
-default charset: windows-1256
-
-OS Locale (lcid: 42a, name: vi-VN): Vietnamese (Vietnam) - 1258
-default locale: ID: vi_VN, Name: Vietnamese (Vietnam)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: vi_VN, Name: Vietnamese (Vietnam)
-default charset: windows-1258
-
-OS Locale (lcid: 42b, name: hy-AM): Armenian (Armenia) - 0
-default locale: ID: hy_AM, Name: Armenian (Armenia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hy_AM, Name: Armenian (Armenia)
-default charset: UTF-8
-
-OS Locale (lcid: 42c, name: az-Latn-AZ): Azeri (Latin) (Azerbaijan) - 1254
-default locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-default charset: windows-1254
-
-OS Locale (lcid: 42c, name: az-Latn): Azeri (Latin) (Azerbaijan) - 1254
-default locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
-default charset: windows-1254
-
-OS Locale (lcid: 42d, name: eu-ES): Basque (Spain) - 1252
-default locale: ID: eu_ES, Name: Basque (Spain)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: eu_ES, Name: Basque (Spain)
-default charset: windows-1252
-
-OS Locale (lcid: 42e, name: hsb-DE): Upper Sorbian (Germany) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 42e, name: hsb): Upper Sorbian (Germany) - 1252
+# OSVersionInfo
+# MajorVersion: 6
+# MinorVersion: 1
+# BuildNumber: 7600
+# CSDVersion:
+
+
+OS Locale (lcid: 7f, name: ): Invariant Language (Invariant Country) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 42f, name: mk-MK): Macedonian (FYROM) (Macedonia (FYROM)) - 1251
-default locale: ID: mk_MK, Name: Macedonian (Macedonia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mk_MK, Name: Macedonian (Macedonia)
-default charset: windows-1251
-
-OS Locale (lcid: 432, name: tn-ZA): Setswana (South Africa) - 1252
-default locale: ID: tn_ZA, Name: Tswana (South Africa)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tn_ZA, Name: Tswana (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 434, name: xh-ZA): isiXhosa (South Africa) - 1252
-default locale: ID: xh_ZA, Name: Xhosa (South Africa)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: xh_ZA, Name: Xhosa (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 435, name: zu-ZA): isiZulu (South Africa) - 1252
-default locale: ID: zu_ZA, Name: Zulu (South Africa)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: zu_ZA, Name: Zulu (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 436, name: af-ZA): Afrikaans (South Africa) - 1252
-default locale: ID: af_ZA, Name: Afrikaans (South Africa)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: af_ZA, Name: Afrikaans (South Africa)
-default charset: windows-1252
-
-OS Locale (lcid: 437, name: ka-GE): Georgian (Georgia) - 0
-default locale: ID: ka_GE, Name: Georgian (Georgia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ka_GE, Name: Georgian (Georgia)
-default charset: UTF-8
-
-OS Locale (lcid: 438, name: fo-FO): Faroese (Faroe Islands) - 1252
-default locale: ID: fo_FO, Name: Faroese (Faroe Islands)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fo_FO, Name: Faroese (Faroe Islands)
-default charset: windows-1252
-
-OS Locale (lcid: 439, name: hi-IN): Hindi (India) - 0
-default locale: ID: hi_IN, Name: Hindi (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: hi_IN, Name: Hindi (India)
-default charset: UTF-8
-
-OS Locale (lcid: 43a, name: mt-MT): Maltese (Malta) - 0
-default locale: ID: mt_MT, Name: Maltese (Malta)
+
+OS Locale (lcid: 401, name: ar-SA): Arabic (Saudi Arabia) - 1256
+default locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mt_MT, Name: Maltese (Malta)
-default charset: UTF-8
-
-OS Locale (lcid: 43b, name: se-NO): Sami (Northern) (Norway) - 1252
-default locale: ID: se_NO, Name: Northern Sami (Norway)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: se_NO, Name: Northern Sami (Norway)
-default charset: windows-1252
-
-OS Locale (lcid: 43e, name: ms-MY): Malay (Malaysia) - 1252
-default locale: ID: ms_MY, Name: Malay (Malaysia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ms_MY, Name: Malay (Malaysia)
-default charset: windows-1252
-
-OS Locale (lcid: 43f, name: kk-KZ): Kazakh (Kazakhstan) - 0
-default locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
-default charset: UTF-8
-
-OS Locale (lcid: 440, name: ky-KG): Kyrgyz (Kyrgyzstan) - 1251
-default locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
+format locale: ID: ar_SA, Name: Arabic (Saudi Arabia)
+default charset: windows-1256
+
+OS Locale (lcid: 402, name: bg-BG): Bulgarian (Bulgaria) - 1251
+default locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
-default charset: windows-1251
-
-OS Locale (lcid: 441, name: sw-KE): Kiswahili (Kenya) - 1252
-default locale: ID: sw_KE, Name: Swahili (Kenya)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sw_KE, Name: Swahili (Kenya)
-default charset: windows-1252
-
-OS Locale (lcid: 442, name: tk-TM): Turkmen (Turkmenistan) - 1250
-default locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
-default charset: windows-1250
-
-OS Locale (lcid: 443, name: uz-Latn): Uzbek (Latin) (Uzbekistan) - 1254
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-default charset: windows-1254
-
-OS Locale (lcid: 443, name: uz-Latn-UZ): Uzbek (Latin) (Uzbekistan) - 1254
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
-default charset: windows-1254
-
-OS Locale (lcid: 444, name: tt-RU): Tatar (Russia) - 1251
-default locale: ID: tt_RU, Name: Tatar (Russia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: tt_RU, Name: Tatar (Russia)
+format locale: ID: bg_BG, Name: Bulgarian (Bulgaria)
default charset: windows-1251
-
-OS Locale (lcid: 445, name: bn-IN): Bengali (India) - 0
-default locale: ID: bn_IN, Name: Bengali (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bn_IN, Name: Bengali (India)
-default charset: UTF-8
-
-OS Locale (lcid: 446, name: pa-IN): Punjabi (India) - 0
-default locale: ID: pa_IN, Name: Panjabi (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: pa_IN, Name: Panjabi (India)
-default charset: UTF-8
-
-OS Locale (lcid: 447, name: gu-IN): Gujarati (India) - 0
-default locale: ID: gu_IN, Name: Gujarati (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: gu_IN, Name: Gujarati (India)
-default charset: UTF-8
-
-OS Locale (lcid: 448, name: or-IN): Oriya (India) - 0
-default locale: ID: or_IN, Name: Oriya (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: or_IN, Name: Oriya (India)
-default charset: UTF-8
-
-OS Locale (lcid: 449, name: ta-IN): Tamil (India) - 0
-default locale: ID: ta_IN, Name: Tamil (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ta_IN, Name: Tamil (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44a, name: te-IN): Telugu (India) - 0
-default locale: ID: te_IN, Name: Telugu (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: te_IN, Name: Telugu (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44b, name: kn-IN): Kannada (India) - 0
-default locale: ID: kn_IN, Name: Kannada (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kn_IN, Name: Kannada (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44c, name: ml-IN): Malayalam (India) - 0
-default locale: ID: ml_IN, Name: Malayalam (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ml_IN, Name: Malayalam (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44d, name: as-IN): Assamese (India) - 0
-default locale: ID: as_IN, Name: Assamese (India)
+
+OS Locale (lcid: 403, name: ca-ES): Catalan (Spain) - 1252
+default locale: ID: ca_ES, Name: Catalan (Spain)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: as_IN, Name: Assamese (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44e, name: mr-IN): Marathi (India) - 0
-default locale: ID: mr_IN, Name: Marathi (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mr_IN, Name: Marathi (India)
-default charset: UTF-8
-
-OS Locale (lcid: 44f, name: sa-IN): Sanskrit (India) - 0
-default locale: ID: sa_IN, Name: Sanskrit (India)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sa_IN, Name: Sanskrit (India)
-default charset: UTF-8
-
-OS Locale (lcid: 450, name: mn-MN): Mongolian (Cyrillic) (Mongolia) - 1251
-default locale: ID: mn_MN, Name: Mongolian (Mongolia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_MN, Name: Mongolian (Mongolia)
-default charset: windows-1251
-
-OS Locale (lcid: 450, name: mn-Cyrl): Mongolian (Cyrillic) (Mongolia) - 1251
-default locale: ID: mn_MN, Name: Mongolian (Mongolia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_MN, Name: Mongolian (Mongolia)
-default charset: windows-1251
-
-OS Locale (lcid: 451, name: bo-CN): Tibetan (People's Republic of China) - 0
-default locale: ID: bo_CN, Name: Tibetan (China)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: bo_CN, Name: Tibetan (China)
-default charset: UTF-8
-
-OS Locale (lcid: 452, name: cy-GB): Welsh (United Kingdom) - 1252
-default locale: ID: cy_GB, Name: Welsh (United Kingdom)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: cy_GB, Name: Welsh (United Kingdom)
-default charset: windows-1252
-
-OS Locale (lcid: 453, name: km-KH): Khmer (Cambodia) - 0
-default locale: ID: km_KH, Name: Khmer (Cambodia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: km_KH, Name: Khmer (Cambodia)
-default charset: UTF-8
-
-OS Locale (lcid: 454, name: lo-LA): Lao (Lao P.D.R.) - 0
-default locale: ID: lo_LA, Name: Lao (Laos)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lo_LA, Name: Lao (Laos)
-default charset: UTF-8
-
-OS Locale (lcid: 456, name: gl-ES): Galician (Spain) - 1252
-default locale: ID: gl_ES, Name: Gallegan (Spain)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: gl_ES, Name: Gallegan (Spain)
+format locale: ID: ca_ES, Name: Catalan (Spain)
default charset: windows-1252
-
-OS Locale (lcid: 457, name: kok-IN): Konkani (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: UTF-8
-
-OS Locale (lcid: 457, name: kok): Konkani (India) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: UTF-8
-
-OS Locale (lcid: 45a, name: syr): Syriac (Syria) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: UTF-8
-
-OS Locale (lcid: 45a, name: syr-SY): Syriac (Syria) - 0
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: UTF-8
-
-OS Locale (lcid: 45b, name: si-LK): Sinhala (Sri Lanka) - 0
-default locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
-default charset: UTF-8
-
-OS Locale (lcid: 45d, name: iu-Cans-CA): Inuktitut (Syllabics) (Canada) - 0
-default locale: ID: iu_CA, Name: Inuktitut (Canada)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
-default charset: UTF-8
-
-OS Locale (lcid: 45d, name: iu-Cans): Inuktitut (Syllabics) (Canada) - 0
-default locale: ID: iu_CA, Name: Inuktitut (Canada)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
-default charset: UTF-8
-
-OS Locale (lcid: 45e, name: am-ET): Amharic (Ethiopia) - 0
-default locale: ID: am_ET, Name: Amharic (Ethiopia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: am_ET, Name: Amharic (Ethiopia)
-default charset: UTF-8
-
-OS Locale (lcid: 461, name: ne-NP): Nepali (Nepal) - 0
-default locale: ID: ne_NP, Name: Nepali (Nepal)
+
+OS Locale (lcid: 404, name: zh-TW): Chinese (Traditional) (Taiwan) - 950
+default locale: ID: zh_TW, Name: Chinese (Taiwan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ne_NP, Name: Nepali (Nepal)
-default charset: UTF-8
-
-OS Locale (lcid: 462, name: fy-NL): Frisian (Netherlands) - 1252
-default locale: ID: fy_NL, Name: Frisian (Netherlands)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: fy_NL, Name: Frisian (Netherlands)
-default charset: windows-1252
-
-OS Locale (lcid: 463, name: ps-AF): Pashto (Afghanistan) - 0
-default locale: ID: ps_AF, Name: Pushto (Afghanistan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ps_AF, Name: Pushto (Afghanistan)
-default charset: UTF-8
-
-OS Locale (lcid: 464, name: fil-PH): Filipino (Philippines) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 464, name: fil): Filipino (Philippines) - 1252
-default locale: ID: en_US, Name: English (United States)
+format locale: ID: zh_TW, Name: Chinese (Taiwan)
+default charset: x-windows-950
+
+OS Locale (lcid: 405, name: cs-CZ): Czech (Czech Republic) - 1250
+default locale: ID: cs_CZ, Name: Czech (Czech Republic)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 465, name: dv-MV): Divehi (Maldives) - 0
-default locale: ID: dv_MV, Name: Divehi (Maldives)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: dv_MV, Name: Divehi (Maldives)
-default charset: UTF-8
-
-OS Locale (lcid: 468, name: ha-Latn-NG): Hausa (Latin) (Nigeria) - 1252
-default locale: ID: ha_NG, Name: Hausa (Nigeria)
+format locale: ID: cs_CZ, Name: Czech (Czech Republic)
+default charset: windows-1250
+
+OS Locale (lcid: 406, name: da-DK): Danish (Denmark) - 1252
+default locale: ID: da_DK, Name: Danish (Denmark)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ha_NG, Name: Hausa (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 468, name: ha-Latn): Hausa (Latin) (Nigeria) - 1252
-default locale: ID: ha_NG, Name: Hausa (Nigeria)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ha_NG, Name: Hausa (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 46a, name: yo-NG): Yoruba (Nigeria) - 1252
-default locale: ID: yo_NG, Name: Yoruba (Nigeria)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: yo_NG, Name: Yoruba (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 46b, name: quz): Quechua (Bolivia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: da_DK, Name: Danish (Denmark)
default charset: windows-1252
-
-OS Locale (lcid: 46b, name: quz-BO): Quechua (Bolivia) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46c, name: nso): Sesotho sa Leboa (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46c, name: nso-ZA): Sesotho sa Leboa (South Africa) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 46d, name: ba-RU): Bashkir (Russia) - 1251
-default locale: ID: ba_RU, Name: Bashkir (Russia)
+
+OS Locale (lcid: 407, name: de-DE): German (Germany) - 1252
+default locale: ID: de_DE, Name: German (Germany)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ba_RU, Name: Bashkir (Russia)
-default charset: windows-1251
-
-OS Locale (lcid: 46e, name: lb-LU): Luxembourgish (Luxembourg) - 1252
-default locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
-default charset: windows-1252
-
-OS Locale (lcid: 46f, name: kl-GL): Greenlandic (Greenland) - 1252
-default locale: ID: kl_GL, Name: Greenlandic (Greenland)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: kl_GL, Name: Greenlandic (Greenland)
-default charset: windows-1252
-
-OS Locale (lcid: 470, name: ig-NG): Igbo (Nigeria) - 1252
-default locale: ID: ig_NG, Name: Igbo (Nigeria)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ig_NG, Name: Igbo (Nigeria)
-default charset: windows-1252
-
-OS Locale (lcid: 478, name: ii-CN): Yi (People's Republic of China) - 0
-default locale: ID: ii_CN, Name: Sichuan Yi (China)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ii_CN, Name: Sichuan Yi (China)
-default charset: UTF-8
-
-OS Locale (lcid: 47a, name: arn): Mapudungun (Chile) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: de_DE, Name: German (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 47a, name: arn-CL): Mapudungun (Chile) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47c, name: moh): Mohawk (Canada) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47c, name: moh-CA): Mohawk (Canada) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 47e, name: br-FR): Breton (France) - 1252
-default locale: ID: br_FR, Name: Breton (France)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: br_FR, Name: Breton (France)
-default charset: windows-1252
-
-OS Locale (lcid: 480, name: ug-CN): Uyghur (People's Republic of China) - 1256
-default locale: ID: ug_CN, Name: Uighur (China)
+
+OS Locale (lcid: 408, name: el-GR): Greek (Greece) - 1253
+default locale: ID: el_GR, Name: Greek (Greece)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: ug_CN, Name: Uighur (China)
-default charset: windows-1256
-
-OS Locale (lcid: 481, name: mi-NZ): Maori (New Zealand) - 0
-default locale: ID: mi_NZ, Name: Maori (New Zealand)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: mi_NZ, Name: Maori (New Zealand)
-default charset: UTF-8
-
-OS Locale (lcid: 482, name: oc-FR): Occitan (France) - 1252
-default locale: ID: oc_FR, Name: Occitan (France)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: oc_FR, Name: Occitan (France)
-default charset: windows-1252
-
-OS Locale (lcid: 483, name: co-FR): Corsican (France) - 1252
-default locale: ID: co_FR, Name: Corsican (France)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: co_FR, Name: Corsican (France)
-default charset: windows-1252
-
-OS Locale (lcid: 484, name: gsw): Alsatian (France) - 1252
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS Locale (lcid: 484, name: gsw-FR): Alsatian (France) - 1252
+format locale: ID: el_GR, Name: Greek (Greece)
+default charset: windows-1253
+
+OS Locale (lcid: 409, name: en-US): English (United States) - 1252
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 485, name: sah): Yakut (Russia) - 1251
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 40b, name: fi-FI): Finnish (Finland) - 1252
+default locale: ID: fi_FI, Name: Finnish (Finland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fi_FI, Name: Finnish (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 40c, name: fr-FR): French (France) - 1252
+default locale: ID: fr_FR, Name: French (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fr_FR, Name: French (France)
+default charset: windows-1252
+
+OS Locale (lcid: 40d, name: he-IL): Hebrew (Israel) - 1255
+default locale: ID: iw_IL, Name: Hebrew (Israel)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iw_IL, Name: Hebrew (Israel)
+default charset: windows-1255
+
+OS Locale (lcid: 40e, name: hu-HU): Hungarian (Hungary) - 1250
+default locale: ID: hu_HU, Name: Hungarian (Hungary)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hu_HU, Name: Hungarian (Hungary)
+default charset: windows-1250
+
+OS Locale (lcid: 40f, name: is-IS): Icelandic (Iceland) - 1252
+default locale: ID: is_IS, Name: Icelandic (Iceland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: is_IS, Name: Icelandic (Iceland)
+default charset: windows-1252
+
+OS Locale (lcid: 410, name: it-IT): Italian (Italy) - 1252
+default locale: ID: it_IT, Name: Italian (Italy)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: it_IT, Name: Italian (Italy)
+default charset: windows-1252
+
+OS Locale (lcid: 411, name: ja-JP): Japanese (Japan) - 932
+default locale: ID: ja_JP, Name: Japanese (Japan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ja_JP, Name: Japanese (Japan)
+default charset: windows-31j
+
+OS Locale (lcid: 412, name: ko-KR): Korean (Korea) - 949
+default locale: ID: ko_KR, Name: Korean (South Korea)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ko_KR, Name: Korean (South Korea)
+default charset: x-windows-949
+
+OS Locale (lcid: 413, name: nl-NL): Dutch (Netherlands) - 1252
+default locale: ID: nl_NL, Name: Dutch (Netherlands)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nl_NL, Name: Dutch (Netherlands)
+default charset: windows-1252
+
+OS Locale (lcid: 414, name: nb-NO): Norwegian (Bokm…l) (Norway) - 1252
+default locale: ID: no_NO, Name: Norwegian (Norway)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: no_NO, Name: Norwegian (Norway)
+default charset: windows-1252
+
+OS Locale (lcid: 415, name: pl-PL): Polish (Poland) - 1250
+default locale: ID: pl_PL, Name: Polish (Poland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: pl_PL, Name: Polish (Poland)
+default charset: windows-1250
+
+OS Locale (lcid: 416, name: pt-BR): Portuguese (Brazil) - 1252
+default locale: ID: pt_BR, Name: Portuguese (Brazil)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: pt_BR, Name: Portuguese (Brazil)
+default charset: windows-1252
+
+OS Locale (lcid: 417, name: rm-CH): Romansh (Switzerland) - 1252
+default locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: rm_CH, Name: Raeto-Romance (Switzerland)
+default charset: windows-1252
+
+OS Locale (lcid: 418, name: ro-RO): Romanian (Romania) - 1250
+default locale: ID: ro_RO, Name: Romanian (Romania)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ro_RO, Name: Romanian (Romania)
+default charset: windows-1250
+
+OS Locale (lcid: 419, name: ru-RU): Russian (Russia) - 1251
+default locale: ID: ru_RU, Name: Russian (Russia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ru_RU, Name: Russian (Russia)
+default charset: windows-1251
+
+OS Locale (lcid: 41a, name: hr-HR): Croatian (Croatia) - 1250
+default locale: ID: hr_HR, Name: Croatian (Croatia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hr_HR, Name: Croatian (Croatia)
+default charset: windows-1250
+
+OS Locale (lcid: 41b, name: sk-SK): Slovak (Slovakia) - 1250
+default locale: ID: sk_SK, Name: Slovak (Slovakia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sk_SK, Name: Slovak (Slovakia)
+default charset: windows-1250
+
+OS Locale (lcid: 41c, name: sq-AL): Albanian (Albania) - 1250
+default locale: ID: sq_AL, Name: Albanian (Albania)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sq_AL, Name: Albanian (Albania)
+default charset: windows-1250
+
+OS Locale (lcid: 41d, name: sv-SE): Swedish (Sweden) - 1252
+default locale: ID: sv_SE, Name: Swedish (Sweden)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sv_SE, Name: Swedish (Sweden)
+default charset: windows-1252
+
+OS Locale (lcid: 41e, name: th-TH): Thai (Thailand) - 874
+default locale: ID: th_TH, Name: Thai (Thailand)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: th_TH, Name: Thai (Thailand)
+default charset: x-windows-874
+
+OS Locale (lcid: 41f, name: tr-TR): Turkish (Turkey) - 1254
+default locale: ID: tr_TR, Name: Turkish (Turkey)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tr_TR, Name: Turkish (Turkey)
+default charset: windows-1254
+
+OS Locale (lcid: 420, name: ur-PK): Urdu (Islamic Republic of Pakistan) - 1256
+default locale: ID: ur_PK, Name: Urdu (Pakistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ur_PK, Name: Urdu (Pakistan)
+default charset: windows-1256
+
+OS Locale (lcid: 421, name: id-ID): Indonesian (Indonesia) - 1252
+default locale: ID: in_ID, Name: Indonesian (Indonesia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: in_ID, Name: Indonesian (Indonesia)
+default charset: windows-1252
+
+OS Locale (lcid: 422, name: uk-UA): Ukrainian (Ukraine) - 1251
+default locale: ID: uk_UA, Name: Ukrainian (Ukraine)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uk_UA, Name: Ukrainian (Ukraine)
+default charset: windows-1251
+
+OS Locale (lcid: 423, name: be-BY): Belarusian (Belarus) - 1251
+default locale: ID: be_BY, Name: Belarusian (Belarus)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: be_BY, Name: Belarusian (Belarus)
default charset: windows-1251
-
-OS Locale (lcid: 485, name: sah-RU): Yakut (Russia) - 1251
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 424, name: sl-SI): Slovenian (Slovenia) - 1250
+default locale: ID: sl_SI, Name: Slovenian (Slovenia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sl_SI, Name: Slovenian (Slovenia)
+default charset: windows-1250
+
+OS Locale (lcid: 425, name: et-EE): Estonian (Estonia) - 1257
+default locale: ID: et_EE, Name: Estonian (Estonia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: et_EE, Name: Estonian (Estonia)
+default charset: windows-1257
+
+OS Locale (lcid: 426, name: lv-LV): Latvian (Latvia) - 1257
+default locale: ID: lv_LV, Name: Latvian (Latvia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lv_LV, Name: Latvian (Latvia)
+default charset: windows-1257
+
+OS Locale (lcid: 427, name: lt-LT): Lithuanian (Lithuania) - 1257
+default locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lt_LT, Name: Lithuanian (Lithuania)
+default charset: windows-1257
+
+OS Locale (lcid: 428, name: tg-Cyrl-TJ): Tajik (Cyrillic) (Tajikistan) - 1251
+default locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+default charset: windows-1251
+
+OS Locale (lcid: 428, name: tg-Cyrl): Tajik (Cyrillic) (Tajikistan) - 1251
+default locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tg_TJ_#Cyrl, Name: Tajik (Cyrillic,Tajikistan)
+default charset: windows-1251
+
+OS Locale (lcid: 429, name: fa-IR): Persian (Iran) - 1256
+default locale: ID: fa_IR, Name: Persian (Iran)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fa_IR, Name: Persian (Iran)
+default charset: windows-1256
+
+OS Locale (lcid: 42a, name: vi-VN): Vietnamese (Vietnam) - 1258
+default locale: ID: vi_VN, Name: Vietnamese (Vietnam)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: vi_VN, Name: Vietnamese (Vietnam)
+default charset: windows-1258
+
+OS Locale (lcid: 42b, name: hy-AM): Armenian (Armenia) - 0
+default locale: ID: hy_AM, Name: Armenian (Armenia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hy_AM, Name: Armenian (Armenia)
+default charset: UTF-8
+
+OS Locale (lcid: 42c, name: az-Latn-AZ): Azeri (Latin) (Azerbaijan) - 1254
+default locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+default charset: windows-1254
+
+OS Locale (lcid: 42c, name: az-Latn): Azeri (Latin) (Azerbaijan) - 1254
+default locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: az_AZ_#Latn, Name: Azerbaijani (Latin,Azerbaijan)
+default charset: windows-1254
+
+OS Locale (lcid: 42d, name: eu-ES): Basque (Spain) - 1252
+default locale: ID: eu_ES, Name: Basque (Spain)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: eu_ES, Name: Basque (Spain)
+default charset: windows-1252
+
+OS Locale (lcid: 42e, name: hsb-DE): Upper Sorbian (Germany) - 1252
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+default charset: windows-1252
+
+OS Locale (lcid: 42e, name: hsb): Upper Sorbian (Germany) - 1252
+default locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hsb_DE, Name: Upper Sorbian (Germany)
+default charset: windows-1252
+
+OS Locale (lcid: 42f, name: mk-MK): Macedonian (FYROM) (Macedonia (FYROM)) - 1251
+default locale: ID: mk_MK, Name: Macedonian (Macedonia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mk_MK, Name: Macedonian (Macedonia)
+default charset: windows-1251
+
+OS Locale (lcid: 432, name: tn-ZA): Setswana (South Africa) - 1252
+default locale: ID: tn_ZA, Name: Tswana (South Africa)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tn_ZA, Name: Tswana (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 434, name: xh-ZA): isiXhosa (South Africa) - 1252
+default locale: ID: xh_ZA, Name: Xhosa (South Africa)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: xh_ZA, Name: Xhosa (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 435, name: zu-ZA): isiZulu (South Africa) - 1252
+default locale: ID: zu_ZA, Name: Zulu (South Africa)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: zu_ZA, Name: Zulu (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 436, name: af-ZA): Afrikaans (South Africa) - 1252
+default locale: ID: af_ZA, Name: Afrikaans (South Africa)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: af_ZA, Name: Afrikaans (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 437, name: ka-GE): Georgian (Georgia) - 0
+default locale: ID: ka_GE, Name: Georgian (Georgia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ka_GE, Name: Georgian (Georgia)
+default charset: UTF-8
+
+OS Locale (lcid: 438, name: fo-FO): Faroese (Faroe Islands) - 1252
+default locale: ID: fo_FO, Name: Faroese (Faroe Islands)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fo_FO, Name: Faroese (Faroe Islands)
+default charset: windows-1252
+
+OS Locale (lcid: 439, name: hi-IN): Hindi (India) - 0
+default locale: ID: hi_IN, Name: Hindi (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: hi_IN, Name: Hindi (India)
+default charset: UTF-8
+
+OS Locale (lcid: 43a, name: mt-MT): Maltese (Malta) - 0
+default locale: ID: mt_MT, Name: Maltese (Malta)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mt_MT, Name: Maltese (Malta)
+default charset: UTF-8
+
+OS Locale (lcid: 43b, name: se-NO): Sami (Northern) (Norway) - 1252
+default locale: ID: se_NO, Name: Northern Sami (Norway)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: se_NO, Name: Northern Sami (Norway)
+default charset: windows-1252
+
+OS Locale (lcid: 43e, name: ms-MY): Malay (Malaysia) - 1252
+default locale: ID: ms_MY, Name: Malay (Malaysia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ms_MY, Name: Malay (Malaysia)
+default charset: windows-1252
+
+OS Locale (lcid: 43f, name: kk-KZ): Kazakh (Kazakhstan) - 0
+default locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kk_KZ, Name: Kazakh (Kazakhstan)
+default charset: UTF-8
+
+OS Locale (lcid: 440, name: ky-KG): Kyrgyz (Kyrgyzstan) - 1251
+default locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ky_KG, Name: Kirghiz (Kyrgyzstan)
+default charset: windows-1251
+
+OS Locale (lcid: 441, name: sw-KE): Kiswahili (Kenya) - 1252
+default locale: ID: sw_KE, Name: Swahili (Kenya)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sw_KE, Name: Swahili (Kenya)
+default charset: windows-1252
+
+OS Locale (lcid: 442, name: tk-TM): Turkmen (Turkmenistan) - 1250
+default locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tk_TM, Name: Turkmen (Turkmenistan)
+default charset: windows-1250
+
+OS Locale (lcid: 443, name: uz-Latn): Uzbek (Latin) (Uzbekistan) - 1254
+default locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+default charset: windows-1254
+
+OS Locale (lcid: 443, name: uz-Latn-UZ): Uzbek (Latin) (Uzbekistan) - 1254
+default locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: uz_UZ_#Latn, Name: Uzbek (Latin,Uzbekistan)
+default charset: windows-1254
+
+OS Locale (lcid: 444, name: tt-RU): Tatar (Russia) - 1251
+default locale: ID: tt_RU, Name: Tatar (Russia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: tt_RU, Name: Tatar (Russia)
default charset: windows-1251
-
-OS Locale (lcid: 486, name: qut): K'iche (Guatemala) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 445, name: bn-IN): Bengali (India) - 0
+default locale: ID: bn_IN, Name: Bengali (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: bn_IN, Name: Bengali (India)
+default charset: UTF-8
+
+OS Locale (lcid: 446, name: pa-IN): Punjabi (India) - 0
+default locale: ID: pa_IN, Name: Panjabi (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: pa_IN, Name: Panjabi (India)
+default charset: UTF-8
+
+OS Locale (lcid: 447, name: gu-IN): Gujarati (India) - 0
+default locale: ID: gu_IN, Name: Gujarati (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gu_IN, Name: Gujarati (India)
+default charset: UTF-8
+
+OS Locale (lcid: 448, name: or-IN): Oriya (India) - 0
+default locale: ID: or_IN, Name: Oriya (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: or_IN, Name: Oriya (India)
+default charset: UTF-8
+
+OS Locale (lcid: 449, name: ta-IN): Tamil (India) - 0
+default locale: ID: ta_IN, Name: Tamil (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ta_IN, Name: Tamil (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44a, name: te-IN): Telugu (India) - 0
+default locale: ID: te_IN, Name: Telugu (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: te_IN, Name: Telugu (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44b, name: kn-IN): Kannada (India) - 0
+default locale: ID: kn_IN, Name: Kannada (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kn_IN, Name: Kannada (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44c, name: ml-IN): Malayalam (India) - 0
+default locale: ID: ml_IN, Name: Malayalam (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ml_IN, Name: Malayalam (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44d, name: as-IN): Assamese (India) - 0
+default locale: ID: as_IN, Name: Assamese (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: as_IN, Name: Assamese (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44e, name: mr-IN): Marathi (India) - 0
+default locale: ID: mr_IN, Name: Marathi (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mr_IN, Name: Marathi (India)
+default charset: UTF-8
+
+OS Locale (lcid: 44f, name: sa-IN): Sanskrit (India) - 0
+default locale: ID: sa_IN, Name: Sanskrit (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sa_IN, Name: Sanskrit (India)
+default charset: UTF-8
+
+OS Locale (lcid: 450, name: mn-MN): Mongolian (Cyrillic) (Mongolia) - 1251
+default locale: ID: mn_MN, Name: Mongolian (Mongolia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mn_MN, Name: Mongolian (Mongolia)
+default charset: windows-1251
+
+OS Locale (lcid: 450, name: mn-Cyrl): Mongolian (Cyrillic) (Mongolia) - 1251
+default locale: ID: mn_MN, Name: Mongolian (Mongolia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mn_MN, Name: Mongolian (Mongolia)
+default charset: windows-1251
+
+OS Locale (lcid: 451, name: bo-CN): Tibetan (People's Republic of China) - 0
+default locale: ID: bo_CN, Name: Tibetan (China)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: bo_CN, Name: Tibetan (China)
+default charset: UTF-8
+
+OS Locale (lcid: 452, name: cy-GB): Welsh (United Kingdom) - 1252
+default locale: ID: cy_GB, Name: Welsh (United Kingdom)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: cy_GB, Name: Welsh (United Kingdom)
+default charset: windows-1252
+
+OS Locale (lcid: 453, name: km-KH): Khmer (Cambodia) - 0
+default locale: ID: km_KH, Name: Khmer (Cambodia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: km_KH, Name: Khmer (Cambodia)
+default charset: UTF-8
+
+OS Locale (lcid: 454, name: lo-LA): Lao (Lao P.D.R.) - 0
+default locale: ID: lo_LA, Name: Lao (Laos)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lo_LA, Name: Lao (Laos)
+default charset: UTF-8
+
+OS Locale (lcid: 456, name: gl-ES): Galician (Spain) - 1252
+default locale: ID: gl_ES, Name: Gallegan (Spain)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gl_ES, Name: Gallegan (Spain)
+default charset: windows-1252
+
+OS Locale (lcid: 457, name: kok-IN): Konkani (India) - 0
+default locale: ID: kok_IN, Name: Konkani (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kok_IN, Name: Konkani (India)
+default charset: UTF-8
+
+OS Locale (lcid: 457, name: kok): Konkani (India) - 0
+default locale: ID: kok_IN, Name: Konkani (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kok_IN, Name: Konkani (India)
+default charset: UTF-8
+
+OS Locale (lcid: 45a, name: syr): Syriac (Syria) - 0
+default locale: ID: syr_SY, Name: Syriac (Syria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: syr_SY, Name: Syriac (Syria)
+default charset: UTF-8
+
+OS Locale (lcid: 45a, name: syr-SY): Syriac (Syria) - 0
+default locale: ID: syr_SY, Name: Syriac (Syria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: syr_SY, Name: Syriac (Syria)
+default charset: UTF-8
+
+OS Locale (lcid: 45b, name: si-LK): Sinhala (Sri Lanka) - 0
+default locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: si_LK, Name: Sinhalese (Sri Lanka)
+default charset: UTF-8
+
+OS Locale (lcid: 45d, name: iu-Cans-CA): Inuktitut (Syllabics) (Canada) - 0
+default locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+default charset: UTF-8
+
+OS Locale (lcid: 45d, name: iu-Cans): Inuktitut (Syllabics) (Canada) - 0
+default locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: iu_CA_#Cans, Name: Inuktitut (Unified Canadian Aboriginal Syllabics,Canada)
+default charset: UTF-8
+
+OS Locale (lcid: 45e, name: am-ET): Amharic (Ethiopia) - 0
+default locale: ID: am_ET, Name: Amharic (Ethiopia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: am_ET, Name: Amharic (Ethiopia)
+default charset: UTF-8
+
+OS Locale (lcid: 461, name: ne-NP): Nepali (Nepal) - 0
+default locale: ID: ne_NP, Name: Nepali (Nepal)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ne_NP, Name: Nepali (Nepal)
+default charset: UTF-8
+
+OS Locale (lcid: 462, name: fy-NL): Frisian (Netherlands) - 1252
+default locale: ID: fy_NL, Name: Frisian (Netherlands)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fy_NL, Name: Frisian (Netherlands)
default charset: windows-1252
-
-OS Locale (lcid: 486, name: qut-GT): K'iche (Guatemala) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 463, name: ps-AF): Pashto (Afghanistan) - 0
+default locale: ID: ps_AF, Name: Pushto (Afghanistan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ps_AF, Name: Pushto (Afghanistan)
+default charset: UTF-8
+
+OS Locale (lcid: 464, name: fil-PH): Filipino (Philippines) - 1252
+default locale: ID: fil_PH, Name: Filipino (Philippines)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fil_PH, Name: Filipino (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 464, name: fil): Filipino (Philippines) - 1252
+default locale: ID: fil_PH, Name: Filipino (Philippines)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: fil_PH, Name: Filipino (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 465, name: dv-MV): Divehi (Maldives) - 0
+default locale: ID: dv_MV, Name: Divehi (Maldives)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: dv_MV, Name: Divehi (Maldives)
+default charset: UTF-8
+
+OS Locale (lcid: 468, name: ha-Latn-NG): Hausa (Latin) (Nigeria) - 1252
+default locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 468, name: ha-Latn): Hausa (Latin) (Nigeria) - 1252
+default locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ha_NG_#Latn, Name: Hausa (Latin,Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 46a, name: yo-NG): Yoruba (Nigeria) - 1252
+default locale: ID: yo_NG, Name: Yoruba (Nigeria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: yo_NG, Name: Yoruba (Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 46b, name: quz): Quechua (Bolivia) - 1252
+default locale: ID: quz_BO, Name: quz (Bolivia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_BO, Name: quz (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 46b, name: quz-BO): Quechua (Bolivia) - 1252
+default locale: ID: quz_BO, Name: quz (Bolivia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_BO, Name: quz (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 46c, name: nso): Sesotho sa Leboa (South Africa) - 1252
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 46c, name: nso-ZA): Sesotho sa Leboa (South Africa) - 1252
+default locale: ID: nso_ZA, Name: Pedi (South Africa)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: nso_ZA, Name: Pedi (South Africa)
+default charset: windows-1252
+
+OS Locale (lcid: 46d, name: ba-RU): Bashkir (Russia) - 1251
+default locale: ID: ba_RU, Name: Bashkir (Russia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ba_RU, Name: Bashkir (Russia)
+default charset: windows-1251
+
+OS Locale (lcid: 46e, name: lb-LU): Luxembourgish (Luxembourg) - 1252
+default locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: lb_LU, Name: Luxembourgish (Luxembourg)
+default charset: windows-1252
+
+OS Locale (lcid: 46f, name: kl-GL): Greenlandic (Greenland) - 1252
+default locale: ID: kl_GL, Name: Greenlandic (Greenland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: kl_GL, Name: Greenlandic (Greenland)
+default charset: windows-1252
+
+OS Locale (lcid: 470, name: ig-NG): Igbo (Nigeria) - 1252
+default locale: ID: ig_NG, Name: Igbo (Nigeria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ig_NG, Name: Igbo (Nigeria)
+default charset: windows-1252
+
+OS Locale (lcid: 478, name: ii-CN): Yi (People's Republic of China) - 0
+default locale: ID: ii_CN, Name: Sichuan Yi (China)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: ii_CN, Name: Sichuan Yi (China)
+default charset: UTF-8
+
+OS Locale (lcid: 47a, name: arn): Mapudungun (Chile) - 1252
+default locale: ID: arn_CL, Name: Mapudungun (Chile)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: arn_CL, Name: Mapudungun (Chile)
+default charset: windows-1252
+
+OS Locale (lcid: 47a, name: arn-CL): Mapudungun (Chile) - 1252
+default locale: ID: arn_CL, Name: Mapudungun (Chile)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: arn_CL, Name: Mapudungun (Chile)
+default charset: windows-1252
+
+OS Locale (lcid: 47c, name: moh): Mohawk (Canada) - 1252
+default locale: ID: moh_CA, Name: Mohawk (Canada)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: moh_CA, Name: Mohawk (Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 47c, name: moh-CA): Mohawk (Canada) - 1252
+default locale: ID: moh_CA, Name: Mohawk (Canada)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: moh_CA, Name: Mohawk (Canada)
+default charset: windows-1252
+
+OS Locale (lcid: 47e, name: br-FR): Breton (France) - 1252
+default locale: ID: br_FR, Name: Breton (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: br_FR, Name: Breton (France)
default charset: windows-1252
-
-OS Locale (lcid: 487, name: rw-RW): Kinyarwanda (Rwanda) - 1252
+
+OS Locale (lcid: 480, name: ug-CN): Uyghur (People's Republic of China) - 1256
+default locale: ID: ug_CN, Name: Uighur (China)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ug_CN, Name: Uighur (China)
+default charset: windows-1256
+
+OS Locale (lcid: 481, name: mi-NZ): Maori (New Zealand) - 0
+default locale: ID: mi_NZ, Name: Maori (New Zealand)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: mi_NZ, Name: Maori (New Zealand)
+default charset: UTF-8
+
+OS Locale (lcid: 482, name: oc-FR): Occitan (France) - 1252
+default locale: ID: oc_FR, Name: Occitan (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: oc_FR, Name: Occitan (France)
+default charset: windows-1252
+
+OS Locale (lcid: 483, name: co-FR): Corsican (France) - 1252
+default locale: ID: co_FR, Name: Corsican (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: co_FR, Name: Corsican (France)
+default charset: windows-1252
+
+OS Locale (lcid: 484, name: gsw): Alsatian (France) - 1252
+default locale: ID: gsw_FR, Name: Swiss German (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gsw_FR, Name: Swiss German (France)
+default charset: windows-1252
+
+OS Locale (lcid: 484, name: gsw-FR): Alsatian (France) - 1252
+default locale: ID: gsw_FR, Name: Swiss German (France)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: gsw_FR, Name: Swiss German (France)
+default charset: windows-1252
+
+OS Locale (lcid: 485, name: sah): Yakut (Russia) - 1251
+default locale: ID: sah_RU, Name: Yakut (Russia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sah_RU, Name: Yakut (Russia)
+default charset: windows-1251
+
+OS Locale (lcid: 485, name: sah-RU): Yakut (Russia) - 1251
+default locale: ID: sah_RU, Name: Yakut (Russia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sah_RU, Name: Yakut (Russia)
+default charset: windows-1251
+
+OS Locale (lcid: 486, name: qut): K'iche (Guatemala) - 1252
+default locale: ID: qut_GT, Name: qut (Guatemala)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: qut_GT, Name: qut (Guatemala)
+default charset: windows-1252
+
+OS Locale (lcid: 486, name: qut-GT): K'iche (Guatemala) - 1252
+default locale: ID: qut_GT, Name: qut (Guatemala)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: qut_GT, Name: qut (Guatemala)
+default charset: windows-1252
+
+OS Locale (lcid: 487, name: rw-RW): Kinyarwanda (Rwanda) - 1252
default locale: ID: rw_RW, Name: Kinyarwanda (Rwanda)
display locale: ID: en_US, Name: English (United States)
format locale: ID: rw_RW, Name: Kinyarwanda (Rwanda)
default charset: windows-1252
-
-OS Locale (lcid: 488, name: wo-SN): Wolof (Senegal) - 1252
+
+OS Locale (lcid: 488, name: wo-SN): Wolof (Senegal) - 1252
default locale: ID: wo_SN, Name: Wolof (Senegal)
display locale: ID: en_US, Name: English (United States)
format locale: ID: wo_SN, Name: Wolof (Senegal)
default charset: windows-1252
-
-OS Locale (lcid: 48c, name: prs): Dari (Afghanistan) - 1256
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 48c, name: prs): Dari (Afghanistan) - 1256
+default locale: ID: prs_AF, Name: prs (Afghanistan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: prs_AF, Name: prs (Afghanistan)
default charset: windows-1256
-
-OS Locale (lcid: 48c, name: prs-AF): Dari (Afghanistan) - 1256
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 48c, name: prs-AF): Dari (Afghanistan) - 1256
+default locale: ID: prs_AF, Name: prs (Afghanistan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: prs_AF, Name: prs (Afghanistan)
default charset: windows-1256
-
-OS Locale (lcid: 491, name: gd-GB): Scottish Gaelic (United Kingdom) - 1252
+
+OS Locale (lcid: 491, name: gd-GB): Scottish Gaelic (United Kingdom) - 1252
default locale: ID: gd_GB, Name: Scottish Gaelic (United Kingdom)
display locale: ID: en_US, Name: English (United States)
format locale: ID: gd_GB, Name: Scottish Gaelic (United Kingdom)
default charset: windows-1252
-
-OS Locale (lcid: 801, name: ar-IQ): Arabic (Iraq) - 1256
+
+OS Locale (lcid: 801, name: ar-IQ): Arabic (Iraq) - 1256
default locale: ID: ar_IQ, Name: Arabic (Iraq)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_IQ, Name: Arabic (Iraq)
default charset: windows-1256
-
-OS Locale (lcid: 804, name: zh-Hans): Chinese (Simplified) (People's Republic of China) - 936
+
+OS Locale (lcid: 804, name: zh-Hans): Chinese (Simplified) (People's Republic of China) - 936
default locale: ID: zh_CN, Name: Chinese (China)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_CN, Name: Chinese (China)
default charset: GBK
-
-OS Locale (lcid: 804, name: zh-CN): Chinese (Simplified) (People's Republic of China) - 936
+
+OS Locale (lcid: 804, name: zh-CN): Chinese (Simplified) (People's Republic of China) - 936
default locale: ID: zh_CN, Name: Chinese (China)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_CN, Name: Chinese (China)
default charset: GBK
-
-OS Locale (lcid: 807, name: de-CH): German (Switzerland) - 1252
+
+OS Locale (lcid: 807, name: de-CH): German (Switzerland) - 1252
default locale: ID: de_CH, Name: German (Switzerland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_CH, Name: German (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 809, name: en-GB): English (United Kingdom) - 1252
+
+OS Locale (lcid: 809, name: en-GB): English (United Kingdom) - 1252
default locale: ID: en_GB, Name: English (United Kingdom)
-display locale: ID: en_GB, Name: English (United Kingdom)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_GB, Name: English (United Kingdom)
default charset: windows-1252
-
-OS Locale (lcid: 80a, name: es-MX): Spanish (Mexico) - 1252
+
+OS Locale (lcid: 80a, name: es-MX): Spanish (Mexico) - 1252
default locale: ID: es_MX, Name: Spanish (Mexico)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_MX, Name: Spanish (Mexico)
default charset: windows-1252
-
-OS Locale (lcid: 80c, name: fr-BE): French (Belgium) - 1252
+
+OS Locale (lcid: 80c, name: fr-BE): French (Belgium) - 1252
default locale: ID: fr_BE, Name: French (Belgium)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_BE, Name: French (Belgium)
default charset: windows-1252
-
-OS Locale (lcid: 810, name: it-CH): Italian (Switzerland) - 1252
+
+OS Locale (lcid: 810, name: it-CH): Italian (Switzerland) - 1252
default locale: ID: it_CH, Name: Italian (Switzerland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: it_CH, Name: Italian (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 813, name: nl-BE): Dutch (Belgium) - 1252
+
+OS Locale (lcid: 813, name: nl-BE): Dutch (Belgium) - 1252
default locale: ID: nl_BE, Name: Dutch (Belgium)
display locale: ID: en_US, Name: English (United States)
format locale: ID: nl_BE, Name: Dutch (Belgium)
default charset: windows-1252
-
-OS Locale (lcid: 814, name: nn-NO): Norwegian (Nynorsk) (Norway) - 1252
+
+OS Locale (lcid: 814, name: nn-NO): Norwegian (Nynorsk) (Norway) - 1252
default locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
display locale: ID: en_US, Name: English (United States)
format locale: ID: no_NO_NY, Name: Norwegian (Norway,Nynorsk)
default charset: windows-1252
-
-OS Locale (lcid: 816, name: pt-PT): Portuguese (Portugal) - 1252
+
+OS Locale (lcid: 816, name: pt-PT): Portuguese (Portugal) - 1252
default locale: ID: pt_PT, Name: Portuguese (Portugal)
display locale: ID: en_US, Name: English (United States)
format locale: ID: pt_PT, Name: Portuguese (Portugal)
default charset: windows-1252
-
-OS Locale (lcid: 81a, name: sr-Latn-CS): Serbian (Latin) (Serbia and Montenegro (Former)) - 1250
-default locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+
+OS Locale (lcid: 81a, name: sr-Latn-CS): Serbian (Latin) (Serbia and Montenegro (Former)) - 1250
+default locale: ID: sr_CS_#Latn, Name: Serbian (Latin,Serbia and Montenegro)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS_#Latn, Name: Serbian (Latin,Serbia and Montenegro)
default charset: windows-1250
-
-OS Locale (lcid: 81d, name: sv-FI): Swedish (Finland) - 1252
+
+OS Locale (lcid: 81d, name: sv-FI): Swedish (Finland) - 1252
default locale: ID: sv_FI, Name: Swedish (Finland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: sv_FI, Name: Swedish (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 82c, name: az-Cyrl-AZ): Azeri (Cyrillic) (Azerbaijan) - 1251
-default locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+
+OS Locale (lcid: 82c, name: az-Cyrl-AZ): Azeri (Cyrillic) (Azerbaijan) - 1251
+default locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+format locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
default charset: windows-1251
-
-OS Locale (lcid: 82c, name: az-Cyrl): Azeri (Cyrillic) (Azerbaijan) - 1251
-default locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+
+OS Locale (lcid: 82c, name: az-Cyrl): Azeri (Cyrillic) (Azerbaijan) - 1251
+default locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: az_AZ, Name: Azerbaijani (Azerbaijan)
+format locale: ID: az_AZ_#Cyrl, Name: Azerbaijani (Cyrillic,Azerbaijan)
default charset: windows-1251
-
-OS Locale (lcid: 82e, name: dsb): Lower Sorbian (Germany) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 82e, name: dsb): Lower Sorbian (Germany) - 1252
+default locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 82e, name: dsb-DE): Lower Sorbian (Germany) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 82e, name: dsb-DE): Lower Sorbian (Germany) - 1252
+default locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: dsb_DE, Name: Lower Sorbian (Germany)
default charset: windows-1252
-
-OS Locale (lcid: 83b, name: se-SE): Sami (Northern) (Sweden) - 1252
+
+OS Locale (lcid: 83b, name: se-SE): Sami (Northern) (Sweden) - 1252
default locale: ID: se_SE, Name: Northern Sami (Sweden)
display locale: ID: en_US, Name: English (United States)
format locale: ID: se_SE, Name: Northern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 83c, name: ga-IE): Irish (Ireland) - 1252
+
+OS Locale (lcid: 83c, name: ga-IE): Irish (Ireland) - 1252
default locale: ID: ga_IE, Name: Irish (Ireland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ga_IE, Name: Irish (Ireland)
default charset: windows-1252
-
-OS Locale (lcid: 83e, name: ms-BN): Malay (Brunei Darussalam) - 1252
+
+OS Locale (lcid: 83e, name: ms-BN): Malay (Brunei Darussalam) - 1252
default locale: ID: ms_BN, Name: Malay (Brunei)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ms_BN, Name: Malay (Brunei)
default charset: windows-1252
-
-OS Locale (lcid: 843, name: uz-Cyrl-UZ): Uzbek (Cyrillic) (Uzbekistan) - 1251
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+
+OS Locale (lcid: 843, name: uz-Cyrl-UZ): Uzbek (Cyrillic) (Uzbekistan) - 1251
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: windows-1251
-
-OS Locale (lcid: 843, name: uz-Cyrl): Uzbek (Cyrillic) (Uzbekistan) - 1251
-default locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+
+OS Locale (lcid: 843, name: uz-Cyrl): Uzbek (Cyrillic) (Uzbekistan) - 1251
+default locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: uz_UZ, Name: Uzbek (Uzbekistan)
+format locale: ID: uz_UZ_#Cyrl, Name: Uzbek (Cyrillic,Uzbekistan)
default charset: windows-1251
-
-OS Locale (lcid: 845, name: bn-BD): Bengali (Bangladesh) - 0
+
+OS Locale (lcid: 845, name: bn-BD): Bengali (Bangladesh) - 0
default locale: ID: bn_BD, Name: Bengali (Bangladesh)
display locale: ID: en_US, Name: English (United States)
format locale: ID: bn_BD, Name: Bengali (Bangladesh)
default charset: UTF-8
-
-OS Locale (lcid: 850, name: mn-Mong-CN): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
-default locale: ID: mn_CN, Name: Mongolian (China)
+
+OS Locale (lcid: 850, name: mn-Mong-CN): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
+default locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_CN, Name: Mongolian (China)
+format locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
default charset: UTF-8
-
-OS Locale (lcid: 850, name: mn-Mong): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
-default locale: ID: mn_CN, Name: Mongolian (China)
+
+OS Locale (lcid: 850, name: mn-Mong): Mongolian (Traditional Mongolian) (People's Republic of China) - 0
+default locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: mn_CN, Name: Mongolian (China)
+format locale: ID: mn_CN_#Mong, Name: Mongolian (Mongolian,China)
default charset: UTF-8
-
-OS Locale (lcid: 85d, name: iu-Latn): Inuktitut (Latin) (Canada) - 1252
-default locale: ID: iu_CA, Name: Inuktitut (Canada)
+
+OS Locale (lcid: 85d, name: iu-Latn): Inuktitut (Latin) (Canada) - 1252
+default locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
+format locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
default charset: windows-1252
-
-OS Locale (lcid: 85d, name: iu-Latn-CA): Inuktitut (Latin) (Canada) - 1252
-default locale: ID: iu_CA, Name: Inuktitut (Canada)
+
+OS Locale (lcid: 85d, name: iu-Latn-CA): Inuktitut (Latin) (Canada) - 1252
+default locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: iu_CA, Name: Inuktitut (Canada)
+format locale: ID: iu_CA_#Latn, Name: Inuktitut (Latin,Canada)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm): Tamazight (Latin) (Algeria) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 85f, name: tzm): Tamazight (Latin) (Algeria) - 1252
+default locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm-Latn-DZ): Tamazight (Latin) (Algeria) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 85f, name: tzm-Latn-DZ): Tamazight (Latin) (Algeria) - 1252
+default locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 85f, name: tzm-Latn): Tamazight (Latin) (Algeria) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 85f, name: tzm-Latn): Tamazight (Latin) (Algeria) - 1252
+default locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: tzm_DZ_#Latn, Name: tzm (Latin,Algeria)
default charset: windows-1252
-
-OS Locale (lcid: 86b, name: quz-EC): Quechua (Ecuador) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 86b, name: quz-EC): Quechua (Ecuador) - 1252
+default locale: ID: quz_EC, Name: quz (Ecuador)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_EC, Name: quz (Ecuador)
default charset: windows-1252
-
-OS Locale (lcid: c01, name: ar-EG): Arabic (Egypt) - 1256
+
+OS Locale (lcid: c01, name: ar-EG): Arabic (Egypt) - 1256
default locale: ID: ar_EG, Name: Arabic (Egypt)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_EG, Name: Arabic (Egypt)
default charset: windows-1256
-
-OS Locale (lcid: c04, name: zh-HK): Chinese (Traditional) (Hong Kong S.A.R.) - 950
+
+OS Locale (lcid: c04, name: zh-HK): Chinese (Traditional) (Hong Kong S.A.R.) - 950
default locale: ID: zh_HK, Name: Chinese (Hong Kong)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_HK, Name: Chinese (Hong Kong)
default charset: x-MS950-HKSCS
-
-OS Locale (lcid: c04, name: zh-Hant): Chinese (Traditional) (Hong Kong S.A.R.) - 950
+
+OS Locale (lcid: c04, name: zh-Hant): Chinese (Traditional) (Hong Kong S.A.R.) - 950
default locale: ID: zh_HK, Name: Chinese (Hong Kong)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_HK, Name: Chinese (Hong Kong)
default charset: x-windows-950
-
-OS Locale (lcid: c07, name: de-AT): German (Austria) - 1252
+
+OS Locale (lcid: c07, name: de-AT): German (Austria) - 1252
default locale: ID: de_AT, Name: German (Austria)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_AT, Name: German (Austria)
default charset: windows-1252
-
-OS Locale (lcid: c09, name: en-AU): English (Australia) - 1252
+
+OS Locale (lcid: c09, name: en-AU): English (Australia) - 1252
default locale: ID: en_AU, Name: English (Australia)
-display locale: ID: en_AU, Name: English (Australia)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_AU, Name: English (Australia)
default charset: windows-1252
-
-OS Locale (lcid: c0a, name: es-ES): Spanish (Spain) - 1252
+
+OS Locale (lcid: c0a, name: es-ES): Spanish (Spain) - 1252
default locale: ID: es_ES, Name: Spanish (Spain)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_ES, Name: Spanish (Spain)
default charset: windows-1252
-
-OS Locale (lcid: c0c, name: fr-CA): French (Canada) - 1252
+
+OS Locale (lcid: c0c, name: fr-CA): French (Canada) - 1252
default locale: ID: fr_CA, Name: French (Canada)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_CA, Name: French (Canada)
default charset: windows-1252
-
-OS Locale (lcid: c1a, name: sr-Cyrl-CS): Serbian (Cyrillic) (Serbia and Montenegro (Former)) - 1251
-default locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+
+OS Locale (lcid: c1a, name: sr-Cyrl-CS): Serbian (Cyrillic) (Serbia and Montenegro (Former)) - 1251
+default locale: ID: sr_CS_#Cyrl, Name: Serbian (Cyrillic,Serbia and Montenegro)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_CS, Name: Serbian (Serbia and Montenegro)
+format locale: ID: sr_CS_#Cyrl, Name: Serbian (Cyrillic,Serbia and Montenegro)
default charset: windows-1251
-
-OS Locale (lcid: c3b, name: se-FI): Sami (Northern) (Finland) - 1252
+
+OS Locale (lcid: c3b, name: se-FI): Sami (Northern) (Finland) - 1252
default locale: ID: se_FI, Name: Northern Sami (Finland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: se_FI, Name: Northern Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: c6b, name: quz-PE): Quechua (Peru) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: c6b, name: quz-PE): Quechua (Peru) - 1252
+default locale: ID: quz_PE, Name: quz (Peru)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: quz_PE, Name: quz (Peru)
default charset: windows-1252
-
-OS Locale (lcid: 1001, name: ar-LY): Arabic (Libya) - 1256
+
+OS Locale (lcid: 1001, name: ar-LY): Arabic (Libya) - 1256
default locale: ID: ar_LY, Name: Arabic (Libya)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_LY, Name: Arabic (Libya)
default charset: windows-1256
-
-OS Locale (lcid: 1004, name: zh-SG): Chinese (Simplified) (Singapore) - 936
+
+OS Locale (lcid: 1004, name: zh-SG): Chinese (Simplified) (Singapore) - 936
default locale: ID: zh_SG, Name: Chinese (Singapore)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_SG, Name: Chinese (Singapore)
default charset: GBK
-
-OS Locale (lcid: 1007, name: de-LU): German (Luxembourg) - 1252
+
+OS Locale (lcid: 1007, name: de-LU): German (Luxembourg) - 1252
default locale: ID: de_LU, Name: German (Luxembourg)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_LU, Name: German (Luxembourg)
default charset: windows-1252
-
-OS Locale (lcid: 1009, name: en-CA): English (Canada) - 1252
+
+OS Locale (lcid: 1009, name: en-CA): English (Canada) - 1252
default locale: ID: en_CA, Name: English (Canada)
-display locale: ID: en_CA, Name: English (Canada)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_CA, Name: English (Canada)
default charset: windows-1252
-
-OS Locale (lcid: 100a, name: es-GT): Spanish (Guatemala) - 1252
+
+OS Locale (lcid: 100a, name: es-GT): Spanish (Guatemala) - 1252
default locale: ID: es_GT, Name: Spanish (Guatemala)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_GT, Name: Spanish (Guatemala)
default charset: windows-1252
-
-OS Locale (lcid: 100c, name: fr-CH): French (Switzerland) - 1252
+
+OS Locale (lcid: 100c, name: fr-CH): French (Switzerland) - 1252
default locale: ID: fr_CH, Name: French (Switzerland)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_CH, Name: French (Switzerland)
default charset: windows-1252
-
-OS Locale (lcid: 101a, name: hr-BA): Croatian (Latin) (Bosnia and Herzegovina) - 1250
+
+OS Locale (lcid: 101a, name: hr-BA): Croatian (Latin) (Bosnia and Herzegovina) - 1250
default locale: ID: hr_BA, Name: Croatian (Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
format locale: ID: hr_BA, Name: Croatian (Bosnia and Herzegovina)
default charset: windows-1250
-
-OS Locale (lcid: 103b, name: smj-NO): Sami (Lule) (Norway) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 103b, name: smj-NO): Sami (Lule) (Norway) - 1252
+default locale: ID: smj_NO, Name: Lule Sami (Norway)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_NO, Name: Lule Sami (Norway)
default charset: windows-1252
-
-OS Locale (lcid: 1401, name: ar-DZ): Arabic (Algeria) - 1256
+
+OS Locale (lcid: 1401, name: ar-DZ): Arabic (Algeria) - 1256
default locale: ID: ar_DZ, Name: Arabic (Algeria)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_DZ, Name: Arabic (Algeria)
default charset: windows-1256
-
-OS Locale (lcid: 1404, name: zh-MO): Chinese (Traditional) (Macao S.A.R.) - 950
+
+OS Locale (lcid: 1404, name: zh-MO): Chinese (Traditional) (Macao S.A.R.) - 950
default locale: ID: zh_MO, Name: Chinese (Macao)
display locale: ID: en_US, Name: English (United States)
format locale: ID: zh_MO, Name: Chinese (Macao)
default charset: x-windows-950
-
-OS Locale (lcid: 1407, name: de-LI): German (Liechtenstein) - 1252
+
+OS Locale (lcid: 1407, name: de-LI): German (Liechtenstein) - 1252
default locale: ID: de_LI, Name: German (Liechtenstein)
display locale: ID: en_US, Name: English (United States)
format locale: ID: de_LI, Name: German (Liechtenstein)
default charset: windows-1252
-
-OS Locale (lcid: 1409, name: en-NZ): English (New Zealand) - 1252
+
+OS Locale (lcid: 1409, name: en-NZ): English (New Zealand) - 1252
default locale: ID: en_NZ, Name: English (New Zealand)
-display locale: ID: en_NZ, Name: English (New Zealand)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_NZ, Name: English (New Zealand)
default charset: windows-1252
-
-OS Locale (lcid: 140a, name: es-CR): Spanish (Costa Rica) - 1252
+
+OS Locale (lcid: 140a, name: es-CR): Spanish (Costa Rica) - 1252
default locale: ID: es_CR, Name: Spanish (Costa Rica)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_CR, Name: Spanish (Costa Rica)
default charset: windows-1252
-
-OS Locale (lcid: 140c, name: fr-LU): French (Luxembourg) - 1252
+
+OS Locale (lcid: 140c, name: fr-LU): French (Luxembourg) - 1252
default locale: ID: fr_LU, Name: French (Luxembourg)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_LU, Name: French (Luxembourg)
default charset: windows-1252
-
-OS Locale (lcid: 141a, name: bs-Latn): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
-default locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 141a, name: bs-Latn): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
+default locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
default charset: windows-1250
-
-OS Locale (lcid: 141a, name: bs-Latn-BA): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
-default locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 141a, name: bs-Latn-BA): Bosnian (Latin) (Bosnia and Herzegovina) - 1250
+default locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Latn, Name: Bosnian (Latin,Bosnia and Herzegovina)
default charset: windows-1250
-
-OS Locale (lcid: 143b, name: smj-SE): Sami (Lule) (Sweden) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 143b, name: smj-SE): Sami (Lule) (Sweden) - 1252
+default locale: ID: smj_SE, Name: Lule Sami (Sweden)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_SE, Name: Lule Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 143b, name: smj): Sami (Lule) (Sweden) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 143b, name: smj): Sami (Lule) (Sweden) - 1252
+default locale: ID: smj_SE, Name: Lule Sami (Sweden)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: smj_SE, Name: Lule Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 1801, name: ar-MA): Arabic (Morocco) - 1256
+
+OS Locale (lcid: 1801, name: ar-MA): Arabic (Morocco) - 1256
default locale: ID: ar_MA, Name: Arabic (Morocco)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_MA, Name: Arabic (Morocco)
default charset: windows-1256
-
-OS Locale (lcid: 1809, name: en-IE): English (Ireland) - 1252
+
+OS Locale (lcid: 1809, name: en-IE): English (Ireland) - 1252
default locale: ID: en_IE, Name: English (Ireland)
-display locale: ID: en_IE, Name: English (Ireland)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_IE, Name: English (Ireland)
default charset: windows-1252
-
-OS Locale (lcid: 180a, name: es-PA): Spanish (Panama) - 1252
+
+OS Locale (lcid: 180a, name: es-PA): Spanish (Panama) - 1252
default locale: ID: es_PA, Name: Spanish (Panama)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_PA, Name: Spanish (Panama)
default charset: windows-1252
-
-OS Locale (lcid: 180c, name: fr-MC): French (Principality of Monaco) - 1252
+
+OS Locale (lcid: 180c, name: fr-MC): French (Principality of Monaco) - 1252
default locale: ID: fr_MC, Name: French (Monaco)
display locale: ID: en_US, Name: English (United States)
format locale: ID: fr_MC, Name: French (Monaco)
default charset: windows-1252
-
-OS Locale (lcid: 181a, name: sr-Latn-BA): Serbian (Latin) (Bosnia and Herzegovina) - 1250
-default locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 181a, name: sr-Latn-BA): Serbian (Latin) (Bosnia and Herzegovina) - 1250
+default locale: ID: sr_BA_#Latn, Name: Serbian (Latin,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+format locale: ID: sr_BA_#Latn, Name: Serbian (Latin,Bosnia and Herzegovina)
default charset: windows-1250
-
-OS Locale (lcid: 183b, name: sma-NO): Sami (Southern) (Norway) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 183b, name: sma-NO): Sami (Southern) (Norway) - 1252
+default locale: ID: sma_NO, Name: Southern Sami (Norway)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_NO, Name: Southern Sami (Norway)
default charset: windows-1252
-
-OS Locale (lcid: 1c01, name: ar-TN): Arabic (Tunisia) - 1256
+
+OS Locale (lcid: 1c01, name: ar-TN): Arabic (Tunisia) - 1256
default locale: ID: ar_TN, Name: Arabic (Tunisia)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_TN, Name: Arabic (Tunisia)
default charset: windows-1256
-
-OS Locale (lcid: 1c09, name: en-ZA): English (South Africa) - 1252
+
+OS Locale (lcid: 1c09, name: en-ZA): English (South Africa) - 1252
default locale: ID: en_ZA, Name: English (South Africa)
-display locale: ID: en_ZA, Name: English (South Africa)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_ZA, Name: English (South Africa)
default charset: windows-1252
-
-OS Locale (lcid: 1c0a, name: es-DO): Spanish (Dominican Republic) - 1252
+
+OS Locale (lcid: 1c0a, name: es-DO): Spanish (Dominican Republic) - 1252
default locale: ID: es_DO, Name: Spanish (Dominican Republic)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_DO, Name: Spanish (Dominican Republic)
default charset: windows-1252
-
-OS Locale (lcid: 1c1a, name: sr-Cyrl-BA): Serbian (Cyrillic) (Bosnia and Herzegovina) - 1251
-default locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 1c1a, name: sr-Cyrl-BA): Serbian (Cyrillic) (Bosnia and Herzegovina) - 1251
+default locale: ID: sr_BA_#Cyrl, Name: Serbian (Cyrillic,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_BA, Name: Serbian (Bosnia and Herzegovina)
+format locale: ID: sr_BA_#Cyrl, Name: Serbian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1251
-
-OS Locale (lcid: 1c3b, name: sma): Sami (Southern) (Sweden) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 1c3b, name: sma): Sami (Southern) (Sweden) - 1252
+default locale: ID: sma_SE, Name: Southern Sami (Sweden)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_SE, Name: Southern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 1c3b, name: sma-SE): Sami (Southern) (Sweden) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 1c3b, name: sma-SE): Sami (Southern) (Sweden) - 1252
+default locale: ID: sma_SE, Name: Southern Sami (Sweden)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sma_SE, Name: Southern Sami (Sweden)
default charset: windows-1252
-
-OS Locale (lcid: 2001, name: ar-OM): Arabic (Oman) - 1256
+
+OS Locale (lcid: 2001, name: ar-OM): Arabic (Oman) - 1256
default locale: ID: ar_OM, Name: Arabic (Oman)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_OM, Name: Arabic (Oman)
default charset: windows-1256
-
-OS Locale (lcid: 2009, name: en-JM): English (Jamaica) - 1252
+
+OS Locale (lcid: 2009, name: en-JM): English (Jamaica) - 1252
default locale: ID: en_JM, Name: English (Jamaica)
-display locale: ID: en_JM, Name: English (Jamaica)
+display locale: ID: en_US, Name: English (United States)
format locale: ID: en_JM, Name: English (Jamaica)
default charset: windows-1252
-
-OS Locale (lcid: 200a, name: es-VE): Spanish (Bolivarian Republic of Venezuela) - 1252
+
+OS Locale (lcid: 200a, name: es-VE): Spanish (Bolivarian Republic of Venezuela) - 1252
default locale: ID: es_VE, Name: Spanish (Venezuela)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_VE, Name: Spanish (Venezuela)
default charset: windows-1252
-
-OS Locale (lcid: 201a, name: bs-Cyrl-BA): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
-default locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 201a, name: bs-Cyrl-BA): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
+default locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1251
-
-OS Locale (lcid: 201a, name: bs-Cyrl): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
-default locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+
+OS Locale (lcid: 201a, name: bs-Cyrl): Bosnian (Cyrillic) (Bosnia and Herzegovina) - 1251
+default locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: bs_BA, Name: Bosnian (Bosnia and Herzegovina)
+format locale: ID: bs_BA_#Cyrl, Name: Bosnian (Cyrillic,Bosnia and Herzegovina)
default charset: windows-1251
-
-OS Locale (lcid: 203b, name: sms-FI): Sami (Skolt) (Finland) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 203b, name: sms-FI): Sami (Skolt) (Finland) - 1252
+default locale: ID: sms_FI, Name: Skolt Sami (Finland)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sms_FI, Name: Skolt Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 203b, name: sms): Sami (Skolt) (Finland) - 1252
-default locale: ID: en_US, Name: English (United States)
+
+OS Locale (lcid: 203b, name: sms): Sami (Skolt) (Finland) - 1252
+default locale: ID: sms_FI, Name: Skolt Sami (Finland)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: sms_FI, Name: Skolt Sami (Finland)
default charset: windows-1252
-
-OS Locale (lcid: 2401, name: ar-YE): Arabic (Yemen) - 1256
+
+OS Locale (lcid: 2401, name: ar-YE): Arabic (Yemen) - 1256
default locale: ID: ar_YE, Name: Arabic (Yemen)
display locale: ID: en_US, Name: English (United States)
format locale: ID: ar_YE, Name: Arabic (Yemen)
default charset: windows-1256
-
-OS Locale (lcid: 2409, name: en-029): English (Caribbean) - 1252
-default locale: ID: en, Name: English
-display locale: ID: en, Name: English
-format locale: ID: en, Name: English
+
+OS Locale (lcid: 2409, name: en-029): English (Caribbean) - 1252
+default locale: ID: en_029, Name: English (Caribbean)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_029, Name: English (Caribbean)
default charset: windows-1252
-
-OS Locale (lcid: 240a, name: es-CO): Spanish (Colombia) - 1252
+
+OS Locale (lcid: 240a, name: es-CO): Spanish (Colombia) - 1252
default locale: ID: es_CO, Name: Spanish (Colombia)
display locale: ID: en_US, Name: English (United States)
format locale: ID: es_CO, Name: Spanish (Colombia)
default charset: windows-1252
-
-OS Locale (lcid: 241a, name: sr-Latn-RS): Serbian (Latin) (Serbia) - 1250
-default locale: ID: sr_RS, Name: Serbian (Serbia)
+
+OS Locale (lcid: 241a, name: sr-Latn-RS): Serbian (Latin) (Serbia) - 1250
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+default charset: windows-1250
+
+OS Locale (lcid: 241a, name: sr-Latn): Serbian (Latin) (Serbia) - 1250
+default locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Latn, Name: Serbian (Latin,Serbia)
+default charset: windows-1250
+
+OS Locale (lcid: 243b, name: smn): Sami (Inari) (Finland) - 1252
+default locale: ID: smn_FI, Name: Inari Sami (Finland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: smn_FI, Name: Inari Sami (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 243b, name: smn-FI): Sami (Inari) (Finland) - 1252
+default locale: ID: smn_FI, Name: Inari Sami (Finland)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: smn_FI, Name: Inari Sami (Finland)
+default charset: windows-1252
+
+OS Locale (lcid: 2801, name: ar-SY): Arabic (Syria) - 1256
+default locale: ID: ar_SY, Name: Arabic (Syria)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_SY, Name: Arabic (Syria)
+default charset: windows-1256
+
+OS Locale (lcid: 2809, name: en-BZ): English (Belize) - 1252
+default locale: ID: en_BZ, Name: English (Belize)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_BZ, Name: English (Belize)
+default charset: windows-1252
+
+OS Locale (lcid: 280a, name: es-PE): Spanish (Peru) - 1252
+default locale: ID: es_PE, Name: Spanish (Peru)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PE, Name: Spanish (Peru)
+default charset: windows-1252
+
+OS Locale (lcid: 281a, name: sr-Cyrl-RS): Serbian (Cyrillic) (Serbia) - 1251
+default locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
+format locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
+default charset: windows-1251
+
+OS Locale (lcid: 281a, name: sr-Cyrl): Serbian (Cyrillic) (Serbia) - 1251
+default locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_RS_#Cyrl, Name: Serbian (Cyrillic,Serbia)
+default charset: windows-1251
+
+OS Locale (lcid: 2c01, name: ar-JO): Arabic (Jordan) - 1256
+default locale: ID: ar_JO, Name: Arabic (Jordan)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_JO, Name: Arabic (Jordan)
+default charset: windows-1256
+
+OS Locale (lcid: 2c09, name: en-TT): English (Trinidad and Tobago) - 1252
+default locale: ID: en_TT, Name: English (Trinidad and Tobago)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_TT, Name: English (Trinidad and Tobago)
+default charset: windows-1252
+
+OS Locale (lcid: 2c0a, name: es-AR): Spanish (Argentina) - 1252
+default locale: ID: es_AR, Name: Spanish (Argentina)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_AR, Name: Spanish (Argentina)
+default charset: windows-1252
+
+OS Locale (lcid: 2c1a, name: sr-Latn-ME): Serbian (Latin) (Montenegro) - 1250
+default locale: ID: sr_ME_#Latn, Name: Serbian (Latin,Montenegro)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_ME_#Latn, Name: Serbian (Latin,Montenegro)
default charset: windows-1250
-
-OS Locale (lcid: 241a, name: sr-Latn): Serbian (Latin) (Serbia) - 1250
-default locale: ID: sr_RS, Name: Serbian (Serbia)
+
+OS Locale (lcid: 3001, name: ar-LB): Arabic (Lebanon) - 1256
+default locale: ID: ar_LB, Name: Arabic (Lebanon)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_LB, Name: Arabic (Lebanon)
+default charset: windows-1256
+
+OS Locale (lcid: 3009, name: en-ZW): English (Zimbabwe) - 1252
+default locale: ID: en_ZW, Name: English (Zimbabwe)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_ZW, Name: English (Zimbabwe)
+default charset: windows-1252
+
+OS Locale (lcid: 300a, name: es-EC): Spanish (Ecuador) - 1252
+default locale: ID: es_EC, Name: Spanish (Ecuador)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_EC, Name: Spanish (Ecuador)
+default charset: windows-1252
+
+OS Locale (lcid: 301a, name: sr-Cyrl-ME): Serbian (Cyrillic) (Montenegro) - 1251
+default locale: ID: sr_ME_#Cyrl, Name: Serbian (Cyrillic,Montenegro)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
-default charset: windows-1250
-
-OS Locale (lcid: 243b, name: smn): Sami (Inari) (Finland) - 1252
-default locale: ID: en_US, Name: English (United States)
+format locale: ID: sr_ME_#Cyrl, Name: Serbian (Cyrillic,Montenegro)
+default charset: windows-1251
+
+OS Locale (lcid: 3401, name: ar-KW): Arabic (Kuwait) - 1256
+default locale: ID: ar_KW, Name: Arabic (Kuwait)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_KW, Name: Arabic (Kuwait)
+default charset: windows-1256
+
+OS Locale (lcid: 3409, name: en-PH): English (Republic of the Philippines) - 1252
+default locale: ID: en_PH, Name: English (Philippines)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_PH, Name: English (Philippines)
+default charset: windows-1252
+
+OS Locale (lcid: 340a, name: es-CL): Spanish (Chile) - 1252
+default locale: ID: es_CL, Name: Spanish (Chile)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_CL, Name: Spanish (Chile)
+default charset: windows-1252
+
+OS Locale (lcid: 3801, name: ar-AE): Arabic (U.A.E.) - 1256
+default locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
+default charset: windows-1256
+
+OS Locale (lcid: 380a, name: es-UY): Spanish (Uruguay) - 1252
+default locale: ID: es_UY, Name: Spanish (Uruguay)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_UY, Name: Spanish (Uruguay)
+default charset: windows-1252
+
+OS Locale (lcid: 3c01, name: ar-BH): Arabic (Bahrain) - 1256
+default locale: ID: ar_BH, Name: Arabic (Bahrain)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_BH, Name: Arabic (Bahrain)
+default charset: windows-1256
+
+OS Locale (lcid: 3c0a, name: es-PY): Spanish (Paraguay) - 1252
+default locale: ID: es_PY, Name: Spanish (Paraguay)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PY, Name: Spanish (Paraguay)
+default charset: windows-1252
+
+OS Locale (lcid: 4001, name: ar-QA): Arabic (Qatar) - 1256
+default locale: ID: ar_QA, Name: Arabic (Qatar)
display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
+format locale: ID: ar_QA, Name: Arabic (Qatar)
+default charset: windows-1256
+
+OS Locale (lcid: 4009, name: en-IN): English (India) - 1252
+default locale: ID: en_IN, Name: English (India)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_IN, Name: English (India)
+default charset: windows-1252
+
+OS Locale (lcid: 400a, name: es-BO): Spanish (Bolivia) - 1252
+default locale: ID: es_BO, Name: Spanish (Bolivia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_BO, Name: Spanish (Bolivia)
+default charset: windows-1252
+
+OS Locale (lcid: 4409, name: en-MY): English (Malaysia) - 1252
+default locale: ID: en_MY, Name: English (Malaysia)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_MY, Name: English (Malaysia)
+default charset: windows-1252
+
+OS Locale (lcid: 440a, name: es-SV): Spanish (El Salvador) - 1252
+default locale: ID: es_SV, Name: Spanish (El Salvador)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_SV, Name: Spanish (El Salvador)
default charset: windows-1252
-
-OS Locale (lcid: 243b, name: smn-FI): Sami (Inari) (Finland) - 1252
+
+OS Locale (lcid: 4809, name: en-SG): English (Singapore) - 1252
+default locale: ID: en_SG, Name: English (Singapore)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: en_SG, Name: English (Singapore)
+default charset: windows-1252
+
+OS Locale (lcid: 480a, name: es-HN): Spanish (Honduras) - 1252
+default locale: ID: es_HN, Name: Spanish (Honduras)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_HN, Name: Spanish (Honduras)
+default charset: windows-1252
+
+OS Locale (lcid: 4c0a, name: es-NI): Spanish (Nicaragua) - 1252
+default locale: ID: es_NI, Name: Spanish (Nicaragua)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_NI, Name: Spanish (Nicaragua)
+default charset: windows-1252
+
+OS Locale (lcid: 500a, name: es-PR): Spanish (Puerto Rico) - 1252
+default locale: ID: es_PR, Name: Spanish (Puerto Rico)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_PR, Name: Spanish (Puerto Rico)
+default charset: windows-1252
+
+OS Locale (lcid: 540a, name: es-US): Spanish (United States) - 1252
+default locale: ID: es_US, Name: Spanish (United States)
+display locale: ID: en_US, Name: English (United States)
+format locale: ID: es_US, Name: Spanish (United States)
+default charset: windows-1252
+
+OS UI Language (name: en-US)
default locale: ID: en_US, Name: English (United States)
display locale: ID: en_US, Name: English (United States)
format locale: ID: en_US, Name: English (United States)
default charset: windows-1252
-
-OS Locale (lcid: 2801, name: ar-SY): Arabic (Syria) - 1256
-default locale: ID: ar_SY, Name: Arabic (Syria)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_SY, Name: Arabic (Syria)
-default charset: windows-1256
-
-OS Locale (lcid: 2809, name: en-BZ): English (Belize) - 1252
-default locale: ID: en_BZ, Name: English (Belize)
-display locale: ID: en_BZ, Name: English (Belize)
-format locale: ID: en_BZ, Name: English (Belize)
-default charset: windows-1252
-
-OS Locale (lcid: 280a, name: es-PE): Spanish (Peru) - 1252
-default locale: ID: es_PE, Name: Spanish (Peru)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PE, Name: Spanish (Peru)
-default charset: windows-1252
-
-OS Locale (lcid: 281a, name: sr-Cyrl-RS): Serbian (Cyrillic) (Serbia) - 1251
-default locale: ID: sr_RS, Name: Serbian (Serbia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
-default charset: windows-1251
-
-OS Locale (lcid: 281a, name: sr-Cyrl): Serbian (Cyrillic) (Serbia) - 1251
-default locale: ID: sr_RS, Name: Serbian (Serbia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_RS, Name: Serbian (Serbia)
-default charset: windows-1251
-
-OS Locale (lcid: 2c01, name: ar-JO): Arabic (Jordan) - 1256
-default locale: ID: ar_JO, Name: Arabic (Jordan)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_JO, Name: Arabic (Jordan)
-default charset: windows-1256
-
-OS Locale (lcid: 2c09, name: en-TT): English (Trinidad and Tobago) - 1252
-default locale: ID: en_TT, Name: English (Trinidad and Tobago)
-display locale: ID: en_TT, Name: English (Trinidad and Tobago)
-format locale: ID: en_TT, Name: English (Trinidad and Tobago)
-default charset: windows-1252
-
-OS Locale (lcid: 2c0a, name: es-AR): Spanish (Argentina) - 1252
-default locale: ID: es_AR, Name: Spanish (Argentina)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_AR, Name: Spanish (Argentina)
-default charset: windows-1252
-
-OS Locale (lcid: 2c1a, name: sr-Latn-ME): Serbian (Latin) (Montenegro) - 1250
-default locale: ID: sr_ME, Name: Serbian (Montenegro)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_ME, Name: Serbian (Montenegro)
-default charset: windows-1250
-
-OS Locale (lcid: 3001, name: ar-LB): Arabic (Lebanon) - 1256
-default locale: ID: ar_LB, Name: Arabic (Lebanon)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_LB, Name: Arabic (Lebanon)
-default charset: windows-1256
-
-OS Locale (lcid: 3009, name: en-ZW): English (Zimbabwe) - 1252
-default locale: ID: en_ZW, Name: English (Zimbabwe)
-display locale: ID: en_ZW, Name: English (Zimbabwe)
-format locale: ID: en_ZW, Name: English (Zimbabwe)
-default charset: windows-1252
-
-OS Locale (lcid: 300a, name: es-EC): Spanish (Ecuador) - 1252
-default locale: ID: es_EC, Name: Spanish (Ecuador)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_EC, Name: Spanish (Ecuador)
-default charset: windows-1252
-
-OS Locale (lcid: 301a, name: sr-Cyrl-ME): Serbian (Cyrillic) (Montenegro) - 1251
-default locale: ID: sr_ME, Name: Serbian (Montenegro)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: sr_ME, Name: Serbian (Montenegro)
-default charset: windows-1251
-
-OS Locale (lcid: 3401, name: ar-KW): Arabic (Kuwait) - 1256
-default locale: ID: ar_KW, Name: Arabic (Kuwait)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_KW, Name: Arabic (Kuwait)
-default charset: windows-1256
-
-OS Locale (lcid: 3409, name: en-PH): English (Republic of the Philippines) - 1252
-default locale: ID: en_PH, Name: English (Philippines)
-display locale: ID: en_PH, Name: English (Philippines)
-format locale: ID: en_PH, Name: English (Philippines)
-default charset: windows-1252
-
-OS Locale (lcid: 340a, name: es-CL): Spanish (Chile) - 1252
-default locale: ID: es_CL, Name: Spanish (Chile)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_CL, Name: Spanish (Chile)
-default charset: windows-1252
-
-OS Locale (lcid: 3801, name: ar-AE): Arabic (U.A.E.) - 1256
-default locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_AE, Name: Arabic (United Arab Emirates)
-default charset: windows-1256
-
-OS Locale (lcid: 380a, name: es-UY): Spanish (Uruguay) - 1252
-default locale: ID: es_UY, Name: Spanish (Uruguay)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_UY, Name: Spanish (Uruguay)
-default charset: windows-1252
-
-OS Locale (lcid: 3c01, name: ar-BH): Arabic (Bahrain) - 1256
-default locale: ID: ar_BH, Name: Arabic (Bahrain)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_BH, Name: Arabic (Bahrain)
-default charset: windows-1256
-
-OS Locale (lcid: 3c0a, name: es-PY): Spanish (Paraguay) - 1252
-default locale: ID: es_PY, Name: Spanish (Paraguay)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PY, Name: Spanish (Paraguay)
-default charset: windows-1252
-
-OS Locale (lcid: 4001, name: ar-QA): Arabic (Qatar) - 1256
-default locale: ID: ar_QA, Name: Arabic (Qatar)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: ar_QA, Name: Arabic (Qatar)
-default charset: windows-1256
-
-OS Locale (lcid: 4009, name: en-IN): English (India) - 1252
-default locale: ID: en_IN, Name: English (India)
-display locale: ID: en_IN, Name: English (India)
-format locale: ID: en_IN, Name: English (India)
-default charset: windows-1252
-
-OS Locale (lcid: 400a, name: es-BO): Spanish (Bolivia) - 1252
-default locale: ID: es_BO, Name: Spanish (Bolivia)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_BO, Name: Spanish (Bolivia)
-default charset: windows-1252
-
-OS Locale (lcid: 4409, name: en-MY): English (Malaysia) - 1252
-default locale: ID: en_MY, Name: English (Malaysia)
-display locale: ID: en_MY, Name: English (Malaysia)
-format locale: ID: en_MY, Name: English (Malaysia)
-default charset: windows-1252
-
-OS Locale (lcid: 440a, name: es-SV): Spanish (El Salvador) - 1252
-default locale: ID: es_SV, Name: Spanish (El Salvador)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_SV, Name: Spanish (El Salvador)
-default charset: windows-1252
-
-OS Locale (lcid: 4809, name: en-SG): English (Singapore) - 1252
-default locale: ID: en_SG, Name: English (Singapore)
-display locale: ID: en_SG, Name: English (Singapore)
-format locale: ID: en_SG, Name: English (Singapore)
-default charset: windows-1252
-
-OS Locale (lcid: 480a, name: es-HN): Spanish (Honduras) - 1252
-default locale: ID: es_HN, Name: Spanish (Honduras)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_HN, Name: Spanish (Honduras)
-default charset: windows-1252
-
-OS Locale (lcid: 4c0a, name: es-NI): Spanish (Nicaragua) - 1252
-default locale: ID: es_NI, Name: Spanish (Nicaragua)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_NI, Name: Spanish (Nicaragua)
-default charset: windows-1252
-
-OS Locale (lcid: 500a, name: es-PR): Spanish (Puerto Rico) - 1252
-default locale: ID: es_PR, Name: Spanish (Puerto Rico)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: es_PR, Name: Spanish (Puerto Rico)
-default charset: windows-1252
-
-OS Locale (lcid: 540a, name: es-US): Spanish (United States) - 1252
-default locale: ID: es_US, Name: Spanish (United States)
-display locale: ID: en, Name: English
-format locale: ID: es_US, Name: Spanish (United States)
-default charset: windows-1252
-
-OS UI Language (name: en-US)
-default locale: ID: en_US, Name: English (United States)
-display locale: ID: en_US, Name: English (United States)
-format locale: ID: en_US, Name: English (United States)
-default charset: windows-1252
-
-OS UI Language (name: ja-JP)
+
+OS UI Language (name: ja-JP)
default locale: ID: en_US, Name: English (United States)
display locale: ID: ja_JP, Name: Japanese (Japan)
format locale: ID: en_US, Name: English (United States)
--- a/jdk/test/java/util/ResourceBundle/Bug4168625Test.java Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/java/util/ResourceBundle/Bug4168625Test.java Sat Nov 13 18:56:50 2010 -0800
@@ -25,7 +25,7 @@
@summary test Resource Bundle for bug 4168625
@build Bug4168625Class Bug4168625Getter Bug4168625Resource Bug4168625Resource3 Bug4168625Resource3_en Bug4168625Resource3_en_CA Bug4168625Resource3_en_IE Bug4168625Resource3_en_US Bug4168625Resource2_en_US Bug4168625Resource2
@run main/timeout=600 Bug4168625Test
- @bug 4168625
+ @bug 4168625 6993339
*/
/*
*
@@ -50,9 +50,8 @@
import java.io.*;
/**
- * This test tries to correct three efficiency problems with the caching
- * mechanism of ResourceBundle. All tests assume that none of the bundles
- * have been previously loaded and cached. It also allows concurrent loads
+ * This test tries to correct two efficiency problems with the caching
+ * mechanism of ResourceBundle. It also allows concurrent loads
* of resource bundles to be performed if the bundles are unrelated (ex. a
* load of a local system resource by one thread while another thread is
* doing a slow load over a network).
@@ -230,83 +229,6 @@
}
}
- /**
- * Previous versions of ResourceBundle exhibited the following caching behavior.
- * Assume the class Bug4168625Resource_en exists. Bug4168625Resource_en_US does
- * not. Two threads, ThreadA and ThreadB both try to get the same bundle.
- * <P>
- * <pre>
- * ThreadA.getBundle("Bug4168625Resource", new Locale("en", "US"));
- * A-->try to load Bug4168625Resource_en_US
- * ThreadB.getBundle("Bug4168625Resource", new Locale("en", "US"));
- * B-->try to load Bug4168625Resource_en_US
- * B-->load Bug4168625Resource_en (#1)
- * A-->load Bug4168625Resource_en (#2)
- * A-->cache Bug4168625Resource_en (#2) as Bug4168625Resource_en
- * A-->cache Bug4168625Resource_en (#2) as Bug4168625Resource_en_US
- * A-->return Bug4168625Resource_en (#2)
- * B-->cache Bug4168625Resource_en (#1) as Bug4168625Resource_en
- * B-->cache Bug4168625Resource_en (#1) as Bug4168625Resource_en_US
- * B-->return Bug4168625Resource_en (#1)
- * </pre>
- * <P>
- * Both threads try and fail to load Bug4168625Resource_en_US. Both
- * threads load Bug4168625Resource_en. Both threads get their own copy
- * of the Bug4168625Resource_en resource.
- *
- * The desired behavior is as follows:
- * <P>
- * <pre>
- * ThreadA.getBundle("Bug4168625Resource", new Locale("en", "US"));
- * A-->try to load Bug4168625Resource_en_US
- * ThreadB.getBundle("Bug4168625Resource", new Locale("en", "US"));
- * B-->try to load Bug4168625Resource_en_US
- * B-->load Bug4168625Resource_en
- * A-->load Bug4168625Resource_en (block in ResourceBundle.getBundle)
- * B-->cache Bug4168625Resource_en as Bug4168625Resource_en
- * B-->cache Bug4168625Resource_en as Bug4168625Resource_en_US
- * A-->return Bug4168625Resource_en
- * B-->return Bug4168625Resource_en
- * </pre>
- * <P>
- * Note that both threads return the same bundle object.
- */
- public void testConcurrentLoading1() throws Exception {
- final Loader loader = new Loader( new String[] { "Bug4168625Class" }, new String[] { "Bug4168625Resource3_en_US", "Bug4168625Resource3_en_CA" });
- final Class c = loader.loadClass("Bug4168625Class");
- final Bug4168625Getter test = (Bug4168625Getter)c.newInstance();
-
- //both threads want the same resource
- ConcurrentLoadingThread thread1 = new ConcurrentLoadingThread(loader, test, new Locale("en", "US"));
- ConcurrentLoadingThread thread2 = new ConcurrentLoadingThread(loader, test, new Locale("en", "US"));
-
- thread1.start(); //start thread 1
- loader.waitForNotify(1); //wait for thread1 to do getBundle & block in loader
- thread2.start(); //start second thread
- loader.waitForNotify(2, 1000); //wait until thread2 blocks somewhere in getBundle
- thread1.ping(); //continue both threads
- thread2.ping();
-
- thread1.join(); //wait unitl both threads complete
- thread2.join();
-
- //Now, examine the class loads that were done.
- loader.logClasses("Classes loaded after completion of both threads:");
-
- boolean dups = false;
- for (int i = loader.loadedClasses.size() - 1; i >= 0 ; i--) {
- final Object item = loader.loadedClasses.elementAt(i);
- loader.loadedClasses.removeElementAt(i);
- if (loader.loadedClasses.contains(item)) {
- logln("Resource loaded more than once: "+item);
- dups = true;
- }
- }
- if (dups) {
- errln("ResourceBundle loaded some classes multiple times");
- }
- }
-
private class ConcurrentLoadingThread extends Thread {
private Loader loader;
public Object bundle;
@@ -355,7 +277,7 @@
* This test ensures that multiple resources can be loading at the same
* time as long as they don't depend on each other in some way.
*/
- public void testConcurrentLoading2() throws Exception {
+ public void testConcurrentLoading() throws Exception {
final Loader loader = new Loader( new String[] { "Bug4168625Class" }, new String[] { "Bug4168625Resource3_en_US", "Bug4168625Resource3_en_CA" });
final Class c = loader.loadClass("Bug4168625Class");
final Bug4168625Getter test = (Bug4168625Getter)c.newInstance();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JComponent/6989617/bug6989617.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 6989617
+ @summary Enable JComponent to control repaintings of its children
+ @author Alexander Potochkin
+ @run main bug6989617
+*/
+
+import javax.swing.*;
+import java.awt.*;
+
+public class bug6989617 {
+
+ private boolean isPaintingOrigin;
+ private boolean innerPanelRepainted, outerPanelRepainted;
+
+ public bug6989617() {
+
+ final JButton button = new JButton("button");
+
+ JPanel innerPanel = new JPanel() {
+ protected boolean isPaintingOrigin() {
+ return isPaintingOrigin;
+ }
+
+ public void repaint(long tm, int x, int y, int width, int height) {
+ if (button.getParent() != null) {
+ innerPanelRepainted = true;
+ if (!button.getSize().equals(new Dimension(width, height))) {
+ throw new RuntimeException("Wrong size of the dirty area");
+ }
+ if (!button.getLocation().equals(new Point(x, y))) {
+ throw new RuntimeException("Wrong location of the dirty area");
+ }
+ }
+ super.repaint(tm, x, y, width, height);
+ }
+ };
+
+ JPanel outerPanel = new JPanel() {
+ protected boolean isPaintingOrigin() {
+ return isPaintingOrigin;
+ }
+
+ public void repaint(long tm, int x, int y, int width, int height) {
+ if (button.getParent() != null) {
+ outerPanelRepainted = true;
+ if (!button.getSize().equals(new Dimension(width, height))) {
+ throw new RuntimeException("Wrong size of the dirty area");
+ }
+ }
+ super.repaint(tm, x, y, width, height);
+ }
+ };
+
+
+ outerPanel.add(innerPanel);
+ innerPanel.add(button);
+
+ outerPanel.setSize(100, 100);
+ innerPanel.setBounds(10, 10, 50, 50);
+ button.setBounds(10, 10, 20, 20);
+
+ if (innerPanelRepainted || outerPanelRepainted) {
+ throw new RuntimeException("Repainted flag is unexpectedly on");
+ }
+ button.repaint();
+ if (innerPanelRepainted || outerPanelRepainted) {
+ throw new RuntimeException("Repainted flag is unexpectedly on");
+ }
+ isPaintingOrigin = true;
+ button.repaint();
+ if (!innerPanelRepainted || !outerPanelRepainted) {
+ throw new RuntimeException("Repainted flag is unexpectedly off");
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ new bug6989617();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JTable/6735286/bug6735286.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 6735286
+ @summary javax.swing.DefaultTableCellRender.getTableCellRendererComponent() doesn't allow passing null Tables
+ @author Pavel Porvatov
+*/
+
+import javax.swing.*;
+
+public class bug6735286 {
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ new JTable().getDefaultRenderer(Object.class).getTableCellRendererComponent(null, "a value",
+ true, true, 0, 0);
+
+ }
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/Test6632810.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6632810
+ * @summary javax.swing.plaf.basic.BasicScrollPaneUI.getBaseline(JComponent, int, int) doesn't throw NPE and IAE
+ * @author Pavel Porvatov
+ */
+
+import javax.swing.*;
+import javax.swing.plaf.basic.BasicScrollPaneUI;
+
+public class Test6632810 {
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ BasicScrollPaneUI ui = new BasicScrollPaneUI();
+
+ ui.installUI(new JScrollPane());
+
+ try {
+ ui.getBaseline(null, 1, 1);
+
+ throw new RuntimeException("getBaseline(null, 1, 1) does not throw NPE");
+ } catch (NullPointerException e) {
+ // Ok
+ }
+
+ int[][] illegelParams = new int[][]{
+ {-1, 1,},
+ {1, -1,},
+ {-1, -1,},
+ };
+
+ for (int[] illegelParam : illegelParams) {
+ try {
+ int width = illegelParam[0];
+ int height = illegelParam[1];
+
+ ui.getBaseline(new JScrollPane(), width, height);
+
+ throw new RuntimeException("getBaseline(new JScrollPane(), " + width + ", " + height +
+ ") does not throw IAE");
+ } catch (IllegalArgumentException e) {
+ // Ok
+ }
+ }
+ }
+ });
+ }
+}
--- a/jdk/test/sun/text/resources/LocaleData Fri Nov 12 08:41:03 2010 -0500
+++ b/jdk/test/sun/text/resources/LocaleData Sat Nov 13 18:56:50 2010 -0800
@@ -5468,12 +5468,12 @@
LocaleNames/fr/GY=Guyana
# bug 4225362
-FormatData/fr/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
-FormatData/fr_BE/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
-FormatData/fr_CA/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
-FormatData/fr_CH/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
-FormatData/fr_FR/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
-FormatData/fr_LU/DateTimePatternChars=GaMjkHmsSEDFwWahKzZ
+FormatData/fr/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
+FormatData/fr_BE/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
+FormatData/fr_CA/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
+FormatData/fr_CH/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
+FormatData/fr_FR/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
+FormatData/fr_LU/DateTimePatternChars=GaMjkHmsSEDFwWxhKzZ
# bug 6547501
FormatData/fr/NumberPatterns/2=#,##0 %
--- a/langtools/.hgtags Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/.hgtags Sat Nov 13 18:56:50 2010 -0800
@@ -91,3 +91,5 @@
e4e7408cdc5b3d91d39161e1e94aad576ecc2dcd jdk7-b114
01e8ac5fbefd35d2d9a0996213cf2390fd164e57 jdk7-b115
857bfcea3f30cb5f4ae96f46a53ae1c772f9b0e5 jdk7-b116
+2129a046f117547fc8a5cb3397a767e6d528f5b6 jdk7-b117
+c491eec0acc73fa41b77e1619ed03e56d8a75b83 jdk7-b118
--- a/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.source.tree;
-
-import java.util.List;
-
-/**
- * A tree node for an annotated type
- *
- * For example:
- * <pre>
- * {@code @}<em>annotationType String</em>
- * {@code @}<em>annotationType</em> ( <em>arguments</em> ) <em>Date</em>
- * </pre>
- *
- * @see "JSR 308: Annotations on Java Types"
- *
- * @author Mahmood Ali
- * @since 1.7
- */
-public interface AnnotatedTypeTree extends ExpressionTree {
- List<? extends AnnotationTree> getAnnotations();
- ExpressionTree getUnderlyingType();
-}
--- a/langtools/src/share/classes/com/sun/source/tree/DisjointTypeTree.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.source.tree;
-
-import java.util.List;
-
-/**
- * A tree node for a disjoint type expression in a multicatch var declaration.
- *
- *
- * @author Maurizio Cimadamore
- *
- * @since 1.7
- */
-public interface DisjointTypeTree extends Tree {
- List<? extends Tree> getTypeComponents();
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/DisjunctiveTypeTree.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a disjunctive type expression in a multicatch var declaration.
+ *
+ *
+ * @author Maurizio Cimadamore
+ *
+ * @since 1.7
+ */
+public interface DisjunctiveTypeTree extends Tree {
+ List<? extends Tree> getTypeAlternatives();
+}
--- a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java Sat Nov 13 18:56:50 2010 -0800
@@ -53,7 +53,7 @@
Tree getReturnType();
List<? extends TypeParameterTree> getTypeParameters();
List<? extends VariableTree> getParameters();
- List<? extends AnnotationTree> getReceiverAnnotations();
+//308 List<? extends AnnotationTree> getReceiverAnnotations();
List<? extends ExpressionTree> getThrows();
BlockTree getBody();
Tree getDefaultValue(); // for annotation types
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java Sat Nov 13 18:56:50 2010 -0800
@@ -46,7 +46,7 @@
*/
public enum Kind {
- ANNOTATED_TYPE(AnnotatedTypeTree.class),
+//308 ANNOTATED_TYPE(AnnotatedTypeTree.class),
/**
* Used for instances of {@link AnnotationTree}.
@@ -234,9 +234,9 @@
PARAMETERIZED_TYPE(ParameterizedTypeTree.class),
/**
- * Used for instances of {@link DisjointTypeTree}.
+ * Used for instances of {@link DisjunctiveTypeTree}.
*/
- DISJOINT_TYPE(DisjointTypeTree.class),
+ DISJUNCTIVE_TYPE(DisjunctiveTypeTree.class),
/**
* Used for instances of {@link TypeCastTree}.
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Sat Nov 13 18:56:50 2010 -0800
@@ -57,7 +57,7 @@
* @since 1.6
*/
public interface TreeVisitor<R,P> {
- R visitAnnotatedType(AnnotatedTypeTree node, P p);
+//308 R visitAnnotatedType(AnnotatedTypeTree node, P p);
R visitAnnotation(AnnotationTree node, P p);
R visitMethodInvocation(MethodInvocationTree node, P p);
R visitAssert(AssertTree node, P p);
@@ -96,7 +96,7 @@
R visitCompilationUnit(CompilationUnitTree node, P p);
R visitTry(TryTree node, P p);
R visitParameterizedType(ParameterizedTypeTree node, P p);
- R visitDisjointType(DisjointTypeTree node, P p);
+ R visitDisjunctiveType(DisjunctiveTypeTree node, P p);
R visitArrayType(ArrayTypeTree node, P p);
R visitTypeCast(TypeCastTree node, P p);
R visitPrimitiveType(PrimitiveTypeTree node, P p);
--- a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Sat Nov 13 18:56:50 2010 -0800
@@ -47,5 +47,5 @@
public interface TypeParameterTree extends Tree {
Name getName();
List<? extends Tree> getBounds();
- List<? extends AnnotationTree> getAnnotations();
+//308 List<? extends AnnotationTree> getAnnotations();
}
--- a/langtools/src/share/classes/com/sun/source/util/AbstractTypeProcessor.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.source.util;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.processing.*;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
-
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.Log;
-
-import com.sun.source.tree.ClassTree;
-
-/**
- * This class is an abstract annotation processor designed to be a
- * convenient superclass for concrete "type processors", processors that
- * require the type information in the processed source.
- *
- * <p>Type processing occurs in one round after the tool (e.g. java compiler)
- * analyzes the source (all sources taken as input to the tool and sources
- * generated by other annotation processors).
- *
- * <p>The tool infrastructure will interact with classes extending this abstract
- * class as follows:
- *
- * <ol>
- * [1-3: Identical to {@link Processor} life cycle]
- *
- * <li>If an existing {@code Processor} object is not being used, to
- * create an instance of a processor the tool calls the no-arg
- * constructor of the processor class.
- *
- * <li>Next, the tool calls the {@link #init init} method with
- * an appropriate {@code ProcessingEnvironment}.
- *
- * <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
- * getSupportedAnnotationTypes}, {@link #getSupportedOptions
- * getSupportedOptions}, and {@link #getSupportedSourceVersion
- * getSupportedSourceVersion}. These methods are only called once per
- * run, not on each round.
- *
- * [4-5Unique to {@code AbstractTypeProcessor} subclasses]
- *
- * <li>For each class containing a supported annotation, the tool calls
- * {@link #typeProcess(TypeElement, TreePath) typeProcess} method on the
- * {@code Processor}. The class is guaranteed to be type-checked Java code
- * and all the tree type and symbol information is resolved.
- *
- * <li>Finally, the tools calls the
- * {@link #typeProcessingOver() typeProcessingOver} method
- * on the {@code Processor}.
- *
- * </ol>
- *
- * <p>The tool is permitted to ask type processors to process a class once
- * it is analyzed before the rest of classes are analyzed. The tool is also
- * permitted to stop type processing immediately if any errors are raised,
- * without invoking {@code typeProcessingOver}
- *
- * <p>A subclass may override any of the methods in this class, as long as the
- * general {@link javax.annotation.processing.Processor Processor}
- * contract is obeyed, with one notable exception.
- * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
- * is called during the regular annotation phase before classes are analyzed.
- *
- * @author Mahmood Ali
- * @since 1.7
- */
-public abstract class AbstractTypeProcessor extends AbstractProcessor {
- private final Set<Name> elements = new HashSet<Name>();
- private boolean hasInvokedTypeProcessingOver = false;
- private JavacProcessingEnvironment env;
- private final AttributionTaskListener listener = new AttributionTaskListener();
-
- /**
- * Constructor for subclasses to call.
- */
- protected AbstractTypeProcessor() { }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void init(ProcessingEnvironment env) {
- super.init(env);
- this.env = (JavacProcessingEnvironment)env;
- prepareContext(this.env.getContext());
- }
-
- /**
- * The use of this method is obsolete in type processors. The method is
- * called during regular annotation processing phase only.
- */
- @Override
- public final boolean process(Set<? extends TypeElement> annotations,
- RoundEnvironment roundEnv) {
- for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) {
- elements.add(elem.getQualifiedName());
- }
- return false;
- }
-
- /**
- * Processes a fully analyzed class that contains a supported annotation
- * (look {@link #getSupportedAnnotationTypes()}).
- *
- * <p>The passed class is always a valid type-checked Java code.
- *
- * @param element element of the analyzed class
- * @param tree the tree path to the element, with the leaf being a
- * {@link ClassTree}
- */
- public abstract void typeProcess(TypeElement element, TreePath tree);
-
- /**
- * A method to be called once all the classes are processed and no error
- * is reported.
- *
- * <p>Subclasses may override this method to do any aggregate analysis
- * (e.g. generate report, persistence) or resource deallocation.
- *
- * <p>If an error (a Java error or a processor error) is reported, this
- * method is not guaranteed to be invoked.
- */
- public void typeProcessingOver() { }
-
- /**
- * adds a listener for attribution.
- */
- private void prepareContext(Context context) {
- TaskListener otherListener = context.get(TaskListener.class);
- if (otherListener == null) {
- context.put(TaskListener.class, listener);
- } else {
- // handle cases of multiple listeners
- context.put(TaskListener.class, (TaskListener)null);
- TaskListeners listeners = new TaskListeners();
- listeners.add(otherListener);
- listeners.add(listener);
- context.put(TaskListener.class, listeners);
- }
- }
-
- /**
- * A task listener that invokes the processor whenever a class is fully
- * analyzed.
- */
- private final class AttributionTaskListener implements TaskListener {
-
- @Override
- public void finished(TaskEvent e) {
- Log log = Log.instance(env.getContext());
-
- if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
- typeProcessingOver();
- hasInvokedTypeProcessingOver = true;
- }
-
- if (e.getKind() != TaskEvent.Kind.ANALYZE)
- return;
-
- if (e.getTypeElement() == null)
- throw new AssertionError("event task without a type element");
- if (e.getCompilationUnit() == null)
- throw new AssertionError("even task without compilation unit");
-
- if (!elements.remove(e.getTypeElement().getQualifiedName()))
- return;
-
- if (log.nerrors != 0)
- return;
-
- TypeElement elem = e.getTypeElement();
- TreePath p = Trees.instance(env).getPath(elem);
-
- typeProcess(elem, p);
-
- if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
- typeProcessingOver();
- hasInvokedTypeProcessingOver = true;
- }
- }
-
- @Override
- public void started(TaskEvent e) { }
-
- }
-
- /**
- * A task listener multiplexer.
- */
- private static class TaskListeners implements TaskListener {
- private final List<TaskListener> listeners = new ArrayList<TaskListener>();
-
- public void add(TaskListener listener) {
- listeners.add(listener);
- }
-
- public void remove(TaskListener listener) {
- listeners.remove(listener);
- }
-
- @Override
- public void finished(TaskEvent e) {
- for (TaskListener listener : listeners)
- listener.finished(e);
- }
-
- @Override
- public void started(TaskEvent e) {
- for (TaskListener listener : listeners)
- listener.started(e);
- }
- }
-}
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Sat Nov 13 18:56:50 2010 -0800
@@ -228,7 +228,7 @@
return defaultAction(node, p);
}
- public R visitDisjointType(DisjointTypeTree node, P p) {
+ public R visitDisjunctiveType(DisjunctiveTypeTree node, P p) {
return defaultAction(node, p);
}
@@ -248,9 +248,9 @@
return defaultAction(node, p);
}
- public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
- return defaultAction(node, p);
- }
+//308 public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
+//308 return defaultAction(node, p);
+//308 }
public R visitErroneous(ErroneousTree node, P p) {
return defaultAction(node, p);
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Sat Nov 13 18:56:50 2010 -0800
@@ -138,7 +138,7 @@
r = scanAndReduce(node.getReturnType(), p, r);
r = scanAndReduce(node.getTypeParameters(), p, r);
r = scanAndReduce(node.getParameters(), p, r);
- r = scanAndReduce(node.getReceiverAnnotations(), p, r);
+//308 r = scanAndReduce(node.getReceiverAnnotations(), p, r);
r = scanAndReduce(node.getThrows(), p, r);
r = scanAndReduce(node.getBody(), p, r);
r = scanAndReduce(node.getDefaultValue(), p, r);
@@ -356,13 +356,13 @@
return r;
}
- public R visitDisjointType(DisjointTypeTree node, P p) {
- return scan(node.getTypeComponents(), p);
+ public R visitDisjunctiveType(DisjunctiveTypeTree node, P p) {
+ return scan(node.getTypeAlternatives(), p);
}
public R visitTypeParameter(TypeParameterTree node, P p) {
- R r = scan(node.getAnnotations(), p);
- r = scanAndReduce(node.getBounds(), p, r);
+ R r = scan(node.getBounds(), p);
+//308 R r = scanAndReduce(node.getAnnotations(), p, r);
return r;
}
@@ -380,11 +380,11 @@
return r;
}
- public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
- R r = scan(node.getAnnotations(), p);
- r = scanAndReduce(node.getUnderlyingType(), p, r);
- return r;
- }
+//308 public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
+//308 R r = scan(node.getAnnotations(), p);
+//308 r = scanAndReduce(node.getUnderlyingType(), p, r);
+//308 return r;
+//308 }
public R visitOther(Tree node, P p) {
return null;
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Sat Nov 13 18:56:50 2010 -0800
@@ -282,9 +282,10 @@
// System.err.println("COMP: " + ((JCCompilationUnit)tree).sourcefile);
env = enter.getTopLevelEnv((JCCompilationUnit)tree);
break;
+ case ANNOTATION_TYPE:
case CLASS:
+ case ENUM:
case INTERFACE:
- case ENUM:
// System.err.println("CLASS: " + ((JCClassDecl)tree).sym.getSimpleName());
env = enter.getClassEnv(((JCClassDecl)tree).sym);
break;
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Sat Nov 13 18:56:50 2010 -0800
@@ -231,9 +231,9 @@
public static final long PROPRIETARY = 1L<<38;
/**
- * Flag that marks a disjoint var in a multi-catch clause
+ * Flag that marks a disjunction var in a multi-catch clause
*/
- public static final long DISJOINT = 1L<<39;
+ public static final long DISJUNCTION = 1L<<39;
/**
* Flag that marks a signature-polymorphic invoke method.
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Sat Nov 13 18:56:50 2010 -0800
@@ -55,8 +55,8 @@
}
public void taFillAndLift(JCClassDecl tree, boolean visitBodies) {
- new TypeAnnotationPositions().scan(tree);
- new TypeAnnotationLift().scan(tree);
+//308 new TypeAnnotationPositions().scan(tree);
+//308 new TypeAnnotationLift().scan(tree);
}
private static class TypeAnnotationPositions extends TreeScanner {
@@ -113,9 +113,10 @@
p.pos = frame.pos;
return p;
+ case ANNOTATION_TYPE:
case CLASS:
+ case ENUM:
case INTERFACE:
- case ENUM:
p.pos = frame.pos;
if (((JCClassDecl)frame).extending == tree) {
p.type = TargetType.CLASS_EXTENDS;
@@ -208,11 +209,11 @@
}
return p;
- case ANNOTATED_TYPE: {
- List<JCTree> newPath = path.tail;
- return resolveFrame(newPath.head, newPath.tail.head,
- newPath, p);
- }
+//308 case ANNOTATED_TYPE: {
+//308 List<JCTree> newPath = path.tail;
+//308 return resolveFrame(newPath.head, newPath.tail.head,
+//308 newPath, p);
+//308 }
case METHOD_INVOCATION: {
JCMethodInvocation invocation = (JCMethodInvocation)frame;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Sat Nov 13 18:56:50 2010 -0800
@@ -121,6 +121,8 @@
sourceName = source.name;
relax = (options.isSet("-retrofit") ||
options.isSet("-relax"));
+ findDiamonds = options.get("findDiamond") != null &&
+ source.allowDiamond();
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
enableSunApiLintControl = options.isSet("enableSunApiLintControl");
}
@@ -154,6 +156,16 @@
*/
boolean allowAnonOuterThis;
+ /** Switch: generates a warning if diamond can be safely applied
+ * to a given new expression
+ */
+ boolean findDiamonds;
+
+ /**
+ * Internally enables/disables diamond finder feature
+ */
+ static final boolean allowDiamondFinder = true;
+
/**
* Switch: warn about use of variable before declaration?
* RFE: 6425594
@@ -1053,9 +1065,9 @@
if ((c.param.sym.flags() & FINAL) == 0) {
log.error(c.param.pos(), "multicatch.param.must.be.final", c.param.sym);
}
- c.param.sym.flags_field = c.param.sym.flags() | DISJOINT;
+ c.param.sym.flags_field = c.param.sym.flags() | DISJUNCTION;
}
- if (c.param.type.tsym.kind == Kinds.VAR) {
+ if (c.param.sym.kind == Kinds.VAR) {
c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
}
chk.checkType(c.param.vartype.pos(),
@@ -1572,6 +1584,24 @@
if (TreeInfo.isDiamond(tree)) {
clazztype = attribDiamond(localEnv, tree, clazztype, mapping, argtypes, typeargtypes);
clazz.type = clazztype;
+ } else if (allowDiamondFinder &&
+ clazztype.getTypeArguments().nonEmpty() &&
+ findDiamonds) {
+ Type inferred = attribDiamond(localEnv,
+ tree,
+ clazztype,
+ mapping,
+ argtypes,
+ typeargtypes);
+ if (!inferred.isErroneous() &&
+ inferred.tag == CLASS &&
+ types.isAssignable(inferred, pt.tag == NONE ? clazztype : pt, Warner.noWarnings) &&
+ chk.checkDiamond((ClassType)inferred).isEmpty()) {
+ String key = types.isSameType(clazztype, inferred) ?
+ "diamond.redundant.args" :
+ "diamond.redundant.args.1";
+ log.warning(tree.clazz.pos(), key, clazztype, inferred);
+ }
}
// If we have made no mistakes in the class type...
@@ -2839,9 +2869,9 @@
result = check(tree, owntype, TYP, pkind, pt);
}
- public void visitTypeDisjoint(JCTypeDisjoint tree) {
- List<Type> componentTypes = attribTypes(tree.components, env);
- tree.type = result = check(tree, types.lub(componentTypes), TYP, pkind, pt);
+ public void visitTypeDisjunction(JCTypeDisjunction tree) {
+ List<Type> alternatives = attribTypes(tree.alternatives, env);
+ tree.type = result = check(tree, types.lub(alternatives), TYP, pkind, pt);
}
public void visitTypeParameter(JCTypeParameter tree) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Sat Nov 13 18:56:50 2010 -0800
@@ -371,7 +371,7 @@
if (sym.adr >= firstadr && trackable(sym)) {
if ((sym.flags() & FINAL) != 0) {
if ((sym.flags() & PARAMETER) != 0) {
- if ((sym.flags() & DISJOINT) != 0) { //multi-catch parameter
+ if ((sym.flags() & DISJUNCTION) != 0) { //multi-catch parameter
log.error(pos, "multicatch.parameter.may.not.be.assigned",
sym);
}
@@ -983,7 +983,7 @@
thrown = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
- ((JCTypeDisjoint)l.head.param.vartype).components :
+ ((JCTypeDisjunction)l.head.param.vartype).alternatives :
List.of(l.head.param.vartype);
for (JCExpression ct : subClauses) {
caught = chk.incl(ct.type, caught);
@@ -1049,7 +1049,7 @@
alive = true;
JCVariableDecl param = l.head.param;
List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
- ((JCTypeDisjoint)l.head.param.vartype).components :
+ ((JCTypeDisjunction)l.head.param.vartype).alternatives :
List.of(l.head.param.vartype);
List<Type> ctypes = List.nil();
List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Sat Nov 13 18:56:50 2010 -0800
@@ -876,7 +876,8 @@
make.at(tree.pos);
if (addBridges) {
ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
- bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
+ if (false) //see CR: 6996415
+ bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
if ((tree.sym.flags() & INTERFACE) == 0)
addBridges(tree.pos(), tree.sym, bridges);
tree.defs = bridges.toList().prependList(tree.defs);
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Sat Nov 13 18:56:50 2010 -0800
@@ -1456,7 +1456,7 @@
List<Integer> gaps) {
if (startpc != endpc) {
List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ?
- ((JCTypeDisjoint)tree.param.vartype).components :
+ ((JCTypeDisjunction)tree.param.vartype).alternatives :
List.of(tree.param.vartype);
while (gaps.nonEmpty()) {
for (JCExpression subCatch : subClauses) {
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Sat Nov 13 18:56:50 2010 -0800
@@ -1090,7 +1090,7 @@
private boolean unrecoverableError() {
for (JCDiagnostic d: log.deferredDiagnostics) {
- if (d.getKind() == JCDiagnostic.Kind.ERROR && !d.isFlagSet(RESOLVE_ERROR))
+ if (d.getKind() == JCDiagnostic.Kind.ERROR && !d.isFlagSet(RECOVERABLE))
return true;
}
return false;
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Sat Nov 13 18:56:50 2010 -0800
@@ -30,6 +30,7 @@
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.util.ListBuffer.lb;
@@ -75,42 +76,6 @@
/** The name table. */
private Names names;
- // Because of javac's limited lookahead, some contexts are ambiguous in
- // the presence of type annotations even though they are not ambiguous
- // in the absence of type annotations. Consider this code:
- // void m(String [] m) { }
- // void m(String ... m) { }
- // After parsing "String", javac calls bracketsOpt which immediately
- // returns if the next character is not '['. Similarly, javac can see
- // if the next token is ... and in that case parse an ellipsis. But in
- // the presence of type annotations:
- // void m(String @A [] m) { }
- // void m(String @A ... m) { }
- // no finite lookahead is enough to determine whether to read array
- // levels or an ellipsis. Furthermore, if you call bracketsOpt, then
- // bracketsOpt first reads all the leading annotations and only then
- // discovers that it needs to fail. bracketsOpt needs a way to push
- // back the extra annotations that it read. (But, bracketsOpt should
- // not *always* be allowed to push back extra annotations that it finds
- // -- in most contexts, any such extra annotation is an error.
- // Another similar case occurs with arrays and receiver annotations:
- // String b() @Array [] @Receiver { }
- // String b() @Receiver { }
- //
- // The following two variables permit type annotations that have
- // already been read to be stored for later use. Alternate
- // implementations are possible but would cause much larger changes to
- // the parser.
- /** Type annotations that have already been read but have not yet been used. **/
- private List<JCTypeAnnotation> typeAnnotationsPushedBack = null;
- /**
- * If the parser notices extra annotations, then it either immediately
- * issues an error (if this variable is false) or places the extra
- * annotations in variable typeAnnotationsPushedBack (if this variable
- * is true).
- */
- private boolean permitTypeAnnotationsPushBack = false;
-
/** Construct a parser from a given scanner, tree factory and log.
*/
protected JavacParser(ParserFactory fac,
@@ -134,19 +99,13 @@
this.allowTWR = source.allowTryWithResources();
this.allowDiamond = source.allowDiamond();
this.allowMulticatch = source.allowMulticatch();
- this.allowTypeAnnotations = source.allowTypeAnnotations();
this.keepDocComments = keepDocComments;
if (keepDocComments)
docComments = new HashMap<JCTree,String>();
this.keepLineMap = keepLineMap;
this.errorTree = F.Erroneous();
- this.debugJSR308 = fac.options.get("TA:parser") != null;
}
- /** Switch: debug output for type-annotations operations
- */
- boolean debugJSR308;
-
/** Switch: Should generics be recognized?
*/
boolean allowGenerics;
@@ -183,10 +142,6 @@
*/
boolean allowAnnotations;
- /** Switch: should we recognize type annotations?
- */
- boolean allowTypeAnnotations;
-
/** Switch: should we recognize automatic resource management?
*/
boolean allowTWR;
@@ -312,9 +267,9 @@
private void reportSyntaxError(int pos, String key, Object... args) {
if (pos > S.errPos() || pos == Position.NOPOS) {
if (S.token() == EOF)
- log.error(pos, "premature.eof");
+ error(pos, "premature.eof");
else
- log.error(pos, key, args);
+ error(pos, key, args);
}
S.errPos(pos);
if (S.pos() == errorPos)
@@ -370,7 +325,7 @@
void checkNoMods(long mods) {
if (mods != 0) {
long lowestMod = mods & -mods;
- log.error(S.pos(), "mod.not.allowed.here",
+ error(S.pos(), "mod.not.allowed.here",
Flags.asFlagSet(lowestMod));
}
}
@@ -464,22 +419,22 @@
return name;
} else if (S.token() == ASSERT) {
if (allowAsserts) {
- log.error(S.pos(), "assert.as.identifier");
+ error(S.pos(), "assert.as.identifier");
S.nextToken();
return names.error;
} else {
- log.warning(S.pos(), "assert.as.identifier");
+ warning(S.pos(), "assert.as.identifier");
Name name = S.name();
S.nextToken();
return name;
}
} else if (S.token() == ENUM) {
if (allowEnums) {
- log.error(S.pos(), "enum.as.identifier");
+ error(S.pos(), "enum.as.identifier");
S.nextToken();
return names.error;
} else {
- log.warning(S.pos(), "enum.as.identifier");
+ warning(S.pos(), "enum.as.identifier");
Name name = S.name();
S.nextToken();
return name;
@@ -525,7 +480,7 @@
TypeTags.INT,
Convert.string2int(strval(prefix), S.radix()));
} catch (NumberFormatException ex) {
- log.error(S.pos(), "int.number.too.large", strval(prefix));
+ error(S.pos(), "int.number.too.large", strval(prefix));
}
break;
case LONGLITERAL:
@@ -534,7 +489,7 @@
TypeTags.LONG,
new Long(Convert.string2long(strval(prefix), S.radix())));
} catch (NumberFormatException ex) {
- log.error(S.pos(), "int.number.too.large", strval(prefix));
+ error(S.pos(), "int.number.too.large", strval(prefix));
}
break;
case FLOATLITERAL: {
@@ -547,9 +502,9 @@
n = Float.NaN;
}
if (n.floatValue() == 0.0f && !isZero(proper))
- log.error(S.pos(), "fp.number.too.small");
+ error(S.pos(), "fp.number.too.small");
else if (n.floatValue() == Float.POSITIVE_INFINITY)
- log.error(S.pos(), "fp.number.too.large");
+ error(S.pos(), "fp.number.too.large");
else
t = F.at(pos).Literal(TypeTags.FLOAT, n);
break;
@@ -564,9 +519,9 @@
n = Double.NaN;
}
if (n.doubleValue() == 0.0d && !isZero(proper))
- log.error(S.pos(), "fp.number.too.small");
+ error(S.pos(), "fp.number.too.small");
else if (n.doubleValue() == Double.POSITIVE_INFINITY)
- log.error(S.pos(), "fp.number.too.large");
+ error(S.pos(), "fp.number.too.large");
else
t = F.at(pos).Literal(TypeTags.DOUBLE, n);
break;
@@ -620,33 +575,7 @@
return term(EXPR);
}
- /**
- * parses (optional) type annotations followed by a type. If the
- * annotations are present before the type and are not consumed during array
- * parsing, this method returns a {@link JCAnnotatedType} consisting of
- * these annotations and the underlying type. Otherwise, it returns the
- * underlying type.
- *
- * <p>
- *
- * Note that this method sets {@code mode} to {@code TYPE} first, before
- * parsing annotations.
- */
public JCExpression parseType() {
- List<JCTypeAnnotation> annotations = typeAnnotationsOpt();
- return parseType(annotations);
- }
-
- public JCExpression parseType(List<JCTypeAnnotation> annotations) {
- JCExpression result = unannotatedType();
-
- if (!annotations.isEmpty())
- result = F.AnnotatedType(annotations, result);
-
- return result;
- }
-
- public JCExpression unannotatedType() {
return term(TYPE);
}
@@ -895,8 +824,8 @@
* | [TypeArguments] THIS [Arguments]
* | [TypeArguments] SUPER SuperSuffix
* | NEW [TypeArguments] Creator
- * | [Annotations] Ident { "." Ident }
- * [ [Annotations] "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
+ * | Ident { "." Ident }
+ * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
* | Arguments
* | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
* ]
@@ -1047,62 +976,23 @@
typeArgs = null;
} else return illegal();
break;
- case MONKEYS_AT:
-
- // only annotated targetting class literals or cast types are valid
- List<JCTypeAnnotation> typeAnnos = typeAnnotationsOpt();
- if (typeAnnos.isEmpty()) {
- // else there would be no '@'
- throw new AssertionError("type annos is empty");
- }
-
- JCExpression expr = term3();
-
- // Type annotations: If term3 just parsed a non-type, expect a
- // class literal (and issue a syntax error if there is no class
- // literal). Otherwise, create a JCAnnotatedType.
- if ((mode & TYPE) == 0) {
- if (expr.getTag() != JCTree.SELECT)
- return illegal(typeAnnos.head.pos);
- JCFieldAccess sel = (JCFieldAccess)expr;
- if (sel.name != names._class)
- return illegal();
- else {
- sel.selected = F.AnnotatedType(typeAnnos, sel.selected);
- t = expr;
- }
- } else {
- // type annotation targeting a cast
- t = toP(F.at(S.pos()).AnnotatedType(typeAnnos, expr));
- }
- break;
case IDENTIFIER: case ASSERT: case ENUM:
if (typeArgs != null) return illegal();
t = toP(F.at(S.pos()).Ident(ident()));
loop: while (true) {
pos = S.pos();
- final List<JCTypeAnnotation> annos = typeAnnotationsOpt();
-
- // need to report an error later if LBRACKET is for array
- // index access rather than array creation level
- if (!annos.isEmpty() && S.token() != LBRACKET && S.token() != ELLIPSIS)
- return illegal(annos.head.pos);
switch (S.token()) {
case LBRACKET:
S.nextToken();
-
if (S.token() == RBRACKET) {
-
S.nextToken();
-
- t = bracketsOpt(t, annos);
+ t = bracketsOpt(t);
t = toP(F.at(pos).TypeArray(t));
t = bracketsSuffix(t);
} else {
if ((mode & EXPR) != 0) {
mode = EXPR;
JCExpression t1 = term();
- if (!annos.isEmpty()) t = illegal(annos.head.pos);
t = to(F.at(pos).Indexed(t, t1));
}
accept(RBRACKET);
@@ -1155,14 +1045,6 @@
// typeArgs saved for next loop iteration.
t = toP(F.at(pos).Select(t, ident()));
break;
- case ELLIPSIS:
- if (this.permitTypeAnnotationsPushBack) {
- this.typeAnnotationsPushedBack = annos;
- } else if (annos.nonEmpty()) {
- // Don't return here -- error recovery attempt
- illegal(annos.head.pos);
- }
- break loop;
default:
break loop;
}
@@ -1201,18 +1083,14 @@
if (typeArgs != null) illegal();
while (true) {
int pos1 = S.pos();
-
- final List<JCTypeAnnotation> annos = typeAnnotationsOpt();
-
if (S.token() == LBRACKET) {
S.nextToken();
-
if ((mode & TYPE) != 0) {
int oldmode = mode;
mode = TYPE;
if (S.token() == RBRACKET) {
S.nextToken();
- t = bracketsOpt(t, annos);
+ t = bracketsOpt(t);
t = toP(F.at(pos1).TypeArray(t));
return t;
}
@@ -1247,12 +1125,6 @@
typeArgs = null;
}
} else {
- if (!annos.isEmpty()) {
- if (permitTypeAnnotationsPushBack)
- typeAnnotationsPushedBack = annos;
- else
- return illegal(annos.head.pos);
- }
break;
}
}
@@ -1262,7 +1134,6 @@
S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t));
S.nextToken();
}
-
return toP(t);
}
@@ -1400,26 +1271,24 @@
}
/** TypeArgument = Type
- * | [Annotations] "?"
- * | [Annotations] "?" EXTENDS Type {"&" Type}
- * | [Annotations] "?" SUPER Type
+ * | "?"
+ * | "?" EXTENDS Type {"&" Type}
+ * | "?" SUPER Type
*/
JCExpression typeArgument() {
- List<JCTypeAnnotation> annotations = typeAnnotationsOpt();
- if (S.token() != QUES) return parseType(annotations);
+ if (S.token() != QUES) return parseType();
int pos = S.pos();
S.nextToken();
- JCExpression result;
if (S.token() == EXTENDS) {
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
S.nextToken();
JCExpression bound = parseType();
- result = F.at(pos).Wildcard(t, bound);
+ return F.at(pos).Wildcard(t, bound);
} else if (S.token() == SUPER) {
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
S.nextToken();
JCExpression bound = parseType();
- result = F.at(pos).Wildcard(t, bound);
+ return F.at(pos).Wildcard(t, bound);
} else if (S.token() == IDENTIFIER) {
//error recovery
reportSyntaxError(S.prevEndPos(), "expected3",
@@ -1427,14 +1296,11 @@
TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
JCExpression wc = toP(F.at(pos).Wildcard(t, null));
JCIdent id = toP(F.at(S.pos()).Ident(ident()));
- result = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
+ return F.at(pos).Erroneous(List.<JCTree>of(wc, id));
} else {
TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
- result = toP(F.at(pos).Wildcard(t, null));
+ return toP(F.at(pos).Wildcard(t, null));
}
- if (!annotations.isEmpty())
- result = toP(F.at(annotations.head.pos).AnnotatedType(annotations,result));
- return result;
}
JCTypeApply typeArguments(JCExpression t) {
@@ -1443,47 +1309,21 @@
return toP(F.at(pos).TypeApply(t, args));
}
- /**
- * BracketsOpt = { [Annotations] "[" "]" }
- *
- * <p>
- *
- * <code>annotations</code> is the list of annotations targeting
- * the expression <code>t</code>.
+ /** BracketsOpt = {"[" "]"}
*/
- private JCExpression bracketsOpt(JCExpression t,
- List<JCTypeAnnotation> annotations) {
- List<JCTypeAnnotation> nextLevelAnnotations = typeAnnotationsOpt();
-
+ private JCExpression bracketsOpt(JCExpression t) {
if (S.token() == LBRACKET) {
int pos = S.pos();
S.nextToken();
-
- JCExpression orig = t;
- t = bracketsOptCont(t, pos, nextLevelAnnotations);
- } else if (!nextLevelAnnotations.isEmpty()) {
- if (permitTypeAnnotationsPushBack) {
- this.typeAnnotationsPushedBack = nextLevelAnnotations;
- } else
- return illegal(nextLevelAnnotations.head.pos);
+ t = bracketsOptCont(t, pos);
+ F.at(pos);
}
-
- int apos = S.pos();
- if (!annotations.isEmpty())
- t = F.at(apos).AnnotatedType(annotations, t);
return t;
}
- /** BracketsOpt = {"[" TypeAnnotations "]"}
- */
- private JCExpression bracketsOpt(JCExpression t) {
- return bracketsOpt(t, List.<JCTypeAnnotation>nil());
- }
-
- private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos,
- List<JCTypeAnnotation> annotations) {
+ private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
accept(RBRACKET);
- t = bracketsOpt(t, annotations);
+ t = bracketsOpt(t);
return toP(F.at(pos).TypeArray(t));
}
@@ -1517,29 +1357,18 @@
return t;
}
- /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
+ /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
*/
JCExpression creator(int newpos, List<JCExpression> typeArgs) {
-
- List<JCTypeAnnotation> newAnnotations = typeAnnotationsOpt();
-
switch (S.token()) {
case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN:
- if (typeArgs == null) {
- if (newAnnotations.isEmpty())
- return arrayCreatorRest(newpos, basicType());
- else
- return arrayCreatorRest(newpos, F.AnnotatedType(newAnnotations, basicType()));
- }
+ if (typeArgs == null)
+ return arrayCreatorRest(newpos, basicType());
break;
default:
}
JCExpression t = qualident();
- // handle type annotations for non primitive arrays
- if (!newAnnotations.isEmpty())
- t = F.AnnotatedType(newAnnotations, t);
-
int oldmode = mode;
mode = TYPE | DIAMOND;
if (S.token() == LT) {
@@ -1556,7 +1385,7 @@
}
}
mode = oldmode;
- if (S.token() == LBRACKET || S.token() == MONKEYS_AT) {
+ if (S.token() == LBRACKET) {
JCExpression e = arrayCreatorRest(newpos, t);
if (typeArgs != null) {
int pos = newpos;
@@ -1572,15 +1401,7 @@
}
return e;
} else if (S.token() == LPAREN) {
- JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t);
- if (newClass.def != null) {
- assert newClass.def.mods.annotations.isEmpty();
- if (newAnnotations.nonEmpty()) {
- newClass.def.mods.pos = earlier(newClass.def.mods.pos, newAnnotations.head.pos);
- newClass.def.mods.annotations = List.convert(JCAnnotation.class, newAnnotations);
- }
- }
- return newClass;
+ return classCreatorRest(newpos, null, typeArgs, t);
} else {
reportSyntaxError(S.pos(), "expected2",
LPAREN, LBRACKET);
@@ -1603,67 +1424,34 @@
return classCreatorRest(newpos, encl, typeArgs, t);
}
- /** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
- * | Expression "]" {[Annotations] "[" Expression "]"} BracketsOpt )
+ /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
+ * | Expression "]" {"[" Expression "]"} BracketsOpt )
*/
JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
-
- List<JCTypeAnnotation> topAnnos = List.nil();
- if (elemtype.getTag() == JCTree.ANNOTATED_TYPE) {
- JCAnnotatedType atype = (JCAnnotatedType) elemtype;
- topAnnos = atype.annotations;
- elemtype = atype.underlyingType;
- }
-
- List<JCTypeAnnotation> annos = typeAnnotationsOpt();
-
accept(LBRACKET);
-
if (S.token() == RBRACKET) {
accept(RBRACKET);
-
- elemtype = bracketsOpt(elemtype, annos);
-
+ elemtype = bracketsOpt(elemtype);
if (S.token() == LBRACE) {
- JCNewArray na = (JCNewArray)arrayInitializer(newpos, elemtype);
-
- na.annotations = topAnnos;
-
- return na;
+ return arrayInitializer(newpos, elemtype);
} else {
return syntaxError(S.pos(), "array.dimension.missing");
}
} else {
ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>();
-
- // maintain array dimension type annotations
- ListBuffer<List<JCTypeAnnotation>> dimAnnotations = ListBuffer.lb();
- dimAnnotations.append(annos);
-
dims.append(parseExpression());
accept(RBRACKET);
- while (S.token() == LBRACKET
- || (S.token() == MONKEYS_AT)) {
- List<JCTypeAnnotation> maybeDimAnnos = typeAnnotationsOpt();
+ while (S.token() == LBRACKET) {
int pos = S.pos();
S.nextToken();
if (S.token() == RBRACKET) {
- elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
+ elemtype = bracketsOptCont(elemtype, pos);
} else {
- if (S.token() == RBRACKET) { // no dimension
- elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
- } else {
- dimAnnotations.append(maybeDimAnnos);
- dims.append(parseExpression());
- accept(RBRACKET);
- }
+ dims.append(parseExpression());
+ accept(RBRACKET);
}
}
-
- JCNewArray na = toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
- na.annotations = topAnnos;
- na.dimAnnotations = dimAnnotations.toList();
- return na;
+ return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
}
}
@@ -1794,7 +1582,7 @@
case ENUM:
case ASSERT:
if (allowEnums && S.token() == ENUM) {
- log.error(S.pos(), "local.enum");
+ error(S.pos(), "local.enum");
stats.
append(classOrInterfaceOrEnumDeclaration(modifiersOpt(),
S.docComment()));
@@ -1941,9 +1729,9 @@
} else {
if (allowTWR) {
if (resources.isEmpty())
- log.error(pos, "try.without.catch.finally.or.resource.decls");
+ error(pos, "try.without.catch.finally.or.resource.decls");
} else
- log.error(pos, "try.without.catch.or.finally");
+ error(pos, "try.without.catch.or.finally");
}
return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
}
@@ -2040,7 +1828,7 @@
JCModifiers mods = optFinal(Flags.PARAMETER);
List<JCExpression> catchTypes = catchTypes();
JCExpression paramType = catchTypes.size() > 1 ?
- toP(F.at(catchTypes.head.getStartPosition()).TypeDisjoint(catchTypes)) :
+ toP(F.at(catchTypes.head.getStartPosition()).TypeDisjunction(catchTypes)) :
catchTypes.head;
JCVariableDecl formal = variableDeclaratorId(mods, paramType);
accept(RPAREN);
@@ -2142,32 +1930,17 @@
new ListBuffer<JCExpressionStatement>()).toList();
}
- enum AnnotationKind { DEFAULT_ANNO, TYPE_ANNO };
-
/** AnnotationsOpt = { '@' Annotation }
*/
- List<JCAnnotation> annotationsOpt(AnnotationKind kind) {
+ List<JCAnnotation> annotationsOpt() {
if (S.token() != MONKEYS_AT) return List.nil(); // optimization
ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>();
- int prevmode = mode;
while (S.token() == MONKEYS_AT) {
int pos = S.pos();
S.nextToken();
- buf.append(annotation(pos, kind));
+ buf.append(annotation(pos));
}
- lastmode = mode;
- mode = prevmode;
- List<JCAnnotation> annotations = buf.toList();
-
- if (debugJSR308 && kind == AnnotationKind.TYPE_ANNO)
- System.out.println("TA: parsing " + annotations
- + " in " + log.currentSourceFile());
- return annotations;
- }
-
- List<JCTypeAnnotation> typeAnnotationsOpt() {
- List<JCAnnotation> annotations = annotationsOpt(AnnotationKind.TYPE_ANNO);
- return List.convert(JCTypeAnnotation.class, annotations);
+ return buf.toList();
}
/** ModifiersOpt = { Modifier }
@@ -2213,13 +1986,13 @@
case MONKEYS_AT : flag = Flags.ANNOTATION; break;
default: break loop;
}
- if ((flags & flag) != 0) log.error(S.pos(), "repeated.modifier");
+ if ((flags & flag) != 0) error(S.pos(), "repeated.modifier");
lastPos = S.pos();
S.nextToken();
if (flag == Flags.ANNOTATION) {
checkAnnotations();
if (S.token() != INTERFACE) {
- JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO);
+ JCAnnotation ann = annotation(lastPos);
// if first modifier is an annotation, set pos to annotation's.
if (flags == 0 && annotations.isEmpty())
pos = ann.pos;
@@ -2250,18 +2023,12 @@
/** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
* @param pos position of "@" token
*/
- JCAnnotation annotation(int pos, AnnotationKind kind) {
+ JCAnnotation annotation(int pos) {
// accept(AT); // AT consumed by caller
checkAnnotations();
- if (kind == AnnotationKind.TYPE_ANNO)
- checkTypeAnnotations();
JCTree ident = qualident();
List<JCExpression> fieldValues = annotationFieldValuesOpt();
- JCAnnotation ann;
- if (kind == AnnotationKind.DEFAULT_ANNO)
- ann = F.at(pos).Annotation(ident, fieldValues);
- else
- ann = F.at(pos).TypeAnnotation(ident, fieldValues);
+ JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
storeEnd(ann, S.prevEndPos());
return ann;
}
@@ -2314,7 +2081,7 @@
case MONKEYS_AT:
pos = S.pos();
S.nextToken();
- return annotation(pos, AnnotationKind.DEFAULT_ANNO);
+ return annotation(pos);
case LBRACE:
pos = S.pos();
accept(LBRACE);
@@ -2565,7 +2332,7 @@
}
} else {
if (S.token() == ENUM) {
- log.error(S.pos(), "enums.not.supported.in.source", source.name);
+ error(S.pos(), "enums.not.supported.in.source", source.name);
allowEnums = true;
return enumDeclaration(mods, dc);
}
@@ -2705,7 +2472,7 @@
S.resetDeprecatedFlag();
}
int pos = S.pos();
- List<JCAnnotation> annotations = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
+ List<JCAnnotation> annotations = annotationsOpt();
JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
List<JCExpression> typeArgs = typeArgumentsOpt();
int identPos = S.pos();
@@ -2802,29 +2569,19 @@
} else {
pos = S.pos();
List<JCTypeParameter> typarams = typeParametersOpt();
- List<JCAnnotation> annosAfterParams = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
-
Name name = S.name();
pos = S.pos();
JCExpression type;
boolean isVoid = S.token() == VOID;
if (isVoid) {
- if (annosAfterParams.nonEmpty())
- illegal(annosAfterParams.head.pos);
type = to(F.at(pos).TypeIdent(TypeTags.VOID));
S.nextToken();
} else {
- if (annosAfterParams.nonEmpty()) {
- mods.annotations = mods.annotations.appendList(annosAfterParams);
- if (mods.pos == Position.NOPOS)
- mods.pos = mods.annotations.head.pos;
- }
- // method returns types are un-annotated types
- type = unannotatedType();
+ type = parseType();
}
if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) {
if (isInterface || name != className)
- log.error(pos, "invalid.meth.decl.ret.type.req");
+ error(pos, "invalid.meth.decl.ret.type.req");
return List.of(methodDeclaratorRest(
pos, mods, null, names.init, typarams,
isInterface, true, dc));
@@ -2856,15 +2613,15 @@
}
/** MethodDeclaratorRest =
- * FormalParameters BracketsOpt [Annotations] [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
+ * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
* VoidMethodDeclaratorRest =
- * FormalParameters [Annotations] [Throws TypeList] ( MethodBody | ";")
+ * FormalParameters [Throws TypeList] ( MethodBody | ";")
* InterfaceMethodDeclaratorRest =
- * FormalParameters BracketsOpt [Annotations] [THROWS TypeList] ";"
+ * FormalParameters BracketsOpt [THROWS TypeList] ";"
* VoidInterfaceMethodDeclaratorRest =
- * FormalParameters [Annotations] [THROWS TypeList] ";"
+ * FormalParameters [THROWS TypeList] ";"
* ConstructorDeclaratorRest =
- * "(" FormalParameterListOpt ")" [Annotations] [THROWS TypeList] MethodBody
+ * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
*/
JCTree methodDeclaratorRest(int pos,
JCModifiers mods,
@@ -2874,22 +2631,7 @@
boolean isInterface, boolean isVoid,
String dc) {
List<JCVariableDecl> params = formalParameters();
-
- List<JCTypeAnnotation> receiverAnnotations;
- if (!isVoid) {
- // need to distinguish between receiver anno and array anno
- // look at typeAnnotationsPushedBack comment
- this.permitTypeAnnotationsPushBack = true;
- type = methodReturnArrayRest(type);
- this.permitTypeAnnotationsPushBack = false;
- if (typeAnnotationsPushedBack == null)
- receiverAnnotations = List.nil();
- else
- receiverAnnotations = typeAnnotationsPushedBack;
- typeAnnotationsPushedBack = null;
- } else
- receiverAnnotations = typeAnnotationsOpt();
-
+ if (!isVoid) type = bracketsOpt(type);
List<JCExpression> thrown = List.nil();
if (S.token() == THROWS) {
S.nextToken();
@@ -2919,51 +2661,20 @@
JCMethodDecl result =
toP(F.at(pos).MethodDef(mods, name, type, typarams,
- params, receiverAnnotations, thrown,
+ params, thrown,
body, defaultValue));
attach(result, dc);
return result;
}
- /** Parses the array levels after the format parameters list, and append
- * them to the return type, while preseving the order of type annotations
- */
- private JCExpression methodReturnArrayRest(JCExpression type) {
- if (type.getTag() != JCTree.TYPEARRAY)
- return bracketsOpt(type);
-
- JCArrayTypeTree baseArray = (JCArrayTypeTree)type;
- while (TreeInfo.typeIn(baseArray.elemtype) instanceof JCArrayTypeTree)
- baseArray = (JCArrayTypeTree)TreeInfo.typeIn(baseArray.elemtype);
-
- if (baseArray.elemtype.getTag() == JCTree.ANNOTATED_TYPE) {
- JCAnnotatedType at = (JCAnnotatedType)baseArray.elemtype;
- at.underlyingType = bracketsOpt(at.underlyingType);
- } else {
- baseArray.elemtype = bracketsOpt(baseArray.elemtype);
- }
-
- return type;
- }
-
- /** QualidentList = [Annotations] Qualident {"," [Annotations] Qualident}
+ /** QualidentList = Qualident {"," Qualident}
*/
List<JCExpression> qualidentList() {
ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
-
- List<JCTypeAnnotation> typeAnnos = typeAnnotationsOpt();
- if (!typeAnnos.isEmpty())
- ts.append(F.AnnotatedType(typeAnnos, qualident()));
- else
- ts.append(qualident());
+ ts.append(qualident());
while (S.token() == COMMA) {
S.nextToken();
-
- typeAnnos = typeAnnotationsOpt();
- if (!typeAnnos.isEmpty())
- ts.append(F.AnnotatedType(typeAnnos, qualident()));
- else
- ts.append(qualident());
+ ts.append(qualident());
}
return ts.toList();
}
@@ -2987,13 +2698,12 @@
}
}
- /** TypeParameter = [Annotations] TypeVariable [TypeParameterBound]
+ /** TypeParameter = TypeVariable [TypeParameterBound]
* TypeParameterBound = EXTENDS Type {"&" Type}
* TypeVariable = Ident
*/
JCTypeParameter typeParameter() {
int pos = S.pos();
- List<JCTypeAnnotation> annos = typeAnnotationsOpt();
Name name = ident();
ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>();
if (S.token() == EXTENDS) {
@@ -3004,7 +2714,7 @@
bounds.append(parseType());
}
}
- return toP(F.at(pos).TypeParameter(name, bounds.toList(), annos));
+ return toP(F.at(pos).TypeParameter(name, bounds.toList()));
}
/** FormalParameters = "(" [ FormalParameterList ] ")"
@@ -3038,37 +2748,26 @@
*/
JCVariableDecl formalParameter() {
JCModifiers mods = optFinal(Flags.PARAMETER);
- // need to distinguish between vararg annos and array annos
- // look at typeAnnotaitonsPushedBack comment
- this.permitTypeAnnotationsPushBack = true;
JCExpression type = parseType();
- this.permitTypeAnnotationsPushBack = false;
-
if (S.token() == ELLIPSIS) {
- List<JCTypeAnnotation> varargsAnnos = typeAnnotationsPushedBack;
- typeAnnotationsPushedBack = null;
checkVarargs();
mods.flags |= Flags.VARARGS;
- // insert var arg type annotations
- if (varargsAnnos != null && varargsAnnos.nonEmpty())
- type = F.at(S.pos()).AnnotatedType(varargsAnnos, type);
type = to(F.at(S.pos()).TypeArray(type));
-
S.nextToken();
- } else {
- // if not a var arg, then typeAnnotationsPushedBack should be null
- if (typeAnnotationsPushedBack != null
- && !typeAnnotationsPushedBack.isEmpty()) {
- reportSyntaxError(typeAnnotationsPushedBack.head.pos,
- "illegal.start.of.type");
- }
- typeAnnotationsPushedBack = null;
}
return variableDeclaratorId(mods, type);
}
/* ---------- auxiliary methods -------------- */
+ void error(int pos, String key, Object ... args) {
+ log.error(DiagnosticFlag.SYNTAX, pos, key, args);
+ }
+
+ void warning(int pos, String key, Object ... args) {
+ log.warning(pos, key, args);
+ }
+
/** Check that given tree is a legal expression statement.
*/
protected JCExpression checkExprStat(JCExpression t) {
@@ -3084,7 +2783,7 @@
case JCTree.ERRONEOUS:
return t;
default:
- log.error(t.pos, "not.stmt");
+ error(t.pos, "not.stmt");
return F.at(t.pos).Erroneous(List.<JCTree>of(t));
}
}
@@ -3231,55 +2930,49 @@
void checkGenerics() {
if (!allowGenerics) {
- log.error(S.pos(), "generics.not.supported.in.source", source.name);
+ error(S.pos(), "generics.not.supported.in.source", source.name);
allowGenerics = true;
}
}
void checkVarargs() {
if (!allowVarargs) {
- log.error(S.pos(), "varargs.not.supported.in.source", source.name);
+ error(S.pos(), "varargs.not.supported.in.source", source.name);
allowVarargs = true;
}
}
void checkForeach() {
if (!allowForeach) {
- log.error(S.pos(), "foreach.not.supported.in.source", source.name);
+ error(S.pos(), "foreach.not.supported.in.source", source.name);
allowForeach = true;
}
}
void checkStaticImports() {
if (!allowStaticImport) {
- log.error(S.pos(), "static.import.not.supported.in.source", source.name);
+ error(S.pos(), "static.import.not.supported.in.source", source.name);
allowStaticImport = true;
}
}
void checkAnnotations() {
if (!allowAnnotations) {
- log.error(S.pos(), "annotations.not.supported.in.source", source.name);
+ error(S.pos(), "annotations.not.supported.in.source", source.name);
allowAnnotations = true;
}
}
- void checkTypeAnnotations() {
- if (!allowTypeAnnotations) {
- log.error(S.pos(), "type.annotations.not.supported.in.source", source.name);
- allowTypeAnnotations = true;
- }
- }
void checkDiamond() {
if (!allowDiamond) {
- log.error(S.pos(), "diamond.not.supported.in.source", source.name);
+ error(S.pos(), "diamond.not.supported.in.source", source.name);
allowDiamond = true;
}
}
void checkMulticatch() {
if (!allowMulticatch) {
- log.error(S.pos(), "multicatch.not.supported.in.source", source.name);
+ error(S.pos(), "multicatch.not.supported.in.source", source.name);
allowMulticatch = true;
}
}
void checkAutomaticResourceManagement() {
if (!allowTWR) {
- log.error(S.pos(), "automatic.resource.management.not.supported.in.source", source.name);
+ error(S.pos(), "automatic.resource.management.not.supported.in.source", source.name);
allowTWR = true;
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Sat Nov 13 18:56:50 2010 -0800
@@ -49,11 +49,11 @@
import javax.tools.JavaFileObject;
import javax.tools.DiagnosticListener;
-import com.sun.tools.javac.api.JavacTrees;
-import com.sun.source.util.AbstractTypeProcessor;
+//308 import com.sun.source.util.AbstractTypeProcessor;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.file.JavacFileManager;
@@ -712,7 +712,7 @@
}
if (matchedNames.size() > 0 || ps.contributed) {
- foundTypeProcessors = foundTypeProcessors || (ps.processor instanceof AbstractTypeProcessor);
+//308 foundTypeProcessors = foundTypeProcessors || (ps.processor instanceof AbstractTypeProcessor);
boolean processingResult = callProcessor(ps.processor, typeElements, renv);
ps.contributed = true;
ps.removeSupportedOptions(unmatchedProcessorOptions);
@@ -939,7 +939,7 @@
break;
case ERROR:
- if (fatalErrors || !d.isFlagSet(RESOLVE_ERROR))
+ if (fatalErrors || !d.isFlagSet(RECOVERABLE))
return true;
break;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Sat Nov 13 18:56:50 2010 -0800
@@ -873,6 +873,13 @@
found raw type: {0}\n\
missing type parameters for generic class {1}
+compiler.warn.diamond.redundant.args=\
+ redundant type arguments in new expression (use diamond operator instead).
+compiler.warn.diamond.redundant.args.1=\
+ redundant type arguments in new expression (use diamond operator instead).\n\
+ explicit: {0}\n\
+ inferred: {1}
+
#####
## The following are tokens which are non-terminals in the language. They should
@@ -1299,9 +1306,9 @@
annotations are not supported in -source {0}\n\
(use -source 5 or higher to enable annotations)
-compiler.err.type.annotations.not.supported.in.source=\
- type annotations are not supported in -source {0}\n\
-(use -source 7 or higher to enable type annotations)
+#308 compiler.err.type.annotations.not.supported.in.source=\
+#308 type annotations are not supported in -source {0}\n\
+#308 (use -source 7 or higher to enable type annotations)
compiler.err.foreach.not.supported.in.source=\
for-each loops are not supported in -source {0}\n\
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Sat Nov 13 18:56:50 2010 -0800
@@ -236,13 +236,13 @@
*/
public static final int TYPEAPPLY = TYPEARRAY + 1;
- /** Disjunctive types, of type TypeDisjoint.
+ /** Disjunction types, of type TypeDisjunction
*/
- public static final int TYPEDISJOINT = TYPEAPPLY + 1;
+ public static final int TYPEDISJUNCTION = TYPEAPPLY + 1;
/** Formal type parameters, of type TypeParameter.
*/
- public static final int TYPEPARAMETER = TYPEDISJOINT + 1;
+ public static final int TYPEPARAMETER = TYPEDISJUNCTION + 1;
/** Type argument.
*/
@@ -1888,30 +1888,30 @@
}
/**
- * A disjoint type, T1 | T2 | ... Tn (used in multicatch statements)
+ * A disjunction type, T1 | T2 | ... Tn (used in multicatch statements)
*/
- public static class JCTypeDisjoint extends JCExpression implements DisjointTypeTree {
+ public static class JCTypeDisjunction extends JCExpression implements DisjunctiveTypeTree {
- public List<JCExpression> components;
+ public List<JCExpression> alternatives;
- protected JCTypeDisjoint(List<JCExpression> components) {
- this.components = components;
+ protected JCTypeDisjunction(List<JCExpression> components) {
+ this.alternatives = components;
}
@Override
- public void accept(Visitor v) { v.visitTypeDisjoint(this); }
+ public void accept(Visitor v) { v.visitTypeDisjunction(this); }
- public Kind getKind() { return Kind.DISJOINT_TYPE; }
+ public Kind getKind() { return Kind.DISJUNCTIVE_TYPE; }
- public List<JCExpression> getTypeComponents() {
- return components;
+ public List<JCExpression> getTypeAlternatives() {
+ return alternatives;
}
@Override
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
- return v.visitDisjointType(this, d);
+ return v.visitDisjunctiveType(this, d);
}
@Override
public int getTag() {
- return TYPEDISJOINT;
+ return TYPEDISJUNCTION;
}
}
@@ -2067,17 +2067,23 @@
}
}
- public static class JCAnnotatedType extends JCExpression implements com.sun.source.tree.AnnotatedTypeTree {
+ public static class JCAnnotatedType extends JCExpression
+//308 implements com.sun.source.tree.AnnotatedTypeTree
+ {
public List<JCTypeAnnotation> annotations;
public JCExpression underlyingType;
protected JCAnnotatedType(List<JCTypeAnnotation> annotations, JCExpression underlyingType) {
- this.annotations = annotations;
- this.underlyingType = underlyingType;
+ throw new UnsupportedOperationException();
+//308 this.annotations = annotations;
+//308 this.underlyingType = underlyingType;
}
@Override
public void accept(Visitor v) { v.visitAnnotatedType(this); }
- public Kind getKind() { return Kind.ANNOTATED_TYPE; }
+ public Kind getKind() {
+ throw new UnsupportedOperationException();
+//308 return Kind.ANNOTATED_TYPE;
+ }
public List<JCTypeAnnotation> getAnnotations() {
return annotations;
}
@@ -2086,7 +2092,8 @@
}
@Override
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
- return v.visitAnnotatedType(this, d);
+ throw new UnsupportedOperationException();
+//308 return v.visitAnnotatedType(this, d);
}
@Override
public int getTag() {
@@ -2277,7 +2284,7 @@
public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); }
public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); }
public void visitTypeApply(JCTypeApply that) { visitTree(that); }
- public void visitTypeDisjoint(JCTypeDisjoint that) { visitTree(that); }
+ public void visitTypeDisjunction(JCTypeDisjunction that) { visitTree(that); }
public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
public void visitWildcard(JCWildcard that) { visitTree(that); }
public void visitTypeBoundKind(TypeBoundKind that) { visitTree(that); }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Sat Nov 13 18:56:50 2010 -0800
@@ -1195,9 +1195,9 @@
}
}
- public void visitTypeDisjoint(JCTypeDisjoint tree) {
+ public void visitTypeDisjunction(JCTypeDisjunction tree) {
try {
- printExprs(tree.components, " | ");
+ printExprs(tree.alternatives, " | ");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Sat Nov 13 18:56:50 2010 -0800
@@ -71,12 +71,12 @@
return lb.toList();
}
- public JCTree visitAnnotatedType(AnnotatedTypeTree node, P p) {
- JCAnnotatedType t = (JCAnnotatedType) node;
- List<JCTypeAnnotation> annotations = copy(t.annotations, p);
- JCExpression underlyingType = copy(t.underlyingType, p);
- return M.at(t.pos).AnnotatedType(annotations, underlyingType);
- }
+//308 public JCTree visitAnnotatedType(AnnotatedTypeTree node, P p) {
+//308 JCAnnotatedType t = (JCAnnotatedType) node;
+//308 List<JCTypeAnnotation> annotations = copy(t.annotations, p);
+//308 JCExpression underlyingType = copy(t.underlyingType, p);
+//308 return M.at(t.pos).AnnotatedType(annotations, underlyingType);
+//308 }
public JCTree visitAnnotation(AnnotationTree node, P p) {
JCAnnotation t = (JCAnnotation) node;
@@ -346,10 +346,10 @@
return M.at(t.pos).TypeApply(clazz, arguments);
}
- public JCTree visitDisjointType(DisjointTypeTree node, P p) {
- JCTypeDisjoint t = (JCTypeDisjoint) node;
- List<JCExpression> components = copy(t.components, p);
- return M.at(t.pos).TypeDisjoint(components);
+ public JCTree visitDisjunctiveType(DisjunctiveTypeTree node, P p) {
+ JCTypeDisjunction t = (JCTypeDisjunction) node;
+ List<JCExpression> components = copy(t.alternatives, p);
+ return M.at(t.pos).TypeDisjunction(components);
}
public JCTree visitArrayType(ArrayTypeTree node, P p) {
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Sat Nov 13 18:56:50 2010 -0800
@@ -119,7 +119,7 @@
}
public static boolean isMultiCatch(JCCatch catchClause) {
- return catchClause.param.vartype.getTag() == JCTree.TYPEDISJOINT;
+ return catchClause.param.vartype.getTag() == JCTree.TYPEDISJUNCTION;
}
/** Is statement an initializer for a synthetic field?
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Sat Nov 13 18:56:50 2010 -0800
@@ -451,8 +451,8 @@
return tree;
}
- public JCTypeDisjoint TypeDisjoint(List<JCExpression> components) {
- JCTypeDisjoint tree = new JCTypeDisjoint(components);
+ public JCTypeDisjunction TypeDisjunction(List<JCExpression> components) {
+ JCTypeDisjunction tree = new JCTypeDisjunction(components);
tree.pos = pos;
return tree;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Sat Nov 13 18:56:50 2010 -0800
@@ -276,8 +276,8 @@
scan(tree.arguments);
}
- public void visitTypeDisjoint(JCTypeDisjoint tree) {
- scan(tree.components);
+ public void visitTypeDisjunction(JCTypeDisjunction tree) {
+ scan(tree.alternatives);
}
public void visitTypeParameter(JCTypeParameter tree) {
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Sat Nov 13 18:56:50 2010 -0800
@@ -368,8 +368,8 @@
result = tree;
}
- public void visitTypeDisjoint(JCTypeDisjoint tree) {
- tree.components = translate(tree.components);
+ public void visitTypeDisjunction(JCTypeDisjunction tree) {
+ tree.alternatives = translate(tree.alternatives);
result = tree;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractLog.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractLog.java Sat Nov 13 18:56:50 2010 -0800
@@ -30,6 +30,7 @@
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
@@ -103,6 +104,19 @@
report(diags.error(source, wrap(pos), key, args));
}
+ /** Report an error, unless another error was already reported at same
+ * source position.
+ * @param flag A flag to set on the diagnostic
+ * @param pos The source position at which to report the error.
+ * @param key The key for the localized error message.
+ * @param args Fields of the error message.
+ */
+ public void error(DiagnosticFlag flag, int pos, String key, Object ... args) {
+ JCDiagnostic d = diags.error(source, wrap(pos), key, args);
+ d.setFlag(flag);
+ report(d);
+ }
+
/** Report a warning, unless suppressed by the -nowarn option or the
* maximum number of warnings has been reached.
* @param pos The source position at which to report the warning.
--- a/langtools/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Sat Nov 13 18:56:50 2010 -0800
@@ -63,17 +63,23 @@
DiagnosticFormatter<JCDiagnostic> formatter;
final String prefix;
+ final Set<DiagnosticFlag> defaultErrorFlags;
/** Create a new diagnostic factory. */
protected Factory(Context context) {
this(JavacMessages.instance(context), "compiler");
context.put(diagnosticFactoryKey, this);
+
+ Options options = Options.instance(context);
+ if (options.isSet("onlySyntaxErrorsUnrecoverable"))
+ defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE);
}
/** Create a new diagnostic factory. */
public Factory(JavacMessages messages, String prefix) {
this.prefix = prefix;
this.formatter = new BasicDiagnosticFormatter(messages);
+ defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY);
}
/**
@@ -85,7 +91,7 @@
*/
public JCDiagnostic error(
DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
- return create(ERROR, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
+ return create(ERROR, null, defaultErrorFlags, source, pos, key, args);
}
/**
@@ -331,7 +337,9 @@
public enum DiagnosticFlag {
MANDATORY,
- RESOLVE_ERROR
+ RESOLVE_ERROR,
+ SYNTAX,
+ RECOVERABLE
}
private final DiagnosticType type;
@@ -547,6 +555,17 @@
public void setFlag(DiagnosticFlag flag) {
flags.add(flag);
+
+ if (type == DiagnosticType.ERROR) {
+ switch (flag) {
+ case SYNTAX:
+ flags.remove(DiagnosticFlag.RECOVERABLE);
+ break;
+ case RESOLVE_ERROR:
+ flags.add(DiagnosticFlag.RECOVERABLE);
+ break;
+ }
+ }
}
public boolean isFlagSet(DiagnosticFlag flag) {
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Sat Nov 13 18:56:50 2010 -0800
@@ -850,6 +850,12 @@
String[] paramTypes, Set<ClassDocImpl> searched) {
//### Note that this search is not necessarily what the compiler would do!
+ Names names = tsym.name.table.names;
+ // do not match constructors
+ if (names.init.contentEquals(methodName)) {
+ return null;
+ }
+
ClassDocImpl cdi;
MethodDocImpl mdi;
@@ -876,7 +882,6 @@
*---------------------------------*/
// search current class
- Names names = tsym.name.table.names;
Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
//### Using modifier filter here isn't really correct,
--- a/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java Sat Nov 13 18:56:50 2010 -0800
@@ -637,6 +637,7 @@
* Should be called only on symbols representing methods.
*/
public MethodDocImpl getMethodDoc(MethodSymbol meth) {
+ assert !meth.isConstructor() : "not expecting a constructor symbol";
MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
if (result != null) return result;
result = new MethodDocImpl(this, meth);
@@ -665,6 +666,7 @@
* Should be called only on symbols representing constructors.
*/
public ConstructorDocImpl getConstructorDoc(MethodSymbol meth) {
+ assert meth.isConstructor() : "expecting a constructor symbol";
ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
if (result != null) return result;
result = new ConstructorDocImpl(this, meth);
--- a/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java Sat Nov 13 18:56:50 2010 -0800
@@ -26,6 +26,7 @@
package com.sun.tools.javah;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -74,6 +75,7 @@
import static javax.tools.Diagnostic.Kind.*;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
+import com.sun.tools.javac.main.CommandLine;
/**
* Javah generates support files for native methods.
@@ -362,7 +364,7 @@
if (fileManager == null)
fileManager = getDefaultFileManager(diagnosticListener, log);
- Iterator<String> iter = args.iterator();
+ Iterator<String> iter = expandAtArgs(args).iterator();
noArgs = !iter.hasNext();
while (iter.hasNext()) {
@@ -416,6 +418,18 @@
throw new BadArgs("err.unknown.option", name).showUsage(true);
}
+ private Iterable<String> expandAtArgs(Iterable<String> args) throws BadArgs {
+ try {
+ List<String> l = new ArrayList<String>();
+ for (String arg: args) l.add(arg);
+ return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));
+ } catch (FileNotFoundException e) {
+ throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());
+ } catch (IOException e) {
+ throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());
+ }
+ }
+
public Boolean call() {
return run();
}
@@ -607,8 +621,8 @@
}
};
+ }
- }
private String getMessage(String key, Object... args) {
return getMessage(task_locale, key, args);
}
--- a/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties Sat Nov 13 18:56:50 2010 -0800
@@ -30,6 +30,8 @@
The directory {0} could not be create for output.
at.args.cant.read=\
Can''t read command line arguments from file {1}.
+at.args.file.not.found=\
+ Can''t find file {0}.
at.args.io.exception=\
The following I/O problem was encountered when processing an @ \
argument on the command line: {0}.
--- a/langtools/test/tools/javac/T6985181.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6985181
- * @summary Annotations lost from classfile
- */
-
-import java.io.*;
-import java.util.*;
-
-public class T6985181 {
- public static void main(String... args) throws Exception{
- new T6985181().run();
- }
-
- public void run() throws Exception {
- String code = "@interface Simple { }\ninterface Test<@Simple T> { }";
-
- File srcFile = writeFile("Test.java", code);
- File classesDir = new File("classes");
- classesDir.mkdirs();
- compile("-d", classesDir.getPath(), srcFile.getPath());
- String out = javap(new File(classesDir, srcFile.getName().replace(".java", ".class")));
- if (!out.contains("RuntimeInvisibleTypeAnnotations"))
- throw new Exception("RuntimeInvisibleTypeAnnotations not found");
- }
-
- void compile(String... args) throws Exception {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- int rc = com.sun.tools.javac.Main.compile(args, pw);
- pw.close();
- String out = sw.toString();
- if (out.length() > 0)
- System.err.println(out);
- if (rc != 0)
- throw new Exception("Compilation failed: rc=" + rc);
- }
-
- String javap(File classFile) throws Exception {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- String[] args = { "-v", classFile.getPath() };
- int rc = com.sun.tools.javap.Main.run(args, pw);
- pw.close();
- String out = sw.toString();
- if (out.length() > 0)
- System.err.println(out);
- if (rc != 0)
- throw new Exception("javap failed: rc=" + rc);
- return out;
- }
-
- File writeFile(String path, String body) throws IOException {
- File f = new File(path);
- FileWriter out = new FileWriter(f);
- try {
- out.write(body);
- } finally {
- out.close();
- }
- return f;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T6993301.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6993301
+ * @summary catch parameters do not have correct kind (i.e. ElementKind.EXCEPTION_PARAMETER)
+ */
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+public class T6993301 {
+ public static void main(String... args) throws Exception {
+ new T6993301().testExceptionParameterCorrectKind();
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+
+ public void testExceptionParameterCorrectKind() throws IOException {
+ final String bootPath = System.getProperty("sun.boot.class.path");
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+
+ String code = "package test; public class Test { { try { } catch (NullPointerException ex) {} } }";
+
+ final JavacTaskImpl ct = (JavacTaskImpl)tool.getTask(null, null, null,
+ Arrays.asList("-bootclasspath", bootPath),
+ null, Arrays.asList(new MyFileObject(code)));
+ CompilationUnitTree cut = ct.parse().iterator().next();
+
+ ct.analyze();
+
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitVariable(VariableTree node, Void p) {
+ Element el = Trees.instance(ct).getElement(getCurrentPath());
+
+ assertNotNull(el);
+ assertEquals(ElementKind.EXCEPTION_PARAMETER, el.getKind());
+
+ return super.visitVariable(node, p);
+ }
+ }.scan(cut, null);
+ }
+
+ private void assertNotNull(Object o) {
+ if (o == null)
+ throw new AssertionError();
+ }
+
+ private <T> void assertEquals(T expected, T actual) {
+ if (expected == null ? actual == null : expected.equals(actual))
+ return;
+ throw new AssertionError("expected: " + expected + ", actual: " + actual);
+ }
+
+}
--- a/langtools/test/tools/javac/annotations/6881115/T6881115.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/annotations/6881115/T6881115.java Sat Nov 13 18:56:50 2010 -0800
@@ -16,5 +16,5 @@
}
@A(b = @B(b2 = 1, b2 = 2),
b_arr = {@B(), @B(b2 = 1, b2 = 2)})
-class T6881115<@A(b = @B(b2 = 1, b2 = 2),
- b_arr = {@B(), @B(b2 = 1, b2 = 2)}) X> {}
+class T6881115</*308 @A(b = @B(b2 = 1, b2 = 2),
+ b_arr = {@B(), @B(b2 = 1, b2 = 2)})*/ X> {}
--- a/langtools/test/tools/javac/annotations/6881115/T6881115.out Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/annotations/6881115/T6881115.out Sat Nov 13 18:56:50 2010 -0800
@@ -8,9 +8,4 @@
T6881115.java:18:13: compiler.err.annotation.missing.default.value.1: B, b1,b2
T6881115.java:18:30: compiler.err.duplicate.annotation.member.value: b2, B
T6881115.java:18:19: compiler.err.annotation.missing.default.value: B, b1
-T6881115.java:19:34: compiler.err.duplicate.annotation.member.value: b2, B
-T6881115.java:19:23: compiler.err.annotation.missing.default.value: B, b1
-T6881115.java:20:28: compiler.err.annotation.missing.default.value.1: B, b1,b2
-T6881115.java:20:45: compiler.err.duplicate.annotation.member.value: b2, B
-T6881115.java:20:34: compiler.err.annotation.missing.default.value: B, b1
-15 errors
+10 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.warn.diamond.redundant.args
+// options: -XDfindDiamond
+
+class Foo<X> {
+ Foo<String> fs = new Foo<String>();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.warn.diamond.redundant.args.1
+// options: -XDfindDiamond
+
+class Foo<X> {
+ Foo<?> fs = new Foo<String>();
+}
--- a/langtools/test/tools/javac/diags/examples/TypeAnnotationsNotSupported.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.err.type.annotations.not.supported.in.source
-// options: -source 6
-
-@interface Anno { }
-
-class TypeAnnotationsNotSupported {
- void m() {
- int i = (@Anno int) 3.14;
- }
-}
--- a/langtools/test/tools/javac/generics/OverrideBridge.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/generics/OverrideBridge.java Sat Nov 13 18:56:50 2010 -0800
@@ -23,7 +23,8 @@
/*
* @test
- * @bug 6337171
+ * @bug 6337171 6996415
+ * @ignore fix has been disabled as a consequence of 6996415
* @summary javac should create bridge methods when type variable bounds restricted
* @run main OverrideBridge
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/T6939780.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,25 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6939780
+ *
+ * @summary add a warning to detect diamond sites
+ * @author mcimadamore
+ * @compile/ref=T6939780.out T6939780.java -XDrawDiagnostics -XDfindDiamond
+ *
+ */
+
+class T6939780 {
+
+ void test() {
+ class Foo<X extends Number> {
+ Foo() {}
+ Foo(X x) {}
+ }
+ Foo<Number> f1 = new Foo<Number>(1);
+ Foo<?> f2 = new Foo<Number>();
+ Foo<?> f3 = new Foo<Integer>();
+ Foo<Number> f4 = new Foo<Number>(1) {};
+ Foo<?> f5 = new Foo<Number>() {};
+ Foo<?> f6 = new Foo<Integer>() {};
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/T6939780.out Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,5 @@
+T6939780.java:19:28: compiler.warn.diamond.redundant.args: Foo<java.lang.Number>, Foo<java.lang.Number>
+T6939780.java:20:28: compiler.warn.diamond.redundant.args.1: Foo<java.lang.Integer>, Foo<java.lang.Number>
+T6939780.java:22:28: compiler.warn.diamond.redundant.args: Foo<java.lang.Number>, Foo<java.lang.Number>
+T6939780.java:23:28: compiler.warn.diamond.redundant.args.1: Foo<java.lang.Integer>, Foo<java.lang.Number>
+4 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/SemanticErrorTest.1.out Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,2 @@
+SemanticErrorTest.java:11:46: compiler.err.repeated.interface
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/SemanticErrorTest.2.out Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,4 @@
+SemanticErrorTest.java:11:46: compiler.err.repeated.interface
+- compiler.err.proc.messager: Deliberate Error
+SemanticErrorTest.java:11:46: compiler.err.repeated.interface
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/SemanticErrorTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6994946
+ * @summary option to specify only syntax errors as unrecoverable
+ * @library ../../lib
+ * @build JavacTestingAbstractProcessor TestProcessor
+ * @compile/fail/ref=SemanticErrorTest.1.out -XDrawDiagnostics -processor TestProcessor SemanticErrorTest.java
+ * @compile/fail/ref=SemanticErrorTest.2.out -XDrawDiagnostics -XDonlySyntaxErrorsUnrecoverable -processor TestProcessor SemanticErrorTest.java
+ */
+
+class SemanticErrorTest implements Runnable, Runnable {
+ public void run() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/SyntaxErrorTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6994946
+ * @summary option to specify only syntax errors as unrecoverable
+ * @library ../../lib
+ * @build JavacTestingAbstractProcessor TestProcessor
+ * @compile/fail/ref=SyntaxErrorTest.out -XDrawDiagnostics -processor TestProcessor SyntaxErrorTest.java
+ * @compile/fail/ref=SyntaxErrorTest.out -XDrawDiagnostics -XDonlySyntaxErrorsUnrecoverable -processor TestProcessor SyntaxErrorTest.java
+ */
+
+class SyntaxErrorTest {
+ int i
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/SyntaxErrorTest.out Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,2 @@
+SyntaxErrorTest.java:12:10: compiler.err.expected: ';'
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/6994946/TestProcessor.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.*;
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import static javax.tools.Diagnostic.Kind.*;
+
+public class TestProcessor extends JavacTestingAbstractProcessor {
+ private int round = 0;
+
+ public boolean process(Set<? extends TypeElement> annotations,
+ RoundEnvironment roundEnv) {
+ if (++round == 1)
+ messager.printMessage(ERROR, "Deliberate Error");
+ return false;
+ }
+}
+
--- a/langtools/test/tools/javac/processing/model/element/TestAnonClassNames.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/processing/model/element/TestAnonClassNames.java Sat Nov 13 18:56:50 2010 -0800
@@ -78,7 +78,7 @@
@Nesting(LOCAL)
class LocalClass{};
- Object o = new @Nesting(ANONYMOUS) Object() { // An anonymous annotated class
+ Object o = new /*@Nesting(ANONYMOUS)*/ Object() { // An anonymous annotated class
public String toString() {
return "I have no name!";
}
@@ -95,9 +95,10 @@
for(Class<?> clazz : classes) {
String name = clazz.getName();
+ Nesting anno = clazz.getAnnotation(Nesting.class);
System.out.format("%s is %s%n",
clazz.getName(),
- clazz.getAnnotation(Nesting.class).value());
+ anno == null ? "(unset/ANONYMOUS)" : anno.value());
testClassName(name);
}
}
@@ -161,8 +162,8 @@
typeElt.getQualifiedName().toString(),
typeElt.getKind().toString(),
nestingKind.toString());
-
- if (typeElt.getAnnotation(Nesting.class).value() != nestingKind) {
+ Nesting anno = typeElt.getAnnotation(Nesting.class);
+ if ((anno == null ? NestingKind.ANONYMOUS : anno.value()) != nestingKind) {
throw new RuntimeException("Mismatch of expected and reported nesting kind.");
}
}
--- a/langtools/test/tools/javac/tree/TreePosTest.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/tree/TreePosTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -357,7 +357,9 @@
check("encl.start <= start", encl, self, encl.start <= self.start);
check("start <= pos", encl, self, self.start <= self.pos);
if (!(self.tag == JCTree.TYPEARRAY
- && (encl.tag == JCTree.VARDEF || encl.tag == JCTree.TYPEARRAY))) {
+ && (encl.tag == JCTree.VARDEF ||
+ encl.tag == JCTree.METHODDEF ||
+ encl.tag == JCTree.TYPEARRAY))) {
check("encl.pos <= start || end <= encl.pos",
encl, self, encl.pos <= self.start || self.end <= encl.pos);
}
--- a/langtools/test/tools/javac/treeannotests/AnnoTreeTests.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @build DA TA Test TestProcessor
- * @compile -proc:only -processor TestProcessor AnnoTreeTests.java
- */
-
-@Test(6)
-class AnnoTreeTests {
- // primitive types
- @DA("int") int i1;
- int i2 = (@TA("int") int) 0;
-
- // simple array types
- @DA("int[]") int[] a1;
- int @TA("int") [] a2;
- int[] a3 = (@TA("int[]") int[]) a1;
- int[] a4 = (int @TA("int") []) a1;
-
- // multi-dimensional array types
- // (still to come)
-}
--- a/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6967002
- * @summary JDK7 b99 javac compilation error (java.lang.AssertionError)
- * @author Maurizio Cimadamore
- * @compile/fail/ref=T6967002.out -XDrawDiagnostics T6967002.java
- */
-class Test {
- private static void m(byte[] octets) {
- return m(octets..., ?);
- }
-}
--- a/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-T6967002.java:33:22: compiler.err.expected: ')'
-T6967002.java:33:25: compiler.err.illegal.start.of.expr
-T6967002.java:33:28: compiler.err.illegal.start.of.expr
-T6967002.java:33:29: compiler.err.illegal.start.of.expr
-T6967002.java:33:27: compiler.err.not.stmt
-T6967002.java:33:30: compiler.err.expected: ';'
-T6967002.java:35:2: compiler.err.premature.eof
-7 errors
--- a/langtools/test/tools/javac/typeAnnotations/InnerClass.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary compiler crashes when visiting inner classes
- * @author Mahmood Ali
- * @compile -source 1.7 InnerClass.java
- */
-
-class InnerClass {
-
- InnerClass() {}
- InnerClass(Object o) {}
-
- private void a() {
- new Object() {
- public <R> void method() { }
- };
- }
-
- Object f1 = new InnerClass() {
- <R> void method() { }
- };
-
- Object f2 = new InnerClass() {
- <@A R> void method() { }
- };
-
- Object f3 = new InnerClass(null) {
- <R> void method() { }
- };
-
- Object f4 = new InnerClass(null) {
- <@A R> void method() { }
- };
- @interface A { }
-}
--- a/langtools/test/tools/javac/typeAnnotations/MultipleTargets.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary check that type annotations may appear on void method if it is a
- * method annotation too.
- * @author Mahmood Ali
- * @compile -source 1.7 MultipleTargets.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class TypeUseTarget<K extends @A Object> {
- @A void voidMethod() { }
-}
-
-@Target({ElementType.TYPE_USE, ElementType.METHOD})
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/TypeParameterTarget.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary check that type annotations may appear on all type parameter
- * @author Mahmood Ali
- * @compile -source 1.7 TypeParameterTarget.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class TypeUseTarget<@A K extends Object> {
- String[] field;
-
- <@A K, @A V> String genericMethod(K k) { return null; }
-}
-
-interface MyInterface { }
-
-@interface MyAnnotation { }
-
-@Target(ElementType.TYPE_PARAMETER)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/TypeUseTarget.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary check that type annotations may appear on all type declarations
- * @author Mahmood Ali
- * @compile -source 1.7 TypeUseTarget.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-@A
-class TypeUseTarget<K extends @A Object> {
- @A String @A [] field;
-
- @A String test(@A String param, @A String @A ... vararg) @A {
- @A Object o = new @A String @A [3];
- TypeUseTarget<@A String> target;
- return (@A String) null;
- }
-
- <K> @A String genericMethod(K k) { return null; }
-}
-
-@A
-interface MyInterface { }
-
-@A
-@interface MyAnnotation { }
-
-@Target(ElementType.TYPE_USE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/attribution/Scopes.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary test scopes of attribution
- * @author Mahmood Ali
- * @compile -source 1.7 Scopes.java
- */
-class Scopes {
-
- void test() @A(VALUE) { }
- void test1() @A(value=VALUE) { }
-
- private static final int VALUE = 1;
- @interface A { int value(); }
-}
--- a/langtools/test/tools/javac/typeAnnotations/classfile/DeadCode.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import java.net.URL;
-import java.util.List;
-
-import com.sun.tools.classfile.*;
-
-/*
- * @test
- * @bug 6917130
- * @summary test that optimized away annotations are not emited to classfile
- */
-
-public class DeadCode {
- public static void main(String[] args) throws Exception {
- new DeadCode().run();
- }
-
- public void run() throws Exception {
- ClassFile cf = getClassFile("DeadCode$Test.class");
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
- URL url = getClass().getResource(name);
- InputStream in = url.openStream();
- try {
- return ClassFile.read(in);
- } finally {
- in.close();
- }
- }
-
- /************ Helper annotations counting methods ******************/
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- void countAnnotations() {
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-
- /*********************** Test class *************************/
- static int expected_invisibles = 1;
- static int expected_visibles = 0;
- static class Test {
- @interface A {}
-
- void test() {
- List<? extends @A Object> o = null;
- o.toString();
-
- @A String m;
- if (false) {
- @A String a;
- @A String b = "m";
- b.toString();
- List<? extends @A Object> c = null;
- c.toString();
- }
- }
- }
-
-}
--- a/langtools/test/tools/javac/typeAnnotations/failures/AnnotationVersion.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test that only java 7 allows type annotations
- * @author Mahmood Ali
- * @compile/fail/ref=AnnotationVersion.out -XDrawDiagnostics -source 1.6 AnnotationVersion.java
- */
-class AnnotationVersion {
- public void method() @A { }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/AnnotationVersion.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-AnnotationVersion.java:9:25: compiler.err.type.annotations.not.supported.in.source: 1.6
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/IncompleteArray.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test incomplete array declaration
- * @author Mahmood Ali
- * @compile/fail/ref=IncompleteArray.out -XDrawDiagnostics -source 1.7 IncompleteArray.java
- */
-class IncompleteArray {
- int @A [] @A var;
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/IncompleteArray.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-IncompleteArray.java:9:13: compiler.err.illegal.start.of.type
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/IncompleteVararg.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test incomplete vararg declaration
- * @author Mahmood Ali
- * @compile/fail/ref=IncompleteVararg.out -XDrawDiagnostics -source 1.7 IncompleteVararg.java
- */
-class IncompleteArray {
- // the last variable may be vararg
- void method(int @A test) { }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/IncompleteVararg.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-IncompleteVararg.java:10:19: compiler.err.illegal.start.of.type
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/IndexArray.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test indexing of an array
- * @author Mahmood Ali
- * @compile/fail/ref=IndexArray.out -XDrawDiagnostics -source 1.7 IndexArray.java
- */
-class IndexArray {
- int[] var;
- int a = var @A [1];
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/IndexArray.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-IndexArray.java:10:15: compiler.err.illegal.start.of.expr
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/LintCast.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-import java.util.List;
-
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test that compiler doesn't warn about annotated redundant casts
- * @author Mahmood Ali
- * @compile/ref=LintCast.out -Xlint:cast -XDrawDiagnostics -source 1.7 LintCast.java
- */
-class LintCast {
- void unparameterized() {
- String s = "m";
- String s1 = (String)s;
- String s2 = (@A String)s;
- }
-
- void parameterized() {
- List<String> l = null;
- List<String> l1 = (List<String>)l;
- List<String> l2 = (List<@A String>)l;
- }
-
- void array() {
- int @A [] a = null;
- int[] a1 = (int[])a;
- int[] a2 = (int @A [])a;
- }
-
- void sameAnnotations() {
- @A String annotated = null;
- String unannotated = null;
-
- // compiler ignore annotated casts even if redundant
- @A String anno1 = (@A String)annotated;
-
- // warn if redundant without an annotation
- String anno2 = (String)annotated;
- String unanno2 = (String)unannotated;
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/LintCast.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-LintCast.java:13:21: compiler.warn.redundant.cast: java.lang.String
-LintCast.java:19:27: compiler.warn.redundant.cast: java.util.List<java.lang.String>
-LintCast.java:25:20: compiler.warn.redundant.cast: int[]
-LintCast.java:37:24: compiler.warn.redundant.cast: java.lang.String
-LintCast.java:38:26: compiler.warn.redundant.cast: java.lang.String
-5 warnings
--- a/langtools/test/tools/javac/typeAnnotations/failures/OldArray.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary test old array syntax
- * @author Mahmood Ali
- * @compile/fail -XDrawDiagnostics -source 1.7 OldArray.java
- */
-class OldArray {
- String [@A] s() { return null; }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/Scopes.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check that A is accessible in the class type parameters
- * @author Mahmood Ali
- * @compile/fail/ref=Scopes.out -XDrawDiagnostics -source 1.7 Scopes.java
- */
-class Scopes<T extends @UniqueInner Object> {
- @interface UniqueInner { };
-}
--- a/langtools/test/tools/javac/typeAnnotations/failures/Scopes.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Scopes.java:8:25: compiler.err.cant.resolve: kindname.class, UniqueInner, ,
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/StaticFields.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary static field access isn't a valid location
- * @author Mahmood Ali
- * @compile/fail/ref=StaticFields.out -XDrawDiagnostics -source 1.7 StaticFields.java
- */
-class C {
- int f;
- int a = @A C.f;
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/StaticFields.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-StaticFields.java:10:17: compiler.err.illegal.start.of.expr
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/StaticMethods.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary static methods don't have receivers
- * @author Mahmood Ali
- * @compile/fail/ref=StaticMethods.out -XDrawDiagnostics -source 1.7 StaticMethods.java
- */
-class StaticMethods {
- static void main() @A { }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/StaticMethods.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-StaticMethods.java:9:22: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/VoidGenericMethod.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary test type annotation on void generic methods
- * @author Mahmood Ali
- * @compile/fail -source 1.7 VoidGenericMethod.java
- */
-class VoidGenericMethod {
- public <T> @A void method() { }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void test() {
- Object a = String @A(value = 2, value = 1) [].class;
- }
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:10:37: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnnotation {
- void test() {
- Object a = String @A @A [].class;
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:11:26: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation {
- void test() {
- Object a = String @A [].class;
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:11:23: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void test() {
- Object a = String @A [].class;
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrayclass/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:10:23: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void test() {
- String @A(value = 2, value = 1) [] s;
- }
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:10:26: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnnotation {
- void test() {
- String @A @A [] s;
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:11:15: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation {
- void test() {
- String @A [] s;
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:11:12: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void test() {
- String @A [] s;
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/arrays/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:10:12: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values for type parameter
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void method() {
- class Inner<@A(value = 2, value = 1) K> {}
- }
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:10:31: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-class DuplicateTypeAnno {
- void innermethod() {
- class Inner<@A @A K> { }
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:10:20: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-class InvalidLocation {
- void innermethod() {
- class Inner<@A K> {}
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:10:17: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void innermethod() {
- class Inner<@A K> { }
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/innertypeparams/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:10:17: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void test() {
- String[] a = new String @A(value = 2, value = 1) [5] ;
- }
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:10:43: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnnotation {
- void test() {
- String[] a = new String @A @A [5] ;
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:11:32: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation {
- void test() {
- String[] s = new String @A [5] ;
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:11:29: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void test() {
- String[] a = new String @A [5];
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/newarray/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:10:29: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values for type parameter
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue<K extends @A(value = 2, value = 1) Object> {
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:8:56: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnno<K extends @A @A Object> {
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:9:38: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation<K extends @A Object> {
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:9:33: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue<K extends @A Object> {
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/parambounds/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:8:40: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values in receiver
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void test() @A(value = 2, value = 1) { }
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:9:29: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations in receiver
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnnotation {
- void test() @A @A { }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:10:18: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation {
- void test() @A {
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:10:15: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void test() @A { }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/receiver/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:9:15: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for Duplicate annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue {
- void test() {
- new @A String();
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:10:9: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnnotation {
- void test() {
- new @A @A String();
- }
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:11:12: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation {
- void test() {
- new @A String();
- }
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:11:9: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue {
- void test() {
- new @A String();
- }
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/rest/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:10:9: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values for type parameter
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue<K> {
- DuplicateAnnotationValue<@A(value = 2, value = 1) String> l;
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:9:42: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnno<K> {
- DuplicateTypeAnno<@A @A String> l;
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:10:24: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation<K> {
- InvalidLocation<@A String> l;
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:10:19: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue<K> {
- MissingAnnotationValue<@A String> l;
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeArgs/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:9:26: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values for type parameter
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue<@A(value = 2, value = 1) K> {
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:8:46: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnno<@A @A K> {
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:9:28: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation<@A K> {
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:9:23: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue<@A K> {
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/typeparams/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:8:30: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/DuplicateAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077 6919944
- * @summary check for duplicate annotation values for type parameter
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
- */
-class DuplicateAnnotationValue<K> {
- DuplicateAnnotationValue<@A(value = 2, value = 1) ?> l;
-}
-
-@interface A { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/DuplicateAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateAnnotationValue.java:9:42: compiler.err.duplicate.annotation.member.value: value, A
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/DuplicateTypeAnnotation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for duplicate annotations
- * @author Mahmood Ali
- * @compile/fail/ref=DuplicateTypeAnnotation.out -XDrawDiagnostics -source 1.7 DuplicateTypeAnnotation.java
- */
-
-class DuplicateTypeAnno<K> {
- DuplicateTypeAnno<@A @A ?> l;
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/DuplicateTypeAnnotation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-DuplicateTypeAnnotation.java:10:24: compiler.err.duplicate.annotation
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/InvalidLocation.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for invalid annotatins given the target
- * @author Mahmood Ali
- * @compile/fail/ref=InvalidLocation.out -XDrawDiagnostics -source 1.7 InvalidLocation.java
- */
-
-class InvalidLocation<K> {
- InvalidLocation<@A ?> l;
-}
-
-@java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/InvalidLocation.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InvalidLocation.java:10:19: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/MissingAnnotationValue.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary check for missing annotation value
- * @author Mahmood Ali
- * @compile/fail/ref=MissingAnnotationValue.out -XDrawDiagnostics -source 1.7 MissingAnnotationValue.java
- */
-class MissingAnnotationValue<K> {
- MissingAnnotationValue<@A ?> l;
-}
-
-@interface A { int field(); }
--- a/langtools/test/tools/javac/typeAnnotations/failures/common/wildcards/MissingAnnotationValue.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-MissingAnnotationValue.java:9:26: compiler.err.annotation.missing.default.value: A, field
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/Constructor.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test invalid location of TypeUse
- * @author Mahmood Ali
- * @compile/fail/ref=Constructor.out -XDrawDiagnostics -source 1.7 Constructor.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class Constructor {
- @A Constructor() { }
-}
-
-@Target(ElementType.TYPE_USE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/Constructor.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Constructor.java:13:3: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/IncompleteArray.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test incomplete array declaration
- * @author Mahmood Ali
- * @compile/fail/ref=IncompleteArray.out -XDrawDiagnostics -source 1.7 IncompleteArray.java
- */
-class IncompleteArray {
- int @A [] @A var;
-}
-
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/IncompleteArray.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-IncompleteArray.java:9:13: compiler.err.illegal.start.of.type
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/NotTypeParameter.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test invalid location of TypeUse
- * @author Mahmood Ali
- * @compile/fail/ref=NotTypeParameter.out -XDrawDiagnostics -source 1.7 NotTypeParameter.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class VoidMethod<@A K> {
- @A void test() { }
-}
-
-@Target(ElementType.TYPE_USE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/NotTypeParameter.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-NotTypeParameter.java:13:3: compiler.err.annotation.type.not.applicable
-NotTypeParameter.java:12:18: compiler.err.annotation.type.not.applicable
-2 errors
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/NotTypeUse.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test invalid location of TypeUse
- * @author Mahmood Ali
- * @compile/fail/ref=NotTypeUse.out -XDrawDiagnostics -source 1.7 NotTypeUse.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class VoidMethod {
- @A void test() { }
-}
-
-@Target(ElementType.TYPE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/NotTypeUse.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-NotTypeUse.java:13:3: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/VoidMethod.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6843077
- * @summary test invalid location of TypeUse
- * @author Mahmood Ali
- * @compile/fail/ref=VoidMethod.out -XDrawDiagnostics -source 1.7 VoidMethod.java
- */
-
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-class VoidMethod {
- @A void test() { }
-}
-
-@Target(ElementType.TYPE_USE)
-@interface A { }
--- a/langtools/test/tools/javac/typeAnnotations/failures/target/VoidMethod.out Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-VoidMethod.java:13:3: compiler.err.annotation.type.not.applicable
-1 error
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/BasicTest.java Fri Nov 12 08:41:03 2010 -0500
+++ b/langtools/test/tools/javac/typeAnnotations/newlocations/BasicTest.java Sat Nov 13 18:56:50 2010 -0800
@@ -27,7 +27,7 @@
* @bug 6843077
* @summary random tests for new locations
* @author Matt Papi
- * @compile -source 1.7 BasicTest.java
+ * @compile/fail/ref=BasicTest.out -XDrawDiagnostics BasicTest.java
*/
import java.util.*;
@@ -38,6 +38,8 @@
@interface C {}
@interface D {}
+//308: Test inverted to verify that type annotations can not be parsed yet.
+
/**
* Tests basic JSR 308 parser functionality. We don't really care about what
* the parse tree looks like, just that these annotations can be parsed.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/typeAnnotations/newlocations/BasicTest.out Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,66 @@
+BasicTest.java:47:27: compiler.err.illegal.start.of.type
+BasicTest.java:47:28: compiler.err.expected: '{'
+BasicTest.java:47:36: compiler.err.expected: token.identifier
+BasicTest.java:47:38: compiler.err.illegal.start.of.type
+BasicTest.java:47:45: compiler.err.expected: token.identifier
+BasicTest.java:47:47: compiler.err.expected: ';'
+BasicTest.java:47:62: compiler.err.expected: token.identifier
+BasicTest.java:47:84: compiler.err.expected: token.identifier
+BasicTest.java:52:22: compiler.err.illegal.start.of.expr
+BasicTest.java:52:31: compiler.err.expected: ';'
+BasicTest.java:52:37: compiler.err.expected: token.identifier
+BasicTest.java:53:21: compiler.err.illegal.start.of.expr
+BasicTest.java:53:23: compiler.err.expected: ';'
+BasicTest.java:53:30: compiler.err.expected: token.identifier
+BasicTest.java:53:32: compiler.err.illegal.start.of.type
+BasicTest.java:53:37: compiler.err.expected: token.identifier
+BasicTest.java:53:38: compiler.err.expected: ';'
+BasicTest.java:56:17: compiler.err.expected: token.identifier
+BasicTest.java:56:23: compiler.err.expected: token.identifier
+BasicTest.java:56:24: compiler.err.expected2: '(', '['
+BasicTest.java:56:25: compiler.err.expected: ';'
+BasicTest.java:56:27: compiler.err.invalid.meth.decl.ret.type.req
+BasicTest.java:56:34: compiler.err.illegal.start.of.type
+BasicTest.java:58:34: compiler.err.illegal.start.of.type
+BasicTest.java:61:16: compiler.err.illegal.start.of.type
+BasicTest.java:61:18: compiler.err.expected: ';'
+BasicTest.java:61:24: compiler.err.illegal.start.of.type
+BasicTest.java:61:26: compiler.err.expected: ';'
+BasicTest.java:61:33: compiler.err.expected: token.identifier
+BasicTest.java:61:34: compiler.err.illegal.start.of.type
+BasicTest.java:61:35: compiler.err.expected: token.identifier
+BasicTest.java:61:37: compiler.err.expected: ';'
+BasicTest.java:61:45: compiler.err.expected: token.identifier
+BasicTest.java:61:50: compiler.err.expected: token.identifier
+BasicTest.java:62:16: compiler.err.expected: token.identifier
+BasicTest.java:62:17: compiler.err.expected2: '(', '['
+BasicTest.java:62:18: compiler.err.expected: ';'
+BasicTest.java:62:28: compiler.err.illegal.start.of.type
+BasicTest.java:62:30: compiler.err.expected: ';'
+BasicTest.java:62:36: compiler.err.illegal.start.of.type
+BasicTest.java:62:38: compiler.err.expected: ';'
+BasicTest.java:62:45: compiler.err.expected: token.identifier
+BasicTest.java:62:46: compiler.err.illegal.start.of.type
+BasicTest.java:62:47: compiler.err.expected: token.identifier
+BasicTest.java:62:49: compiler.err.expected: ';'
+BasicTest.java:62:57: compiler.err.expected: token.identifier
+BasicTest.java:62:58: compiler.err.illegal.start.of.type
+BasicTest.java:62:59: compiler.err.expected: token.identifier
+BasicTest.java:64:25: compiler.err.illegal.start.of.type
+BasicTest.java:64:27: compiler.err.expected: ';'
+BasicTest.java:64:34: compiler.err.expected: token.identifier
+BasicTest.java:64:38: compiler.err.expected: token.identifier
+BasicTest.java:64:41: compiler.err.illegal.start.of.expr
+BasicTest.java:64:50: compiler.err.expected: ';'
+BasicTest.java:64:56: compiler.err.expected: token.identifier
+BasicTest.java:69:17: compiler.err.expected: ';'
+BasicTest.java:69:24: compiler.err.illegal.start.of.type
+BasicTest.java:69:30: compiler.err.expected: ';'
+BasicTest.java:69:59: compiler.err.expected: token.identifier
+BasicTest.java:69:74: compiler.err.expected: ';'
+BasicTest.java:74:22: compiler.err.expected: token.identifier
+BasicTest.java:74:24: compiler.err.expected: ';'
+BasicTest.java:74:25: compiler.err.illegal.start.of.type
+BasicTest.java:74:33: compiler.err.expected: ';'
+BasicTest.java:77:2: compiler.err.premature.eof
+65 errors
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/ClassExtends.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: class extends/implements
- * @author Mahmood Ali
- * @compile -source 1.7 ClassExtends.java
- */
-abstract class MyClass extends @A ParameterizedClass<@B String>
- implements @B CharSequence, @A ParameterizedInterface<@B String> { }
-
-interface MyInterface extends @A ParameterizedInterface<@A String>,
- @B CharSequence { }
-
-class ParameterizedClass<K> {}
-interface ParameterizedInterface<K> {}
-@interface A {}
-@interface B {}
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/ClassLiterals.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: class literals
- * @author Mahmood Ali
- * @compile -source 1.7 ClassLiterals.java
- */
-
-class ClassLiterals {
-
- public static void main(String[] args) {
- if (String.class != @A String.class) throw new Error();
- if (@A int.class != int.class) throw new Error();
- if (@A int.class != Integer.TYPE) throw new Error();
- if (@A int @B(0) [].class != int[].class) throw new Error();
-
- if (String[].class != @A String[].class) throw new Error();
- if (String[].class != String @A [].class) throw new Error();
- if (@A int[].class != int[].class) throw new Error();
- if (@A int @B(0) [].class != int[].class) throw new Error();
- }
-}
-
-@interface A {}
-@interface B { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/ClassParameters.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: class type parameter bounds
- * @author Mahmood Ali
- * @compile -source 1.7 ClassParameters.java
- */
-class Unannotated<K> { }
-
-class ExtendsBound<K extends @A String> { }
-class ExtendsGeneric<K extends @A Unannotated<@B String>> { }
-class TwoBounds<K extends @A String, V extends @B String> { }
-
-class Complex1<K extends @A String&Runnable> { }
-class Complex2<K extends String & @B Runnable> { }
-class ComplexBoth<K extends @A String & @A Runnable> { }
-
-class Outer {
- void inner() {
- class Unannotated<K> { }
-
- class ExtendsBound<K extends @A String> { }
- class ExtendsGeneric<K extends @A Unannotated<@B String>> { }
- class TwoBounds<K extends @A String, V extends @B String> { }
-
- class Complex1<K extends @A String&Runnable> { }
- class Complex2<K extends String & @B Runnable> { }
- class ComplexBoth<K extends @A String & @A Runnable> { }
- }
-}
-
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/ConstructorTypeArgs.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: constructor type args
- * @author Mahmood Ali
- * @compile -source 1.7 ConstructorTypeArgs.java
- */
-
-class ConstructorTypeArgs {
- void oneArg() {
- new @A MyList<@A String>();
- new MyList<@A MyList<@B(0) String>>();
- }
-
- void twoArg() {
- new MyMap<String, String>();
- new MyMap<@A String, @B(0) MyList<@A String>>();
- }
-
- void withArraysIn() {
- new MyList<String[]>();
- new MyList<@A String @B(0) [] @A []>();
-
- new MyMap<@A String[], @B(0) MyList<@A String> @A []>();
- }
-}
-
-class MyList<E> { }
-class MyMap<K, V> { }
-
-@interface A { }
-@interface B { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Expressions.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: expressions
- * @author Mahmood Ali
- * @compile -source 1.7 Expressions.java
- */
-class Expressions {
- void instanceOf() {
- Object o = null;
- boolean a = o instanceof @A String;
- boolean b = o instanceof @B(0) String;
- }
-
- void instanceOfArray() {
- Object o = null;
- boolean a1 = o instanceof @A String [];
- boolean a2 = o instanceof @B(0) String [];
-
- boolean b1 = o instanceof String @A [];
- boolean b2 = o instanceof String @B(0) [];
- }
-
- void objectCreation() {
- new @A String();
- new @B(0) String();
- }
-
- void objectCreationArray() {
- Object a1 = new @A String [] [] { };
- Object a2 = new @A String [1] [];
- Object a3 = new @A String [1] [2];
-
- Object b1 = new @A String @B(0) [] [] { };
- Object b2 = new @A String @B(0) [1] [];
- Object b3 = new @A String @B(0) [1] [2];
-
- Object c1 = new @A String [] @B(0) [] { };
- Object c2 = new @A String [1] @B(0) [];
- Object c3 = new @A String [1] @B(0) [2];
-
- Object d1 = new @A String @B(0) [] @B(0) [] { };
- Object d2 = new @A String @B(0) [1] @B(0) [];
- Object d3 = new @A String @B(0) [1] @B(0) [2];
-
- Object rand = new @A String @B(value = 0) [1] @B(value = 0) [2];
-
- }
-}
-
-@interface A { }
-@interface B { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Fields.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: field type array/generics
- * @author Mahmood Ali
- * @compile -source 1.7 Fields.java
- */
-
-class DefaultScope {
- Parameterized<String, String> unannotated;
- Parameterized<@A String, String> firstTypeArg;
- Parameterized<String, @A String> secondTypeArg;
- Parameterized<@A String, @B String> bothTypeArgs;
-
- Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized;
-
- @A String [] array1;
- @A String @B [] array1Deep;
- @A String [] [] array2;
- @A String @A [] @B [] array2Deep;
- String @A [] [] array2First;
- String [] @B [] array2Second;
-}
-
-class ModifiedScoped {
- public final Parameterized<String, String> unannotated = null;
- public final Parameterized<@A String, String> firstTypeArg = null;
- public final Parameterized<String, @A String> secondTypeArg = null;
- public final Parameterized<@A String, @B String> bothTypeArgs = null;
-
- public final Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized = null;
-
- public final @A String [] array1 = null;
- public final @A String @B [] array1Deep = null;
- public final @A String [] [] array2 = null;
- public final @A String @A [] @B [] array2Deep = null;
- public final String @A [] [] array2First = null;
- public final String [] @B [] array2Second = null;
-}
-
-class Parameterized<K, V> { }
-
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/LocalVariables.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: local variables array/generics
- * @author Mahmood Ali
- * @compile -source 1.7 LocalVariables.java
- */
-
-class DefaultScope {
- void parameterized() {
- Parameterized<String, String> unannotated;
- Parameterized<@A String, String> firstTypeArg;
- Parameterized<String, @A String> secondTypeArg;
- Parameterized<@A String, @B String> bothTypeArgs;
-
- Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized;
- }
-
- void arrays() {
- @A String [] array1;
- @A String @B [] array1Deep;
- @A String [] [] array2;
- @A String @A [] @B [] array2Deep;
- String @A [] [] array2First;
- String [] @B [] array2Second;
- }
-}
-
-class ModifiedVars {
- void parameterized() {
- final Parameterized<String, String> unannotated = null;
- final Parameterized<@A String, String> firstTypeArg = null;
- final Parameterized<String, @A String> secondTypeArg = null;
- final Parameterized<@A String, @B String> bothTypeArgs = null;
-
- final Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized = null;
- }
-
- void arrays() {
- final @A String [] array1 = null;
- final @A String @B [] array1Deep = null;
- final @A String [] [] array2 = null;
- final @A String @A [] @B [] array2Deep = null;
- final String @A [] [] array2First = null;
- final String [] @B [] array2Second = null;
- }
-}
-
-class Parameterized<K, V> { }
-
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/MethodReturnType.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: method return type array/generics
- * @author Mahmood Ali
- * @compile -source 1.7 MethodReturnType.java
- */
-
-class DefaultScope {
- Parameterized<String, String> unannotated() { return null; }
- Parameterized<@A String, String> firstTypeArg() { return null; }
- Parameterized<String, @A String> secondTypeArg() { return null; }
- Parameterized<@A String, @B String> bothTypeArgs() { return null; }
-
- Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized() { return null; }
-
- public <T> @A String method() { return null; }
-
- @A String [] array1() { return null; }
- @A String @B [] array1Deep() { return null; }
- @A String [] [] array2() { return null; }
- @A String @A [] @B [] array2Deep() { return null; }
- String @A [] [] array2First() { return null; }
- String [] @B [] array2Second() { return null; }
-}
-
-class ModifiedScoped {
- public final Parameterized<String, String> unannotated() { return null; }
- public final Parameterized<@A String, String> firstTypeArg() { return null; }
- public final Parameterized<String, @A String> secondTypeArg() { return null; }
- public final Parameterized<@A String, @B String> bothTypeArgs() { return null; }
-
- public final Parameterized<@A Parameterized<@A String, @B String>, @B String>
- nestedParameterized() { return null; }
-
- public final @A String [] array1() { return null; }
- public final @A String @B [] array1Deep() { return null; }
- public final @A String [] [] array2() { return null; }
- public final @A String @A [] @B [] array2Deep() { return null; }
- public final String @A [] [] array2First() { return null; }
- public final String [] @B [] array2Second() { return null; }
-}
-
-class Parameterized<K, V> { }
-
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/MethodTypeArgs.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: method type args
- * @author Mahmood Ali
- * @compile -source 1.7 MethodTypeArgs.java
- */
-
-class MethodTypeArgs {
- void oneArg() {
- this.<@A String>newList();
- this.<@A MyList<@B(0) String>>newList();
-
- MethodTypeArgs.<@A String>newList();
- MethodTypeArgs.<@A MyList<@B(0) String>>newList();
- }
-
- void twoArg() {
- this.<String, String>newMap();
- this.<@A String, @B(0) MyList<@A String>>newMap();
-
- MethodTypeArgs.<String, String>newMap();
- MethodTypeArgs.<@A String, @B(0) MyList<@A String>>newMap();
- }
-
- void withArraysIn() {
- this.<String[]>newList();
- this.<@A String @B(0) [] @A []>newList();
-
- this.<@A String[], @B(0) MyList<@A String> @A []>newMap();
- }
-
- static <E> void newList() { }
- static <K, V> void newMap() { }
-}
-
-class MyList<E> { }
-@interface A { }
-@interface B { int value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/MethodTypeParameters.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: method type parameter bounds
- * @author Mahmood Ali
- * @compile -source 1.7 MethodTypeParameters.java
- */
-
-class UnscopedUnmodified {
- <K extends @A String> void methodExtends() {}
- <K extends @A Parameterized<@B String>> void nestedExtends() {}
- <K extends @A String, V extends @A Parameterized<@B String>> void dual() {}
- <K extends String, V extends Parameterized<@B String>> void dualOneAnno() {}
-}
-
-class PublicModifiedMethods {
- public final <K extends @A String> void methodExtends() {}
- public final <K extends @A Parameterized<@B String>> void nestedExtends() {}
- public final <K extends @A String, V extends @A Parameterized<@B String>> void dual() {}
- public final <K extends String, V extends Parameterized<@B String>> void dualOneAnno() {}
-}
-
-class Parameterized<K> { }
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Parameters.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: parameter type array/generics
- * @author Mahmood Ali
- * @compile -source 1.7 Parameters.java
- */
-
-class Parameters {
- void unannotated(Parameterized<String, String> a) {}
- void firstTypeArg(Parameterized<@A String, String> a) {}
- void secondTypeArg(Parameterized<String, @A String> a) {}
- void bothTypeArgs(Parameterized<@A String, @B String> both) {}
-
- void nestedParameterized(Parameterized<@A Parameterized<@A String, @B String>, @B String> a) {}
-
- void array1(@A String [] a) {}
- void array1Deep(@A String @B [] a) {}
- void array2(@A String [] [] a) {}
- void array2Deep(@A String @A [] @B [] a) {}
- void array2First(String @A [] [] a) {}
- void array2Second(String [] @B [] a) {}
-}
-
-class Parameterized<K, V> { }
-
-@interface A { }
-@interface B { }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Receivers.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: receivers
- * @author Mahmood Ali
- * @compile -source 1.7 Receivers.java
- */
-class DefaultUnmodified {
- void plain() @A { }
- <T> void generic() @A { }
- void withException() @A throws Exception { }
- String nonVoid() @A { return null; }
- <T extends Runnable> void accept(T r) @A throws Exception { }
-}
-
-class PublicModified {
- public final void plain() @A { }
- public final <T> void generic() @A { }
- public final void withException() @A throws Exception { }
- public final String nonVoid() @A { return null; }
- public final <T extends Runnable> void accept(T r) @A throws Exception { }
-}
-
-class WithValue {
- void plain() @B("m") { }
- <T> void generic() @B("m") { }
- void withException() @B("m") throws Exception { }
- String nonVoid() @B("m") { return null; }
- <T extends Runnable> void accept(T r) @B("m") throws Exception { }
-}
-
-@interface A {}
-@interface B { String value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Throws.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: throw clauses
- * @author Mahmood Ali
- * @compile -source 1.7 Throws.java
- */
-class DefaultUnmodified {
- void oneException() throws @A Exception {}
- void twoExceptions() throws @A RuntimeException, @A Exception {}
-}
-
-class PublicModified {
- public final void oneException(String a) throws @A Exception {}
- public final void twoExceptions(String a) throws @A RuntimeException, @A Exception {}
-}
-
-class WithValue {
- void oneException() throws @B("m") Exception {}
- void twoExceptions() throws @B(value="m") RuntimeException, @A Exception {}
-}
-
-@interface A {}
-@interface B { String value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/TypeCasts.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: type casts
- * @author Mahmood Ali
- * @compile -source 1.7 TypeCasts.java
- */
-class TypeCasts {
- void methodA() {
- String s = (@A String) null;
- Object o = (@A Class<@A String>) null;
- }
-
- void methodB() {
- String s = (@B("m") String) null;
- Object o = (@B("m") Class<@B("m") String>) null;
- }
-}
-
-@interface A { }
-@interface B { String value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/TypeParameters.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: class and method type parameters
- * @author Mahmood Ali
- * @compile -source 1.7 TypeParameters.java
- */
-
-class Unannotated<K> { }
-class OneAnnotated<@A K> { }
-class TwoAnnotated<@A K, @A V> { }
-class SecondAnnotated<K, @A V extends String> { }
-
-class TestMethods {
- <K> void unannotated() { }
- <@A K> void oneAnnotated() { }
- <@A K, @B("m") V> void twoAnnotated() { }
- <K, @A V extends @A String> void secondAnnotated() { }
-}
-
-class UnannotatedB<K> { }
-class OneAnnotatedB<@B("m") K> { }
-class TwoAnnotatedB<@B("m") K, @B("m") V> { }
-class SecondAnnotatedB<K, @B("m") V extends @B("m") String> { }
-
-@interface A { }
-@interface B { String value(); }
--- a/langtools/test/tools/javac/typeAnnotations/newlocations/Wildcards.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6843077
- * @summary new type annotation location: wildcard bound
- * @author Mahmood Ali
- * @compile -source 1.7 Wildcards.java
- */
-class BoundTest {
- void wcExtends(MyList<? extends @A String> l) { }
- void wcSuper(MyList<? super @A String> l) { }
-
- MyList<? extends @A String> returnWcExtends() { return null; }
- MyList<? super @A String> returnWcSuper() { return null; }
- MyList<? extends @A MyList<? super @B("m") String>> complex() { return null; }
-}
-
-class BoundWithValue {
- void wcExtends(MyList<? extends @B("m") String> l) { }
- void wcSuper(MyList<? super @B(value="m") String> l) { }
-
- MyList<? extends @B("m") String> returnWcExtends() { return null; }
- MyList<? super @B(value="m") String> returnWcSuper() { return null; }
- MyList<? extends @B("m") MyList<? super @B("m") String>> complex() { return null; }
-}
-
-class SelfTest {
- void wcExtends(MyList<@A ?> l) { }
- void wcSuper(MyList<@A ?> l) { }
-
- MyList<@A ?> returnWcExtends() { return null; }
- MyList<@A ?> returnWcSuper() { return null; }
- MyList<@A ? extends @A MyList<@B("m") ?>> complex() { return null; }
-}
-
-class SelfWithValue {
- void wcExtends(MyList<@B("m") ?> l) { }
- void wcSuper(MyList<@B(value="m") ?> l) { }
-
- MyList<@B("m") ?> returnWcExtends() { return null; }
- MyList<@B(value="m") ?> returnWcSuper() { return null; }
- MyList<@B("m") ? extends MyList<@B("m") ? super String>> complex() { return null; }
-}
-
-class MyList<K> { }
-
-@interface A { }
-@interface B { String value(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/T6551367.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 6551367
+ * @summary javadoc throws ClassCastException when an link tag tries to reference constructor.
+ * @author A. Sundararajan
+ * @run main T6551367 T6551367.java
+ */
+
+import com.sun.javadoc.*;
+import java.io.File;
+import static com.sun.tools.javadoc.Main.execute;
+
+public class T6551367 extends com.sun.tools.doclets.standard.Standard {
+ public T6551367() {}
+
+ /** Here, in the javadoc for this method, I try to link to
+ * {@link #<init> a constructor}.
+ */
+ public static void main(String... args) {
+ File testSrc = new File(System.getProperty("test.src", "."));
+ File destDir = new File(System.getProperty("user.dir", "."));
+ for (String file : args) {
+ File source = new File(testSrc, file);
+ int rc = execute("javadoc", "T6551367",
+ T6551367.class.getClassLoader(),
+ new String[]{source.getPath(), "-d", destDir.getAbsolutePath()});
+ if (rc != 0)
+ throw new Error("unexpected exit from javadoc: " + rc);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javah/T6994608.java Sat Nov 13 18:56:50 2010 -0800
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6994608
+ * @summary javah no longer accepts parameter files as input
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class T6994608 {
+ public static void main(String... args) throws Exception {
+ new T6994608().run();
+ }
+
+ void run() throws Exception {
+ Locale prev = Locale.getDefault();
+ Locale.setDefault(Locale.ENGLISH);
+ try {
+ File f = writeFile(new File("classList"), "java.lang.Object");
+ test(Arrays.asList("@" + f.getPath()), 0, null);
+ test(Arrays.asList("@badfile"), 1, "Can't find file badfile");
+ if (errors > 0)
+ throw new Exception(errors + " errors occurred");
+ } finally {
+ Locale.setDefault(prev);
+ }
+ }
+
+ void test(List<String> args, int expectRC, String expectOut) {
+ System.err.println("Test: " + args
+ + " rc:" + expectRC
+ + ((expectOut != null) ? " out:" + expectOut : ""));
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ int rc = com.sun.tools.javah.Main.run(args.toArray(new String[args.size()]), pw);
+ pw.close();
+ String out = sw.toString();
+ if (!out.isEmpty())
+ System.err.println(out);
+
+ if (rc != expectRC)
+ error("Unexpected exit code: " + rc + "; expected: " + expectRC);
+ if (expectOut != null && !out.contains(expectOut))
+ error("Expected string not found: " + expectOut);
+
+ System.err.println();
+ }
+
+ File writeFile(File f, String s) throws IOException {
+ if (f.getParentFile() != null)
+ f.getParentFile().mkdirs();
+ try (FileWriter out = new FileWriter(f)) {
+ out.write(s);
+ }
+ return f;
+ }
+
+ void error(String msg) {
+ System.err.println(msg);
+ errors++;
+ }
+
+ int errors;
+}
+
--- a/langtools/test/tools/javap/typeAnnotations/ArrayClassLiterals.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test ArrayClassLiterals
- * @bug 6863814
- * @summary test that class literals array doesn't crash javap
- */
-
-public class ArrayClassLiterals {
- public static void main(String[] args) throws Exception {
- new ArrayClassLiterals().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
-
- for (ExtendedAnnotation anno : tAttr.annotations)
- anno.position.toString();
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
-
- for (ExtendedAnnotation anno : tAttr.annotations)
- anno.position.toString();
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
-
- for (ExtendedAnnotation anno : tAttr.annotations)
- anno.position.toString();
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Testa.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.util.*;");
- out.println("class Testa { ");
- out.println(" @interface A { }");
-
- out.println(" void test() {");
- out.println(" Object a = @A String.class;");
- out.println(" Object b = @A String @A [] @A [].class;");
- out.println(" }");
- out.println("}");
-
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_visibles = 0, expected_invisibles = 4;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/ArrayClassLiterals2.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6918625
- * @summary javap dumps type information of array class literals
- */
-
-import java.io.*;
-
-public class ArrayClassLiterals2 {
- public static void main(String[] args) throws Exception {
- new ArrayClassLiterals2().run();
- }
-
- public void run() throws IOException {
- File classFile = new File(System.getProperty("test.classes"), "ArrayClassLiterals2$Test.class");
-
- verify(classFile,
- "RuntimeInvisibleTypeAnnotations:",
- "CLASS_LITERAL_GENERIC_OR_ARRAY"
- );
-
- if (errors > 0)
- throw new Error(errors + " found.");
- }
-
- String javap(File f) {
- StringWriter sw = new StringWriter();
- PrintWriter out = new PrintWriter(sw);
- int rc = com.sun.tools.javap.Main.run(new String[] { "-v", f.getPath() }, out);
- if (rc != 0)
- throw new Error("javap failed. rc=" + rc);
- out.close();
- return sw.toString();
- }
-
- void verify(File classFile, String... expects) {
- String output = javap(classFile);
- for (String expect: expects) {
- if (output.indexOf(expect)< 0)
- error(expect + " not found");
- }
- }
-
- void error(String msg) {
- System.err.println(msg);
- errors++;
- }
-
- int errors;
-
-
- /*********************** Test class *************************/
- static class Test {
- @interface A { }
- void test() {
- Object a = @A String @A [] @A [].class;
- }
- }
-}
--- a/langtools/test/tools/javap/typeAnnotations/ClassLiterals.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test ClassLiterals
- * @bug 6843077
- * @summary test that all type annotations are present in the classfile
- */
-
-public class ClassLiterals {
- public static void main(String[] args) throws Exception {
- new ClassLiterals().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Testa.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.util.*;");
- out.println("class Testa { ");
- out.println(" @interface A { }");
-
- out.println(" void test() {");
- out.println(" Object a = @A String.class;");
- out.println(" Object b = @A String @A [] @A [].class;");
- out.println(" }");
- out.println("}");
-
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_visibles = 0, expected_invisibles = 4;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/JSR175Annotations.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test JSR175Annotations
- * @bug 6843077
- * @summary test that only type annotations are recorded as such in classfile
- */
-
-public class JSR175Annotations {
- public static void main(String[] args) throws Exception {
- new JSR175Annotations().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Test.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.lang.annotation.Retention;");
- out.println("import java.lang.annotation.RetentionPolicy;");
- out.println("abstract class Test { ");
- out.println(" @Retention(RetentionPolicy.RUNTIME)");
- out.println(" @interface A { }");
- out.println(" @A String m;");
- out.println(" @A String method(@A String a) {");
- out.println(" return a;");
- out.println(" }");
- out.println("}");
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_visibles = 0, expected_invisibles = 0;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/NewArray.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test NewArray
- * @bug 6843077
- * @summary test that all type annotations are present in the classfile
- */
-
-public class NewArray {
- public static void main(String[] args) throws Exception {
- new NewArray().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Test.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.util.*;");
- out.println("class Test { ");
- out.println(" @interface A { }");
-
- out.println(" void test() {");
- out.println(" Object a = new @A String @A [5] @A [];");
- out.println(" Object b = new @A String @A [5] @A [3];");
- out.println(" Object c = new @A String @A [] @A [] {};");
- out.println(" }");
- out.println("}");
-
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_visibles = 0, expected_invisibles = 9;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/Presence.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test Presence
- * @bug 6843077
- * @summary test that all type annotations are present in the classfile
- */
-
-public class Presence {
- public static void main(String[] args) throws Exception {
- new Presence().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Test.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.util.*;");
- out.println("class Test<@Test.A T extends @Test.A List<@Test.A String>> { ");
- out.println(" @interface A { }");
-
- out.println(" Map<@A String, Map<@A String, @A String>> f1;");
-
- out.println(" <@A T extends @A List<@A String>>");
- out.println(" Map<@A String, @A List<@A String>>");
- out.println(" method(List<@A String> @A [] param1, String @A [] @A ... param2) @A");
- out.println(" throws @A Exception {");
- out.println(" @A String lc1 = null;");
- out.println(" @A List<@A String> lc2 = null;");
- out.println(" @A String @A [] [] @A[] lc3 = null;");
- out.println(" List<? extends @A List<@A String>> lc4 = null;");
- out.println(" Object lc5 = (@A List<@A String>) null;");
- out.println(" boolean lc6 = lc1 instanceof @A String;");
- out.println(" boolean lc7 = lc5 instanceof @A String @A [] @A [];");
- out.println(" new @A ArrayList<@A String>();");
- out.println(" Object lc8 = new @A String @A [4];");
- out.println(" Object lc9 = @A String.class;");
- out.println(" Object lc10 = @A int.class;");
- out.println(" return null;");
- out.println(" }");
- out.println(" void vararg1(String @A ... t) { } ");
- out.println("}");
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_visibles = 0, expected_invisibles = 39;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/PresenceInner.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test PresenceInner
- * @bug 6843077
- * @summary test that annotations in inner types count only once
- */
-
-public class PresenceInner {
- public static void main(String[] args) throws Exception {
- new PresenceInner().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- test(cf);
- for (Field f : cf.fields) {
- test(cf, f);
- }
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- // counts are zero when vising outer class
- countAnnotations(0);
-
- // visit inner class
- File innerFile = new File("Test$1Inner.class");
- ClassFile icf = ClassFile.read(innerFile);
- test(icf);
- for (Field f : icf.fields) {
- test(cf, f);
- }
- for (Method m: icf.methods) {
- test(cf, m);
- }
-
- countAnnotations(1);
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf) {
- test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- void test(ClassFile cf, Field m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, String name, boolean visible) {
- int index = cf.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = cf.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Field m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Test.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
-
- out.println("class Test {");
- out.println(" void method() {");
- out.println(" class Inner<T extends @A Object> { }");
- out.println(" }");
- out.println("}");
- out.println("@interface A { }");
- out.close();
- System.out.println(f.getAbsolutePath());
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations(int expected_invisibles) {
- int expected_visibles = 0;
- int expected_all = expected_visibles + expected_invisibles;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}
--- a/langtools/test/tools/javap/typeAnnotations/T6855990.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-
-/*
- * @test
- * @bug 6855990
- * @summary InstructionDetailWriter should support new 308 annotations attribute
- */
-
-public class T6855990 {
- public static void main(String[] args) throws Exception {
- new T6855990().run();
- }
-
- public void run() throws Exception {
- @Simple String[] args = { "-c", "-XDdetails:typeAnnotations", "T6855990" };
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- int rc = com.sun.tools.javap.Main.run(args, pw);
- pw.close();
- String out = sw.toString();
- System.out.println(out);
- if (out.indexOf("@Simple: LOCAL_VARIABLE") == -1)
- throw new Exception("expected output not found");
- }
-}
-
-@interface Simple { }
-
--- a/langtools/test/tools/javap/typeAnnotations/Visibility.java Fri Nov 12 08:41:03 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.*;
-import com.sun.tools.classfile.*;
-
-/*
- * @test Visibility
- * @bug 6843077
- * @summary test that type annotations are recorded in the classfile
- */
-
-public class Visibility {
- public static void main(String[] args) throws Exception {
- new Visibility().run();
- }
-
- public void run() throws Exception {
- File javaFile = writeTestFile();
- File classFile = compileTestFile(javaFile);
-
- ClassFile cf = ClassFile.read(classFile);
- for (Method m: cf.methods) {
- test(cf, m);
- }
-
- countAnnotations();
-
- if (errors > 0)
- throw new Exception(errors + " errors found");
- System.out.println("PASSED");
- }
-
- void test(ClassFile cf, Method m) {
- test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
- test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
- }
-
- // test the result of Attributes.getIndex according to expectations
- // encoded in the method's name
- void test(ClassFile cf, Method m, String name, boolean visible) {
- int index = m.attributes.getIndex(cf.constant_pool, name);
- if (index != -1) {
- Attribute attr = m.attributes.get(index);
- assert attr instanceof RuntimeTypeAnnotations_attribute;
- RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
- all += tAttr.annotations.length;
- if (visible)
- visibles += tAttr.annotations.length;
- else
- invisibles += tAttr.annotations.length;
- }
- }
-
- File writeTestFile() throws IOException {
- File f = new File("Test.java");
- PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
- out.println("import java.lang.annotation.Retention;");
- out.println("import java.lang.annotation.RetentionPolicy;");
- out.println("abstract class Test { ");
- // visible annotations: RUNTIME
- out.println(" @Retention(RetentionPolicy.RUNTIME)");
- out.println(" @interface A { }");
- out.println(" void visible() @A { }");
-
- // invisible annotations: CLASS
- out.println(" @Retention(RetentionPolicy.CLASS)");
- out.println(" @interface B { }");
- out.println(" void invisible() @B { }");
-
- // source annotations
- out.println(" @Retention(RetentionPolicy.SOURCE)");
- out.println(" @interface C { }");
- out.println(" void source() @C { }");
-
- // default visibility: CLASS
- out.println(" @interface D { }");
- out.println(" void def() @D { }");
- out.println("}");
- out.close();
- return f;
- }
-
- File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.7", "-g", f.getPath() });
- if (rc != 0)
- throw new Error("compilation failed. rc=" + rc);
- String path = f.getPath();
- return new File(path.substring(0, path.length() - 5) + ".class");
- }
-
- void countAnnotations() {
- int expected_all = 3, expected_visibles = 1, expected_invisibles = 2;
-
- if (expected_all != all) {
- errors++;
- System.err.println("expected " + expected_all
- + " annotations but found " + all);
- }
-
- if (expected_visibles != visibles) {
- errors++;
- System.err.println("expected " + expected_visibles
- + " visibles annotations but found " + visibles);
- }
-
- if (expected_invisibles != invisibles) {
- errors++;
- System.err.println("expected " + expected_invisibles
- + " invisibles annotations but found " + invisibles);
- }
-
- }
-
- int errors;
- int all;
- int visibles;
- int invisibles;
-}