From: <ls...@us...> - 2007-01-07 05:41:45
|
Revision: 2994 http://jnode.svn.sourceforge.net/jnode/?rev=2994&view=rev Author: lsantha Date: 2007-01-06 21:41:44 -0800 (Sat, 06 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/java/java/lang/System.java trunk/core/src/classpath/java/java/security/PrivilegedExceptionAction.java trunk/core/src/classpath/vm/java/lang/Thread.java Modified: trunk/core/src/classpath/java/java/lang/System.java =================================================================== --- trunk/core/src/classpath/java/java/lang/System.java 2007-01-07 05:41:17 UTC (rev 2993) +++ trunk/core/src/classpath/java/java/lang/System.java 2007-01-07 05:41:44 UTC (rev 2994) @@ -44,6 +44,14 @@ import java.io.InputStream; import java.io.PrintStream; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.Properties; import java.util.PropertyPermission; @@ -98,6 +106,11 @@ public static final PrintStream err = VMSystem.makeStandardErrorStream(); /** + * A cached copy of the environment variable map. + */ + private static Map<String,String> environmentMap; + + /** * This class is uninstantiable. */ private System() @@ -118,6 +131,7 @@ SecurityManager sm = SecurityManager.current; // Be thread-safe. if (sm != null) sm.checkPermission(new RuntimePermission("setIO")); + VMSystem.setIn(in); } @@ -223,6 +237,38 @@ } /** + * <p> + * Returns the current value of a nanosecond-precise system timer. + * The value of the timer is an offset relative to some arbitrary fixed + * time, which may be in the future (making the value negative). This + * method is useful for timing events where nanosecond precision is + * required. This is achieved by calling this method before and after the + * event, and taking the difference betweent the two times: + * </p> + * <p> + * <code>long startTime = System.nanoTime();</code><br /> + * <code>... <emph>event code</emph> ...</code><br /> + * <code>long endTime = System.nanoTime();</code><br /> + * <code>long duration = endTime - startTime;</code><br /> + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. + * </p> + * + * @return the time of a system timer in nanoseconds. + * @since 1.5 + */ + public static long nanoTime() + { + //todo + throw new RuntimeException("Implement it"); + //return VMSystem.nanoTime(); + } + + /** * Copy one array onto another from <code>src[srcStart]</code> ... * <code>src[srcStart+len-1]</code> to <code>dest[destStart]</code> ... * <code>dest[destStart+len-1]</code>. First, the arguments are validated: @@ -319,6 +365,7 @@ * <dt>gnu.java.io.encoding_scheme_alias.iso-latin-_?</dt> <dd>8859_?</dd> * <dt>gnu.java.io.encoding_scheme_alias.latin?</dt> <dd>8859_?</dd> * <dt>gnu.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd> + * <dt>gnu.javax.print.server</dt> <dd>Hostname of external CUPS server.</dd> * </dl> * * @return the system properties, will never be null @@ -364,7 +411,7 @@ SecurityManager sm = SecurityManager.current; // Be thread-safe. if (sm != null) sm.checkPropertyAccess(key); - else if (key.length() == 0) + if (key.length() == 0) throw new IllegalArgumentException("key can't be empty"); return SystemProperties.getProperty(key); } @@ -385,6 +432,10 @@ SecurityManager sm = SecurityManager.current; // Be thread-safe. if (sm != null) sm.checkPropertyAccess(key); + // This handles both the null pointer exception and the illegal + // argument exception. + if (key.length() == 0) + throw new IllegalArgumentException("key can't be empty"); return SystemProperties.getProperty(key, def); } @@ -405,6 +456,10 @@ SecurityManager sm = SecurityManager.current; // Be thread-safe. if (sm != null) sm.checkPermission(new PropertyPermission(key, "write")); + // This handles both the null pointer exception and the illegal + // argument exception. + if (key.length() == 0) + throw new IllegalArgumentException("key can't be empty"); return SystemProperties.setProperty(key, value); } Modified: trunk/core/src/classpath/java/java/security/PrivilegedExceptionAction.java =================================================================== --- trunk/core/src/classpath/java/java/security/PrivilegedExceptionAction.java 2007-01-07 05:41:17 UTC (rev 2993) +++ trunk/core/src/classpath/java/java/security/PrivilegedExceptionAction.java 2007-01-07 05:41:44 UTC (rev 2994) @@ -46,9 +46,9 @@ * * @author Aaron M. Renn (ar...@ur...) * @since 1.1 - * @status updated to 1.4 + * @status updated to 1.5 */ -public interface PrivilegedExceptionAction +public interface PrivilegedExceptionAction<T> { /** * This method performs an operation that requires higher privileges to @@ -61,5 +61,5 @@ * @see AccessController#doPrivileged(PrivilegedExceptionAction, * AccessControlContext) */ - Object run() throws Exception; + T run() throws Exception; } // interface PrivilegedExceptionAction Modified: trunk/core/src/classpath/vm/java/lang/Thread.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-07 05:41:17 UTC (rev 2993) +++ trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-07 05:41:44 UTC (rev 2994) @@ -262,6 +262,56 @@ InheritableThreadLocal.newChildThread(this); // FDy : CLASSPATH patch ? } + /** + * Allocate a new Thread object, as if by + * <code>Thread(group, null, name)</code>, and give it the specified stack + * size, in bytes. The stack size is <b>highly platform independent</b>, + * and the virtual machine is free to round up or down, or ignore it + * completely. A higher value might let you go longer before a + * <code>StackOverflowError</code>, while a lower value might let you go + * longer before an <code>OutOfMemoryError</code>. Or, it may do absolutely + * nothing! So be careful, and expect to need to tune this value if your + * virtual machine even supports it. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @param size the stack size, in bytes; 0 to be ignored + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @since 1.4 + */ + public Thread(ThreadGroup group, Runnable target, String name, long size) + { + Thread current = currentThread(); + + if (group != null) { + group.checkAccess(); + } else { + group = current.getThreadGroup(); + } + + if (group == null) { + throw new InternalError("Live thread has invalid group: " + name); + } + + group.addThread(this); + + this.group = group; + this.target = target; + this.name = name; + this.parent = current; + + this.daemon = current.isDaemon(); + + this.vmThread = VmProcessor.current().createThread(this); + this.vmThread.setPriority(current.getPriority()); + this.vmThread.updateName(); + + InheritableThreadLocal.newChildThread(this); // FDy : CLASSPATH patch ? + } + /** * Create a new instance with a given group as containing group, a runnable * as thread runner and a given name. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ls...@us...> - 2007-01-07 05:43:42
|
Revision: 2997 http://jnode.svn.sourceforge.net/jnode/?rev=2997&view=rev Author: lsantha Date: 2007-01-06 21:43:40 -0800 (Sat, 06 Jan 2007) Log Message: ----------- Classpath patches. Added Paths: ----------- trunk/core/src/classpath/sun/ trunk/core/src/classpath/sun/sun/ trunk/core/src/classpath/sun/sun/misc/ trunk/core/src/classpath/sun/sun/misc/Service.java trunk/core/src/classpath/sun/sun/misc/ServiceConfigurationError.java trunk/core/src/classpath/sun/sun/reflect/ trunk/core/src/classpath/sun/sun/reflect/annotation/ trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationInvocationHandler.java trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationParser.java trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationType.java trunk/core/src/classpath/sun/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java trunk/core/src/classpath/sun/sun/reflect/annotation/ExceptionProxy.java Added: trunk/core/src/classpath/sun/sun/misc/Service.java =================================================================== --- trunk/core/src/classpath/sun/sun/misc/Service.java (rev 0) +++ trunk/core/src/classpath/sun/sun/misc/Service.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,66 @@ +/* Service.java -- A wrapper around GNU service provision. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package sun.misc; + +import gnu.classpath.ServiceFactory; + +import java.util.Iterator; + +public class Service +{ + + /** + * Returns an {@link Iterator} over the service providers which + * provide a service of the given class, and are available from + * the specified classloader. + * + * @param c the service provider interface which must be + * implemented by any loaded service providers. + * @param cl the class loader that will be used to load the + * service providers, or <code>null</code> for the system class + * loader. + * @return an iterator over the service providers. + */ + public static <P> Iterator<P> providers(Class<P> c, ClassLoader cl) + { + return (Iterator<P>) ServiceFactory.lookupProviders(c, cl); + } + +} + Added: trunk/core/src/classpath/sun/sun/misc/ServiceConfigurationError.java =================================================================== --- trunk/core/src/classpath/sun/sun/misc/ServiceConfigurationError.java (rev 0) +++ trunk/core/src/classpath/sun/sun/misc/ServiceConfigurationError.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,64 @@ +/* ServiceConfigurationError.java -- An error from service configuration. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package sun.misc; + +public class ServiceConfigurationError + extends Error +{ + + /** + * Constructs a new {@link ServiceConfigurationError} + */ + public ServiceConfigurationError() + { + super(); + } + + /** + * Constructs a new {@link ServiceConfigurationError} + * with the specified message. + */ + public ServiceConfigurationError(String message) + { + super(message); + } + + +} + Added: trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationInvocationHandler.java =================================================================== --- trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationInvocationHandler.java (rev 0) +++ trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationInvocationHandler.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,340 @@ +/* sun.reflect.annotation.AnnotationInvocationHandler + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package sun.reflect.annotation; + +import java.io.Serializable; +import java.lang.annotation.AnnotationTypeMismatchException; +import java.lang.annotation.IncompleteAnnotationException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + * This class exists for serialization compatibility with the JDK. + * VMs can choose to implement annotations by constructing proxies + * with this invocation handler, but that is not required. + * If a different strategy for proxy objects is chosen, they can + * have a writeReplace method to substitute a Proxy based on this + * invocation handler is used for serialization. + */ +public final class AnnotationInvocationHandler + implements InvocationHandler, Serializable +{ + private static final long serialVersionUID = 6182022883658399397L; + private final Class type; + private final Map memberValues; + + /** + * Construct a new invocation handler for an annotation proxy. + * Note that the VM is responsible for filling the memberValues map + * with the default values of all the annotation members. + */ + public AnnotationInvocationHandler(Class type, Map memberValues) + { + this.type = type; + this.memberValues = memberValues; + } + + /** + * Compare an instance of AnnotationInvocationHandler with another object. + * Note that the other object does not have to be an + * AnnotationInvocationHandler, any implementation of the annotation + * interface is allowed to be compared for equality. + * Note that this makes the equals method asymmetric, but this behavior + * is specified by Annotation.equals and identical to the JDK. + * + * This method is public for use by other parts of the VM. Some VMs + * (can) use different representations of annotations that reuse this + * method. + */ + public static boolean equals(Class type, Map memberValues, Object other) + { + if (type.isInstance(other)) + { + try + { + Method[] methods = type.getDeclaredMethods(); + if (methods.length == memberValues.size()) + { + for (int i = 0; i < methods.length; i++) + { + String key = methods[i].getName(); + Object val = methods[i].invoke(other, new Object[0]); + if (! deepEquals(memberValues.get(key), val)) + { + return false; + } + } + return true; + } + } + catch (IllegalAccessException _) + { + // Ignore exception, like the JDK + } + catch (InvocationTargetException _) + { + // Ignore exception, like the JDK + } + } + return false; + } + + private static boolean deepEquals(Object o1, Object o2) + { + if (o1 == o2) + return true; + + if (o1 == null || o2 == null) + return false; + + if (o1 instanceof boolean[] && o2 instanceof boolean[]) + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + + if (o1 instanceof byte[] && o2 instanceof byte[]) + return Arrays.equals((byte[]) o1, (byte[]) o2); + + if (o1 instanceof char[] && o2 instanceof char[]) + return Arrays.equals((char[]) o1, (char[]) o2); + + if (o1 instanceof short[] && o2 instanceof short[]) + return Arrays.equals((short[]) o1, (short[]) o2); + + if (o1 instanceof int[] && o2 instanceof int[]) + return Arrays.equals((int[]) o1, (int[]) o2); + + if (o1 instanceof float[] && o2 instanceof float[]) + return Arrays.equals((float[]) o1, (float[]) o2); + + if (o1 instanceof long[] && o2 instanceof long[]) + return Arrays.equals((long[]) o1, (long[]) o2); + + if (o1 instanceof double[] && o2 instanceof double[]) + return Arrays.equals((double[]) o1, (double[]) o2); + + if (o1 instanceof Object[] && o2 instanceof Object[]) + return Arrays.equals((Object[]) o1, (Object[]) o2); + + return o1.equals(o2); + } + + private static int deepHashCode(Object obj) + { + if (obj instanceof boolean[]) + return Arrays.hashCode((boolean[]) obj); + + if (obj instanceof byte[]) + return Arrays.hashCode((byte[]) obj); + + if (obj instanceof char[]) + return Arrays.hashCode((char[]) obj); + + if (obj instanceof short[]) + return Arrays.hashCode((short[]) obj); + + if (obj instanceof int[]) + return Arrays.hashCode((int[]) obj); + + if (obj instanceof float[]) + return Arrays.hashCode((float[]) obj); + + if (obj instanceof long[]) + return Arrays.hashCode((long[]) obj); + + if (obj instanceof double[]) + return Arrays.hashCode((double[]) obj); + + if (obj instanceof Object[]) + return Arrays.hashCode((Object[]) obj); + + return obj.hashCode(); + } + + /** + * Compute the hashCode for an annotation. Note that the algorithm is + * specified by Annotation.hashCode. + * + * This method is public for use by other parts of the VM. Some VMs + * (can) use different representations of annotations that reuse this + * method. + */ + public static int hashCode(Class type, Map memberValues) + { + int h = 0; + Iterator iter = memberValues.keySet().iterator(); + while (iter.hasNext()) + { + Object key = iter.next(); + Object val = memberValues.get(key); + h += deepHashCode(val) ^ 127 * key.hashCode(); + } + return h; + } + + private static String deepToString(Object obj) + { + if (obj instanceof boolean[]) + return Arrays.toString((boolean[]) obj); + + if (obj instanceof byte[]) + return Arrays.toString((byte[]) obj); + + if (obj instanceof char[]) + return Arrays.toString((char[]) obj); + + if (obj instanceof short[]) + return Arrays.toString((short[]) obj); + + if (obj instanceof int[]) + return Arrays.toString((int[]) obj); + + if (obj instanceof float[]) + return Arrays.toString((float[]) obj); + + if (obj instanceof long[]) + return Arrays.toString((long[]) obj); + + if (obj instanceof double[]) + return Arrays.toString((double[]) obj); + + if (obj instanceof Object[]) + return Arrays.toString((Object[]) obj); + + return obj.toString(); + } + + /** + * This method is public for use by other parts of the VM. Some VMs + * (can) use different representations of annotations that reuse this + * method. + */ + public static String toString(Class type, Map memberValues) + { + StringBuffer sb = new StringBuffer(); + sb.append('@').append(type.getName()).append('('); + String sep = ""; + Iterator iter = memberValues.keySet().iterator(); + while (iter.hasNext()) + { + Object key = iter.next(); + Object val = memberValues.get(key); + sb.append(sep).append(key).append('=').append(deepToString(val)); + sep = ", "; + } + sb.append(')'); + return sb.toString(); + } + + private static Class getBoxedReturnType(Method method) + { + Class returnType = method.getReturnType(); + + if (returnType == boolean.class) + return Boolean.class; + + if (returnType == byte.class) + return Byte.class; + + if (returnType == char.class) + return Character.class; + + if (returnType == short.class) + return Short.class; + + if (returnType == int.class) + return Integer.class; + + if (returnType == float.class) + return Float.class; + + if (returnType == long.class) + return Long.class; + + if (returnType == double.class) + return Double.class; + + return returnType; + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable + { + String methodName = method.getName().intern(); + if (args == null || args.length == 0) + { + if (methodName == "toString") + { + return toString(type, memberValues); + } + else if (methodName == "hashCode") + { + return Integer.valueOf(hashCode(type, memberValues)); + } + else if (methodName == "annotationType") + { + return type; + } + else + { + Object val = memberValues.get(methodName); + if (val == null) + { + throw new IncompleteAnnotationException(type, methodName); + } + if (! getBoxedReturnType(method).isInstance(val)) + { + throw new AnnotationTypeMismatchException(method, + val.getClass().getName()); + } + return val; + } + } + else if (args.length == 1) + { + if (methodName == "equals") + { + return Boolean.valueOf(equals(type, memberValues, args[0])); + } + } + throw new InternalError("Invalid annotation proxy"); + } +} Added: trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationParser.java =================================================================== --- trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationParser.java (rev 0) +++ trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationParser.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,57 @@ +/* sun.reflect.annotation.AnnotationParser + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package sun.reflect.annotation; + +import gnu.classpath.NotImplementedException; + +import java.lang.annotation.Annotation; + +import java.util.Map; + +public class AnnotationParser +{ + + public static Annotation annotationForMap(Class<? extends Annotation> annoType, + Map<String, Object> map) + throws NotImplementedException + { + return null; + } + +} Added: trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationType.java =================================================================== --- trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationType.java (rev 0) +++ trunk/core/src/classpath/sun/sun/reflect/annotation/AnnotationType.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,52 @@ +/* sun.reflect.annotation.AnnotationType + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package sun.reflect.annotation; + +import gnu.classpath.NotImplementedException; + +public class AnnotationType +{ + + public static Class<?> invocationHandlerReturnType(Class<?> returnClass) + throws NotImplementedException + { + return null; + } + +} Added: trunk/core/src/classpath/sun/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java =================================================================== --- trunk/core/src/classpath/sun/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java (rev 0) +++ trunk/core/src/classpath/sun/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,52 @@ +/* sun.reflect.annotation.EnumConstantNotPresentExceptionProxy + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package sun.reflect.annotation; + +import gnu.classpath.NotImplementedException; + +public class EnumConstantNotPresentExceptionProxy + extends ExceptionProxy +{ + + public EnumConstantNotPresentExceptionProxy(Class c, String s) + throws NotImplementedException + { + } + +} Added: trunk/core/src/classpath/sun/sun/reflect/annotation/ExceptionProxy.java =================================================================== --- trunk/core/src/classpath/sun/sun/reflect/annotation/ExceptionProxy.java (rev 0) +++ trunk/core/src/classpath/sun/sun/reflect/annotation/ExceptionProxy.java 2007-01-07 05:43:40 UTC (rev 2997) @@ -0,0 +1,46 @@ +/* sun.reflect.annotation.ExceptionProxy + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package sun.reflect.annotation; + +import gnu.classpath.NotImplementedException; + +public class ExceptionProxy +{ + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ls...@us...> - 2007-01-07 12:59:53
|
Revision: 3026 http://jnode.svn.sourceforge.net/jnode/?rev=3026&view=rev Author: lsantha Date: 2007-01-07 04:59:51 -0800 (Sun, 07 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java trunk/core/src/classpath/vm/java/lang/Class.java trunk/core/src/classpath/vm/java/lang/Thread.java trunk/core/src/classpath/vm/java/lang/VMSystem.java trunk/core/src/classpath/vm/java/lang/reflect/Method.java Added Paths: ----------- trunk/core/src/classpath/vm/java/lang/VMProcess.java Modified: trunk/core/src/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java =================================================================== --- trunk/core/src/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java 2007-01-07 12:57:57 UTC (rev 3025) +++ trunk/core/src/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -238,6 +238,6 @@ ClassNotFoundException { // Write no fields. - }; + } } Modified: trunk/core/src/classpath/vm/java/lang/Class.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/Class.java 2007-01-07 12:57:57 UTC (rev 3025) +++ trunk/core/src/classpath/vm/java/lang/Class.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -1,24 +1,41 @@ -/* - * $Id$ - * - * JNode.org - * Copyright (C) 2003-2006 JNode.org - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; If not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +/* Class.java -- Representation of a Java class. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + package java.lang; import gnu.java.lang.VMClassHelper; @@ -56,10 +73,34 @@ import org.jnode.vm.classmgr.VmType; /** - * Class. If you change any fields in this class, also change - * <code>emitClass</code> in <code>org.jnode.build.ObjectEmitter</code>. + * A Class represents a Java type. There will never be multiple Class + * objects with identical names and ClassLoaders. Primitive types, array + * types, and void also have a Class object. * - * @author epr + * <p>Arrays with identical type and number of dimensions share the same class. + * The array class ClassLoader is the same as the ClassLoader of the element + * type of the array (which can be null to indicate the bootstrap classloader). + * The name of an array class is <code>[<signature format>;</code>. + * <p> For example, + * String[]'s class is <code>[Ljava.lang.String;</code>. boolean, byte, + * short, char, int, long, float and double have the "type name" of + * Z,B,S,C,I,J,F,D for the purposes of array classes. If it's a + * multidimensioned array, the same principle applies: + * <code>int[][][]</code> == <code>[[[I</code>. + * + * <p>There is no public constructor - Class objects are obtained only through + * the virtual machine, as defined in ClassLoaders. + * + * @serialData Class objects serialize specially: + * <code>TC_CLASS ClassDescriptor</code>. For more serialization information, + * see {@link ObjectStreamClass}. + * + * @author John Keiser + * @author Eric Blake (eb...@em...) + * @author Tom Tromey (tr...@re...) + * @author Andrew John Hughes (gnu...@me...) + * @since 1.0 + * @see ClassLoader */ public final class Class<T> implements AnnotatedElement, Serializable, Type, GenericDeclaration { @@ -369,7 +410,7 @@ * @throws InstantiationException * @throws IllegalAccessException */ - public final Object newInstance() throws InstantiationException, + public final T newInstance() throws InstantiationException, IllegalAccessException { if (defaultConstructor == null) { defaultConstructor = getLinkedVmClass().getDeclaredMethod("<init>", @@ -379,7 +420,7 @@ throw new InstantiationException("No default constructor"); } try { - return VmReflection.newInstance(defaultConstructor); + return (T)VmReflection.newInstance(defaultConstructor); } catch (InvocationTargetException ex) { final InstantiationException ie = new InstantiationException(); ie.initCause(ex); Modified: trunk/core/src/classpath/vm/java/lang/Thread.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-07 12:57:57 UTC (rev 3025) +++ trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -1,21 +1,18 @@ -/* - * $Id$ +/* Thread -- an independent thread of executable code + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 * - * JNode.org - * Copyright (C) 2003-2006 JNode.org - * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * - * This library is distributed in the hope that it will be useful, but + * This library 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 Lesser General Public + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with this library; If not, write to the Free Software Foundation, Inc., + * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -712,7 +709,37 @@ } return locals; } + /** + * <p> + * Represents the current state of a thread, according to the VM rather + * than the operating system. It can be one of the following: + * </p> + * <ul> + * <li>NEW -- The thread has just been created but is not yet running.</li> + * <li>RUNNABLE -- The thread is currently running or can be scheduled + * to run.</li> + * <li>BLOCKED -- The thread is blocked waiting on an I/O operation + * or to obtain a lock.</li> + * <li>WAITING -- The thread is waiting indefinitely for another thread + * to do something.</li> + * <li>TIMED_WAITING -- The thread is waiting for a specific amount of time + * for another thread to do something.</li> + * <li>TERMINATED -- The thread has exited.</li> + * </ul> + * + * @since 1.5 + */ + public enum State + { + BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING; + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 605505746047245783L; + } + + /** * Returns the current state of the thread. This * is designed for monitoring thread behaviour, rather @@ -720,9 +747,9 @@ * * @return the current thread state. */ - public String getState() + public State getState() { //todo implement - return "UNKNOWN"; + throw new UnsupportedClassVersionError(); } } Added: trunk/core/src/classpath/vm/java/lang/VMProcess.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/VMProcess.java (rev 0) +++ trunk/core/src/classpath/vm/java/lang/VMProcess.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -0,0 +1,410 @@ +/* java.lang.VMProcess -- VM implementation of java.lang.Process + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Represents one external process. Each instance of this class is in + * one of three states: INITIAL, RUNNING, or TERMINATED. The instance + * is {@link Object#notifyAll notifyAll()}'d each time the state changes. + * The state of all instances is managed by a single dedicated thread + * which does the actual fork()/exec() and wait() system calls. User + * threads {@link Object#wait()} on the instance when creating the + * process or waiting for it to terminate. + * + * <p> + * See + * <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11801">GCC bug + * #11801</a> for the motivation behind the design of this class. + * + * @author Archie Cobbs + * @see Process + * @see Runtime#exec(String) + */ +final class VMProcess extends Process +{ + + // Possible states for a VMProcess + private static final int INITIAL = 0; + private static final int RUNNING = 1; + private static final int TERMINATED = 2; + + // Dedicated thread that does all the fork()'ing and wait()'ing. + static Thread processThread; + + // New processes waiting to be spawned by processThread. + static final LinkedList workList = new LinkedList(); + + // Return values set by nativeReap() when a child is reaped. + // These are only accessed by processThread so no locking required. + static long reapedPid; + static int reapedExitValue; + + // Information about this process + int state; // current state of process + final String[] cmd; // copied from Runtime.exec() + final String[] env; // copied from Runtime.exec() + final File dir; // copied from Runtime.exec() + Throwable exception; // if process failed to start + long pid; // process id + OutputStream stdin; // process input stream + InputStream stdout; // process output stream + InputStream stderr; // process error stream + int exitValue; // process exit value + boolean redirect; // redirect stderr -> stdout + + // + // Dedicated thread that does all the fork()'ing and wait()'ing + // for external processes. This is needed because some systems like + // Linux use a process-per-thread model, which means the same thread + // that did the fork()/exec() must also do the wait(). + // + private static class ProcessThread extends Thread + { + + // Max time (in ms) we'll delay before trying to reap another child. + private static final int MAX_REAP_DELAY = 1000; + + // Processes created but not yet terminated; maps Long(pid) -> VMProcess + // Only used in run() and spawn() method from this Thread, so no locking. + private final HashMap activeMap = new HashMap(); + + // We have an explicit constructor, because the default + // constructor will be private, which means the compiler will have + // to generate a second package-private constructor, which is + // bogus. + ProcessThread () + { + } + + public void run() + { + final LinkedList workList = VMProcess.workList; + while (true) + { + + // Get the next process to spawn (if any) and spawn it. Spawn + // at most one at a time before checking for reapable children. + VMProcess process = null; + synchronized (workList) + { + if (!workList.isEmpty()) + process = (VMProcess)workList.removeFirst(); + } + + if (process != null) + spawn(process); + + + // Check for termination of active child processes + while (!activeMap.isEmpty() && VMProcess.nativeReap()) + { + long pid = VMProcess.reapedPid; + int exitValue = VMProcess.reapedExitValue; + process = (VMProcess)activeMap.remove(new Long(pid)); + if (process != null) + { + synchronized (process) + { + process.exitValue = exitValue; + process.state = TERMINATED; + process.notify(); + } + } + else + System.err.println("VMProcess WARNING reaped unknown process: " + + pid); + } + + + // If there are more new processes to create, go do that now. + // If there is nothing left to do, exit this thread. Otherwise, + // sleep a little while, and then check again for reapable children. + // We will get woken up immediately if there are new processes to + // spawn, but not if there are new children to reap. So we only + // sleep a short time, in effect polling while processes are active. + synchronized (workList) + { + if (!workList.isEmpty()) + continue; + if (activeMap.isEmpty()) + { + processThread = null; + break; + } + + try + { + workList.wait(MAX_REAP_DELAY); + } + catch (InterruptedException e) + { + /* ignore */ + } + } + } + } + + // Spawn a process + private void spawn(VMProcess process) + { + + // Spawn the process and put it in our active map indexed by pid. + // If the spawn operation fails, store the exception with the process. + // In either case, wake up thread that created the process. + synchronized (process) + { + try + { + process.nativeSpawn(process.cmd, process.env, process.dir, + process.redirect); + process.state = RUNNING; + activeMap.put(new Long(process.pid), process); + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + process.state = TERMINATED; + process.exception = t; + } + process.notify(); + } + } + } + + // Constructor + private VMProcess(String[] cmd, String[] env, File dir, boolean redirect) + throws IOException + { + + // Initialize this process + this.state = INITIAL; + this.cmd = cmd; + this.env = env; + this.dir = dir; + this.redirect = redirect; + + // Add process to the new process work list and wakeup processThread + synchronized (workList) + { + workList.add(this); + if (processThread == null) + { + processThread = new ProcessThread(); + processThread.setDaemon(true); + processThread.start(); + } + else + { + workList.notify(); + } + } + + // Wait for processThread to spawn this process and update its state + synchronized (this) + { + while (state == INITIAL) + { + try + { + wait(); + } + catch (InterruptedException e) + { + /* ignore */ + } + } + } + + // If spawning failed, rethrow the exception in this thread + if (exception != null) + { + exception.fillInStackTrace(); + if (exception instanceof IOException) + throw (IOException)exception; + + if (exception instanceof Error) + throw (Error)exception; + + if (exception instanceof RuntimeException) + throw (RuntimeException)exception; + + throw new RuntimeException(exception); + } + } + + // Invoked by native code (from nativeSpawn()) to record process info. + private void setProcessInfo(OutputStream stdin, + InputStream stdout, InputStream stderr, long pid) + { + this.stdin = stdin; + this.stdout = stdout; + if (stderr == null) + this.stderr = new InputStream() + { + public int read() throws IOException + { + return -1; + } + }; + else + this.stderr = stderr; + this.pid = pid; + } + + /** + * Entry point from Runtime.exec(). + */ + static Process exec(String[] cmd, String[] env, File dir) throws IOException + { + return new VMProcess(cmd, env, dir, false); + } + + static Process exec(List cmd, Map env, + File dir, boolean redirect) throws IOException + { + String[] acmd = (String[]) cmd.toArray(new String[cmd.size()]); + String[] aenv = new String[env.size()]; + + int i = 0; + Iterator iter = env.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry entry = (Map.Entry) iter.next(); + aenv[i++] = entry.getKey() + "=" + entry.getValue(); + } + + return new VMProcess(acmd, aenv, dir, redirect); + } + + public OutputStream getOutputStream() + { + return stdin; + } + + public InputStream getInputStream() + { + return stdout; + } + + public InputStream getErrorStream() + { + return stderr; + } + + public synchronized int waitFor() throws InterruptedException + { + while (state != TERMINATED) + wait(); + return exitValue; + } + + public synchronized int exitValue() + { + if (state != TERMINATED) + throw new IllegalThreadStateException(); + return exitValue; + } + + public synchronized void destroy() + { + if (state == TERMINATED) + return; + + nativeKill(pid); + + while (state != TERMINATED) + { + try + { + wait(); + } + catch (InterruptedException e) + { + /* ignore */ + } + } + } + + /** + * Does the fork()/exec() thing to create the O/S process. + * Must invoke setProcessInfo() before returning successfully. + * This method is only invoked by processThread. + * + * @throws IOException if the O/S process could not be created. + */ + void nativeSpawn(String[] cmd, String[] env, File dir, + boolean redirect) throws IOException{ + //TODO implement it + throw new UnsupportedOperationException(); + }; + + /** + * Test for a reapable child process, and reap if so. Does not block. + * If a child was reaped, this method must set reapedPid and + * reapedExitValue appropriately before returning. + * This method is only invoked by processThread. + * + * @return true if a child was reaped, otherwise false + */ + // This is not private as it is called from an inner class. + static boolean nativeReap(){ + //TODO implement it + throw new UnsupportedOperationException(); + } + + /** + * Kill a process. This sends it a fatal signal but does not reap it. + */ + private static void nativeKill(long pid){ + //TODO implement it + throw new UnsupportedOperationException(); + } +} Modified: trunk/core/src/classpath/vm/java/lang/VMSystem.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/VMSystem.java 2007-01-07 12:57:57 UTC (rev 3025) +++ trunk/core/src/classpath/vm/java/lang/VMSystem.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -1,29 +1,46 @@ -/* - * $Id$ - * - * JNode.org - * Copyright (C) 2003-2006 JNode.org - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; If not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +/* VMSystem.java -- helper for java.lang.system + Copyright (C) 1998, 2002, 2004 Free Software Foundation +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + package java.lang; import java.io.InputStream; import java.io.PrintStream; import java.nio.ByteOrder; +import java.util.List; import org.jnode.util.EmptyInputStream; import org.jnode.util.SystemInputStream; @@ -152,14 +169,53 @@ return VmSystem.currentTimeMillis(); } - /** + /** + * <p> + * Returns the current value of a nanosecond-precise system timer. + * The value of the timer is an offset relative to some arbitrary fixed + * time, which may be in the future (making the value negative). This + * method is useful for timing events where nanosecond precision is + * required. This is achieved by calling this method before and after the + * event, and taking the difference betweent the two times: + * </p> + * <p> + * <code>long startTime = System.nanoTime();</code><br /> + * <code>... <emph>event code</emph> ...</code><br /> + * <code>long endTime = System.nanoTime();</code><br /> + * <code>long duration = endTime - startTime;</code><br /> + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. + * </p> + * + * @return the time of a system timer in nanoseconds. + * @since 1.5 + */ + public static long nanoTime(){ + //TODO implement it + throw new UnsupportedOperationException(); + }; + + /** + * Returns a list of 'name=value' pairs representing the current environment + * variables. + * + * @return a list of 'name=value' pairs. + */ + static List environ(){ + //TODO implement it + throw new UnsupportedOperationException(); + } + /** * Helper method which creates the standard input stream. VM implementors * may choose to construct these streams differently. This method can also * return null if the stream is created somewhere else in the VM startup * sequence. */ - - static InputStream makeStandardInputStream() { + static InputStream makeStandardInputStream() { return SystemInputStream.getInstance(); // JNode specific } @@ -169,7 +225,6 @@ * return null if the stream is created somewhere else in the VM startup * sequence. */ - static PrintStream makeStandardOutputStream() { return VmSystem.getSystemOut(); } Modified: trunk/core/src/classpath/vm/java/lang/reflect/Method.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/Method.java 2007-01-07 12:57:57 UTC (rev 3025) +++ trunk/core/src/classpath/vm/java/lang/reflect/Method.java 2007-01-07 12:59:51 UTC (rev 3026) @@ -323,7 +323,7 @@ * @throws ExceptionInInitializerError if accessing a static method triggered * class initialization, which then failed */ - public Object invoke(Object o, Object[] args) + public Object invoke(Object o, Object... args) throws IllegalAccessException, InvocationTargetException { return VmReflection.invoke(vmMethod, o, args); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ls...@us...> - 2007-01-07 18:42:55
|
Revision: 3045 http://jnode.svn.sourceforge.net/jnode/?rev=3045&view=rev Author: lsantha Date: 2007-01-07 10:42:54 -0800 (Sun, 07 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/Main.java trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java Modified: trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/Main.java =================================================================== --- trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/Main.java 2007-01-07 18:42:15 UTC (rev 3044) +++ trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/Main.java 2007-01-07 18:42:54 UTC (rev 3045) @@ -266,7 +266,6 @@ else { // Warn user about missing security manager. - /* @jnode disable security warning System.err.println(Messages.getString("Main.SecurityWarning") + "\n"); System.err.println(Messages.getString("Main.ContinuationPrompt")); @@ -290,7 +289,6 @@ System.exit(0); } - */ if (code == null) { // The --code option wasn't given and there are no URL Modified: trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java =================================================================== --- trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java 2007-01-07 18:42:15 UTC (rev 3044) +++ trunk/core/src/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java 2007-01-07 18:42:54 UTC (rev 3045) @@ -130,7 +130,7 @@ { ArrayList allTags = new ArrayList(); if (document == null) - return null;; + return null; recurseDocument(document.getChildNodes()); Modified: trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java 2007-01-07 18:42:15 UTC (rev 3044) +++ trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java 2007-01-07 18:42:54 UTC (rev 3045) @@ -79,7 +79,12 @@ * @since 1.1 * @status updated to 1.4 */ -public final class Constructor extends AccessibleObject implements Member, AnnotatedElement, GenericDeclaration { +public final class Constructor<T> + extends AccessibleObject + implements GenericDeclaration, Member +{ + private Class<T> clazz; + private int slot; private final VmMethod vmMethod; private ArrayList<Class> parameterTypes; @@ -99,8 +104,8 @@ * Gets the class that declared this constructor. * @return the class that declared this member */ - public Class getDeclaringClass() { - return vmMethod.getDeclaringClass().asClass(); + public Class<T> getDeclaringClass() { + return (Class<T>) vmMethod.getDeclaringClass().asClass(); } /** @@ -108,9 +113,9 @@ * it was declared in). * @return the name of this constructor */ - public String getName() { - final Class<?> declClass = getDeclaringClass(); - return declClass.getName(); + public String getName() + { + return getDeclaringClass().getName(); } /** @@ -164,7 +169,7 @@ * * @return a list of the types of the constructor's parameters */ - public Class[] getParameterTypes() { + public Class<?>[] getParameterTypes() { if (parameterTypes == null) { int cnt = vmMethod.getNoArguments(); ArrayList<Class> list = new ArrayList<Class>(cnt); @@ -183,7 +188,7 @@ * * @return a list of the types in the constructor's throws clause */ - public Class[] getExceptionTypes() { + public Class<?>[] getExceptionTypes() { if (exceptionTypes == null) { final VmExceptions exceptions = vmMethod.getExceptions(); final int cnt = exceptions.getLength(); @@ -216,9 +221,9 @@ * * @return the hash code for the object */ - public int hashCode() { - final Class<?> declClass = getDeclaringClass(); - return declClass.getName().hashCode(); + public int hashCode() + { + return getDeclaringClass().getName().hashCode(); } /** @@ -233,7 +238,7 @@ */ public String toString() { // 128 is a reasonable buffer initial size for constructor - StringBuffer sb = new StringBuffer(128); + StringBuilder sb = new StringBuilder(128); Modifier.toString(getModifiers(), sb).append(' '); final Class<?> declClass = getDeclaringClass(); sb.append(declClass.getName()).append('('); @@ -285,8 +290,8 @@ * @throws ExceptionInInitializerError if construction triggered class * initialization, which then failed */ - public Object newInstance(Object args[]) throws InstantiationException, IllegalAccessException, InvocationTargetException { - return VmReflection.newInstance(vmMethod, args); + public T newInstance(Object... args) throws InstantiationException, IllegalAccessException, InvocationTargetException { + return (T) VmReflection.newInstance(vmMethod, args); } /** @@ -318,6 +323,7 @@ MethodSignatureParser p = new MethodSignatureParser(this, sig); return p.getTypeParameters(); } + /** * Returns an array of <code>Type</code> objects that represents * the exception types declared by this constructor, in declaration order. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ls...@us...> - 2007-01-27 07:54:11
|
Revision: 3087 http://jnode.svn.sourceforge.net/jnode/?rev=3087&view=rev Author: lsantha Date: 2007-01-26 23:54:10 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/java/java/lang/reflect/AccessibleObject.java trunk/core/src/classpath/java/java/lang/reflect/Proxy.java trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java trunk/core/src/classpath/vm/java/lang/reflect/Field.java trunk/core/src/classpath/vm/java/lang/reflect/Method.java Modified: trunk/core/src/classpath/java/java/lang/reflect/AccessibleObject.java =================================================================== --- trunk/core/src/classpath/java/java/lang/reflect/AccessibleObject.java 2007-01-20 08:55:33 UTC (rev 3086) +++ trunk/core/src/classpath/java/java/lang/reflect/AccessibleObject.java 2007-01-27 07:54:10 UTC (rev 3087) @@ -1,5 +1,5 @@ /* java.lang.reflect.AccessibleObject - Copyright (C) 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ package java.lang.reflect; +import java.lang.annotation.Annotation; + /** * This class is the superclass of various reflection classes, and * allows sufficiently trusted code to bypass normal restrictions to @@ -53,9 +55,10 @@ * @see Method * @see ReflectPermission * @since 1.2 - * @status updated to 1.4 + * @status updated to 1.5 */ public class AccessibleObject + implements AnnotatedElement { /** * True if this object is marked accessible, which means the reflected @@ -156,4 +159,24 @@ throw new SecurityException("Cannot make object accessible: " + this); this.flag = flag; } + + public <T extends Annotation> T getAnnotation(Class<T> annotationClass) + { + throw new AssertionError("Subclass must override this method"); + } + + public Annotation[] getAnnotations() + { + return getDeclaredAnnotations(); + } + + public Annotation[] getDeclaredAnnotations() + { + throw new AssertionError("Subclass must override this method"); + } + + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) + { + return getAnnotation(annotationClass) != null; + } } Modified: trunk/core/src/classpath/java/java/lang/reflect/Proxy.java =================================================================== --- trunk/core/src/classpath/java/java/lang/reflect/Proxy.java 2007-01-20 08:55:33 UTC (rev 3086) +++ trunk/core/src/classpath/java/java/lang/reflect/Proxy.java 2007-01-27 07:54:10 UTC (rev 3087) @@ -158,7 +158,7 @@ * @see Class * @author Eric Blake (eb...@em...) * @since 1.3 - * @status updated to 1.4, except for the use of ProtectionDomain + * @status updated to 1.5, except for the use of ProtectionDomain */ public class Proxy implements Serializable { @@ -257,8 +257,8 @@ */ // synchronized so that we aren't trying to build the same class // simultaneously in two threads - public static synchronized Class getProxyClass(ClassLoader loader, - Class[] interfaces) + public static synchronized Class<?> getProxyClass(ClassLoader loader, + Class<?>... interfaces) { interfaces = (Class[]) interfaces.clone(); ProxyType pt = new ProxyType(loader, interfaces); @@ -312,7 +312,7 @@ * @see Constructor#newInstance(Object[]) */ public static Object newProxyInstance(ClassLoader loader, - Class[] interfaces, + Class<?>[] interfaces, InvocationHandler handler) { try @@ -360,7 +360,7 @@ */ // This is synchronized on the off chance that another thread is // trying to add a class to the map at the same time we read it. - public static synchronized boolean isProxyClass(Class clazz) + public static synchronized boolean isProxyClass(Class<?> clazz) { if (! Proxy.class.isAssignableFrom(clazz)) return false; @@ -889,7 +889,7 @@ // constant_pool[], filled in as we go // access_flags - putU2(/*Modifier.SUPER |*/ Modifier.FINAL | Modifier.PUBLIC); + putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC); // this_class qualName = (data.pack + "$Proxy" + data.id); putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false))); Modified: trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java 2007-01-20 08:55:33 UTC (rev 3086) +++ trunk/core/src/classpath/vm/java/lang/reflect/Constructor.java 2007-01-27 07:54:10 UTC (rev 3087) @@ -38,6 +38,7 @@ package java.lang.reflect; +import gnu.java.lang.ClassHelper; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -46,6 +47,8 @@ import org.jnode.vm.classmgr.VmMethod; import gnu.java.lang.reflect.MethodSignatureParser; +import java.util.Arrays; + /** * The Constructor class represents a constructor of a class. It also allows * dynamic creation of an object, via reflection. Invocation on Constructor @@ -104,7 +107,8 @@ * Gets the class that declared this constructor. * @return the class that declared this member */ - public Class<T> getDeclaringClass() { + public Class<T> getDeclaringClass() + { return (Class<T>) vmMethod.getDeclaringClass().asClass(); } @@ -123,12 +127,11 @@ * this will include the synthetic and varargs bits. * @return the constructor's modifiers */ - private int getModifiersInternal() { + private int getModifiersInternal() + { return vmMethod.getModifiers(); } - - /** * Gets the modifiers this constructor uses. Use the <code>Modifier</code> * class to interpret the values. A constructor can only have a subset of the @@ -169,7 +172,8 @@ * * @return a list of the types of the constructor's parameters */ - public Class<?>[] getParameterTypes() { + public Class<?>[] getParameterTypes() + { if (parameterTypes == null) { int cnt = vmMethod.getNoArguments(); ArrayList<Class> list = new ArrayList<Class>(cnt); @@ -211,8 +215,16 @@ * @param o the object to compare to * @return <code>true</code> if they are equal; <code>false</code> if not. */ - public boolean equals(Object o) { - return (this == o); + public boolean equals(Object o) + { + if (!(o instanceof Constructor)) + return false; + Constructor that = (Constructor)o; + if (this.getDeclaringClass() != that.getDeclaringClass()) + return false; + if (!Arrays.equals(this.getParameterTypes(), that.getParameterTypes())) + return false; + return true; } /** @@ -240,23 +252,60 @@ // 128 is a reasonable buffer initial size for constructor StringBuilder sb = new StringBuilder(128); Modifier.toString(getModifiers(), sb).append(' '); - final Class<?> declClass = getDeclaringClass(); - sb.append(declClass.getName()).append('('); - Class<?>[] c = getParameterTypes(); - if (c.length > 0) { - sb.append(c[0].getName()); - for (int i = 1; i < c.length; i++) { - sb.append(',').append(c[i].getName()); + sb.append(getDeclaringClass().getName()).append('('); + Class[] c = getParameterTypes(); + if (c.length > 0) + { + sb.append(ClassHelper.getUserName(c[0])); + for (int i = 1; i < c.length; i++) + sb.append(',').append(ClassHelper.getUserName(c[i])); } - } sb.append(')'); c = getExceptionTypes(); if (c.length > 0) { sb.append(" throws ").append(c[0].getName()); - for (int i = 1; i < c.length; i++) { + for (int i = 1; i < c.length; i++) sb.append(',').append(c[i].getName()); } + return sb.toString(); } + + static <X extends GenericDeclaration> + void addTypeParameters(StringBuilder sb, TypeVariable<X>[] typeArgs) + { + if (typeArgs.length == 0) + return; + sb.append('<'); + for (int i = 0; i < typeArgs.length; ++i) + { + if (i > 0) + sb.append(','); + sb.append(typeArgs[i]); + } + sb.append("> "); + } + + public String toGenericString() + { + StringBuilder sb = new StringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + addTypeParameters(sb, getTypeParameters()); + sb.append(getDeclaringClass().getName()).append('('); + Type[] types = getGenericParameterTypes(); + if (types.length > 0) + { + sb.append(types[0]); + for (int i = 1; i < types.length; ++i) + sb.append(',').append(types[i]); + } + sb.append(')'); + types = getGenericExceptionTypes(); + if (types.length > 0) + { + sb.append(" throws ").append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } return sb.toString(); } @@ -294,14 +343,6 @@ return (T) VmReflection.newInstance(vmMethod, args); } - /** - * Return the String in the Signature attribute for this constructor. If there - * is no Signature attribute, return null. - */ - private String getSignature(){ - //todo implement it - return null; - } /** * Returns an array of <code>TypeVariable</code> objects that represents @@ -315,7 +356,7 @@ * specification, version 3. * @since 1.5 */ - public TypeVariable[] getTypeParameters() + public TypeVariable<Constructor<T>>[] getTypeParameters() { String sig = getSignature(); if (sig == null) @@ -325,6 +366,15 @@ } /** + * Return the String in the Signature attribute for this constructor. If there + * is no Signature attribute, return null. + */ + private String getSignature() + { + return vmMethod.getSignature(); + } + + /** * Returns an array of <code>Type</code> objects that represents * the exception types declared by this constructor, in declaration order. * An array of size zero is returned if this constructor declares no Modified: trunk/core/src/classpath/vm/java/lang/reflect/Field.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/Field.java 2007-01-20 08:55:33 UTC (rev 3086) +++ trunk/core/src/classpath/vm/java/lang/reflect/Field.java 2007-01-27 07:54:10 UTC (rev 3087) @@ -1,56 +1,71 @@ -/* - * $Id$ - * - * JNode.org - * Copyright (C) 2003-2006 JNode.org - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; If not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - +/* java.lang.reflect.Field - reflection of Java fields + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + package java.lang.reflect; -import java.lang.annotation.Annotation; +import gnu.java.lang.ClassHelper; +import gnu.java.lang.reflect.FieldSignatureParser; import org.jnode.vm.VmReflection; import org.jnode.vm.classmgr.VmField; +import java.lang.annotation.Annotation; /** * The Field class represents a member variable of a class. It also allows - * dynamic access to a member, via reflection. This works for both static and - * instance fields. Operations on Field objects know how to do widening - * conversions, but throw {@link IllegalArgumentException}if a narrowing - * conversion would be necessary. You can query for information on this Field - * regardless of location, but get and set access may be limited by Java - * language access controls. If you can't do it in the compiler, you can't - * normally do it here either. - * <p> + * dynamic access to a member, via reflection. This works for both + * static and instance fields. Operations on Field objects know how to + * do widening conversions, but throw {@link IllegalArgumentException} if + * a narrowing conversion would be necessary. You can query for information + * on this Field regardless of location, but get and set access may be limited + * by Java language access controls. If you can't do it in the compiler, you + * can't normally do it here either.<p> * - * <B>Note: </B> This class returns and accepts types as Classes, even primitive - * types; there are Class types defined that represent each different primitive - * type. They are <code>java.lang.Boolean.TYPE, - * java.lang.Byte.TYPE,</code>, - * also available as <code>boolean.class, - * byte.class</code>, etc. These are - * not to be confused with the classes - * <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real - * classes. - * <p> + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> * - * Also note that this is not a serializable class. It is entirely feasible to - * make it serializable using the Externalizable interface, but this is on Sun, - * not me. + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. * * @author John Keiser * @author Eric Blake <eb...@em...> @@ -63,8 +78,9 @@ * @since 1.1 * @status updated to 1.4 */ -public final class Field extends AccessibleObject implements Member, AnnotatedElement { - +public final class Field +extends AccessibleObject implements Member +{ private final VmField vmField; private static final int FIELD_MODIFIERS @@ -80,13 +96,13 @@ } /** - * Gets the class that declared this field, or the class where this field is - * a non-inherited member. - * + * Gets the class that declared this field, or the class where this field + * is a non-inherited member. * @return the class that declared this member */ - public Class getDeclaringClass() { - return vmField.getDeclaringClass().asClass(); + public Class<?> getDeclaringClass() + { + return vmField.getDeclaringClass().asClass(); } /** @@ -99,13 +115,8 @@ } /** - * Gets the modifiers this field uses. Use the <code>Modifier</code> class - * to interpret the values. A field can only have a subset of the following - * modifiers: public, private, protected, static, final, transient, and - * volatile. - * - * @return an integer representing the modifiers to this Member - * @see Modifier + * Return the raw modifiers for this field. + * @return the field's modifiers */ public int getModifiersInternal() { return vmField.getModifiers(); @@ -154,68 +165,82 @@ } /** - * Compare two objects to see if they are semantically equivalent. Two - * Fields are semantically equivalent if they have the same declaring class, - * name, and type. Since you can't creat a Field except through the VM, this - * is just the == relation. + * Compare two objects to see if they are semantically equivalent. + * Two Fields are semantically equivalent if they have the same declaring + * class, name, and type. Since you can't creat a Field except through + * the VM, this is just the == relation. * - * @param o - * the object to compare to - * @return <code>true</code> if they are equal; <code>false</code> if - * not + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not */ - public boolean equals(Object o) { - return this == o; + public boolean equals(Object o) + { + if (!(o instanceof Field)) + return false; + Field that = (Field)o; + if (this.getDeclaringClass() != that.getDeclaringClass()) + return false; + if (!this.getName().equals(that.getName())) + return false; + if (this.getType() != that.getType()) + return false; + return true; } /** - * Get the hash code for the Field. The Field hash code is the hash code of - * its name XOR'd with the hash code of its class name. + * Get the hash code for the Field. The Field hash code is the hash code + * of its name XOR'd with the hash code of its class name. * * @return the hash code for the object. */ - public int hashCode() { - final Class<?> declClass = getDeclaringClass(); - return declClass.getName().hashCode() ^ getName().hashCode(); + public int hashCode() + { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); } /** - * Get a String representation of the Field. A Field's String representation - * is "<modifiers> <type> <class>.<fieldname>". <br> - * Example: + * Get a String representation of the Field. A Field's String + * representation is "<modifiers> <type> + * <class>.<fieldname>".<br> Example: * <code>public transient boolean gnu.parse.Parser.parseComplete</code> * * @return the String representation of the Field */ public String toString() { // 64 is a reasonable buffer initial size for field - StringBuffer sb = new StringBuffer(64); + StringBuilder sb = new StringBuilder(64); Modifier.toString(getModifiers(), sb).append(' '); - final Class<?> type = getType(); - final Class<?> declClass = getDeclaringClass(); - sb.append(type.getName()).append(' '); - sb.append(declClass.getName()).append('.'); + sb.append(ClassHelper.getUserName(getType())).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); sb.append(getName()); return sb.toString(); } + public String toGenericString() + { + StringBuilder sb = new StringBuilder(64); + Modifier.toString(getModifiers(), sb).append(' '); + sb.append(getGenericType()).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); + sb.append(getName()); + return sb.toString(); + } + /** - * Get the value of this Field. If it is primitive, it will be wrapped in - * the appropriate wrapper type (boolean = java.lang.Boolean). - * <p> + * Get the value of this Field. If it is primitive, it will be wrapped + * in the appropriate wrapper type (boolean = java.lang.Boolean).<p> * * If the field is static, <code>o</code> will be ignored. Otherwise, if * <code>o</code> is null, you get a <code>NullPointerException</code>, - * and if it is incompatible with the declaring class of the field, you get - * an <code>IllegalArgumentException</code>. - * <p> + * and if it is incompatible with the declaring class of the field, you + * get an <code>IllegalArgumentException</code>.<p> * * Next, if this Field enforces access control, your runtime context is * evaluated, and you may have an <code>IllegalAccessException</code> if - * you could not access this field in similar compiled code. If the field is - * static, and its class is uninitialized, you trigger class initialization, - * which may end in a <code>ExceptionInInitializerError</code>. - * <p> + * you could not access this field in similar compiled code. If the field + * is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> * * Finally, the field is accessed, and primitives are wrapped (but not * necessarily in new objects). This method accesses the field of the @@ -333,22 +358,17 @@ * Get the value of this Field as a short. If the field is static, * <code>o</code> will be ignored. * - * @param o - * the object to get the value of this Field from + * @param o the object to get the value of this Field from * @return the value of the Field - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte or short field of <code>o</code>, or - * if <code>o</code> is not an instance of the declaring class - * of this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte or short + * field of <code>o</code>, or if <code>o</code> is not an instance + * of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #get(Object) */ public short getShort(Object o) throws IllegalAccessException { @@ -359,22 +379,17 @@ * Get the value of this Field as an int. If the field is static, * <code>o</code> will be ignored. * - * @param o - * the object to get the value of this Field from + * @param o the object to get the value of this Field from * @return the value of the Field - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte, short, char, or int field of - * <code>o</code>, or if <code>o</code> is not an instance - * of the declaring class of this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, or + * int field of <code>o</code>, or if <code>o</code> is not an + * instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #get(Object) */ public int getInt(Object o) throws IllegalAccessException { @@ -385,22 +400,17 @@ * Get the value of this Field as a long. If the field is static, * <code>o</code> will be ignored. * - * @param o - * the object to get the value of this Field from + * @param o the object to get the value of this Field from * @return the value of the Field - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte, short, char, int, or long field of - * <code>o</code>, or if <code>o</code> is not an instance - * of the declaring class of this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * or long field of <code>o</code>, or if <code>o</code> is not an + * instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #get(Object) */ public long getLong(Object o) throws IllegalAccessException { @@ -411,22 +421,17 @@ * Get the value of this Field as a float. If the field is static, * <code>o</code> will be ignored. * - * @param o - * the object to get the value of this Field from + * @param o the object to get the value of this Field from * @return the value of the Field - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte, short, char, int, long, or float field - * of <code>o</code>, or if <code>o</code> is not an - * instance of the declaring class of this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * long, or float field of <code>o</code>, or if <code>o</code> is + * not an instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #get(Object) */ public float getFloat(Object o) throws IllegalAccessException { @@ -437,22 +442,18 @@ * Get the value of this Field as a double. If the field is static, * <code>o</code> will be ignored. * - * @param o - * the object to get the value of this Field from + * @param o the object to get the value of this Field from * @return the value of the Field - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte, short, char, int, long, float, or - * double field of <code>o</code>, or if <code>o</code> is - * not an instance of the declaring class of this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * long, float, or double field of <code>o</code>, or if + * <code>o</code> is not an instance of the declaring class of this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #get(Object) */ public double getDouble(Object o) throws IllegalAccessException { @@ -460,50 +461,41 @@ } /** - * Set the value of this Field. If it is a primitive field, the value will - * be unwrapped from the passed object (boolean = java.lang.Boolean). - * <p> + * Set the value of this Field. If it is a primitive field, the value + * will be unwrapped from the passed object (boolean = java.lang.Boolean).<p> * * If the field is static, <code>o</code> will be ignored. Otherwise, if * <code>o</code> is null, you get a <code>NullPointerException</code>, - * and if it is incompatible with the declaring class of the field, you get - * an <code>IllegalArgumentException</code>. - * <p> + * and if it is incompatible with the declaring class of the field, you + * get an <code>IllegalArgumentException</code>.<p> * * Next, if this Field enforces access control, your runtime context is * evaluated, and you may have an <code>IllegalAccessException</code> if * you could not access this field in similar compiled code. This also - * occurs whether or not there is access control if the field is final. If - * the field is primitive, and unwrapping your argument fails, you will get - * an <code>IllegalArgumentException</code>; likewise, this error happens - * if <code>value</code> cannot be cast to the correct object type. If the - * field is static, and its class is uninitialized, you trigger class + * occurs whether or not there is access control if the field is final. + * If the field is primitive, and unwrapping your argument fails, you will + * get an <code>IllegalArgumentException</code>; likewise, this error + * happens if <code>value</code> cannot be cast to the correct object type. + * If the field is static, and its class is uninitialized, you trigger class * initialization, which may end in a - * <code>ExceptionInInitializerError</code>. - * <p> + * <code>ExceptionInInitializerError</code>.<p> * * Finally, the field is set with the widened value. This method accesses * the field of the declaring class, even if the instance passed in belongs * to a subclass which declares another field to hide this one. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if <code>value</code> cannot be converted by a widening - * conversion to the underlying type of the Field, or if - * <code>o</code> is not an instance of the class declaring - * this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if <code>value</code> cannot be + * converted by a widening conversion to the underlying type of + * the Field, or if <code>o</code> is not an instance of the class + * declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #setBoolean(Object, boolean) * @see #setByte(Object, byte) * @see #setChar(Object, char) @@ -552,22 +544,17 @@ * Set this boolean Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a boolean field, or if <code>o</code> is not - * an instance of the class declaring this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a boolean field, or if + * <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setBoolean(Object o, boolean value) @@ -579,23 +566,17 @@ * Set this byte Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a byte, short, int, long, float, or double - * field, or if <code>o</code> is not an instance of the class - * declaring this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setByte(Object o, byte value) throws IllegalAccessException { @@ -606,23 +587,17 @@ * Set this char Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a char, int, long, float, or double field, or - * if <code>o</code> is not an instance of the class declaring - * this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a char, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setChar(Object o, char value) throws IllegalAccessException { @@ -633,23 +608,17 @@ * Set this short Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a short, int, long, float, or double field, or - * if <code>o</code> is not an instance of the class declaring - * this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a short, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setShort(Object o, short value) throws IllegalAccessException { @@ -660,23 +629,17 @@ * Set this int Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not an int, long, float, or double field, or if - * <code>o</code> is not an instance of the class declaring - * this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not an int, long, float, or + * double field, or if <code>o</code> is not an instance of the + * class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setInt(Object o, int value) throws IllegalAccessException { @@ -687,23 +650,17 @@ * Set this long Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a long, float, or double field, or if - * <code>o</code> is not an instance of the class declaring - * this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a long, float, or double + * field, or if <code>o</code> is not an instance of the class + * declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setLong(Object o, long value) throws IllegalAccessException { @@ -714,22 +671,17 @@ * Set this float Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a float or long field, or if <code>o</code> - * is not an instance of the class declaring this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a float or long field, or + * if <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setFloat(Object o, float value) throws IllegalAccessException { @@ -740,22 +692,17 @@ * Set this double Field. If the field is static, <code>o</code> will be * ignored. * - * @param o - * the object to set this Field on - * @param value - * the value to set this Field to - * @throws IllegalAccessException - * if you could not normally access this field (i.e. it is not - * public) - * @throws IllegalArgumentException - * if this is not a double field, or if <code>o</code> is not - * an instance of the class declaring this field - * @throws NullPointerException - * if <code>o</code> is null and this field requires an - * instance - * @throws ExceptionInInitializerError - * if accessing a static field triggered class initialization, - * which then failed + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a double field, or if + * <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed * @see #set(Object, Object) */ public void setDouble(Object o, double value) throws IllegalAccessException { @@ -763,6 +710,35 @@ } /** + * Return the generic type of the field. If the field type is not a generic + * type, the method returns the same as <code>getType()</code>. + * + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type getGenericType() + { + String signature = getSignature(); + if (signature == null) + return getType(); + FieldSignatureParser p = new FieldSignatureParser(getDeclaringClass(), + signature); + return p.getFieldType(); + } + + /** + * Return the String in the Signature attribute for this field. If there + * is no Signature attribute, return null. + */ + private String getSignature() { + return vmField.getSignature(); + } + + + + /** * @see java.lang.reflect.AnnotatedElement#getAnnotation(java.lang.Class) */ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { Modified: trunk/core/src/classpath/vm/java/lang/reflect/Method.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/Method.java 2007-01-20 08:55:33 UTC (rev 3086) +++ trunk/core/src/classpath/vm/java/lang/reflect/Method.java 2007-01-27 07:54:10 UTC (rev 3087) @@ -38,6 +38,7 @@ package java.lang.reflect; +import gnu.java.lang.ClassHelper; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -104,7 +105,8 @@ * is a non-inherited member. * @return the class that declared this member */ - public Class getDeclaringClass() { + public Class<?> getDeclaringClass() + { return vmMethod.getDeclaringClass().asClass(); } @@ -112,7 +114,8 @@ * Gets the name of this method. * @return the name of this method */ - public String getName() { + public String getName() + { return vmMethod.getName(); } @@ -120,7 +123,8 @@ * Return the raw modifiers for this method. * @return the method's modifiers */ - private int getModifiersInternal() { + private int getModifiersInternal() + { return vmMethod.getModifiers(); } @@ -172,7 +176,8 @@ * Gets the return type of this method. * @return the type of this method */ - public Class getReturnType() { + public Class<?> getReturnType() + { return vmMethod.getReturnType().asClass(); } @@ -182,7 +187,8 @@ * * @return a list of the types of the method's parameters */ - public Class[] getParameterTypes() { + public Class<?>[] getParameterTypes() + { if (parameterTypes == null) { int cnt = vmMethod.getNoArguments(); ArrayList<Class> list = new ArrayList<Class>(cnt); @@ -201,7 +207,8 @@ * * @return a list of the types in the method's throws clause */ - public Class[] getExceptionTypes() { + public Class<?>[] getExceptionTypes() + { if (exceptionTypes == null) { final VmExceptions exceptions = vmMethod.getExceptions(); final int cnt = exceptions.getLength(); @@ -234,7 +241,18 @@ * @return <code>true</code> if they are equal; <code>false</code> if not */ public boolean equals(Object o) { - return (this == o); + if (!(o instanceof Method)) + return false; + Method that = (Method)o; + if (this.getDeclaringClass() != that.getDeclaringClass()) + return false; + if (!this.getName().equals(that.getName())) + return false; + if (this.getReturnType() != that.getReturnType()) + return false; + if (!Arrays.equals(this.getParameterTypes(), that.getParameterTypes())) + return false; + return true; } /** @@ -243,9 +261,9 @@ * * @return the hash code for the object */ - public int hashCode() { - final Class<?> declClass = getDeclaringClass(); - return declClass.getName().hashCode() ^ getName().hashCode(); + public int hashCode() + { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); } /** @@ -259,18 +277,17 @@ */ public String toString() { // 128 is a reasonable buffer initial size for constructor - StringBuffer sb = new StringBuffer(128); + StringBuilder sb = new StringBuilder(128); Modifier.toString(getModifiers(), sb).append(' '); - final Class<?> retType = getReturnType(); - final Class<?> declClass = getDeclaringClass(); - sb.append(retType.getName()).append(' '); - sb.append(declClass.getName()).append('.'); + sb.append(ClassHelper.getUserName(getReturnType())).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); sb.append(getName()).append('('); - Class<?>[] c = getParameterTypes(); - if (c.length > 0) { - sb.append(c[0].getName()); + Class[] c = getParameterTypes(); + if (c.length > 0) + { + sb.append(ClassHelper.getUserName(c[0])); for (int i = 1; i < c.length; i++) - sb.append(',').append(c[i].getName()); + sb.append(',').append(ClassHelper.getUserName(c[i])); } sb.append(')'); c = getExceptionTypes(); @@ -282,6 +299,33 @@ return sb.toString(); } + public String toGenericString() + { + // 128 is a reasonable buffer initial size for constructor + StringBuilder sb = new StringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + Constructor.addTypeParameters(sb, getTypeParameters()); + sb.append(getGenericReturnType()).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); + sb.append(getName()).append('('); + Type[] types = getGenericParameterTypes(); + if (types.length > 0) + { + sb.append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + sb.append(')'); + types = getGenericExceptionTypes(); + if (types.length > 0) + { + sb.append(" throws ").append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + return sb.toString(); + } + /** * Invoke the method. Arguments are automatically unwrapped and widened, * and the result is automatically wrapped, if needed.<p> @@ -353,9 +397,9 @@ * Return the String in the Signature attribute for this method. If there * is no Signature attribute, return null. */ - private String getSignature() { - //todo implement it - return null; + private String getSignature() + { + return vmMethod.getSignature(); } /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ls...@us...> - 2007-01-27 09:39:36
|
Revision: 3088 http://jnode.svn.sourceforge.net/jnode/?rev=3088&view=rev Author: lsantha Date: 2007-01-27 01:39:31 -0800 (Sat, 27 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/gnu/gnu/java/awt/peer/GLightweightPeer.java trunk/core/src/classpath/java/java/awt/CheckboxMenuItem.java trunk/core/src/classpath/java/java/awt/MenuItem.java trunk/core/src/classpath/java/java/awt/image/AffineTransformOp.java trunk/core/src/classpath/java/java/awt/image/BandCombineOp.java trunk/core/src/classpath/java/java/awt/image/ColorConvertOp.java trunk/core/src/classpath/java/java/awt/image/ColorModel.java trunk/core/src/classpath/java/java/awt/image/ConvolveOp.java trunk/core/src/classpath/java/java/awt/image/ImageConsumer.java trunk/core/src/classpath/java/java/awt/image/ImageFilter.java trunk/core/src/classpath/java/java/awt/image/LookupOp.java trunk/core/src/classpath/java/java/awt/image/PixelGrabber.java trunk/core/src/classpath/java/java/awt/image/RGBImageFilter.java trunk/core/src/classpath/java/java/awt/image/Raster.java trunk/core/src/classpath/java/java/awt/image/RenderedImage.java trunk/core/src/classpath/java/java/awt/image/ReplicateScaleFilter.java trunk/core/src/classpath/java/java/awt/image/RescaleOp.java trunk/core/src/classpath/java/java/awt/image/SampleModel.java trunk/core/src/classpath/java/java/awt/image/SinglePixelPackedSampleModel.java trunk/core/src/classpath/java/java/awt/image/WritableRaster.java trunk/core/src/classpath/java/java/text/DateFormat.java trunk/core/src/classpath/java/java/text/DateFormatSymbols.java trunk/core/src/classpath/java/java/text/DecimalFormatSymbols.java trunk/core/src/classpath/java/java/text/NumberFormat.java trunk/core/src/classpath/java/java/util/Arrays.java trunk/core/src/classpath/javax/javax/swing/ToolTipManager.java trunk/core/src/classpath/javax/javax/swing/TransferHandler.java trunk/core/src/classpath/tools/gnu/classpath/tools/jarsigner/JarVerifier.java trunk/core/src/classpath/tools/gnu/classpath/tools/jarsigner/Main.java trunk/core/src/classpath/tools/gnu/classpath/tools/jarsigner/Messages.java trunk/core/src/classpath/tools/gnu/classpath/tools/jarsigner/SFHelper.java trunk/core/src/classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java Added Paths: ----------- trunk/core/src/classpath/gnu/gnu/java/awt/ComponentReshapeEvent.java trunk/core/src/classpath/gnu/gnu/java/awt/dnd/ trunk/core/src/classpath/gnu/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java trunk/core/src/classpath/java/java/text/spi/DateFormatProvider.java trunk/core/src/classpath/java/java/text/spi/DecimalFormatSymbolsProvider.java trunk/core/src/classpath/java/java/text/spi/NumberFormatProvider.java trunk/core/src/classpath/javax/javax/management/AttributeChangeNotification.java Added: trunk/core/src/classpath/gnu/gnu/java/awt/ComponentReshapeEvent.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/awt/ComponentReshapeEvent.java (rev 0) +++ trunk/core/src/classpath/gnu/gnu/java/awt/ComponentReshapeEvent.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -0,0 +1,85 @@ +/* WindowResizeEvent.java -- Used to synchronize the AWT and peer sizes + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt; + +import java.awt.AWTEvent; +import java.awt.Component; + +/** + * This is used to update the AWT's knowledge about a Window's size when + * the user changes the window bounds. + * + * This event is _not_ posted to the eventqueue, but rather dispatched directly + * via Window.dispatchEvent(). It is the cleanest way we could find to update + * the AWT's knowledge of the window size. Small testprograms showed the + * following: + * - Component.reshape() and its derivatives are _not_ called. This makes sense + * as it could end up in loops,because this calls back into the peers. + * - Intercepting event dispatching for any events in + * EventQueue.dispatchEvent() showed that the size is still updated. So it + * is not done via an event dispatched over the eventqueue. + * + * Possible other candidates for implementation would have been: + * - Call a (private) callback method in Window/Component from the native + * side. + * - Call a (private) callback method in Window/Component via reflection. + * + * Both is uglier than sending this event directly. Note however that this + * is impossible to test, as Component.dispatchEvent() is final and can't be + * intercepted from outside code. But this impossibility to test the issue from + * outside code also means that this shouldn't raise any compatibility issues. + */ +public class ComponentReshapeEvent + extends AWTEvent +{ + + public int x; + public int y; + public int width; + public int height; + + public ComponentReshapeEvent(Component c, int x, int y, int width, int height) + { + super(c, 1999); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} Added: trunk/core/src/classpath/gnu/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java (rev 0) +++ trunk/core/src/classpath/gnu/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -0,0 +1,172 @@ +/* GtkMouseDragGestureRecognizer.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.dnd; + +import java.awt.Component; +import java.awt.Point; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.MouseDragGestureRecognizer; +import java.awt.event.MouseEvent; + +public class GtkMouseDragGestureRecognizer + extends MouseDragGestureRecognizer +{ + + public GtkMouseDragGestureRecognizer (DragSource ds) + { + this(ds, null, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c) + { + this (ds, c, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act) + { + this(ds, c, act, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act, + DragGestureListener dgl) + { + super(ds, c, act, dgl); + } + + public void registerListeners () + { + super.registerListeners(); + } + + public void unregisterListeners () + { + super.unregisterListeners(); + } + + public void mouseClicked (MouseEvent e) + { + // Nothing to do here. + } + + public void mousePressed (MouseEvent e) + { + events.clear(); + if (getDropActionFromEvent(e) != DnDConstants.ACTION_NONE) + appendEvent(e); + } + + public void mouseReleased (MouseEvent e) + { + events.clear(); + } + + public void mouseEntered (MouseEvent e) + { + events.clear(); + } + + public void mouseExited(MouseEvent e) + { + if (!events.isEmpty()) + if (getDropActionFromEvent(e) == DnDConstants.ACTION_NONE) + events.clear(); + } + + public void mouseDragged(MouseEvent e) + { + if (!events.isEmpty()) + { + int act = getDropActionFromEvent(e); + + if (act == DnDConstants.ACTION_NONE) + return; + + Point origin = ((MouseEvent) events.get(0)).getPoint(); + Point current = e.getPoint(); + int dx = Math.abs(origin.x - current.x); + int dy = Math.abs(origin.y - current.y); + int threshold = DragSource.getDragThreshold(); + + if (dx > threshold || dy > threshold) + fireDragGestureRecognized(act, origin); + else + appendEvent(e); + } + } + + public void mouseMoved (MouseEvent e) + { + // Nothing to do here. + } + + private int getDropActionFromEvent(MouseEvent e) + { + int modEx = e.getModifiersEx(); + int buttons = modEx & (MouseEvent.BUTTON1_DOWN_MASK + | MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); + if (!(buttons == MouseEvent.BUTTON1_DOWN_MASK || + buttons == MouseEvent.BUTTON2_DOWN_MASK)) + return DnDConstants.ACTION_NONE; + + // Convert modifier to a drop action + int sourceActions = getSourceActions(); + int mod = modEx + & (MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK); + switch (mod) + { + case MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_LINK & sourceActions; + case MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_COPY & sourceActions; + case MouseEvent.SHIFT_DOWN_MASK: + return DnDConstants.ACTION_MOVE & sourceActions; + default: + if ((sourceActions & DnDConstants.ACTION_MOVE) != 0) + return DnDConstants.ACTION_MOVE & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_COPY) != 0) + return DnDConstants.ACTION_COPY & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_LINK) != 0) + return DnDConstants.ACTION_LINK & sourceActions; + } + + return DnDConstants.ACTION_NONE & sourceActions; + } +} Modified: trunk/core/src/classpath/gnu/gnu/java/awt/peer/GLightweightPeer.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/awt/peer/GLightweightPeer.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/gnu/gnu/java/awt/peer/GLightweightPeer.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -163,8 +163,10 @@ public FontMetrics getFontMetrics(Font f) { - // Nothing to do here for lightweights. - return null; + // We shouldn't end up here, but if we do we can still try do something + // reasonable. + Toolkit tk = Toolkit.getDefaultToolkit(); + return tk.getFontMetrics(f); } /* Returning null here tells the Component object that called us to @@ -201,7 +203,31 @@ public void handleEvent(AWTEvent e) { - // Nothing to do here for lightweights. + // This can only happen when an application posts a PaintEvent for + // a lightweight component directly. We still support painting for + // this case. + if (e instanceof PaintEvent) + { + PaintEvent pe = (PaintEvent) e; + Component target = (Component) e.getSource(); + if (target != null && target.isShowing()) + { + Graphics g = target.getGraphics(); + if (g != null) + { + try + { + Rectangle clip = pe.getUpdateRect(); + g.setClip(clip); + target.paint(g); + } + finally + { + g.dispose(); + } + } + } + } } public void hide() Modified: trunk/core/src/classpath/java/java/awt/CheckboxMenuItem.java =================================================================== --- trunk/core/src/classpath/java/java/awt/CheckboxMenuItem.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/CheckboxMenuItem.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -318,7 +318,7 @@ * @exception ClassCastException If listenerType doesn't specify a class or * interface that implements java.util.EventListener. */ - public EventListener[] getListeners (Class listenerType) + public <T extends EventListener> T[] getListeners (Class<T> listenerType) { if (listenerType == ItemListener.class) return AWTEventMulticaster.getListeners (item_listeners, listenerType); Modified: trunk/core/src/classpath/java/java/awt/MenuItem.java =================================================================== --- trunk/core/src/classpath/java/java/awt/MenuItem.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/MenuItem.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -523,11 +523,11 @@ * ClassClassException is thrown. * @since 1.3 */ - public EventListener[] getListeners(Class listenerType) + public <T extends EventListener> T[] getListeners(Class<T> listenerType) { if (listenerType == ActionListener.class) - return getActionListeners(); - return (EventListener[]) Array.newInstance(listenerType, 0); + return (T[]) getActionListeners(); + return (T[]) Array.newInstance(listenerType, 0); } /*************************************************************************/ Modified: trunk/core/src/classpath/java/java/awt/image/AffineTransformOp.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/AffineTransformOp.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/AffineTransformOp.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -39,6 +39,7 @@ package java.awt.image; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; @@ -48,8 +49,11 @@ import java.util.Arrays; /** - * This class performs affine transformation between two images or - * rasters in 2 dimensions. + * AffineTransformOp performs matrix-based transformations (translations, + * scales, flips, rotations, and shears). + * + * If interpolation is required, nearest neighbour, bilinear, and bicubic + * methods are available. * * @author Olga Rodimina (rod...@re...) * @author Francis Kung (fk...@re...) @@ -115,14 +119,14 @@ } /** - * Creates empty BufferedImage with the size equal to that of the - * transformed image and correct number of bands. The newly created + * Creates a new BufferedImage with the size equal to that of the + * transformed image and the correct number of bands. The newly created * image is created with the specified ColorModel. - * If the ColorModel is equal to null, an appropriate ColorModel is used. + * If a ColorModel is not specified, an appropriate ColorModel is used. * - * @param src source image - * @param destCM color model for the destination image - * @return new compatible destination image + * @param src the source image. + * @param destCM color model for the destination image (can be null). + * @return a new compatible destination image. */ public BufferedImage createCompatibleDestImage (BufferedImage src, ColorModel destCM) @@ -145,21 +149,18 @@ } /** - * Creates empty WritableRaster with the size equal to the transformed - * source raster and correct number of bands + * Creates a new WritableRaster with the size equal to the transformed + * source raster and correct number of bands . * - * @param src source raster - * @throws RasterFormatException if resulting width or height of raster is 0 - * @return new compatible raster + * @param src the source raster. + * @throws RasterFormatException if resulting width or height of raster is 0. + * @return a new compatible raster. */ public WritableRaster createCompatibleDestRaster (Raster src) { Rectangle2D rect = getBounds2D(src); - // throw RasterFormatException if resulting width or height of the - // transformed raster is 0 - - if (rect.getWidth () == 0 || rect.getHeight () == 0) + if (rect.getWidth() == 0 || rect.getHeight() == 0) throw new RasterFormatException("width or height is 0"); return src.createCompatibleWritableRaster((int) rect.getWidth(), @@ -175,24 +176,22 @@ * @param dst destination image * @throws IllegalArgumentException if the source and destination image are * the same - * @return transformed source image + * @return transformed source image. */ public final BufferedImage filter (BufferedImage src, BufferedImage dst) { - if (dst == src) - throw new IllegalArgumentException ("src image cannot be the same as " + - "the dst image"); + throw new IllegalArgumentException("src image cannot be the same as " + + "the dst image"); // If the destination image is null, then use a compatible BufferedImage if (dst == null) dst = createCompatibleDestImage(src, null); - Graphics2D gr = (Graphics2D) dst.createGraphics (); - gr.setRenderingHints (hints); - gr.drawImage (src, transform, null); + Graphics2D gr = (Graphics2D) dst.createGraphics(); + gr.setRenderingHints(hints); + gr.drawImage(src, transform, null); return dst; - } /** @@ -204,10 +203,11 @@ * @param dst destination raster * @throws IllegalArgumentException if the source and destination are not * compatible - * @return transformed raster + * @return transformed raster. */ - public final WritableRaster filter (Raster src, WritableRaster dst) + public final WritableRaster filter(Raster src, WritableRaster dst) { + // Initial checks if (dst == src) throw new IllegalArgumentException("src image cannot be the same as" + " the dst image"); @@ -219,6 +219,24 @@ throw new IllegalArgumentException("src and dst must have same number" + " of bands"); + // Optimization for rasters that can be represented in the RGB colormodel: + // wrap the rasters in images, and let Cairo do the transformation + if (ColorModel.getRGBdefault().isCompatibleSampleModel(src.getSampleModel()) + && ColorModel.getRGBdefault().isCompatibleSampleModel(dst.getSampleModel())) + { + WritableRaster src2 = Raster.createWritableRaster(src.getSampleModel(), + src.getDataBuffer(), + new Point(src.getMinX(), + src.getMinY())); + BufferedImage iSrc = new BufferedImage(ColorModel.getRGBdefault(), + src2, false, null); + BufferedImage iDst = new BufferedImage(ColorModel.getRGBdefault(), dst, + false, null); + + return filter(iSrc, iDst).getRaster(); + } + + // Otherwise, we need to do the transformation in java code... // Create arrays to hold all the points double[] dstPts = new double[dst.getHeight() * dst.getWidth() * 2]; double[] srcPts = new double[dst.getHeight() * dst.getWidth() * 2]; @@ -287,7 +305,7 @@ } /** - * Returns interpolation type used during transformations + * Returns interpolation type used during transformations. * * @return interpolation type */ @@ -319,7 +337,7 @@ /** * Returns rendering hints that are used during transformation. * - * @return rendering hints + * @return the rendering hints used in this Op. */ public final RenderingHints getRenderingHints () { @@ -330,7 +348,7 @@ * Returns transform used in transformation between source and destination * image. * - * @return transform + * @return the transform used in this Op. */ public final AffineTransform getTransform () { @@ -377,6 +395,18 @@ { Rectangle srcbounds = src.getBounds(); + Object xyarr = null; + Object xp1arr = null; + Object yp1arr = null; + Object xyp1arr = null; + + double xy; + double xp1; + double yp1; + double xyp1; + + double[] result = new double[src.getNumBands()]; + // For all points in the destination raster, use bilinear interpolation // to find the value from the corrosponding source points for (int i = 0; i < dpts.length; i += 2) @@ -401,21 +431,64 @@ double xdiff = pts[i] + src.getMinX() - x; double ydiff = pts[i + 1] + src.getMinY() - y; - // Run the interpolation for each band + // Get surrounding pixels used in interpolation... optimized + // to use the smallest datatype possible. + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + xyarr = src.getPixel(x, y, (double[])xyarr); + xp1arr = src.getPixel(x+1, y, (double[])xp1arr); + yp1arr = src.getPixel(x, y+1, (double[])yp1arr); + xyp1arr = src.getPixel(x+1, y+1, (double[])xyp1arr); + } + else + { + xyarr = src.getPixel(x, y, (int[])xyarr); + xp1arr = src.getPixel(x+1, y, (int[])xp1arr); + yp1arr = src.getPixel(x, y+1, (int[])yp1arr); + xyp1arr = src.getPixel(x+1, y+1, (int[])xyp1arr); + } + // using + // array[] pixels = src.getPixels(x, y, 2, 2, pixels); + // instead of doing four individual src.getPixel() calls + // should be faster, but benchmarking shows that it's not... + + // Run interpolation for each band for (int j = 0; j < src.getNumBands(); j++) { - double result = (src.getSampleDouble(x, y, j) * (1 - xdiff) - + src.getSampleDouble(x + 1, y, j) * xdiff) - * (1 - ydiff) - + (src.getSampleDouble(x, y + 1, j) - * (1 - xdiff) - + src.getSampleDouble(x + 1, y + 1, j) - * xdiff) + // Pull individual sample values out of array + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + xy = ((double[])xyarr)[j]; + xp1 = ((double[])xp1arr)[j]; + yp1 = ((double[])yp1arr)[j]; + xyp1 = ((double[])xyp1arr)[j]; + } + else + { + xy = ((int[])xyarr)[j]; + xp1 = ((int[])xp1arr)[j]; + yp1 = ((int[])yp1arr)[j]; + xyp1 = ((int[])xyp1arr)[j]; + } + + // If all four samples are identical, there's no need to + // calculate anything + if (xy == xp1 && xy == yp1 && xy == xyp1) + result[j] = xy; + + // Run bilinear interpolation formula + else + result[j] = (xy * (1-xdiff) + xp1 * xdiff) + * (1-ydiff) + + (yp1 * (1-xdiff) + xyp1 * xdiff) * ydiff; - dst.setSample((int) dpts[i] + dst.getMinX(), - (int) dpts[i + 1] + dst.getMinY(), - j, result); } + + dst.setPixel((int)dpts[i] + dst.getMinX(), + (int)dpts[i+1] + dst.getMinY(), + result); } } } @@ -434,10 +507,11 @@ double[] pts) { Rectangle srcbounds = src.getBounds(); + double[] result = new double[src.getNumBands()]; + Object pixels = null; // For all points on the destination raster, perform bicubic interpolation // from corrosponding source points - double[] result = new double[src.getNumBands()]; for (int i = 0; i < dpts.length; i += 2) { if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(), @@ -450,7 +524,6 @@ Arrays.fill(result, 0); for (int m = - 1; m < 3; m++) - { for (int n = - 1; n < 3; n++) { // R(x) = ( P(x+2)^3 - 4 P(x+1)^3 + 6 P(x)^3 - 4 P(x-1)^3 ) / 6 @@ -459,7 +532,6 @@ // Calculate R(m - dx) double rx = m - dx + 2; - if (rx > 0) r1 += rx * rx * rx; rx = m - dx + 1; @@ -509,17 +581,27 @@ else if (srcY < src.getMinY()) srcY = src.getMinY(); - // Calculate once for each band + // Calculate once for each band, using the smallest + // datatype possible + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + pixels = src.getPixel(srcX, srcY, (double[])pixels); for (int j = 0; j < result.length; j++) - result[j] += src.getSample(srcX, srcY, j) * r1 * r2; + result[j] += ((double[])pixels)[j] * r1 * r2; + } + else + { + pixels = src.getPixel(srcX, srcY, (int[])pixels); + for (int j = 0; j < result.length; j++) + result[j] += ((int[])pixels)[j] * r1 * r2; } } // Put it all together - for (int j = 0; j < result.length; j++) - dst.setSample((int) dpts[i] + dst.getMinX(), - (int) dpts[i + 1] + dst.getMinY(), - j, result[j]); + dst.setPixel((int)dpts[i] + dst.getMinX(), + (int)dpts[i+1] + dst.getMinY(), + result); } } } Modified: trunk/core/src/classpath/java/java/awt/image/BandCombineOp.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/BandCombineOp.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/BandCombineOp.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -40,6 +40,7 @@ import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.util.Arrays; /** * Filter Raster pixels by applying a matrix. @@ -53,6 +54,9 @@ * for the destination. Therefore the destination Raster must contain the * same number of bands as the number of rows in the filter matrix. * + * This Op assumes that samples are integers; floating point sample types will + * be rounded to their nearest integer value during filtering. + * * @author Jerry Quinn (jl...@op...) */ public class BandCombineOp implements RasterOp @@ -109,19 +113,27 @@ throw new IllegalArgumentException("Destination raster is incompatible with source raster"); // Filter the pixels - float[] spix = new float[matrix[0].length - 1]; - float[] dpix = new float[matrix.length]; + int[] spix = new int[matrix[0].length - 1]; + int[] spix2 = new int[matrix[0].length - 1]; + int[] dpix = new int[matrix.length]; for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) { // In case matrix rows have implicit translation - spix[spix.length - 1] = 1.0f; + spix[spix.length - 1] = 1; src.getPixel(x, y, spix); + + // Do not re-calculate if pixel is identical to the last one + // (ie, blocks of the same colour) + if (!Arrays.equals(spix, spix2)) + { + System.arraycopy(spix, 0, spix2, 0, spix.length); for (int i = 0; i < matrix.length; i++) { dpix[i] = 0; for (int j = 0; j < matrix[0].length - 1; j++) - dpix[i] += spix[j] * matrix[i][j]; + dpix[i] += spix[j] * (int)matrix[i][j]; + } } dest.setPixel(x, y, dpix); } Modified: trunk/core/src/classpath/java/java/awt/image/ColorConvertOp.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/ColorConvertOp.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/ColorConvertOp.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -38,6 +38,8 @@ package java.awt.image; +import gnu.java.awt.Buffers; + import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; @@ -283,7 +285,8 @@ for (int i = 0; i < spaces.length - 2; i++) { WritableRaster tmp = createCompatibleDestRaster(src, spaces[i + 1], - false); + false, + src.getTransferType()); copyraster(src, spaces[i], tmp, spaces[i + 1]); src = tmp; } @@ -291,7 +294,8 @@ // The last conversion is done outside of the loop so that we can // use the dest raster supplied, instead of creating our own temp raster if (dest == null) - dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false); + dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false, + DataBuffer.TYPE_BYTE); copyraster(src, spaces[spaces.length - 2], dest, spaces[spaces.length - 1]); return dest; @@ -324,7 +328,8 @@ return new BufferedImage(dstCM, createCompatibleDestRaster(src.getRaster(), dstCM.getColorSpace(), - src.getColorModel().hasAlpha), + src.getColorModel().hasAlpha, + dstCM.getTransferType()), src.isPremultiplied, null); } @@ -349,7 +354,8 @@ // Create a new raster with the last ColorSpace in the conversion // chain, and with no alpha (implied) - return createCompatibleDestRaster(src, spaces[spaces.length-1], false); + return createCompatibleDestRaster(src, spaces[spaces.length-1], false, + DataBuffer.TYPE_BYTE); } /** @@ -417,11 +423,16 @@ return src.getBounds(); } - // Copy a source image to a destination image, respecting their colorspaces - // and performing colorspace conversions if necessary. This is done - // using Graphics2D in order to use the rendering hints. + /** + * Copy a source image to a destination image, respecting their colorspaces + * and performing colorspace conversions if necessary. + * + * @param src The source image. + * @param dst The destination image. + */ private void copyimage(BufferedImage src, BufferedImage dst) { + // This is done using Graphics2D in order to respect the rendering hints. Graphics2D gg = dst.createGraphics(); // If no hints are set there is no need to call @@ -433,8 +444,16 @@ gg.dispose(); } - // Copy a source raster to a destination raster, performing a colorspace - // conversion. + /** + * Copy a source raster to a destination raster, performing a colorspace + * conversion between the two. The conversion will respect the + * KEY_COLOR_RENDERING rendering hint if one is present. + * + * @param src The source raster. + * @param scs The colorspace of the source raster. + * @dst The destination raster. + * @dcs The colorspace of the destination raster. + */ private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, ColorSpace dcs) { float[] sbuf = new float[src.getNumBands()]; @@ -459,11 +478,19 @@ } } - // This method creates a compatible color model, given a source image and - // a colorspace. The choice of ComponentColorModel and DataBuffer.TYPE_BYTE - // is based on Mauve testing of the reference implementation. + /** + * This method creates a color model with the same colorspace and alpha + * settings as the source image. The created color model will always be a + * ComponentColorModel and have a BYTE transfer type. + * + * @param img The source image. + * @param cs The ColorSpace to use. + * @return A color model compatible with the source image. + */ private ColorModel createCompatibleColorModel(BufferedImage img, ColorSpace cs) { + // The choice of ComponentColorModel and DataBuffer.TYPE_BYTE is based on + // Mauve testing of the reference implementation. return new ComponentColorModel(cs, img.getColorModel().hasAlpha(), img.isAlphaPremultiplied(), @@ -471,13 +498,22 @@ DataBuffer.TYPE_BYTE); } - // This method creates a compatible Raster, given a source raster and - // colorspace. - private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs, boolean hasAlpha) + /** + * This method creates a compatible Raster, given a source raster, colorspace, + * alpha value, and transfer type. + * + * @param src The source raster. + * @param cs The ColorSpace to use. + * @param hasAlpha Whether the raster should include a component for an alpha. + * @param transferType The size of a single data element. + * @return A compatible WritableRaster. + */ + private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs, + boolean hasAlpha, + int transferType) { - // The use of a PixelInterleavedSampleModel (and it's parameters) and - // a DataBufferByte were determined using mauve tests, based on the - // reference implementation + // The use of a PixelInterleavedSampleModel weas determined using mauve + // tests, based on the reference implementation int numComponents = cs.getNumComponents(); if (hasAlpha) @@ -487,13 +523,15 @@ for (int i = 0; i < offsets.length; i++) offsets[i] = i; - return new WritableRaster(new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, + DataBuffer db = Buffers.createBuffer(transferType, + src.getWidth() * src.getHeight() * numComponents, + 1); + return new WritableRaster(new PixelInterleavedSampleModel(transferType, src.getWidth(), src.getHeight(), numComponents, numComponents * src.getWidth(), offsets), - new DataBufferByte(src.getWidth() * src.getHeight() * numComponents, 1), - new Point(src.getMinX(), src.getMinY())); + db, new Point(src.getMinX(), src.getMinY())); } } Modified: trunk/core/src/classpath/java/java/awt/image/ColorModel.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/ColorModel.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/ColorModel.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -119,12 +119,8 @@ */ public ColorModel(int bits) { - // @classpath-bugfix Fix difference between Sun's class and this class. - //this(bits * 4, // total bits, sRGB, four channels - this(bits, // total bits, sRGB, four channels - //nArray(bits, 4), // bits for each channel - nArray(bits / 4, 4), // bits for each channel - // @classpath-bugfix-end + this(bits * 4, // total bits, sRGB, four channels + nArray(bits, 4), // bits for each channel ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB true, // has alpha false, // not premultiplied @@ -628,40 +624,40 @@ return cspace; } - // Typically overridden public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { - if (this.isAlphaPremultiplied == isAlphaPremultiplied || ! hasAlpha) - return this; + // This method should always be overridden, but is not abstract. + throw new UnsupportedOperationException(); + } + protected void coerceDataWorker(WritableRaster raster, + boolean isAlphaPremultiplied) + { int w = raster.getWidth(); int h = raster.getHeight(); int x = raster.getMinX(); int y = raster.getMinY(); - int size = w*h; + int size = w * h; int numColors = getNumColorComponents(); int numComponents = getNumComponents(); - int alphaScale = (1<<getComponentSize(numColors)) - 1; + int alphaScale = (1 << getComponentSize(numColors)) - 1; double[] pixels = raster.getPixels(x, y, w, h, (double[]) null); - for (int i=0; i<size; i++) + for (int i = 0; i < size; i++) { - double alpha = pixels[i*numComponents+numColors]*alphaScale; - for (int c=0; c<numColors; c++) + double alpha = pixels[i * numComponents + numColors] / alphaScale; + for (int c = 0; c < numColors; c++) { - int offset = i*numComponents+c; + int offset = i * numComponents + c; if (isAlphaPremultiplied) - pixels[offset] = pixels[offset]/alpha; + pixels[offset] = Math.round(pixels[offset] * alpha); else - pixels[offset] = pixels[offset]*alpha; + pixels[offset] = Math.round(pixels[offset] / alpha); } } raster.setPixels(0, 0, w, h, pixels); - - // FIXME: what can we return? - return null; } /** Modified: trunk/core/src/classpath/java/java/awt/image/ConvolveOp.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/ConvolveOp.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/ConvolveOp.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -38,7 +38,6 @@ package java.awt.image; -import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; @@ -51,11 +50,13 @@ * with elements in the kernel to compute a new pixel. * * Each band in a Raster is convolved and copied to the destination Raster. + * For BufferedImages, convolution is applied to all components. Color + * conversion will be applied if needed. * - * For BufferedImages, convolution is applied to all components. If the - * source is not premultiplied, the data will be premultiplied before - * convolving. Premultiplication will be undone if the destination is not - * premultiplied. Color conversion will be applied if needed. + * Note that this filter ignores whether the source or destination is alpha + * premultiplied. The reference spec states that data will be premultiplied + * prior to convolving and divided back out afterwards (if needed), but testing + * has shown that this is not the case with their implementation. * * @author jl...@op... */ @@ -104,59 +105,83 @@ hints = null; } - - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, - * java.awt.image.BufferedImage) + /** + * Converts the source image using the kernel specified in the + * constructor. The resulting image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * The source and destination BufferedImage (if one is supplied) must have + * the same dimensions. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @return The convolved image. */ public final BufferedImage filter(BufferedImage src, BufferedImage dst) { if (src == dst) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Source and destination images " + + "cannot be the same."); if (dst == null) dst = createCompatibleDestImage(src, src.getColorModel()); // Make sure source image is premultiplied BufferedImage src1 = src; - if (!src.isPremultiplied) + // The spec says we should do this, but mauve testing shows that Sun's + // implementation does not check this. + /* + if (!src.isAlphaPremultiplied()) { src1 = createCompatibleDestImage(src, src.getColorModel()); src.copyData(src1.getRaster()); src1.coerceData(true); } + */ BufferedImage dst1 = dst; - if (!src.getColorModel().equals(dst.getColorModel())) + if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType()) dst1 = createCompatibleDestImage(src, src.getColorModel()); filter(src1.getRaster(), dst1.getRaster()); + // Since we don't coerceData above, we don't need to divide it back out. + // This is wrong (one mauve test specifically tests converting a non- + // premultiplied image to a premultiplied image, and it shows that Sun + // simply ignores the premultipled flag, contrary to the spec), but we + // mimic it for compatibility. + /* + if (! dst.isAlphaPremultiplied()) + dst1.coerceData(false); + */ + + // Convert between color models if needed if (dst1 != dst) - { - // Convert between color models. - // TODO Check that premultiplied alpha is handled correctly here. - Graphics2D gg = dst.createGraphics(); - gg.setRenderingHints(hints); - gg.drawImage(dst1, 0, 0, null); - gg.dispose(); - } + new ColorConvertOp(hints).filter(dst1, dst); return dst; } - /* (non-Javadoc) - * @see - * java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, - * java.awt.image.ColorModel) + /** + * Creates an empty BufferedImage with the size equal to the source and the + * correct number of bands. The new image is created with the specified + * ColorModel, or if no ColorModel is supplied, an appropriate one is chosen. + * + * @param src The source image. + * @param dstCM A color model for the destination image (may be null). + * @return The new compatible destination image. */ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { - // FIXME: set properties to those in src + if (dstCM != null) return new BufferedImage(dstCM, src.getRaster().createCompatibleWritableRaster(), - src.isPremultiplied, null); + src.isAlphaPremultiplied(), null); + + return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); } /* (non-Javadoc) @@ -168,6 +193,8 @@ } /** + * Get the edge condition for this Op. + * * @return The edge condition. */ public int getEdgeCondition() @@ -185,9 +212,22 @@ return (Kernel) kernel.clone(); } - /* (non-Javadoc) - * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, - * java.awt.image.WritableRaster) + /** + * Converts the source raster using the kernel specified in the constructor. + * The resulting raster is stored in the destination raster if one is + * provided; otherwise a new WritableRaster is created and returned. + * + * If the convolved value for a sample is outside the range of [0-255], it + * will be clipped. + * + * The source and destination raster (if one is supplied) cannot be the same, + * and must also have the same dimensions. + * + * @param src The source raster. + * @param dest The destination raster. + * @throws IllegalArgumentException if the rasters identical. + * @throws ImagingOpException if the convolution is not possible. + * @return The transformed raster. */ public final WritableRaster filter(Raster src, WritableRaster dest) { @@ -209,6 +249,11 @@ int top = kernel.getYOrigin(); int bottom = Math.max(kHeight - top - 1, 0); + // Calculate max sample values for clipping + int[] maxValue = src.getSampleModel().getSampleSize(); + for (int i = 0; i < maxValue.length; i++) + maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1; + // process the region that is reachable... int regionW = src.width - left - right; int regionH = src.height - top - bottom; @@ -229,6 +274,13 @@ // FIXME: in the above line, I've had to reverse the order of // the samples array to make the tests pass. I haven't worked // out why this is necessary. + + // This clipping is is undocumented, but determined by testing. + if (v > maxValue[b]) + v = maxValue[b]; + else if (v < 0) + v = 0; + dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(), b, v); } @@ -310,13 +362,14 @@ return src.getBounds(); } - /** Return corresponding destination point for source point. + /** + * Returns the corresponding destination point for a source point. Because + * this is not a geometric operation, the destination and source points will + * be identical. * - * ConvolveOp will return the value of src unchanged. * @param src The source point. - * @param dst The destination point. - * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, - * java.awt.geom.Point2D) + * @param dst The transformed destination point. + * @return The transformed destination point. */ public final Point2D getPoint2D(Point2D src, Point2D dst) { Modified: trunk/core/src/classpath/java/java/awt/image/ImageConsumer.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/ImageConsumer.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/ImageConsumer.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -136,7 +136,7 @@ * * @param props the list of properties associated with this image */ - void setProperties(Hashtable props); + void setProperties(Hashtable<?,?> props); /** * This <code>ColorModel</code> should indicate the model used by Modified: trunk/core/src/classpath/java/java/awt/image/ImageFilter.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/ImageFilter.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/ImageFilter.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -104,12 +104,8 @@ */ public ImageFilter getFilterInstance(ImageConsumer ic) { - if ( ic == null ) - throw new IllegalArgumentException("null argument for ImageFilter.getFilterInstance(ImageConsumer)"); - - consumer = ic; ImageFilter f = (ImageFilter)clone(); - consumer = null; + f.consumer = ic; return f; } @@ -125,7 +121,6 @@ */ public void setDimensions(int width, int height) { - if (consumer != null) consumer.setDimensions(width, height); } @@ -135,11 +130,16 @@ * * @param props the list of properties associated with this image */ - public void setProperties(Hashtable props) + public void setProperties(Hashtable<?,?> props) { - props.put("filters", "ImageFilter"); - if (consumer != null) - consumer.setProperties(props); + Hashtable copy = (Hashtable) props.clone(); + Object o = copy.get("filters"); + if (o == null) + copy.put("filters", toString()); + else if (o instanceof String) + copy.put("filters", ((String) o) + toString()); + + consumer.setProperties(copy); } /** @@ -148,10 +148,11 @@ * method of the consumer is called with the specified <code>model</code>. * * @param model the color model to be used most often by setPixels - * @see ColorModel */ + * + * @see ColorModel + */ public void setColorModel(ColorModel model) { - if (consumer != null) consumer.setColorModel(model); } @@ -167,7 +168,6 @@ */ public void setHints(int flags) { - if (consumer != null) consumer.setHints(flags); } @@ -186,9 +186,9 @@ * @param scansize the width to use in extracting pixels from the <code>pixels</code> array */ public void setPixels(int x, int y, int w, int h, - ColorModel model, byte[] pixels, int offset, int scansize) + ColorModel model, byte[] pixels, int offset, + int scansize) { - if (consumer != null) consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); } @@ -207,9 +207,9 @@ * @param scansize the width to use in extracting pixels from the <code>pixels</code> array */ public void setPixels(int x, int y, int w, int h, - ColorModel model, int[] pixels, int offset, int scansize) + ColorModel model, int[] pixels, int offset, + int scansize) { - if (consumer != null) consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); } @@ -221,8 +221,6 @@ */ public void imageComplete(int status) { - if (consumer != null) consumer.imageComplete(status); } } - Modified: trunk/core/src/classpath/java/java/awt/image/LookupOp.java =================================================================== --- trunk/core/src/classpath/java/java/awt/image/LookupOp.java 2007-01-27 07:54:10 UTC (rev 3087) +++ trunk/core/src/classpath/java/java/awt/image/LookupOp.java 2007-01-27 09:39:31 UTC (rev 3088) @@ -38,7 +38,6 @@ package java.awt.image; -import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; @@ -67,7 +66,8 @@ private LookupTable lut; private RenderingHints hints; - /** Construct a new LookupOp. + /** + * Construct a new LookupOp using the given LookupTable. * * @param lookup LookupTable to use. * @param hints Rendering hints (can be null). @@ -78,16 +78,40 @@ this.hints = hints; } - /* (non-Javadoc) - * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage) + /** + * Converts the source image using the lookup table specified in the + * constructor. The resulting image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * The source image cannot use an IndexColorModel, and the destination image + * (if one is provided) must have the same size. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @throws ArrayIndexOutOfBoundsException if a pixel in the source is not + * contained in the LookupTable. + * @return The convolved image. */ public final BufferedImage filter(BufferedImage src, BufferedImage dst) { if (src.getColorModel() instanceof IndexColorModel) throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " + "not allowed"); + + if (lut.getNumComponents() != 1 + && lut.getNumComponents() != src.getColorModel().getNumComponents() + && lut.getNumComponents() != src.getColorModel().getNumColorComponents()) + throw new IllegalArgumentException("LookupOp.filter: Incompatible " + + "lookup table and source image"); + if (dst == null) - dst = createCompatibleDestImage(src, src.getColorModel()); + dst = createCompatibleDestImage(src, null); + + else if (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth()) + throw new IllegalArgumentException("Source and destination images are " + + "different sizes."); // Set up for potential colormodel mismatch BufferedImage tgt; @@ -116,15 +140,23 @@ sr.getPixel(x, y, dbuf); System.arraycopy(dbuf, 0, tmp, 0, tmpBands); dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf)); + + /* The reference implementation does not use LookupTable.lookupPixel, + * but rather it seems to copy the table into a native array. The + * effect of this (a probable bug in their implementation) is that + * an out-of-bounds lookup on a ByteLookupTable will *not* throw an + * out of bounds exception, but will instead return random garbage. + * A bad lookup on a ShortLookupTable, however, will throw an + * exception. + * + * Instead of mimicing this behaviour, we always throw an + * ArrayOutofBoundsException by virtue of using + * LookupTable.lookupPixle. + */ } } - else if (lut.getNumComponents() != 1 - && - lut.getNumComponents() != src.getColorModel().getNumComponents()) - throw new IllegalArgumentException("LookupOp.filter: " - + "Incompatible lookup " - + "table and source image"); - + else + { // No alpha to ignore int[] dbuf = new int[src.getColorModel().getNumComponents()]; @@ -132,16 +164,10 @@ for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf)); + } if (tgt != dst) - { - // Convert between color models. - // TODO Check that premultiplied alpha is handled correctly here. - Graphics2D gg = dst.createGraphics(); - gg.setRenderingHints(hints); - gg.drawImage(tgt, 0, 0, null); - gg.dispose(); - } + new ColorConvertOp(hints).filter(tgt, dst); return dst; } @@ -160,18 +186,27 @@ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { - // FIXME: set properties to those in src + if (dstCM != null) return new BufferedImage(dstCM, src.getRaster().createCompatibleWritableRaster(), - src.isPremultiplied, null); + src.isAlphaPremultiplied(), null); + + // This is a strange exception, done for compatibility with the reference + // (as demonstrated by a mauve testcase) + int imgType = src.getType(); + if (imgType == BufferedImage.TYPE_USHORT_GRAY) + imgType = BufferedImage.TYPE_BYTE_GRAY; + + return new BufferedImage(src.getWidth(), src.getHeight(), imgType); } - /** Return corresponding destination point for source point. + /** + * Returns the corresponding destination point for a given source point. * - * LookupOp will return the value of src unchanged. + * This Op will return the source point unchanged. + * * @param src The source point. * @param dst The destination point. - * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) */ public final Point2D getPoint2D(Point2D src, Point2D dst) { @@ -182,7 +217,11 @@ return dst; } - /** Return the LookupTable for this op. */ + /** + * Return the LookupTable for this op. + * + * @return The lookup table. + */ public final LookupTable getTable() { return lut; @@ -196,7 +235,8 @@ return hints; } - /** Filter a raster through a lookup table. + /** + * Filter a raster through a lookup table. * * Applies the lookup table for this Rasterop to each pixel of src and * puts the results in dest. If dest is null, a new Raster is created and @@ -207,7 +247,8 @@ * @return The WritableRaster with the filtered pixels. * @throws IllegalArgumentException if lookup ta... [truncated message content] |
From: <ls...@us...> - 2007-01-27 11:43:22
|
Revision: 3091 http://jnode.svn.sourceforge.net/jnode/?rev=3091&view=rev Author: lsantha Date: 2007-01-27 03:43:17 -0800 (Sat, 27 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/gnu/gnu/java/awt/java2d/AbstractGraphics2D.java trunk/core/src/classpath/java/java/lang/InheritableThreadLocal.java trunk/core/src/classpath/java/java/lang/StringBuffer.java trunk/core/src/classpath/java/java/lang/ThreadLocal.java Added Paths: ----------- trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectionKeyImpl.java trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectorImpl.java trunk/core/src/classpath/gnu/gnu/java/nio/VMChannelOwner.java trunk/core/src/classpath/java/java/util/concurrent/locks/ReentrantReadWriteLock.java Modified: trunk/core/src/classpath/gnu/gnu/java/awt/java2d/AbstractGraphics2D.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/awt/java2d/AbstractGraphics2D.java 2007-01-27 10:06:33 UTC (rev 3090) +++ trunk/core/src/classpath/gnu/gnu/java/awt/java2d/AbstractGraphics2D.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -166,14 +166,14 @@ * Caches certain shapes to avoid massive creation of such Shapes in * the various draw* and fill* methods. */ - private static final ThreadLocal shapeCache = - new ThreadLocal(); + private static final ThreadLocal<ShapeCache> shapeCache = + new ThreadLocal<ShapeCache>(); /** * The scanline converters by thread. */ - private static final ThreadLocal scanlineConverters = - new ThreadLocal(); + private static final ThreadLocal<ScanlineConverter> scanlineConverters = + new ThreadLocal<ScanlineConverter>(); /** * The transformation for this Graphics2D instance @@ -1947,7 +1947,7 @@ */ private ShapeCache getShapeCache() { - ShapeCache sc = (ShapeCache) shapeCache.get(); + ShapeCache sc = shapeCache.get(); if (sc == null) { sc = new ShapeCache(); @@ -1963,7 +1963,7 @@ */ private ScanlineConverter getScanlineConverter() { - ScanlineConverter sc = (ScanlineConverter) scanlineConverters.get(); + ScanlineConverter sc = scanlineConverters.get(); if (sc == null) { sc = new ScanlineConverter(); Added: trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectionKeyImpl.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectionKeyImpl.java (rev 0) +++ trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectionKeyImpl.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -0,0 +1,189 @@ +/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectionKey; + +/** + * @author Casey Marshall (cs...@gn...) + */ +public class KqueueSelectionKeyImpl extends AbstractSelectionKey +{ + int interestOps; + int readyOps; + int activeOps = 0; + int key; + int fd; + + /** The selector we were created for. */ + private final KqueueSelectorImpl selector; + + /** The channel we are attached to. */ + private final SelectableChannel channel; + + private final VMChannelOwner natChannel; + + public KqueueSelectionKeyImpl(KqueueSelectorImpl selector, + SelectableChannel channel) + { + this.selector = selector; + this.channel = channel; + natChannel = (VMChannelOwner) channel; + interestOps = 0; + readyOps = 0; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#channel() + */ + //@Override + public SelectableChannel channel() + { + return channel; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps() + */ + //@Override + public int interestOps() + { + return interestOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps(int) + */ + //@Override + public SelectionKey interestOps(int ops) + { + if (!isValid()) + throw new IllegalStateException("key is invalid"); + if ((ops & ~channel.validOps()) != 0) + throw new IllegalArgumentException("channel does not support all operations"); + + selector.setInterestOps(this, ops); + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#readyOps() + */ + //@Override + public int readyOps() + { + return readyOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#selector() + */ + //@Override + public Selector selector() + { + return selector; + } + + public String toString() + { + if (!isValid()) + return super.toString() + " [ fd: " + fd + " <<invalid>> ]"; + return super.toString() + " [ fd: " + fd + " interest ops: {" + + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((interestOps & OP_READ) != 0 ? " OP_READ" : "") + + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " }; ready ops: {" + + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((readyOps & OP_READ) != 0 ? " OP_READ" : "") + + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " } ]"; + } + + public int hashCode() + { + return fd; + } + + public boolean equals(Object o) + { + if (!(o instanceof KqueueSelectionKeyImpl)) + return false; + KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o; + return that.fd == this.fd && that.channel.equals(this.channel); + } + + + boolean isReadActive() + { + return (activeOps & (OP_READ | OP_ACCEPT)) != 0; + } + + boolean isReadInterested() + { + return (interestOps & (OP_READ | OP_ACCEPT)) != 0; + } + + boolean isWriteActive() + { + return (activeOps & (OP_WRITE | OP_CONNECT)) != 0; + } + + boolean isWriteInterested() + { + return (interestOps & (OP_WRITE | OP_CONNECT)) != 0; + } + + boolean needCommitRead() + { + return isReadActive() == (!isReadInterested()); + } + + boolean needCommitWrite() + { + return isWriteActive() == (!isWriteInterested()); + } +} Added: trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectorImpl.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectorImpl.java (rev 0) +++ trunk/core/src/classpath/gnu/gnu/java/nio/KqueueSelectorImpl.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -0,0 +1,527 @@ +/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A {@link Selector} implementation that uses the <code>kqueue</code> + * event notification facility. + * + * @author Casey Marshall (cs...@gn...) + */ +public class KqueueSelectorImpl extends AbstractSelector +{ + // Prepended underscore to field name to make it distinct + // from the method with the similar name. + private static final int _sizeof_struct_kevent; + + private static final int MAX_DOUBLING_CAPACITY = 16384; + private static final int CAP_INCREMENT = 1024; + private static final int INITIAL_CAPACITY; + + static + { + try + { + System.loadLibrary("javanio"); + } + catch (Exception x) + { + x.printStackTrace(); + } + + if (kqueue_supported ()) + _sizeof_struct_kevent = sizeof_struct_kevent(); + else + _sizeof_struct_kevent = -1; + INITIAL_CAPACITY = 16 * _sizeof_struct_kevent; + } + + /** + * Tell if kqueue-based selectors are supported on this system. + * + * @return True if this system has kqueue support, and support for it was + * compiled in to Classpath. + */ + public static native boolean kqueue_supported(); + + /* Our native file descriptor. */ + private int kq; + + private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys; + private HashSet/*<KqueueSelectionKeyImpl>*/ selected; + private Thread blockedThread; + private ByteBuffer events; + + private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT; + private static final int OP_CONNECT = SelectionKey.OP_CONNECT; + private static final int OP_READ = SelectionKey.OP_READ; + private static final int OP_WRITE = SelectionKey.OP_WRITE; + + public KqueueSelectorImpl(SelectorProvider provider) throws IOException + { + super(provider); + kq = implOpen(); + keys = new HashMap/*<KqueueSelectionKeyImpl>*/(); + events = ByteBuffer.allocateDirect(INITIAL_CAPACITY); + } + + protected void implCloseSelector() throws IOException + { + implClose(kq); + kq = -1; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout == 0) + timeout = -1; + return doSelect(timeout); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + if (blockedThread != null) + blockedThread.interrupt(); + return this; + } + + public String toString() + { + return super.toString() + " [ fd: " + kq + " ]"; + } + + public boolean equals(Object o) + { + if (!(o instanceof KqueueSelectorImpl)) + return false; + + return ((KqueueSelectorImpl) o).kq == kq; + } + + int doSelect(long timeout) throws IOException + { + Set cancelled = cancelledKeys(); + synchronized (cancelled) + { + synchronized (keys) + { + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + key.interestOps = 0; + } + + int events_size = (2 * _sizeof_struct_kevent) * keys.size(); + int num_events = 0; + + for (Iterator it = keys.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue(); + + SelectableChannel ch = key.channel(); + if (ch instanceof VMChannelOwner) + { + if (!((VMChannelOwner) ch).getVMChannel().getState().isValid()) + { + // closed channel; removed from kqueue automatically. + it.remove(); + continue; + } + } + + // If this key is registering a read filter, add it to the buffer. + if (key.needCommitRead()) + { + kevent_set(events, num_events, key.fd, + key.interestOps & (OP_READ | OP_ACCEPT), + key.activeOps & (OP_READ | OP_ACCEPT), key.key); + num_events++; + } + + // If this key is registering a write filter, add it to the buffer. + if (key.needCommitWrite()) + { + kevent_set(events, num_events, key.fd, + key.interestOps & (OP_WRITE | OP_CONNECT), + key.activeOps & (OP_WRITE | OP_CONNECT), key.key); + num_events++; + } + } + events.rewind().limit(events.capacity()); + + //System.out.println("dump of keys to select:"); + //dump_selection_keys(events.duplicate()); + + int n = 0; + try + { + //System.out.println("[" + kq + "] kevent enter selecting from " + keys.size()); + begin(); + blockedThread = Thread.currentThread(); + if (blockedThread.isInterrupted()) + timeout = 0; + n = kevent(kq, events, num_events, + events.capacity() / _sizeof_struct_kevent, timeout); + } + finally + { + end(); + blockedThread = null; + Thread.interrupted(); + //System.out.println("[" + kq + "kevent exit selected " + n); + } + + //System.out.println("dump of keys selected:"); + //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * _sizeof_struct_kevent)); + + // Commit the operations we've just added in the call to kevent. + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + key.activeOps = key.interestOps; + } + + selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n); + int x = 0; + for (int i = 0; i < n; i++) + { + events.position(x).limit(x + _sizeof_struct_kevent); + x += _sizeof_struct_kevent; + int y = fetch_key(events.slice()); + KqueueSelectionKeyImpl key = + (KqueueSelectionKeyImpl) keys.get(new Integer(y)); + + if (key == null) + { + System.out.println("WARNING! no key found for selected key " + y); + continue; + } + // Keys that have been cancelled may be returned here; don't + // add them to the selected set. + if (!key.isValid()) + continue; + key.readyOps = ready_ops(events.slice(), key.interestOps); + selected.add(key); + } + + // Finally, remove the cancelled keys. + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + keys.remove(new Integer(key.key)); + deregister(key); + it.remove(); + } + + reallocateBuffer(); + + return selected.size(); + } + } + } + + protected SelectionKey register(AbstractSelectableChannel channel, + int interestOps, + Object attachment) + { + int native_fd = -1; + try + { + if (channel instanceof VMChannelOwner) + native_fd = ((VMChannelOwner) channel).getVMChannel() + .getState().getNativeFD(); + else + throw new IllegalArgumentException("cannot handle channel type " + + channel.getClass().getName()); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("channel is closed or invalid"); + } + + KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel); + result.interestOps = interestOps; + result.attach(attachment); + result.fd = native_fd; + result.key = System.identityHashCode(result); + synchronized (keys) + { + while (keys.containsKey(new Integer(result.key))) + result.key++; + keys.put(new Integer(result.key), result); + reallocateBuffer(); + } + return result; + } + + void setInterestOps(KqueueSelectionKeyImpl key, int ops) + { + synchronized (keys) + { + key.interestOps = ops; + } + } + + /** + * Reallocate the events buffer. This is the destination buffer for + * events returned by kevent. This method will: + * + * * Grow the buffer if there is insufficent space for all registered + * events. + * * Shrink the buffer if it is more than twice the size needed. + * + */ + private void reallocateBuffer() + { + synchronized (keys) + { + if (events.capacity() < (2 * _sizeof_struct_kevent) * keys.size()) + { + int cap = events.capacity(); + if (cap >= MAX_DOUBLING_CAPACITY) + cap += CAP_INCREMENT; + else + cap = cap << 1; + + events = ByteBuffer.allocateDirect(cap); + } + else if (events.capacity() > 4 * (_sizeof_struct_kevent) * keys.size() + 1 + && events.capacity() > INITIAL_CAPACITY) + { + int cap = events.capacity(); + cap = cap >>> 1; + events = ByteBuffer.allocateDirect(cap); + } + } + } + + //synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps) + //{ + // updateOps(key, interestOps, 0, false); + //} + + /*void updateOps(KqueueSelectionKeyImpl key, int interestOps, + int activeOps, int fd) + { + //System.out.println(">> updating kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + synchronized (keys) + { + kevent_set(key.nstate, fd, interestOps, activeOps, key.key); + } + //System.out.println(">> updated kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + }*/ + + private void dump_selection_keys(ByteBuffer keys) + { + // WARNING! This method is not guaranteed to be portable! This works + // on darwin/x86, but the sizeof and offsetof these fields may be + // different on other platforms! + int i = 0; + keys.order(ByteOrder.nativeOrder()); + while (keys.hasRemaining()) + { + System.out.println("struct kevent { ident: " + + Integer.toString(keys.getInt()) + + " filter: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " flags: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " fflags: " + + Integer.toHexString(keys.getInt()) + + " data: " + + Integer.toHexString(keys.getInt()) + + " udata: " + + Integer.toHexString(keys.getInt()) + + " }"); + } + } + + /** + * Return the size of a <code>struct kevent</code> on this system. + * + * @return The size of <code>struct kevent</code>. + */ + private static native int sizeof_struct_kevent(); + + /** + * Opens a kqueue descriptor. + * + * @return The new kqueue descriptor. + * @throws IOException If opening fails. + */ + private static native int implOpen() throws IOException; + + /** + * Closes the kqueue file descriptor. + * + * @param kq The kqueue file descriptor. + * @throws IOException + */ + private static native void implClose(int kq) throws IOException; + + /** + * Initialize the specified native state for the given interest ops. + * + * @param nstate The native state structures; in this buffer should be + * the <code>struct kevent</code>s created for a key. + * @param fd The file descriptor. If 0, the native FD is unmodified. + * @param interestOps The operations to enable. + * @param key A unique key that will reference the associated key later. + * @param delete Set to true if this event should be deleted from the + * kqueue (if false, this event is added/updated). + */ + private static native void kevent_set(ByteBuffer nstate, int i, int fd, + int interestOps, int activeOps, int key); + + /** + * Poll for events. The source events are stored in <code>events</code>, + * which is also where polled events will be placed. + * + * @param events The events to poll. This buffer is also the destination + * for events read from the queue. + * @param nevents The number of events to poll (that is, the number of + * events in the <code>events</code> buffer). + * @param nout The maximum number of events that may be returned. + * @param timeout The timeout. A timeout of -1 returns immediately; a timeout + * of 0 waits indefinitely. + * @return The number of events read. + */ + private static native int kevent(int kq, ByteBuffer events, int nevents, + int nout, long timeout); + + /** + * Fetch a polled key from a native state buffer. For each kevent key we + * create, we put the native state info (one or more <code>struct + * kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate} + * buffer, and place the pointer of the key in the <code>udata</code> field + * of that structure. This method fetches that pointer from the given + * buffer (assumed to be a <code>struct kqueue</code>) and returns it. + * + * @param nstate The buffer containing the <code>struct kqueue</code> to read. + * @return The key object. + */ + private static native int fetch_key(ByteBuffer nstate); + + /** + * Fetch the ready ops of the associated native state. That is, this + * inspects the first argument as a <code>struct kevent</code>, looking + * at its operation (the input is assumed to have been returned via a + * previous call to <code>kevent</code>), and translating that to the + * appropriate Java bit set, based on the second argument. + * + * @param nstate The native state. + * @param interestOps The enabled operations for the key. + * @return The bit set representing the ready operations. + */ + private static native int ready_ops(ByteBuffer nstate, int interestOps); + + /** + * Check if kevent returned EV_EOF for a selection key. + * + * @param nstate The native state. + * @return True if the kevent call returned EOF. + */ + private static native boolean check_eof(ByteBuffer nstate); +} Added: trunk/core/src/classpath/gnu/gnu/java/nio/VMChannelOwner.java =================================================================== --- trunk/core/src/classpath/gnu/gnu/java/nio/VMChannelOwner.java (rev 0) +++ trunk/core/src/classpath/gnu/gnu/java/nio/VMChannelOwner.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -0,0 +1,57 @@ +/* NativeFD.java -- interface for Channels that have an underlying file descriptor. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + +/** + * This interface is meant to be implemented by any {@link Channel} + * implementation we support that uses a platform-specific {@link VMChannel} + * at their core. This is primarily used by {@link Selector} implementations, + * for easier access to the native state. + * + * @author Casey Marshall (cs...@gn...) + */ +interface VMChannelOwner +{ + /** + * Return the underlying platform-specific Channel instance. + * + * @return The platform channel object. + */ + VMChannel getVMChannel(); +} Modified: trunk/core/src/classpath/java/java/lang/InheritableThreadLocal.java =================================================================== --- trunk/core/src/classpath/java/java/lang/InheritableThreadLocal.java 2007-01-27 10:06:33 UTC (rev 3090) +++ trunk/core/src/classpath/java/java/lang/InheritableThreadLocal.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -53,12 +53,15 @@ * * @author Mark Wielaard (ma...@kl...) * @author Eric Blake (eb...@em...) + * @author Tom Tromey (tr...@re...) + * @author Andrew John Hughes (gnu...@me...) * @see ThreadLocal * @since 1.2 * @status updated to 1.4 */ public class InheritableThreadLocal extends ThreadLocal { + /** * Creates a new InheritableThreadLocal that has no values associated * with it yet. Modified: trunk/core/src/classpath/java/java/lang/StringBuffer.java =================================================================== --- trunk/core/src/classpath/java/java/lang/StringBuffer.java 2007-01-27 10:06:33 UTC (rev 3090) +++ trunk/core/src/classpath/java/java/lang/StringBuffer.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -72,8 +72,12 @@ * @since 1.0 * @status updated to 1.4 */ -public final class StringBuffer implements Serializable, CharSequence +public final class StringBuffer + implements Serializable, CharSequence, Appendable { + // Implementation note: if you change this class, you usually will + // want to change StringBuilder as well. + /** * Compatible with JDK 1.0+. */ @@ -148,21 +152,22 @@ } /** - * Create a new <code>StringBuffer</code> with the characters from the + * Create a new <code>StringBuffer</code> with the characters in the * specified <code>CharSequence</code>. Initial capacity will be the - * size of the CharSequence plus 16. + * length of the sequence plus 16; if the sequence reports a length + * less than or equal to 0, then the initial capacity will be 16. * - * @param sequence the <code>String</code> to convert + * @param seq the initializing <code>CharSequence</code> * @throws NullPointerException if str is null - * * @since 1.5 */ - public StringBuffer(CharSequence sequence) + public StringBuffer(CharSequence seq) { - count = Math.max(0, sequence.length()); + int len = seq.length(); + count = len <= 0 ? 0 : len; value = new char[count + DEFAULT_CAPACITY]; - for (int i = 0; i < count; ++i) - value[i] = sequence.charAt(i); + for (int i = 0; i < len; ++i) + value[i] = seq.charAt(i); } /** @@ -391,46 +396,6 @@ } /** - * Append the <code>CharSequence</code> value of the argument to this - * <code>StringBuffer</code>. - * - * @param sequence the <code>CharSequence</code> to append - * @return this <code>StringBuffer</code> - * @see #append(Object) - * @since 1.5 - */ - public synchronized StringBuffer append(CharSequence sequence) - { - if (sequence == null) - sequence = "null"; - return append(sequence, 0, sequence.length()); - } - - /** - * Append the specified subsequence of the <code>CharSequence</code> - * argument to this <code>StringBuffer</code>. - * - * @param sequence the <code>CharSequence</code> to append - * @param start the starting index - * @param end one past the ending index - * @return this <code>StringBuffer</code> - * @see #append(Object) - * @since 1.5 - */ - public synchronized StringBuffer append(CharSequence sequence, - int start, int end) - { - if (sequence == null) - sequence = "null"; - if (start < 0 || end < 0 || start > end || end > sequence.length()) - throw new IndexOutOfBoundsException(); - ensureCapacity_unsynchronized(this.count + end - start); - for (int i = start; i < end; ++i) - value[count++] = sequence.charAt(i); - return this; - } - - /** * Append the <code>char</code> array to this <code>StringBuffer</code>. * This is similar (but more efficient) than * <code>append(new String(data))</code>, except in the case of null. @@ -470,6 +435,25 @@ } /** + * Append the code point to this <code>StringBuffer</code>. + * This is like #append(char), but will append two characters + * if a supplementary code point is given. + * + * @param code the code point to append + * @return this <code>StringBuffer</code> + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public synchronized StringBuffer appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity_unsynchronized(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** * Append the <code>String</code> value of the argument to this * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert * to <code>String</code>. @@ -497,21 +481,39 @@ } /** - * Append the code point to this <code>StringBuffer</code>. - * This is like #append(char), but will append two characters - * if a supplementary code point is given. + * Append the characters in the <code>CharSequence</code> to this + * buffer. * - * @param code the code point to append + * @param seq the <code>CharSequence</code> providing the characters * @return this <code>StringBuffer</code> - * @see Character#toChars(int, char[], int) * @since 1.5 */ - public synchronized StringBuffer appendCodePoint(int code) + public synchronized StringBuffer append(CharSequence seq) { - int len = Character.charCount(code); - ensureCapacity_unsynchronized(count + len); - Character.toChars(code, value, count); - count += len; + return append(seq, 0, seq.length()); + } + + /** + * Append some characters from the <code>CharSequence</code> to this + * buffer. If the argument is null, the four characters "null" are + * appended. + * + * @param seq the <code>CharSequence</code> providing the characters + * @param start the starting index + * @param end one past the final index + * @return this <code>StringBuffer</code> + * @since 1.5 + */ + public synchronized StringBuffer append(CharSequence seq, int start, int end) + { + if (seq == null) + return append("null"); + if (end - start > 0) + { + ensureCapacity_unsynchronized(count + end - start); + for (; start < end; ++start) + value[count++] = seq.charAt(start); + } return this; } Modified: trunk/core/src/classpath/java/java/lang/ThreadLocal.java =================================================================== --- trunk/core/src/classpath/java/java/lang/ThreadLocal.java 2007-01-27 10:06:33 UTC (rev 3090) +++ trunk/core/src/classpath/java/java/lang/ThreadLocal.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -84,9 +84,9 @@ * @author Mark Wielaard (ma...@kl...) * @author Eric Blake (eb...@em...) * @since 1.2 - * @status updated to 1.4 + * @status updated to 1.5 */ -public class ThreadLocal +public class ThreadLocal<T> { /** * Placeholder to distinguish between uninitialized and null set by the @@ -125,7 +125,7 @@ * * @return the initial value of the variable in this thread */ - protected Object initialValue() + protected T initialValue() { return null; } @@ -138,7 +138,7 @@ * * @return the value of the variable in this thread */ - public Object get() + public T get() { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will @@ -149,7 +149,7 @@ value = initialValue(); map.put(key, value == null ? NULL : value); } - return value == NULL ? null : value; + return value == NULL ? null : (T) value; } /** @@ -160,11 +160,22 @@ * * @param value the value to set this thread's view of the variable to */ - public void set(Object value) + public void set(T value) { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will // ever modify the map. map.put(key, value == null ? NULL : value); } + + /** + * Removes the value associated with the ThreadLocal object for the + * currently executing Thread. + * @since 1.5 + */ + public void remove() + { + Map map = Thread.getThreadLocals(); + map.remove(this); } +} Added: trunk/core/src/classpath/java/java/util/concurrent/locks/ReentrantReadWriteLock.java =================================================================== --- trunk/core/src/classpath/java/java/util/concurrent/locks/ReentrantReadWriteLock.java (rev 0) +++ trunk/core/src/classpath/java/java/util/concurrent/locks/ReentrantReadWriteLock.java 2007-01-27 11:43:17 UTC (rev 3091) @@ -0,0 +1,1346 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An implementation of {@link ReadWriteLock} supporting similar + * semantics to {@link ReentrantLock}. + * <p>This class has the following properties: + * + * <ul> + * <li><b>Acquisition order</b> + * + * <p> This class does not impose a reader or writer preference + * ordering for lock access. However, it does support an optional + * <em>fairness</em> policy. + * + * <dl> + * <dt><b><i>Non-fair mode (default)</i></b> + * <dd>When constructed as non-fair (the default), the order of entry + * to the read and write lock is unspecified, subject to reentrancy + * constraints. A nonfair lock that is continously contended may + * indefinitely postpone one or more reader or writer threads, but + * will normally have higher throughput than a fair lock. + * <p> + * + * <dt><b><i>Fair mode</i></b> + * <dd> When constructed as fair, threads contend for entry using an + * approximately arrival-order policy. When the currently held lock + * is released either the longest-waiting single writer thread will + * be assigned the write lock, or if there is a group of reader threads + * waiting longer than all waiting writer threads, that group will be + * assigned the read lock. + * + * <p>A thread that tries to acquire a fair read lock (non-reentrantly) + * will block if either the write lock is held, or there is a waiting + * writer thread. The thread will not acquire the read lock until + * after the oldest currently waiting writer thread has acquired and + * released the write lock. Of course, if a waiting writer abandons + * its wait, leaving one or more reader threads as the longest waiters + * in the queue with the write lock free, then those readers will be + * assigned the read lock. + * + * <p>A thread that tries to acquire a fair write lock (non-reentrantly) + * will block unless both the read lock and write lock are free (which + * implies there are no waiting threads). (Note that the non-blocking + * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods + * do not honor this fair setting and will acquire the lock if it is + * possible, regardless of waiting threads.) + * <p> + * </dl> + * + * <li><b>Reentrancy</b> + * + * <p>This lock allows both readers and writers to reacquire read or + * write locks in the style of a {@link ReentrantLock}. Non-reentrant + * readers are not allowed until all write locks held by the writing + * thread have been released. + * + * <p>Additionally, a writer can acquire the read lock, but not + * vice-versa. Among other applications, reentrancy can be useful + * when write locks are held during calls or callbacks to methods that + * perform reads under read locks. If a reader tries to acquire the + * write lock it will never succeed. + * + * <li><b>Lock downgrading</b> + * <p>Reentrancy also allows downgrading from the write lock to a read lock, + * by acquiring the write lock, then the read lock and then releasing the + * write lock. However, upgrading from a read lock to the write lock is + * <b>not</b> possible. + * + * <li><b>Interruption of lock acquisition</b> + * <p>The read lock and write lock both support interruption during lock + * acquisition. + * + * <li><b>{@link Condition} support</b> + * <p>The write lock provides a {@link Condition} implementation that + * behaves in the same way, with respect to the write lock, as the + * {@link Condition} implementation provided by + * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}. + * This {@link Condition} can, of course, only be used with the write lock. + * + * <p>The read lock does not support a {@link Condition} and + * {@code readLock().newCondition()} throws + * {@code UnsupportedOperationException}. + * + * <li><b>Instrumentation</b> + * <p>This class supports methods to determine whether locks + * are held or contended. These methods are designed for monitoring + * system state, not for synchronization control. + * </ul> + * + * <p>Serialization of this class behaves in the same way as built-in + * locks: a deserialized lock is in the unlocked state, regardless of + * its state when serialized. + * + * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit + * reentrancy to perform lock downgrading after updating a cache (exception + * handling is elided for simplicity): + * <pre> + * class CachedData { + * Object data; + * volatile boolean cacheValid; + * ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + * + * void processCachedData() { + * rwl.readLock().lock(); + * if (!cacheValid) { + * // Must release read lock before acquiring write lock + * rwl.readLock().unlock(); + * rwl.writeLock().lock(); + * // Recheck state because another thread might have acquired + * // write lock and changed state before we did. + * if (!cacheValid) { + * data = ... + * cacheValid = true; + * } + * // Downgrade by acquiring read lock before releasing write lock + * rwl.readLock().lock(); + * rwl.writeLock().unlock(); // Unlock write, still hold read + * } + * + * use(data); + * rwl.readLock().unlock(); + * } + * } + * </pre> + * + * ReentrantReadWriteLocks can be used to improve concurrency in some + * uses of some kinds of Collections. This is typically worthwhile + * only when the collections are expected to be large, accessed by + * more reader threads than writer threads, and entail operations with + * overhead that outweighs synchronization overhead. For example, here + * is a class using a TreeMap that is expected to be large and + * concurrently accessed. + * + * <pre>{@code + * class RWDictionary { + * private final Map<String, Data> m = new TreeMap<String, Data>(); + * private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + * private final Lock r = rwl.readLock(); + * private final Lock w = rwl.writeLock(); + * + * public Data get(String key) { + * r.lock(); + * try { return m.get(key); } + * finally { r.unlock(); } + * } + * public String[] allKeys() { + * r.lock(); + * try { return m.keySet().toArray(); } + * finally { r.unlock(); } + * } + * public Data put(String key, Data value) { + * w.lock(); + * try { return m.put(key, value); } + * finally { w.unlock(); } + * } + * public void clear() { + * w.lock(); + * try { m.clear(); } + * finally { w.unlock(); } + * } + * }}</pre> + * + * <h3>Implementation Notes</h3> + * + * <p>This lock supports a maximum of 65535 recursive write locks + * and 65535 read locks. Attempts to exceed these limits result in + * {@link Error} throws from locking methods. + * + * @since 1.5 + * @author Doug Lea + * + */ +public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { + private static final long serialVersionUID = -6992448646407690164L; + /** Inner class providing readlock */ + private final ReentrantReadWriteLock.ReadLock readerLock; + /** Inner class providing writelock */ + private final ReentrantReadWriteLock.WriteLock writerLock; + /** Performs all synchronization mechanics */ + private final Sync sync; + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * default (nonfair) ordering properties. + */ + public ReentrantReadWriteLock() { + this(false); + } + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * the given fairness policy. + * + * @param fair {@code true} if this lock should use a fair ordering policy + */ + public ReentrantReadWriteLock(boolean fair) { + sync = (fair)? new FairSync() : new NonfairSync(); + readerLock = new ReadLock(this); + writerLock = new WriteLock(this); + } + + public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } + public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } + + /** + * Synchronization implementation for ReentrantReadWriteLock. + * Subclassed into fair and nonfair versions. + */ + static abstract class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 6317671515068378041L; + + /* + * Read vs write count extraction constants and functions. + * Lock state is logically divided into two shorts: The lower + * one representing the exclusive (writer) lock hold count, + * and the upper the shared (reader) hold count. + */ + + static final int SHARED_SHIFT = 16; + static final int SHARED_UNIT = (1 << SHARED_SHIFT); + static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; + static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; + + /** Returns the number of shared holds represented in count */ + static int sharedCount(int c) { return c >>> SHARED_SHIFT; } + /** Returns the number of exclusive holds represented in count */ + static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } + + /** + * A counter for per-thread read hold counts. + * Maintained as a ThreadLocal; cached in cachedHoldCounter + */ + static final class HoldCounter { + int count; + // Use id, not reference, to avoid garbage retention + final long tid = Thread.currentThread().getId(); + /** Decrement if positive; return previous value */ + int tryDecrement() { + int c = count; + if (c > 0) + count = c - 1; + return c; + } + } + + /** + * ThreadLocal subclass. Easiest to explicitly define for sake + * of deserialization mechanics. + */ + static final class ThreadLocalHoldCounter + extends ThreadLocal<HoldCounter> { + public HoldCounter initialValue() { + return new HoldCounter(); + } + } + + /** + * The number of read locks held by current thread. + * Initialized only in constructor and readObject. + */ + transient ThreadLocalHoldCounter readHolds; + + /** + * The hold count of the last thread to successfully acquire + * readLock. This saves ThreadLocal lookup in the common case + * where the next thread to release is the last one to + * acquire. This is non-volatile since it is just used + * as a heuristic, and would be great for threads to cache. + */ + transient HoldCounter cachedHoldCounter; + + Sync() { + readHolds = new ThreadLocalHoldCounter(); + setState(getState()); // ensures visibility of readHolds + } + + /* + * Acquires and releases use the same code for fair and + * nonfair locks, but differ in whether/how they allow barging + * when queues are non-empty. + */ + + /** + * Return true if a reader thread that is otherwise + * eligible for lock should block because of policy + * for overtaking other waiting threads. + */ + abstract boolean readerShouldBlock(Thread current); + + /** + * Return true if a writer thread that is otherwise + * eligible for lock should block because of policy + * for overtaking other waiting threads. + */ + abstract boolean writerShouldBlock(Thread current); + + /* + * Note that tryRelease and tryAcquire can be called by + * Conditions. So it is possible that their arguments contain + * both read and write holds that are all released during a + * condition wait and re-established in tryAcquire. + */ + + protected final boolean tryRelease(int releases) { + int nextc = getState() - releases; + if (Thread.currentThread() != getExclusiveOwnerThread()) + throw new IllegalMonitorStateException(); + if (exclusiveCount(nextc) == 0) { + setExclusiveOwnerThread(null); + setState(nextc); + return true; + } else { + setState(nextc); + return false; + } + } + + protected final boolean tryAcquire(int acquires) { + /* + * Walkthrough: + * 1. if read count nonzero or write count nonzero + * and owner is a different thread, fail. + * 2. If count would saturate, fail. (This can only + * happen if count is already nonzero.) + * 3. Otherwise, this thread is eligible for lock if + * it is either a reentrant acquire or + * queue policy allows it. If so, update state + * and set owner. + */ + Thread current = Thread.currentThread(); + int c = getState(); + int w = exclusiveCount(c); + if (c != 0) { + // (Note: if c != 0 and w == 0 then shared count != 0) + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w + exclusiveCount(acquires) > MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + } + if ((w == 0 && writerShouldBlock(current)) || + !compareAndSetState(c, c + acquires)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + protected final boolean tryReleaseShared(int unused) { + HoldCounter rh = cachedHoldCounter; + Thread current = Thread.currentThread(); + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + if (rh.tryDecrement() <= 0) + throw new IllegalMonitorStateException(); + for (;;) { + int c = getState(); + int nextc = c - SHARED_UNIT; + if (compareAndSetState(c, nextc)) + return nextc == 0; + } + } + + protected final int tryAcquireShared(int unused) { + /* + * Walkthrough: + * 1. If write lock held by another thread, fail + * 2. If count saturated, throw error + * 3. Otherwise, this thread is eligible for + * lock wrt state, so ask if it should block + * because of queue policy. If not, try + * to grant by CASing state and updating count. + * Note that step does not check for reentrant + * acquires, which is postponed to full version + * to avoid having to check hold count in + * the more typical non-reentrant case. + * 4. If step 3 fails either because thread + * apparently not eligible or CAS fails, + * chain to version with full retry loop. + */ + Thread current = Thread.currentThread(); + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return -1; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (!readerShouldBlock(current) && + compareAndSetState(c, c + SHARED_UNIT)) { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + rh.count++; + return 1; + } + return fullTryAcquireShared(current); + } + + /** + * Full version of acquire for reads, that handles CAS misses + * and reentrant reads not dealt with in tryAcquireShared. + */ + final int fullTryAcquireShared(Thread current) { + /* + * This code is in part redundant with that in + * tryAcquireShared but is simpler overall by not + * complicating tryAcquireShared with interactions between + * retries and lazily reading hold counts. + */ + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + for (;;) { + int c = getState(); + int w = exclusiveCount(c); + if ((w != 0 && getExclusiveOwnerThread() != current) || + ((rh.count | w) == 0 && readerShouldBlock(current))) + return -1; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + cachedHoldCounter = rh; // cache for release + rh.count++; + return 1; + } + } + } + + /** + * Performs tryLock for write, enabling barging in both modes. + * This is identical in effect to tryAcquire except for lack + * of calls to writerShouldBlock + */ + final boolean tryWriteLock() { + Thread current = Thread.currentThread(); + int c = getState(); + if (c != 0) { + int w = exclusiveCount(c); + if (w == 0 ||current != getExclusiveOwnerThread()) + return false; + if (w == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + } + if (!compareAndSetState(c, c + 1)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + /** + * Performs tryLock for read, enabling barging in both modes. + * This is identical in effect to tryAcquireShared except for + * lack of calls to readerShouldBlock + */ + final boolean tryReadLock() { + Thread current = Thread.currentThread(); + for (;;) { + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return false; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + rh.count++; + return true; + } + } + } + + protected final boolean isHeldExclusively() { + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); + } + + // Methods relayed to outer class + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + final Thread getOwner() { + // Must read state before owner to ensure memory consistency + return ((exclusiveCount(getState()) == 0)? + null : + getExclusiveOwnerThread()); + } + + final int getReadLockCount() { + return sharedCount(getState()); + } + + final boolean isWriteLocked() { + return exclusiveCount(getState()) != 0; + } + + final int getWriteHoldCount() { + return isHeldExclusively() ? exclusiveCount(getState()) : 0; + } + + final int getReadHoldCount() { + return getReadLockCount() == 0? 0 : readHolds.get().count; + } + + /** + * Reconstitute this lock instance from a stream + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + readHolds = new ThreadLocalHoldCounter(); + setState(0); // reset to unlocked state + } + + final int getCount() { return getState(); } + } + + /** + * Nonfair version of Sync + */ + final static class NonfairSync extends Sync { + private static final long serialVersionUID = -8159625535654395037L; + final boolean writerShouldBlock(Thread current) { + return false; // writers can always barge + } + final boolean readerShouldBlock(Thread current) { + /* As a heuristic to avoid indefinite writer starvation, + * block if the thread that momentarily appears to be head + * of queue, if one exists, is a waiting writer. This is + * only a probablistic effect since a new reader will not + * block if there is a waiting writer behind other enabled + * readers that have not yet drained from the queue. + */ + return apparentlyFirstQueuedIsExclusive(); + } + } + + /** + * Fair version of Sync + */ + final static class FairSync extends Sync { + private static final long serialVersionUID = -2274990926593161451L; + final boolean writerShouldBlock(Thread current) { + // only proceed if queue is empty or current thread at head + return !isFirst(current); + } + final boolean readerShouldBlock(Thread current) { + // only proceed if queue is empty or current thread at head + return !isFirst(current); + } + } + + /** + * The lock returned by method {@link ReentrantReadWriteLock#readLock}. + */ + public static class ReadLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = -5992448646407690164L; + private final Sync sync; + + /** + * Constructor for use by subclasses + * + * @param lock the outer lock object + * @throws NullPointerException i... [truncated message content] |
From: <ls...@us...> - 2007-01-27 21:52:49
|
Revision: 3095 http://jnode.svn.sourceforge.net/jnode/?rev=3095&view=rev Author: lsantha Date: 2007-01-27 13:52:45 -0800 (Sat, 27 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/java/java/lang/Compiler.java trunk/core/src/classpath/java/java/lang/Math.java trunk/core/src/classpath/java/java/lang/SecurityManager.java trunk/core/src/classpath/java/java/lang/StrictMath.java trunk/core/src/classpath/java/java/lang/ThreadGroup.java trunk/core/src/classpath/vm/java/lang/Thread.java Added Paths: ----------- trunk/core/src/classpath/vm/java/lang/VMMath.java Modified: trunk/core/src/classpath/java/java/lang/Compiler.java =================================================================== --- trunk/core/src/classpath/java/java/lang/Compiler.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/java/java/lang/Compiler.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -74,7 +74,7 @@ * compilation failed, <code>true</code> if compilation succeeded * @throws NullPointerException if oneClass is null */ - public static boolean compileClass(Class oneClass) + public static boolean compileClass(Class<?> oneClass) { return VMCompiler.compileClass(oneClass); } Modified: trunk/core/src/classpath/java/java/lang/Math.java =================================================================== --- trunk/core/src/classpath/java/java/lang/Math.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/java/java/lang/Math.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -1,5 +1,5 @@ -/* java.lang.Math -- common mathematical functions, native allowed - Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* java.lang.Math -- common mathematical functions, native allowed (VMMath) + Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ package java.lang; +import gnu.classpath.Configuration; + import java.util.Random; /** @@ -50,10 +52,26 @@ * @author Paul Fisher * @author John Keiser * @author Eric Blake (eb...@em...) + * @author Andrew John Hughes (gnu...@me...) * @since 1.0 */ public final class Math { + + // FIXME - This is here because we need to load the "javalang" system + // library somewhere late in the bootstrap cycle. We cannot do this + // from VMSystem or VMRuntime since those are used to actually load + // the library. This is mainly here because historically Math was + // late enough in the bootstrap cycle to start using System after it + // was initialized (called from the java.util classes). + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalang"); + } + } + /** * Math is non-instantiable */ @@ -288,11 +306,10 @@ * @param a the angle (in radians) * @return sin(a) */ - // @classpath-bugfix-22918 - public static double sin(double a) { - return StrictMath.sin(a); + public static double sin(double a) + { + return VMMath.sin(a); } - // @classpath-bugfix-end /** * The trigonometric function <em>cos</em>. The cosine of NaN or infinity is @@ -301,11 +318,10 @@ * @param a the angle (in radians) * @return cos(a) */ - // @classpath-bugfix-22918 - public static double cos(double a) { - return StrictMath.cos(a); + public static double cos(double a) + { + return VMMath.cos(a); } - // @classpath-bugfix-end /** * The trigonometric function <em>tan</em>. The tangent of NaN or infinity @@ -315,11 +331,10 @@ * @param a the angle (in radians) * @return tan(a) */ - // @classpath-bugfix-22918 - public static double tan(double a) { - return StrictMath.tan(a); + public static double tan(double a) + { + return VMMath.tan(a); } - // @classpath-bugfix-end /** * The trigonometric function <em>arcsin</em>. The range of angles returned @@ -330,11 +345,10 @@ * @param a the sin to turn back into an angle * @return arcsin(a) */ - // @classpath-bugfix-22918 - public static double asin(double a) { - return StrictMath.asin(a); + public static double asin(double a) + { + return VMMath.asin(a); } - // @classpath-bugfix-end /** * The trigonometric function <em>arccos</em>. The range of angles returned @@ -345,11 +359,10 @@ * @param a the cos to turn back into an angle * @return arccos(a) */ - // @classpath-bugfix-22918 - public static double acos(double a) { - return StrictMath.acos(a); + public static double acos(double a) + { + return VMMath.acos(a); } - // @classpath-bugfix-end /** * The trigonometric function <em>arcsin</em>. The range of angles returned @@ -361,11 +374,10 @@ * @return arcsin(a) * @see #atan2(double, double) */ - // @classpath-bugfix-22918 - public static double atan(double a) { - return StrictMath.atan(a); + public static double atan(double a) + { + return VMMath.atan(a); } - // @classpath-bugfix-end /** * A special version of the trigonometric function <em>arctan</em>, for @@ -414,11 +426,10 @@ * @return <em>theta</em> in the conversion of (x, y) to (r, theta) * @see #atan(double) */ - // @classpath-bugfix-22918 - public static double atan2(double y, double x) { - return StrictMath.atan2(y, x); + public static double atan2(double y, double x) + { + return VMMath.atan2(y,x); } - // @classpath-bugfix-end /** * Take <em>e</em><sup>a</sup>. The opposite of <code>log()</code>. If the @@ -432,11 +443,10 @@ * @see #log(double) * @see #pow(double, double) */ - // @classpath-bugfix-22918 - public static double exp(double a) { - return StrictMath.exp(a); + public static double exp(double a) + { + return VMMath.exp(a); } - // @classpath-bugfix-end /** * Take ln(a) (the natural log). The opposite of <code>exp()</code>. If the @@ -452,11 +462,10 @@ * @return the natural log of <code>a</code> * @see #exp(double) */ - // @classpath-bugfix-22918 - public static double log(double a) { - return StrictMath.log(a); + public static double log(double a) + { + return VMMath.log(a); } - // @classpath-bugfix-end /** * Take a square root. If the argument is NaN or negative, the result is @@ -464,17 +473,18 @@ * infinity; and if the result is either zero, the result is the same. * This is accurate within the limits of doubles. * - * <p>For other roots, use pow(a, 1 / rootNumber). + * <p>For a cube root, use <code>cbrt</code>. For other roots, use + * <code>pow(a, 1 / rootNumber)</code>.</p> * * @param a the numeric argument * @return the square root of the argument + * @see #cbrt(double) * @see #pow(double, double) */ - // @classpath-bugfix-22918 - public static double sqrt(double a) { - return StrictMath.sqrt(a); + public static double sqrt(double a) + { + return VMMath.sqrt(a); } - // @classpath-bugfix-end /** * Raise a number to a power. Special cases:<ul> @@ -544,11 +554,10 @@ * @param b the power to raise it to * @return a<sup>b</sup> */ - // @classpath-bugfix-22918 - public static double pow(double a, double b) { - return StrictMath.pow(a, b); + public static double pow(double a, double b) + { + return VMMath.pow(a,b); } - // @classpath-bugfix-end /** * Get the IEEE 754 floating point remainder on two numbers. This is the @@ -564,11 +573,10 @@ * @return the IEEE 754-defined floating point remainder of x/y * @see #rint(double) */ - // @classpath-bugfix-22918 - public static double IEEEremainder(double x, double y) { - return StrictMath.IEEEremainder(x, y); + public static double IEEEremainder(double x, double y) + { + return VMMath.IEEEremainder(x,y); } - // @classpath-bugfix-end /** * Take the nearest integer that is that is greater than or equal to the @@ -579,11 +587,10 @@ * @param a the value to act upon * @return the nearest integer >= <code>a</code> */ - // @classpath-bugfix-22918 - public static double ceil(double a) { - return StrictMath.ceil(a); + public static double ceil(double a) + { + return VMMath.ceil(a); } - // @classpath-bugfix-end /** * Take the nearest integer that is that is less than or equal to the @@ -593,11 +600,10 @@ * @param a the value to act upon * @return the nearest integer <= <code>a</code> */ - // @classpath-bugfix-22918 - public static double floor(double a) { - return StrictMath.floor(a); + public static double floor(double a) + { + return VMMath.floor(a); } - // @classpath-bugfix-end /** * Take the nearest integer to the argument. If it is exactly between @@ -607,12 +613,10 @@ * @param a the value to act upon * @return the nearest integer to <code>a</code> */ - // @classpath-bugfix-22918 public static double rint(double a) { - return StrictMath.rint(a); + return VMMath.rint(a); } - // @classpath-bugfix-end /** * Take the nearest integer to the argument. This is equivalent to @@ -701,6 +705,99 @@ /** * <p> + * Take a cube root. If the argument is <code>NaN</code>, an infinity or + * zero, then the original value is returned. The returned result is + * within 1 ulp of the exact result. For a finite value, <code>x</code>, + * the cube root of <code>-x</code> is equal to the negation of the cube root + * of <code>x</code>. + * </p> + * <p> + * For a square root, use <code>sqrt</code>. For other roots, use + * <code>pow(a, 1 / rootNumber)</code>. + * </p> + * + * @param a the numeric argument + * @return the cube root of the argument + * @see #sqrt(double) + * @see #pow(double, double) + * @since 1.5 + */ + public static double cbrt(double a) + { + return VMMath.cbrt(a); + } + + /** + * <p> + * Returns the hyperbolic cosine of the given value. For a value, + * <code>x</code>, the hyperbolic cosine is <code>(e<sup>x</sup> + + * e<sup>-x</sup>)/2</code> + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. + * </p> + * <p> + * If the supplied value is <code>NaN</code>, then the original value is + * returned. For either infinity, positive infinity is returned. + * The hyperbolic cosine of zero is 1.0. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic cosine of <code>a</code>. + * @since 1.5 + */ + public static double cosh(double a) + { + return VMMath.cosh(a); + } + + /** + * <p> + * Returns <code>e<sup>a</sup> - 1. For values close to 0, the + * result of <code>expm1(a) + 1</code> tend to be much closer to the + * exact result than simply <code>exp(x)</code>. The result is within + * 1 ulp of the exact result, and results are semi-monotonic. For finite + * inputs, the returned value is greater than or equal to -1.0. Once + * a result enters within half a ulp of this limit, the limit is returned. + * </p> + * <p> + * For <code>NaN</code>, positive infinity and zero, the original value + * is returned. Negative infinity returns a result of -1.0 (the limit). + * </p> + * + * @param a the numeric argument + * @return <code>e<sup>a</sup> - 1</code> + * @since 1.5 + */ + public static double expm1(double a) + { + return VMMath.expm1(a); + } + + /** + * <p> + * Returns the hypotenuse, <code>a<sup>2</sup> + b<sup>2</sup></code>, + * without intermediate overflow or underflow. The returned result is + * within 1 ulp of the exact result. If one parameter is held constant, + * then the result in the other parameter is semi-monotonic. + * </p> + * <p> + * If either of the arguments is an infinity, then the returned result + * is positive infinity. Otherwise, if either argument is <code>NaN</code>, + * then <code>NaN</code> is returned. + * </p> + * + * @param a the first parameter. + * @param b the second parameter. + * @return the hypotenuse matching the supplied parameters. + * @since 1.5 + */ + public static double hypot(double a, double b) + { + return VMMath.hypot(a,b); + } + + /** + * <p> * Returns the base 10 logarithm of the supplied value. The returned * result is within 1 ulp of the exact result, and the results are * semi-monotonic. @@ -719,7 +816,7 @@ */ public static double log10(double a) { - return log(a)/log(10); + return VMMath.log10(a); } /** @@ -744,7 +841,7 @@ */ public static double log1p(double a) { - return log(a + 1); + return VMMath.log1p(a); } /** @@ -800,7 +897,58 @@ return -1.0f; return a; } + /** + * <p> + * Returns the hyperbolic sine of the given value. For a value, + * <code>x</code>, the hyperbolic sine is <code>(e<sup>x</sup> - + * e<sup>-x</sup>)/2</code> + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. + * </p> + * <p> + * If the supplied value is <code>NaN</code>, an infinity or a zero, then the + * original value is returned. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic sine of <code>a</code>. + * @since 1.5 + */ + public static double sinh(double a) + { + return VMMath.sinh(a); + } + + /** + * <p> + * Returns the hyperbolic tangent of the given value. For a value, + * <code>x</code>, the hyperbolic tangent is <code>(e<sup>x</sup> - + * e<sup>-x</sup>)/(e<sup>x</sup> + e<sup>-x</sup>)</code> + * (i.e. <code>sinh(a)/cosh(a)</code>) + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. The absolute value + * of the exact result is always less than 1. Computed results are thus + * less than or equal to 1 for finite arguments, with results within + * half a ulp of either positive or negative 1 returning the appropriate + * limit value (i.e. as if the argument was an infinity). + * </p> + * <p> + * If the supplied value is <code>NaN</code> or zero, then the original + * value is returned. Positive infinity returns +1.0 and negative infinity + * returns -1.0. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic tangent of <code>a</code>. + * @since 1.5 + */ + public static double tanh(double a) + { + return VMMath.tanh(a); + } + + /** * Return the ulp for the given double argument. The ulp is the * difference between the argument and the next larger double. Note * that the sign of the double argument is ignored, that is, Modified: trunk/core/src/classpath/java/java/lang/SecurityManager.java =================================================================== --- trunk/core/src/classpath/java/java/lang/SecurityManager.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/java/java/lang/SecurityManager.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -1,5 +1,5 @@ /* SecurityManager.java -- security checks for privileged actions - Copyright (C) 1998, 1999, 2001, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -240,7 +240,7 @@ * @return the most recent non-system Class on the execution stack * @deprecated use {@link #checkPermission(Permission)} instead */ - protected Class currentLoadedClass() + protected Class<?> currentLoadedClass() { int i = classLoaderDepth(); return i >= 0 ? getClassContext()[i] : null; @@ -421,7 +421,7 @@ public void checkAccess(Thread thread) { if (thread.getThreadGroup() != null - && thread.getThreadGroup().getParent() == null) + && thread.getThreadGroup().parent == null) checkPermission(new RuntimePermission("modifyThread")); } @@ -454,7 +454,7 @@ */ public void checkAccess(ThreadGroup g) { - if (g.getParent() == null) + if (g.parent == null) checkPermission(new RuntimePermission("modifyThreadGroup")); } @@ -983,7 +983,7 @@ * @see Member#PUBLIC * @since 1.1 */ - public void checkMemberAccess(Class c, int memberType) + public void checkMemberAccess(Class<?> c, int memberType) { if (c == null) throw new NullPointerException(); Modified: trunk/core/src/classpath/java/java/lang/StrictMath.java =================================================================== --- trunk/core/src/classpath/java/java/lang/StrictMath.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/java/java/lang/StrictMath.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -1,5 +1,5 @@ /* java.lang.StrictMath -- common mathematical functions, strict Java - Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -633,6 +633,381 @@ } /** + * Returns the hyperbolic sine of <code>x</code> which is defined as + * (exp(x) - exp(-x)) / 2. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is negative + * infinity.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>sinh</em> + * @return the hyperbolic sine of <code>x</code> + * + * @since 1.5 + */ + public static double sinh(double x) + { + // Method : + // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + // 1. Replace x by |x| (sinh(-x) = -sinh(x)). + // 2. + // E + E/(E+1) + // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + // 2 + // + // 22 <= x <= lnovft : sinh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : sinh(x) := +inf (overflow) + + double t, w, h; + + long bits; + long h_bits; + long l_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + + if (x < 0) + h = - 0.5; + else + h = 0.5; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ignore sign + l_bits = getLowDWord(bits); + + // |x| in [0, 22], return sign(x) * 0.5 * (E+E/(E+1)) + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3e300000L) // |x| < 2^-28 + return x; // for tiny arguments return x + + t = expm1(abs(x)); + + if (h_bits < 0x3ff00000L) + return h * (2.0 * t - t * t / (t + 1.0)); + + return h * (t + t / (t + 1.0)); + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (h_bits < 0x40862e42L) + return h * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold] + if ((h_bits < 0x408633ceL) + || ((h_bits == 0x408633ceL) && (l_bits <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = h * w; + + return t * w; + } + + // |x| > overflowthershold + return h * Double.POSITIVE_INFINITY; + } + + /** + * Returns the hyperbolic cosine of <code>x</code>, which is defined as + * (exp(x) + exp(-x)) / 2. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is positive + * infinity.</li> + * <li>If the argument is zero, the result is one.</li> + * </ul> + * + * @param x the argument to <em>cosh</em> + * @return the hyperbolic cosine of <code>x</code> + * + * @since 1.5 + */ + public static double cosh(double x) + { + // Method : + // mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 + // 1. Replace x by |x| (cosh(x) = cosh(-x)). + // 2. + // [ exp(x) - 1 ]^2 + // 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- + // 2*exp(x) + // + // exp(x) + 1/exp(x) + // ln2/2 <= x <= 22 : cosh(x) := ------------------ + // 2 + // 22 <= x <= lnovft : cosh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : cosh(x) := +inf (overflow) + + double t, w; + long bits; + long hx; + long lx; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.POSITIVE_INFINITY; + + bits = Double.doubleToLongBits(x); + hx = getHighDWord(bits) & 0x7fffffffL; // ignore sign + lx = getLowDWord(bits); + + // |x| in [0, 0.5 * ln(2)], return 1 + expm1(|x|)^2 / (2 * exp(|x|)) + if (hx < 0x3fd62e43L) + { + t = expm1(abs(x)); + w = 1.0 + t; + + // for tiny arguments return 1. + if (hx < 0x3c800000L) + return w; + + return 1.0 + (t * t) / (w + w); + } + + // |x| in [0.5 * ln(2), 22], return exp(|x|)/2 + 1 / (2 * exp(|x|)) + if (hx < 0x40360000L) + { + t = exp(abs(x)); + + return 0.5 * t + 0.5 / t; + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (hx < 0x40862e42L) + return 0.5 * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold], + // return exp(x/2)/2 * exp(x/2) + if ((hx < 0x408633ceL) + || ((hx == 0x408633ceL) && (lx <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = 0.5 * w; + + return t * w; + } + + // |x| > overflowthreshold + return Double.POSITIVE_INFINITY; + } + + /** + * Returns the hyperbolic tangent of <code>x</code>, which is defined as + * (exp(x) - exp(-x)) / (exp(x) + exp(-x)), i.e. sinh(x) / cosh(x). + * + Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is 1.</li> + * <li>If the argument is negative infinity, the result is -1.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>tanh</em> + * @return the hyperbolic tagent of <code>x</code> + * + * @since 1.5 + */ + public static double tanh(double x) + { + // Method : + // 0. tanh(x) is defined to be (exp(x) - exp(-x)) / (exp(x) + exp(-x)) + // 1. reduce x to non-negative by tanh(-x) = -tanh(x). + // 2. 0 <= x <= 2^-55 : tanh(x) := x * (1.0 + x) + // -t + // 2^-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) + // t + 2 + // 2 + // 1 <= x <= 22.0 : tanh(x) := 1 - ----- ; t=expm1(2x) + // t + 2 + // 22.0 < x <= INF : tanh(x) := 1. + + double t, z; + + long bits; + long h_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return 1.0; + if (x == Double.NEGATIVE_INFINITY) + return -1.0; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ingnore sign + + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3c800000L) // |x| < 2^-55 + return x * (1.0 + x); + + if (h_bits >= 0x3ff00000L) // |x| >= 1 + { + t = expm1(2.0 * abs(x)); + z = 1.0 - 2.0 / (t + 2.0); + } + else // |x| < 1 + { + t = expm1(-2.0 * abs(x)); + z = -t / (t + 2.0); + } + } + else // |x| >= 22 + z = 1.0; + + return (x >= 0) ? z : -z; + } + + /** + * Returns the lower two words of a long. This is intended to be + * used like this: + * <code>getLowDWord(Double.doubleToLongBits(x))</code>. + */ + private static long getLowDWord(long x) + { + return x & 0x00000000ffffffffL; + } + + /** + * Returns the higher two words of a long. This is intended to be + * used like this: + * <code>getHighDWord(Double.doubleToLongBits(x))</code>. + */ + private static long getHighDWord(long x) + { + return (x & 0xffffffff00000000L) >> 32; + } + + /** + * Returns a double with the IEEE754 bit pattern given in the lower + * and higher two words <code>lowDWord</code> and <code>highDWord</code>. + */ + private static double buildDouble(long lowDWord, long highDWord) + { + return Double.longBitsToDouble(((highDWord & 0xffffffffL) << 32) + | (lowDWord & 0xffffffffL)); + } + + /** + * Returns the cube root of <code>x</code>. The sign of the cube root + * is equal to the sign of <code>x</code>. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is negative + * infinity.</li> + * <li>If the argument is zero, the result is zero with the same + * sign as the argument.</li> + * </ul> + * + * @param x the number to take the cube root of + * @return the cube root of <code>x</code> + * @see #sqrt(double) + * + * @since 1.5 + */ + public static double cbrt(double x) + { + boolean negative = (x < 0); + double r; + double s; + double t; + double w; + + long bits; + long l; + long h; + + // handle the special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + if (x == 0) + return x; + + x = abs(x); + bits = Double.doubleToLongBits(x); + + if (bits < 0x0010000000000000L) // subnormal number + { + t = TWO_54; + t *= x; + + // __HI(t)=__HI(t)/3+B2; + bits = Double.doubleToLongBits(t); + h = getHighDWord(bits); + l = getLowDWord(bits); + + h = h / 3 + CBRT_B2; + + t = buildDouble(l, h); + } + else + { + // __HI(t)=__HI(x)/3+B1; + h = getHighDWord(bits); + l = 0; + + h = h / 3 + CBRT_B1; + t = buildDouble(l, h); + } + + // new cbrt to 23 bits + r = t * t / x; + s = CBRT_C + r * t; + t *= CBRT_G + CBRT_F / (s + CBRT_E + CBRT_D / s); + + // chopped to 20 bits and make it larger than cbrt(x) + bits = Double.doubleToLongBits(t); + h = getHighDWord(bits); + + // __LO(t)=0; + // __HI(t)+=0x00000001; + l = 0; + h += 1; + t = buildDouble(l, h); + + // one step newton iteration to 53 bits with error less than 0.667 ulps + s = t * t; // t * t is exact + r = x / s; + w = t + t; + r = (r - t) / (w + r); // r - t is exact + t = t + t * r; + + return negative ? -t : t; + } + + /** * Take <em>e</em><sup>a</sup>. The opposite of <code>log()</code>. If the * argument is NaN, the result is NaN; if the argument is positive infinity, * the result is positive infinity; and if the argument is negative @@ -694,6 +1069,254 @@ } /** + * Returns <em>e</em><sup>x</sup> - 1. + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN.</li> + * <li>If the argument is positive infinity, the result is positive + * infinity</li> + * <li>If the argument is negative infinity, the result is -1.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>e</em><sup>x</sup> - 1. + * @return <em>e</em> raised to the power <code>x</code> minus one. + * @see #exp(double) + */ + public static double expm1(double x) + { + // Method + // 1. Argument reduction: + // Given x, find r and integer k such that + // + // x = k * ln(2) + r, |r| <= 0.5 * ln(2) + // + // Here a correction term c will be computed to compensate + // the error in r when rounded to a floating-point number. + // + // 2. Approximating expm1(r) by a special rational function on + // the interval [0, 0.5 * ln(2)]: + // Since + // r*(exp(r)+1)/(exp(r)-1) = 2 + r^2/6 - r^4/360 + ... + // we define R1(r*r) by + // r*(exp(r)+1)/(exp(r)-1) = 2 + r^2/6 * R1(r*r) + // That is, + // R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + // = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + // = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + // We use a special Remes algorithm on [0, 0.347] to generate + // a polynomial of degree 5 in r*r to approximate R1. The + // maximum error of this polynomial approximation is bounded + // by 2**-61. In other words, + // R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + // where Q1 = -1.6666666666666567384E-2, + // Q2 = 3.9682539681370365873E-4, + // Q3 = -9.9206344733435987357E-6, + // Q4 = 2.5051361420808517002E-7, + // Q5 = -6.2843505682382617102E-9; + // (where z=r*r, and Q1 to Q5 are called EXPM1_Qx in the source) + // with error bounded by + // | 5 | -61 + // | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + // | | + // + // expm1(r) = exp(r)-1 is then computed by the following + // specific way which minimize the accumulation rounding error: + // 2 3 + // r r [ 3 - (R1 + R1*r/2) ] + // expm1(r) = r + --- + --- * [--------------------] + // 2 2 [ 6 - r*(3 - R1*r/2) ] + // + // To compensate the error in the argument reduction, we use + // expm1(r+c) = expm1(r) + c + expm1(r)*c + // ~ expm1(r) + c + r*c + // Thus c+r*c will be added in as the correction terms for + // expm1(r+c). Now rearrange the term to avoid optimization + // screw up: + // ( 2 2 ) + // ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + // expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + // ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + // ( ) + // + // = r - E + // 3. Scale back to obtain expm1(x): + // From step 1, we have + // expm1(x) = either 2^k*[expm1(r)+1] - 1 + // = or 2^k*[expm1(r) + (1-2^-k)] + // 4. Implementation notes: + // (A). To save one multiplication, we scale the coefficient Qi + // to Qi*2^i, and replace z by (x^2)/2. + // (B). To achieve maximum accuracy, we compute expm1(x) by + // (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + // (ii) if k=0, return r-E + // (iii) if k=-1, return 0.5*(r-E)-0.5 + // (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + // else return 1.0+2.0*(r-E); + // (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + // (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + // (vii) return 2^k(1-((E+2^-k)-r)) + + boolean negative = (x < 0); + double y, hi, lo, c, t, e, hxs, hfx, r1; + int k; + + long bits; + long h_bits; + long l_bits; + + c = 0.0; + y = abs(x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + // handle special cases and large arguments + if (h_bits >= 0x4043687aL) // if |x| >= 56 * ln(2) + { + if (h_bits >= 0x40862e42L) // if |x| >= EXP_LIMIT_H + { + if (h_bits >= 0x7ff00000L) + { + if (((h_bits & 0x000fffffL) | (l_bits & 0xffffffffL)) != 0) + return x; // exp(NaN) = NaN + else + return negative ? -1.0 : x; // exp({+-inf}) = {+inf, -1} + } + + if (x > EXP_LIMIT_H) + return Double.POSITIVE_INFINITY; // overflow + } + + if (negative) // x <= -56 * ln(2) + return -1.0; + } + + // argument reduction + if (h_bits > 0x3fd62e42L) // |x| > 0.5 * ln(2) + { + if (h_bits < 0x3ff0a2b2L) // |x| < 1.5 * ln(2) + { + if (negative) + { + hi = x + LN2_H; + lo = -LN2_L; + k = -1; + } + else + { + hi = x - LN2_H; + lo = LN2_L; + k = 1; + } + } + else + { + k = (int) (INV_LN2 * x + (negative ? - 0.5 : 0.5)); + t = k; + hi = x - t * LN2_H; + lo = t * LN2_L; + } + + x = hi - lo; + c = (hi - x) - lo; + + } + else if (h_bits < 0x3c900000L) // |x| < 2^-54 return x + return x; + else + k = 0; + + // x is now in primary range + hfx = 0.5 * x; + hxs = x * hfx; + r1 = 1.0 + hxs * (EXPM1_Q1 + + hxs * (EXPM1_Q2 + + hxs * (EXPM1_Q3 + + hxs * (EXPM1_Q4 + + hxs * EXPM1_Q5)))); + t = 3.0 - r1 * hfx; + e = hxs * ((r1 - t) / (6.0 - x * t)); + + if (k == 0) + { + return x - (x * e - hxs); // c == 0 + } + else + { + e = x * (e - c) - c; + e -= hxs; + + if (k == -1) + return 0.5 * (x - e) - 0.5; + + if (k == 1) + { + if (x < - 0.25) + return -2.0 * (e - (x + 0.5)); + else + return 1.0 + 2.0 * (x - e); + } + + if (k <= -2 || k > 56) // sufficient to return exp(x) - 1 + { + y = 1.0 - (e - x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + + return y - 1.0; + } + + t = 1.0; + if (k < 20) + { + bits = Double.doubleToLongBits(t); + h_bits = 0x3ff00000L - (0x00200000L >> k); + l_bits = getLowDWord(bits); + + t = buildDouble(l_bits, h_bits); // t = 1 - 2^(-k) + y = t - (e - x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + } + else + { + bits = Double.doubleToLongBits(t); + h_bits = (0x000003ffL - k) << 20; + l_bits = getLowDWord(bits); + + t = buildDouble(l_bits, h_bits); // t = 2^(-k) + + y = x - (e + t); + y += 1.0; + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + } + } + + return y; + } + + /** * Take ln(a) (the natural log). The opposite of <code>exp()</code>. If the * argument is NaN or negative, the result is NaN; if the argument is * positive infinity, the result is positive infinity; and if the argument @@ -1429,6 +2052,33 @@ AT10 = 0.016285820115365782; // Long bits 0x3f90ad3ae322da11L. /** + * Constants for computing {@link #cbrt(double)}. + */ + private static final int + CBRT_B1 = 715094163, // B1 = (682-0.03306235651)*2**20 + CBRT_B2 = 696219795; // B2 = (664-0.03306235651)*2**20 + + /** + * Constants for computing {@link #cbrt(double)}. + */ + private static final double + CBRT_C = 5.42857142857142815906e-01, // Long bits 0x3fe15f15f15f15f1L + CBRT_D = -7.05306122448979611050e-01, // Long bits 0xbfe691de2532c834L + CBRT_E = 1.41428571428571436819e+00, // Long bits 0x3ff6a0ea0ea0ea0fL + CBRT_F = 1.60714285714285720630e+00, // Long bits 0x3ff9b6db6db6db6eL + CBRT_G = 3.57142857142857150787e-01; // Long bits 0x3fd6db6db6db6db7L + + /** + * Constants for computing {@link #expm1(double)} + */ + private static final double + EXPM1_Q1 = -3.33333333333331316428e-02, // Long bits 0xbfa11111111110f4L + EXPM1_Q2 = 1.58730158725481460165e-03, // Long bits 0x3f5a01a019fe5585L + EXPM1_Q3 = -7.93650757867487942473e-05, // Long bits 0xbf14ce199eaadbb7L + EXPM1_Q4 = 4.00821782732936239552e-06, // Long bits 0x3ed0cfca86e65239L + EXPM1_Q5 = -2.01099218183624371326e-07; // Long bits 0xbe8afdb76e09c32dL + + /** * Helper function for reducing an angle to a multiple of pi/2 within * [-pi/4, pi/4]. * @@ -1628,8 +2278,9 @@ j |= iq[i]; if (j == 0) // Need recomputation. { - int k; - for (k = 1; iq[jk - k] == 0; k++); // k = no. of terms needed. + int k; // k = no. of terms needed. + for (k = 1; iq[jk - k] == 0; k++) + ; for (i = jz + 1; i <= jz + k; i++) // Add q[jz+1] to q[jz+k]. { @@ -1841,4 +2492,84 @@ double t = (float) a; return t + a * (1 + t * z + t * v); } + + /** + * <p> + * Returns the sign of the argument as follows: + * </p> + * <ul> + * <li>If <code>a</code> is greater than zero, the result is 1.0.</li> + * <li>If <code>a</code> is less than zero, the result is -1.0.</li> + * <li>If <code>a</code> is <code>NaN</code>, the result is <code>NaN</code>. + * <li>If <code>a</code> is positive or negative zero, the result is the + * same.</li> + * </ul> + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static double signum(double a) + { + // There's no difference. + return Math.signum(a); } + + /** + * <p> + * Returns the sign of the argument as follows: + * </p> + * <ul> + * <li>If <code>a</code> is greater than zero, the result is 1.0f.</li> + * <li>If <code>a</code> is less than zero, the result is -1.0f.</li> + * <li>If <code>a</code> is <code>NaN</code>, the result is <code>NaN</code>. + * <li>If <code>a</code> is positive or negative zero, the result is the + * same.</li> + * </ul> + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static float signum(float a) + { + // There's no difference. + return Math.signum(a); + } + + /** + * Return the ulp for the given double argument. The ulp is the + * difference between the argument and the next larger double. Note + * that the sign of the double argument is ignored, that is, + * ulp(x) == ulp(-x). If the argument is a NaN, then NaN is returned. + * If the argument is an infinity, then +Inf is returned. If the + * argument is zero (either positive or negative), then + * {@link Double#MIN_VALUE} is returned. + * @param d the double whose ulp should be returned + * @return the difference between the argument and the next larger double + * @since 1.5 + */ + public static double ulp(double d) + { + // There's no difference. + return Math.ulp(d); + } + + /** + * Return the ulp for the given float argument. The ulp is the + * difference between the argument and the next larger float. Note + * that the sign of the float argument is ignored, that is, + * ulp(x) == ulp(-x). If the argument is a NaN, then NaN is returned. + * If the argument is an infinity, then +Inf is returned. If the + * argument is zero (either positive or negative), then + * {@link Float#MIN_VALUE} is returned. + * @param f the float whose ulp should be returned + * @return the difference between the argument and the next larger float + * @since 1.5 + */ + public static float ulp(float f) + { + // There's no difference. + return Math.ulp(f); + } +} Modified: trunk/core/src/classpath/java/java/lang/ThreadGroup.java =================================================================== --- trunk/core/src/classpath/java/java/lang/ThreadGroup.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/java/java/lang/ThreadGroup.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -37,6 +37,7 @@ package java.lang; +import java.lang.Thread.UncaughtExceptionHandler; import java.util.Vector; /** @@ -53,7 +54,7 @@ * @since 1.0 * @status updated to 1.4 */ -public class ThreadGroup +public class ThreadGroup implements UncaughtExceptionHandler { /** The Initial, top-level ThreadGroup. */ static ThreadGroup root = new ThreadGroup(); @@ -65,7 +66,7 @@ static boolean had_uncaught_exception; /** The parent thread group. */ - private final ThreadGroup parent; + final ThreadGroup parent; /** The group name, non-null. */ final String name; @@ -545,6 +546,8 @@ { if (parent != null) parent.uncaughtException(thread, t); + else if (Thread.getDefaultUncaughtExceptionHandler() != null) + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, t); else if (! (t instanceof ThreadDeath)) { if (t == null) @@ -746,4 +749,43 @@ parent.removeGroup(this); } } + + /* + * Helper method for the VM. Find a Thread by its Id. + * + * @param id The Thread Id. + * @return Thread object or null if thread doesn't exist. + */ + static Thread getThreadFromId(long id) + { + return root.getThreadFromIdImpl(id); + } + + private Thread getThreadFromIdImpl(long id) + { + synchronized (threads) + { + for (int i = 0; i < threads.size(); i++) + { + Thread t = (Thread) threads.get(i); + if (t.getId() == id) + return t; + } + } + Vector groups = this.groups; + if (groups != null) + { + synchronized (groups) + { + for (int i = 0; i < groups.size(); i++) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + Thread t = g.getThreadFromIdImpl(id); + if (t != null) + return t; + } + } + } + return null; + } } // class ThreadGroup Modified: trunk/core/src/classpath/vm/java/lang/Thread.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-27 21:37:48 UTC (rev 3094) +++ trunk/core/src/classpath/vm/java/lang/Thread.java 2007-01-27 21:52:45 UTC (rev 3095) @@ -1,21 +1,41 @@ /* Thread -- an independent thread of executable code Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; If not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ + Free Software Foundation +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + package java.lang; import java.util.Map; @@ -32,205 +52,270 @@ import org.jnode.vm.scheduler.VmProcessor; import org.jnode.vm.scheduler.VmThread; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete to version 1.4, with caveats. We do not + * implement the deprecated (and dangerous) stop, suspend, and resume + * methods. Security implementation is not complete. + */ + /** - * Kore implementation of the <code>java.lang.Thread</code> class. - * <p> - * All native methods are indirected through <code>java.lang.NativeLang</code>. - * - * @version Kore 0.0.3, June 1997 - * @author Glynn Clements <a href="mailto:gl...@se...">gl...@se... - * </a> - * @author E. Prangsma (connection to JNode) + * Thread represents a single thread of execution in the VM. When an + * application VM starts up, it creates a non-daemon Thread which calls the + * main() method of a particular class. There may be other Threads running, + * such as the garbage collection thread. + * + * <p>Threads have names to identify them. These names are not necessarily + * unique. Every Thread has a priority, as well, which tells the VM which + * Threads should get more running time. New threads inherit the priority + * and daemon status of the parent thread, by default. + * + * <p>There are two methods of creating a Thread: you may subclass Thread and + * implement the <code>run()</code> method, at which point you may start the + * Thread by calling its <code>start()</code> method, or you may implement + * <code>Runnable</code> in the class you want to use and then call new + * <code>Thread(your_obj).start()</code>. + * + * <p>The virtual machine runs until all non-daemon threads have died (either + * by returning from the run() method as invoked by start(), or by throwing + * an uncaught exception); or until <code>System.exit</code> is called with + * adequate permissions. + * + * <p>It is unclear at what point a Thread should be added to a ThreadGroup, + * and at what point it should be removed. Should it be inserted when it + * starts, or when it is created? Should it be removed when it is suspended + * or interrupted? The only thing that is clear is that the Thread should be + * removed when it is stopped. + * + * @author Tom Tromey + * @author John Keiser + * @author Eric Blake (eb...@em...) + * @author Andrew John Hughes (gnu...@me...) + * @see Runnable + * @see Runtime#exit(int) + * @see #run() + * @see #start() + * @see ThreadLocal + * @since 1.0 + * @status updated to 1.4 */ -public class Thread implements Runnable { +public class Thread implements Runnable +{ + /** The minimum priority for a Thread. */ + public static final int MIN_PRIORITY = 1; - /** - * Number of threads created. Used only for generating "unique" names. - * - * @see java.lang.Thread#autoName() + /** The priority a Thread gets by default. */ + public static final int NORM_PRIORITY = 5; + + /** The maximum priority for a Thread. */ + public static final int MAX_PRIORITY = 10; + + /** The VM thread implementing this thread */ + private final VmThread vmThread; + + /** The group this thread belongs to. + * */ - private static int count = 0; + ThreadGroup group; - private static final JNodePermission GETVMTHREAD_PERM = new JNodePermission( - "getVmThread"); + /** The object to run(), null if this is the target. */ + final Runnable runnable; - public final static int MAX_PRIORITY = 10; + /** The name of this thread */ + String name; - public final static int MIN_PRIORITY = 1; + /** Is this a daemon thread? */ + private boolean daemon; - public final static int NORM_PRIORITY = 5; + /** The context classloader of this thread */ + private ClassLoader contextClassLoader; + /** The thread in which I was created */ + private final Thread parent; + + /** The default exception handler. */ + private static UncaughtExceptionHandler defaultHandler; + /** Thread local storage. Package accessible for use by * InheritableThreadLocal. */ WeakHashMap locals; - /** - * Gets the active number of threads in the current thread's thread group. - * - * @return the active number of threads in the current thread's thread - * group. - */ - public static int activeCount() { - return currentThread().getThreadGroup().activeCount(); - } + /** The uncaught exception handler. */ + UncaughtExceptionHandler exceptionHandler; /** - * Generate a "unique" default name for a thread. + * Number of threads created. Used only for generating "unique" names. + * + * @see java.lang.Thread#autoName() */ - private static synchronized String autoName() { - return "Thread-" + (++count); - } + private static int count = 0; - /** - * Gets the current thread. - * - * @return - */ - public static Thread currentThread() { - VmThread current = VmThread.currentThread(); - if (current != null) { - return current.asThread(); - } else { - return null; - } - } + private static final JNodePermission GETVMTHREAD_PERM = new JNodePermission( + "getVmThread"); /** - * Prints a stack trace of the current thread. - */ - public static void dumpStack() { - new Exception("Stack trace").printStackTrace(); + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, null,</code> + * <i>gname</i><code>)</code>, where <b><i>gname</i></b> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. + * <p> + * Threads created this way must have overridden their + * <code>run()</code> method to actually do anything. An example + * illustrating this method being used follows: + * <p><blockquote><pre> + * import java.lang.*; + * + * class plain01 implements Runnable { + * String name; + * plain01() { + * name = null; + * } + * plain01(String s) { + * name = s; + * } + * public void run() { + * if (name == null) + * System.out.println("A new thread created"); + * else + * System.out.println("A new thread with name " + name + + * " created"); + * } + * } + * class threadtest01 { + * public static void main(String args[] ) { + * int failed = 0 ; + * + * <b>Thread t1 = new Thread();</b> + * if (t1 != null) + * System.out.println("new Thread() succeed"); + * else { + * System.out.println("new Thread() failed"); + * failed++; + * } + * } + * } + * </pre></blockquote> + * + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread() + { + this(null, null, autoName()); } - public static int enumerate(Thread[] threads) { - return currentThread().getThreadGroup().enumerate(threads); - } - /** - * Checks whether the current thread holds the monitor on a given object. - * This allows you to do <code>assert Thread.holdsLock(obj)</code>. + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, target,</code> + * <i>gname</i><code>)</code>, where <i>gname</i> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. * - * @param obj - * the object to test lock ownership on. - * @return true if the current thread is currently synchronized on obj - * @throws NullPointerException - * if obj is null - * @since 1.4 + * @param target the object whose <code>run</code> method is called. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) */ - public static boolean holdsLock(Object obj) { - return MonitorManager.holdsLock(obj); + public Thread(Runnable target) + { + this(null, target, autoName()); } /** - * Has the current thread been interrupted. - * The interrupted flag is cleared. - * @return + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, null, name)</code>. + * + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) */ - public static boolean interrupted() { - VmThread current = VmThread.currentThread(); - if (current != null) { - return current.isInterrupted(true); - } else { - return false; - } + public Thread(String name) + { + this(null, null, name); } - public static void sleep(long millis) throws InterruptedException { - sleep(millis, 0); - } - /** - * XXX needs to be synchronized to avoid losing interrupts? it checks and - * sets state, which should be protected... + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(group, target,</code> + * <i>gname</i><code>)</code>, where <i>gname</i> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) */ - public static void sleep(long millis, int nanos) - throws InterruptedException { - VmThread.currentThread().sleep(millis, nanos); + public Thread(ThreadGroup group, Runnable target) + { + this(group, target, autoName()); } - public static void yield() { - VmThread.yield(); - } - - /** The context classloader of this thread */ - private ClassLoader contextClassLoader; - - /** Is this a daemon thread? */ - private boolean daemon; - - /** The group this thread belongs to */ - ThreadGroup group; - - /** The name of this thread */ - String name; - - /** The thread in which I was created */ - private final Thread parent; - - /** A runnable target (if any) */ - private final Runnable target; - - /** The VM thread implementing this thread */ - private final VmThread vmThread; - /** - * Create a new default instance - * - * @see java.lang.Object#Object() + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(group, null, name)</code> + * + * @param group the group to put the Thread into + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) */ - public Thread() { - this(null, null, autoName()); + public Thread(ThreadGroup group, String name) + { + this(group, null, name); } /** - * Create a new instance with a runnable as thread runner. + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, target, name)</code>. * - * @param target + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @see #Thread(ThreadGroup, Runnable, String) */ - public Thread(Runnable target) { - this(null, target, autoName()); - } - - /** - * Create a new instance with a runnable as thread runner and a given name. - * - * @param target - * @param name - */ - public Thread(Runnable target, String name) { + public Thread(Runnable target, String name) + { this(null, target, name); } /** - * Create a new instance with a given name. + * Allocate a new Thread object, with the specified ThreadGroup and name, and + * using the specified Runnable object's <code>run()</code> method to + * execute. If the Runnable object is null, <code>this</code> (which is + * a Runnable) is used instead. * - * @param name + * <p>If the ThreadGroup is null, the security manager is checked. If a + * manager exists and returns a non-null object for + * <code>getThreadGroup</code>, that group is used; otherwise the group + * of the creating thread is used. Note that the security manager calls + * <code>checkAccess</code> if the ThreadGroup is not null. + * + * <p>The new Thread will inherit its creator's priority and daemon status. + * These can be changed with <code>setPriority</code> and + * <code>setDaemon</code>. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see Runnable#run() + * @see #run() + * @see #setDaemon(boolean) + * @see #setPriority(int) + * @see SecurityManager#checkAccess(ThreadGroup) + * @see ThreadGroup#checkAccess() */ - public Thread(String name) { - this(null, null, name); - } - - /** - * Create a new instance with a given group as containing group and a - * runnable as thread runner. - * - * @param group - * @param target - */ - public Thread(ThreadGroup group, Runnable target) { - this(group, target, autoName()); - } - - /** - * Create a new instance with a given group as containing group, a runnable - * as thread runner and a given name. - * - * @param group - * @param target - * @param name - */ - public Thread(ThreadGroup group, Runnable target, String name) { + public Thread(ThreadGroup group, Runnable target, String name) + { Thread current = currentThread(); if (group != null) { @@ -246,7 +331,7 @@ group.addThread(this); this.group = group; - this.target = target; + this.runnable = target; this.name = name; this.parent = current; @@ -296,7 +381,7 @@ group.addThread(this); this.group = group; - this.target = target; + this.runnable = target; this.name = name; this.parent = current; @@ -328,7 +413,7 @@ group.addThread(this); ... [truncated message content] |
From: <ls...@us...> - 2007-01-28 20:52:04
|
Revision: 3096 http://jnode.svn.sourceforge.net/jnode/?rev=3096&view=rev Author: lsantha Date: 2007-01-28 12:52:02 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/java/java/lang/reflect/Array.java Added Paths: ----------- trunk/core/src/classpath/vm/java/lang/reflect/VMArray.java Modified: trunk/core/src/classpath/java/java/lang/reflect/Array.java =================================================================== --- trunk/core/src/classpath/java/java/lang/reflect/Array.java 2007-01-27 21:52:45 UTC (rev 3095) +++ trunk/core/src/classpath/java/java/lang/reflect/Array.java 2007-01-28 20:52:02 UTC (rev 3096) @@ -35,19 +35,9 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ + package java.lang.reflect; -import org.jnode.vm.Vm; -import org.jnode.vm.memmgr.VmHeapManager; -import org.jnode.vm.classmgr.VmType; -import org.jnode.vm.classmgr.VmClassLoader; -import org.jnode.vm.classmgr.VmArrayClass; - -import gnu.java.security.action.InvokeAction; - -import java.security.AccessController; -import java.security.PrivilegedAction; - /** * Array holds static helper functions that allow you to create and * manipulate arrays by reflection. Operations know how to perform widening @@ -105,10 +95,10 @@ * @throws NegativeArraySizeException when length is less than 0 * @throws OutOfMemoryError if memory allocation fails */ - public static Object newInstance(Class componentType, int length) + public static Object newInstance(Class<?> componentType, int length) { - if (!componentType.isPrimitive()) - return createObjectArray(componentType, length); + if (! componentType.isPrimitive()) + return VMArray.createObjectArray(componentType, length); if (componentType == boolean.class) return new boolean[length]; if (componentType == byte.class) @@ -153,10 +143,10 @@ * than 0 * @throws OutOfMemoryError if memory allocation fails */ - public static Object newInstance(Class componentType, int[] dimensions) + public static Object newInstance(Class<?> componentType, int[] dimensions) { if (dimensions.length <= 0) - throw new IllegalArgumentException("Empty dimensions array."); + throw new IllegalArgumentException ("Empty dimensions array."); return createMultiArray(componentType, dimensions, dimensions.length - 1); } @@ -175,7 +165,7 @@ if (array instanceof boolean[]) return ((boolean[]) array).length; if (array instanceof byte[]) - return ((byte[]) array).length; + return ((byte[]) array). length; if (array instanceof char[]) return ((char[]) array).length; if (array instanceof short[]) @@ -654,7 +644,7 @@ Object toAdd = createMultiArray(type, dimensions, index - 1); Class thisType = toAdd.getClass(); Object[] retval - = (Object[]) createObjectArray(thisType, dimensions[index]); + = (Object[]) VMArray.createObjectArray(thisType, dimensions[index]); if (dimensions[index] > 0) retval[0] = toAdd; int i = dimensions[index]; @@ -663,49 +653,4 @@ return retval; } - - // LS - // @classpath-bugfix-22923 should be placed in VMArray - /** - * Dynamically create an array of objects. - * - * @param type guaranteed to be a valid object type - * @param dim the length of the array - * @return the new array - * @throws NegativeArraySizeException if dim is negative - * @throws OutOfMemoryError if memory allocation fails - */ - private static Object createObjectArray(final Class type, int dim) { - final VmType vmClass = (VmType) AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return type.getVmClass(); - } - }); - - final String arrClsName = vmClass.getArrayClassName(); - final VmType arrCls; - try { - final VmClassLoader curLoader = vmClass.getLoader(); - arrCls = curLoader.loadClass(arrClsName, true); - //Screen.debug("an cls{"); - //Screen.debug(vmClass.getName()); - if (arrCls == null) { - throw new NoClassDefFoundError(arrClsName); - } - } catch (ClassNotFoundException ex) { - throw new NoClassDefFoundError(arrClsName); - } - - VmHeapManager hm = heapManager; - if (hm == null) { - heapManager = hm = Vm.getVm().getHeapManager(); - } - final Object result = hm.newArray((VmArrayClass) arrCls, dim); - - //Screen.debug("}"); - return result; - } - private static VmHeapManager heapManager; - // @classpath-bugfix-end } Added: trunk/core/src/classpath/vm/java/lang/reflect/VMArray.java =================================================================== --- trunk/core/src/classpath/vm/java/lang/reflect/VMArray.java (rev 0) +++ trunk/core/src/classpath/vm/java/lang/reflect/VMArray.java 2007-01-28 20:52:02 UTC (rev 3096) @@ -0,0 +1,91 @@ +/* java.lang.reflect.VMArray - VM class for array manipulation by reflection. + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +import gnu.classpath.Configuration; +import org.jnode.vm.classmgr.VmType; +import org.jnode.vm.classmgr.VmClassLoader; +import org.jnode.vm.classmgr.VmArrayClass; +import org.jnode.vm.Vm; +import java.security.AccessController; +import java.security.PrivilegedAction; + +class VMArray +{ + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalangreflect"); + } + } + + /** + * Dynamically create an array of objects. + * + * @param type guaranteed to be a valid object type + * @param dim the length of the array + * @return the new array + * @throws NegativeArraySizeException if dim is negative + * @throws OutOfMemoryError if memory allocation fails + */ + static Object createObjectArray(final Class type, int dim) { + final VmType vmClass = AccessController.doPrivileged( + new PrivilegedAction<VmType>() { + public VmType run() { + return type.getVmClass(); + } + }); + + final String arrClsName = vmClass.getArrayClassName(); + final VmType arrCls; + try { + final VmClassLoader curLoader = vmClass.getLoader(); + arrCls = curLoader.loadClass(arrClsName, true); + if (arrCls == null) { + throw new NoClassDefFoundError(arrClsName); + } + } catch (ClassNotFoundException ex) { + throw new NoClassDefFoundError(arrClsName); + } + + return Vm.getHeapManager().newArray((VmArrayClass) arrCls, dim); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |