diff options
Diffstat (limited to 'libjava/java/lang')
239 files changed, 38943 insertions, 0 deletions
diff --git a/libjava/java/lang/AbstractMethodError.h b/libjava/java/lang/AbstractMethodError.h new file mode 100644 index 000000000..92a757da2 --- /dev/null +++ b/libjava/java/lang/AbstractMethodError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_AbstractMethodError__ +#define __java_lang_AbstractMethodError__ + +#pragma interface + +#include <java/lang/IncompatibleClassChangeError.h> + +class java::lang::AbstractMethodError : public ::java::lang::IncompatibleClassChangeError +{ + +public: + AbstractMethodError(); + AbstractMethodError(::java::lang::String *); +private: + static const jlong serialVersionUID = -1654391082989018462LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_AbstractMethodError__ diff --git a/libjava/java/lang/AbstractStringBuffer.h b/libjava/java/lang/AbstractStringBuffer.h new file mode 100644 index 000000000..256004c24 --- /dev/null +++ b/libjava/java/lang/AbstractStringBuffer.h @@ -0,0 +1,85 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_AbstractStringBuffer__ +#define __java_lang_AbstractStringBuffer__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::AbstractStringBuffer : public ::java::lang::Object +{ + +public: // actually package-private + AbstractStringBuffer(); + AbstractStringBuffer(jint); + AbstractStringBuffer(::java::lang::String *); + AbstractStringBuffer(::java::lang::CharSequence *); +public: + virtual void ensureCapacity(jint); + virtual void setLength(jint); + virtual jchar charAt(jint); + virtual jint codePointAt(jint); + virtual jint codePointBefore(jint); + virtual void getChars(jint, jint, JArray< jchar > *, jint); + virtual void setCharAt(jint, jchar); + virtual ::java::lang::AbstractStringBuffer * append(::java::lang::Object *); + virtual ::java::lang::AbstractStringBuffer * append(::java::lang::String *); + virtual ::java::lang::AbstractStringBuffer * append(::java::lang::StringBuffer *); + virtual ::java::lang::AbstractStringBuffer * append(JArray< jchar > *); + virtual ::java::lang::AbstractStringBuffer * append(JArray< jchar > *, jint, jint); + virtual ::java::lang::AbstractStringBuffer * append(jboolean); + virtual ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(jchar); + virtual ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *); + virtual ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *, jint, jint); + virtual ::java::lang::AbstractStringBuffer * append(jint); + virtual ::java::lang::AbstractStringBuffer * append(jlong); + virtual ::java::lang::AbstractStringBuffer * append(jfloat); + virtual ::java::lang::AbstractStringBuffer * append(jdouble); + virtual ::java::lang::AbstractStringBuffer * appendCodePoint(jint); + virtual ::java::lang::AbstractStringBuffer * delete$(jint, jint); + virtual ::java::lang::AbstractStringBuffer * deleteCharAt(jint); + virtual ::java::lang::AbstractStringBuffer * replace(jint, jint, ::java::lang::String *); + virtual ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *, jint, jint); + virtual ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::Object *); + virtual ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::String *); + virtual ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *); + virtual ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *, jint, jint); + virtual ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jboolean); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jchar); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jint); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jlong); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jfloat); + virtual ::java::lang::AbstractStringBuffer * insert(jint, jdouble); + virtual jint indexOf(::java::lang::String *); + virtual jint indexOf(::java::lang::String *, jint); + virtual jint lastIndexOf(::java::lang::String *); + virtual jint lastIndexOf(::java::lang::String *, jint); + virtual ::java::lang::AbstractStringBuffer * reverse(); + virtual void trimToSize(); + virtual jint codePointCount(jint, jint); + virtual jint offsetByCodePoints(jint, jint); +public: // actually package-private + virtual void ensureCapacity_unsynchronized(jint); +private: + jboolean regionMatches(jint, ::java::lang::String *); +public: + virtual ::java::lang::Appendable * append(::java::lang::CharSequence *, jint, jint); + virtual ::java::lang::Appendable * append(::java::lang::CharSequence *); + virtual ::java::lang::Appendable * append(jchar); + virtual jint length() = 0; + virtual ::java::lang::CharSequence * subSequence(jint, jint) = 0; +public: // actually package-private + jint __attribute__((aligned(__alignof__( ::java::lang::Object)))) count; + JArray< jchar > * value; +private: + static const jint DEFAULT_CAPACITY = 16; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_AbstractStringBuffer__ diff --git a/libjava/java/lang/AbstractStringBuffer.java b/libjava/java/lang/AbstractStringBuffer.java new file mode 100644 index 000000000..fe128b8af --- /dev/null +++ b/libjava/java/lang/AbstractStringBuffer.java @@ -0,0 +1,1027 @@ +/* AbstractStringBuffer.java -- Growable strings + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 + 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.Serializable; + +/** + * This class is based on gnu.classpath.ClasspathStringBuffer but + * is package-private to java.lang so it can be used as the basis + * for StringBuffer and StringBuilder. + * If you modify this, please consider also modifying that code. + */ +abstract class AbstractStringBuffer + implements Serializable, CharSequence, Appendable +{ + + /** + * Index of next available character (and thus the size of the current + * string contents). Note that this has permissions set this way so that + * String can get the value. + * + * @serial the number of characters in the buffer + */ + int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + char[] value; + + /** + * The default capacity of a buffer. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * Create a new AbstractStringBuffer with default capacity 16. + */ + AbstractStringBuffer() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty <code>StringBuffer</code> with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + AbstractStringBuffer(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new <code>StringBuffer</code> with the characters in the + * specified <code>String</code>. Initial capacity will be the size of the + * String plus 16. + * + * @param str the <code>String</code> to convert + * @throws NullPointerException if str is null + */ + AbstractStringBuffer(String str) + { + count = str.count; + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new <code>StringBuffer</code> with the characters in the + * specified <code>CharSequence</code>. Initial capacity will be the + * 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 seq the initializing <code>CharSequence</code> + * @throws NullPointerException if str is null + * @since 1.5 + */ + AbstractStringBuffer(CharSequence seq) + { + int len = seq.length(); + count = len <= 0 ? 0 : len; + value = new char[count + DEFAULT_CAPACITY]; + for (int i = 0; i < len; ++i) + value[i] = seq.charAt(i); + } + + /** + * Increase the capacity of this <code>StringBuffer</code>. This will + * ensure that an expensive growing operation will not occur until + * <code>minimumCapacity</code> is reached. The buffer is grown to the + * larger of <code>minimumCapacity</code> and + * <code>capacity() * 2 + 2</code>, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public void ensureCapacity(int minimumCapacity) + { + ensureCapacity_unsynchronized(minimumCapacity); + } + + /** + * Set the length of this StringBuffer. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first <code>newLength</code> + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity_unsynchronized in order to preserve + copy-on-write semantics. */ + ensureCapacity_unsynchronized(newLength); + + if (newLength < valueLength) + { + /* If the StringBuffer's value just grew, then we know that + value is newly allocated and the region between count and + newLength is filled with '\0'. */ + count = newLength; + } + else + { + /* The StringBuffer's value doesn't need to grow. However, + we should clear out any cruft that may exist. */ + while (count < newLength) + value[count++] = '\0'; + } + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointAt(int index) + { + return Character.codePointAt(value, index, count); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at <code>index-1</code> and + * <code>index-2</code> to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointBefore(int index) + { + // Character.codePointBefore() doesn't perform this check. We + // could use the CharSequence overload, but this is just as easy. + if (index >= count) + throw new IndexOutOfBoundsException(); + return Character.codePointBefore(value, index, 1); + } + + /** + * Get the specified array of characters. <code>srcOffset - srcEnd</code> + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(count); + value[index] = ch; + } + + /** + * 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>. + * + * @param obj the <code>Object</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(Object) + * @see #append(String) + */ + public AbstractStringBuffer append(Object obj) + { + return append(String.valueOf(obj)); + } + + /** + * Append the <code>String</code> to this <code>StringBuffer</code>. If + * str is null, the String "null" is appended. + * + * @param str the <code>String</code> to append + * @return this <code>StringBuffer</code> + */ + public AbstractStringBuffer append(String str) + { + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the <code>StringBuilder</code> value of the argument to this + * <code>StringBuilder</code>. This behaves the same as + * <code>append((Object) stringBuffer)</code>, except it is more efficient. + * + * @param stringBuffer the <code>StringBuilder</code> to convert and append + * @return this <code>StringBuilder</code> + * @see #append(Object) + */ + public AbstractStringBuffer append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.count; + ensureCapacity(count + len); + System.arraycopy(stringBuffer.value, 0, value, count, len); + count += len; + } + 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. + * + * @param data the <code>char[]</code> to append + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @see #append(char[], int, int) + */ + public AbstractStringBuffer append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the <code>char</code> array to this + * <code>StringBuffer</code>. This is similar (but more efficient) than + * <code>append(new String(data, offset, count))</code>, except in the case + * of null. + * + * @param data the <code>char[]</code> to append + * @param offset the start location in <code>str</code> + * @param count the number of characters to get from <code>str</code> + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public AbstractStringBuffer append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity_unsynchronized(this.count + count); + System.arraycopy(data, offset, value, this.count, count); + this.count += count; + 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>. + * + * @param bool the <code>boolean</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(boolean) + */ + public AbstractStringBuffer append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the <code>char</code> to this <code>StringBuffer</code>. + * + * @param ch the <code>char</code> to append + * @return this <code>StringBuffer</code> + */ + public AbstractStringBuffer append(char ch) + { + ensureCapacity_unsynchronized(count + 1); + value[count++] = ch; + return this; + } + + /** + * Append the characters in the <code>CharSequence</code> to this + * buffer. + * + * @param seq the <code>CharSequence</code> providing the characters + * @return this <code>StringBuffer</code> + * @since 1.5 + */ + public AbstractStringBuffer append(CharSequence seq) + { + return append(seq, 0, seq.length()); + } + + /** + * Append some characters from the <code>CharSequence</code> to this + * buffer. If the argument is null, the <code>seq</code> is assumed + * to be equal to the string <code>"null"</code>. + * + * @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 AbstractStringBuffer append(CharSequence seq, int start, int end) + { + if (seq == null) + seq = "null"; + if (end - start > 0) + { + ensureCapacity_unsynchronized(count + end - start); + for (; start < end; ++start) + value[count++] = seq.charAt(start); + } + 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>. + * + * @param inum the <code>int</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(int) + */ + // GCJ LOCAL: this is native for efficiency. + public native AbstractStringBuffer append (int inum); + + /** + * 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>. + * + * @param lnum the <code>long</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(long) + */ + public AbstractStringBuffer append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * 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>. + * + * @param fnum the <code>float</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(float) + */ + public AbstractStringBuffer append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * 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>. + * + * @param dnum the <code>double</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(double) + */ + public AbstractStringBuffer append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * 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 AbstractStringBuffer appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity_unsynchronized(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** + * Delete characters from this <code>StringBuffer</code>. + * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @since 1.2 + */ + public AbstractStringBuffer delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + ensureCapacity_unsynchronized(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this <code>StringBuffer</code>. + * + * @param index the index of the character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if index is out of bounds + * @since 1.2 + */ + public AbstractStringBuffer deleteCharAt(int index) + { + return delete(index, index + 1); + } + + /** + * Replace characters between index <code>start</code> (inclusive) and + * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> + * is larger than the size of this StringBuffer, all characters after + * <code>start</code> are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + * @since 1.2 + */ + public AbstractStringBuffer replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.count; + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity_unsynchronized(count + delta); + + if (delta != 0 && end < count) + System.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Insert a subarray of the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param str the <code>char[]</code> to insert + * @param str_offset the index in <code>str</code> to start inserting from + * @param len the number of characters to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if any index is out of bounds + * @since 1.2 + */ + public AbstractStringBuffer insert(int offset, char[] str, int str_offset, int len) + { + if (offset < 0 || offset > count || len < 0 + || str_offset < 0 || str_offset > str.length - len) + throw new StringIndexOutOfBoundsException(); + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + System.arraycopy(str, str_offset, value, offset, len); + count += len; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param obj the <code>Object</code> to convert and insert + * @return this <code>StringBuffer</code> + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public AbstractStringBuffer insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the <code>String</code> argument into this + * <code>StringBuffer</code>. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public AbstractStringBuffer insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset is out of bounds + * @since 1.5 + */ + public AbstractStringBuffer insert(int offset, CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return insert(offset, sequence, 0, sequence.length()); + } + + /** + * Insert a subsequence of the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + * @since 1.5 + */ + public AbstractStringBuffer insert(int offset, CharSequence sequence, int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + int len = end - start; + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + for (int i = start; i < end; ++i) + value[offset++] = sequence.charAt(i); + count += len; + return this; + } + + /** + * Insert the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param data the <code>char[]</code> to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>data</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public AbstractStringBuffer insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param bool the <code>boolean</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public AbstractStringBuffer insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the <code>char</code> argument into this <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param ch the <code>char</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public AbstractStringBuffer insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity_unsynchronized(count + 1); + System.arraycopy(value, offset, value, offset + 1, count - offset); + value[offset] = ch; + count++; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param inum the <code>int</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public AbstractStringBuffer insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param lnum the <code>long</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public AbstractStringBuffer insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param fnum the <code>float</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public AbstractStringBuffer insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param dnum the <code>double</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public AbstractStringBuffer insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first instance of a substring in this StringBuilder. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuffer, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + * @since 1.4 + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this StringBuffer, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuffer. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this <code>StringBuffer</code> + */ + public AbstractStringBuffer reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(count); + for (int i = count >> 1, j = count - i; --i >= 0; ++j) + { + char c = value[i]; + value[i] = value[j]; + value[j] = c; + } + return this; + } + + /** + * This may reduce the amount of memory used by the StringBuffer, + * by resizing the internal array to remove unused space. However, + * this method is not required to resize, so this behavior cannot + * be relied upon. + * @since 1.5 + */ + public void trimToSize() + { + int wouldSave = value.length - count; + // Some random heuristics: if we save less than 20 characters, who + // cares. + if (wouldSave < 20) + return; + // If we save more than 200 characters, shrink. + // If we save more than 1/4 of the buffer, shrink. + if (wouldSave > 200 || wouldSave * 4 > value.length) + { + char[] newValue = new char[count]; + System.arraycopy(value, 0, newValue, 0, count); + value = newValue; + } + } + + /** + * Return the number of code points between two indices in the + * <code>StringBuffer</code>. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public int codePointCount(int start, int end) + { + if (start < 0 || end >= count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Starting at the given index, this counts forward by the indicated + * number of code points, and then returns the resulting index. An + * unpaired surrogate counts as a single code point for this + * purpose. + * + * @param start the starting index + * @param codePoints the number of code points + * @return the resulting index + * @since 1.5 + */ + public int offsetByCodePoints(int start, int codePoints) + { + while (codePoints > 0) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + --codePoints; + } + return start; + } + + /** + * Increase the capacity of this <code>StringBuilder</code>. This will + * ensure that an expensive growing operation will not occur until + * <code>minimumCapacity</code> is reached. The buffer is grown to the + * larger of <code>minimumCapacity</code> and + * <code>capacity() * 2 + 2</code>, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + void ensureCapacity_unsynchronized(int minimumCapacity) + { + if (minimumCapacity > value.length) + { + int max = value.length * 2 + 2; + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + } + } + + /** + * Predicate which determines if a substring of this matches another String + * starting at a specified offset for each String and continuing for a + * specified length. This is more efficient than creating a String to call + * indexOf on. + * + * @param toffset index to start comparison at for this String + * @param other non-null String to compare to region of this + * @return true if regions match, false otherwise + * @see #indexOf(String, int) + * @see #lastIndexOf(String, int) + * @see String#regionMatches(boolean, int, String, int, int) + */ + // GCJ LOCAL: native for gcj. + private native boolean regionMatches(int toffset, String other); + +} diff --git a/libjava/java/lang/Appendable.h b/libjava/java/lang/Appendable.h new file mode 100644 index 000000000..d304ff9cf --- /dev/null +++ b/libjava/java/lang/Appendable.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Appendable__ +#define __java_lang_Appendable__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Appendable : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Appendable * append(jchar) = 0; + virtual ::java::lang::Appendable * append(::java::lang::CharSequence *) = 0; + virtual ::java::lang::Appendable * append(::java::lang::CharSequence *, jint, jint) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Appendable__ diff --git a/libjava/java/lang/ArithmeticException.h b/libjava/java/lang/ArithmeticException.h new file mode 100644 index 000000000..8d784adb7 --- /dev/null +++ b/libjava/java/lang/ArithmeticException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ArithmeticException__ +#define __java_lang_ArithmeticException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::ArithmeticException : public ::java::lang::RuntimeException +{ + +public: + ArithmeticException(); + ArithmeticException(::java::lang::String *); +private: + static const jlong serialVersionUID = 2256477558314496007LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ArithmeticException__ diff --git a/libjava/java/lang/ArrayIndexOutOfBoundsException.h b/libjava/java/lang/ArrayIndexOutOfBoundsException.h new file mode 100644 index 000000000..8e65f70f7 --- /dev/null +++ b/libjava/java/lang/ArrayIndexOutOfBoundsException.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ArrayIndexOutOfBoundsException__ +#define __java_lang_ArrayIndexOutOfBoundsException__ + +#pragma interface + +#include <java/lang/IndexOutOfBoundsException.h> + +class java::lang::ArrayIndexOutOfBoundsException : public ::java::lang::IndexOutOfBoundsException +{ + +public: + ArrayIndexOutOfBoundsException(); + ArrayIndexOutOfBoundsException(::java::lang::String *); + ArrayIndexOutOfBoundsException(jint); +private: + static const jlong serialVersionUID = -5116101128118950844LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ArrayIndexOutOfBoundsException__ diff --git a/libjava/java/lang/ArrayStoreException.h b/libjava/java/lang/ArrayStoreException.h new file mode 100644 index 000000000..8e120d11c --- /dev/null +++ b/libjava/java/lang/ArrayStoreException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ArrayStoreException__ +#define __java_lang_ArrayStoreException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::ArrayStoreException : public ::java::lang::RuntimeException +{ + +public: + ArrayStoreException(); + ArrayStoreException(::java::lang::String *); +private: + static const jlong serialVersionUID = -4522193890499838241LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ArrayStoreException__ diff --git a/libjava/java/lang/AssertionError.h b/libjava/java/lang/AssertionError.h new file mode 100644 index 000000000..0154c04b3 --- /dev/null +++ b/libjava/java/lang/AssertionError.h @@ -0,0 +1,29 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_AssertionError__ +#define __java_lang_AssertionError__ + +#pragma interface + +#include <java/lang/Error.h> + +class java::lang::AssertionError : public ::java::lang::Error +{ + +public: + AssertionError(); + AssertionError(::java::lang::Object *); + AssertionError(jboolean); + AssertionError(jchar); + AssertionError(jint); + AssertionError(jlong); + AssertionError(jfloat); + AssertionError(jdouble); +private: + static const jlong serialVersionUID = -5013299493970297370LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_AssertionError__ diff --git a/libjava/java/lang/Boolean.h b/libjava/java/lang/Boolean.h new file mode 100644 index 000000000..0ead5b527 --- /dev/null +++ b/libjava/java/lang/Boolean.h @@ -0,0 +1,40 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Boolean__ +#define __java_lang_Boolean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Boolean : public ::java::lang::Object +{ + +public: + Boolean(jboolean); + Boolean(::java::lang::String *); + jboolean booleanValue(); + static ::java::lang::Boolean * valueOf(jboolean); + static ::java::lang::Boolean * valueOf(::java::lang::String *); + static ::java::lang::String * toString(jboolean); + ::java::lang::String * toString(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + static jboolean getBoolean(::java::lang::String *); + jint Boolean$compareTo(::java::lang::Boolean *); + static jboolean parseBoolean(::java::lang::String *); + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -3665804199014368530LL; +public: + static ::java::lang::Boolean * TRUE; + static ::java::lang::Boolean * FALSE; + static ::java::lang::Class * TYPE; +private: + jboolean __attribute__((aligned(__alignof__( ::java::lang::Object)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Boolean__ diff --git a/libjava/java/lang/Byte.h b/libjava/java/lang/Byte.h new file mode 100644 index 000000000..fc9e3b33f --- /dev/null +++ b/libjava/java/lang/Byte.h @@ -0,0 +1,51 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Byte__ +#define __java_lang_Byte__ + +#pragma interface + +#include <java/lang/Number.h> +#include <gcj/array.h> + + +class java::lang::Byte : public ::java::lang::Number +{ + +public: + Byte(jbyte); + Byte(::java::lang::String *); + static ::java::lang::String * toString(jbyte); + static jbyte parseByte(::java::lang::String *); + static jbyte parseByte(::java::lang::String *, jint); + static ::java::lang::Byte * valueOf(::java::lang::String *, jint); + static ::java::lang::Byte * valueOf(::java::lang::String *); + static ::java::lang::Byte * valueOf(jbyte); + static ::java::lang::Byte * decode(::java::lang::String *); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + ::java::lang::String * toString(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + jint Byte$compareTo(::java::lang::Byte *); + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -7183698231559129828LL; +public: + static const jbyte MIN_VALUE = -128; + static const jbyte MAX_VALUE = 127; + static ::java::lang::Class * TYPE; + static const jint SIZE = 8; +private: + static JArray< ::java::lang::Byte * > * byteCache; + jbyte __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Byte__ diff --git a/libjava/java/lang/CharSequence.h b/libjava/java/lang/CharSequence.h new file mode 100644 index 000000000..1348b564d --- /dev/null +++ b/libjava/java/lang/CharSequence.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_CharSequence__ +#define __java_lang_CharSequence__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::CharSequence : public ::java::lang::Object +{ + +public: + virtual jchar charAt(jint) = 0; + virtual jint length() = 0; + virtual ::java::lang::CharSequence * subSequence(jint, jint) = 0; + virtual ::java::lang::String * toString() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_CharSequence__ diff --git a/libjava/java/lang/Character$Subset.h b/libjava/java/lang/Character$Subset.h new file mode 100644 index 000000000..93f2ba1cb --- /dev/null +++ b/libjava/java/lang/Character$Subset.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Character$Subset__ +#define __java_lang_Character$Subset__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Character$Subset : public ::java::lang::Object +{ + +public: // actually protected + Character$Subset(::java::lang::String *); +public: + virtual jboolean equals(::java::lang::Object *); + virtual jint hashCode(); + virtual ::java::lang::String * toString(); +private: + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) name; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Character$Subset__ diff --git a/libjava/java/lang/Character$UnicodeBlock$NameType.h b/libjava/java/lang/Character$UnicodeBlock$NameType.h new file mode 100644 index 000000000..2b83115b0 --- /dev/null +++ b/libjava/java/lang/Character$UnicodeBlock$NameType.h @@ -0,0 +1,29 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Character$UnicodeBlock$NameType__ +#define __java_lang_Character$UnicodeBlock$NameType__ + +#pragma interface + +#include <java/lang/Enum.h> +#include <gcj/array.h> + + +class java::lang::Character$UnicodeBlock$NameType : public ::java::lang::Enum +{ + + Character$UnicodeBlock$NameType(::java::lang::String *, jint); +public: + static JArray< ::java::lang::Character$UnicodeBlock$NameType * > * values(); + static ::java::lang::Character$UnicodeBlock$NameType * valueOf(::java::lang::String *); + static ::java::lang::Character$UnicodeBlock$NameType * CANONICAL; + static ::java::lang::Character$UnicodeBlock$NameType * NO_SPACES; + static ::java::lang::Character$UnicodeBlock$NameType * CONSTANT; +private: + static JArray< ::java::lang::Character$UnicodeBlock$NameType * > * ENUM$VALUES; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Character$UnicodeBlock$NameType__ diff --git a/libjava/java/lang/Character$UnicodeBlock.h b/libjava/java/lang/Character$UnicodeBlock.h new file mode 100644 index 000000000..b32f2121e --- /dev/null +++ b/libjava/java/lang/Character$UnicodeBlock.h @@ -0,0 +1,161 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Character$UnicodeBlock__ +#define __java_lang_Character$UnicodeBlock__ + +#pragma interface + +#include <java/lang/Character$Subset.h> +#include <gcj/array.h> + + +class java::lang::Character$UnicodeBlock : public ::java::lang::Character$Subset +{ + + Character$UnicodeBlock(jint, jint, ::java::lang::String *, ::java::lang::String *); +public: + static ::java::lang::Character$UnicodeBlock * of(jchar); + static ::java::lang::Character$UnicodeBlock * of(jint); + static ::java::lang::Character$UnicodeBlock * forName(::java::lang::String *); +public: // actually package-private + static JArray< jint > * $SWITCH_TABLE$java$lang$Character$UnicodeBlock$NameType(); +private: + jint __attribute__((aligned(__alignof__( ::java::lang::Character$Subset)))) start; + jint end; + ::java::lang::String * canonicalName; +public: + static ::java::lang::Character$UnicodeBlock * BASIC_LATIN; + static ::java::lang::Character$UnicodeBlock * LATIN_1_SUPPLEMENT; + static ::java::lang::Character$UnicodeBlock * LATIN_EXTENDED_A; + static ::java::lang::Character$UnicodeBlock * LATIN_EXTENDED_B; + static ::java::lang::Character$UnicodeBlock * IPA_EXTENSIONS; + static ::java::lang::Character$UnicodeBlock * SPACING_MODIFIER_LETTERS; + static ::java::lang::Character$UnicodeBlock * COMBINING_DIACRITICAL_MARKS; + static ::java::lang::Character$UnicodeBlock * GREEK; + static ::java::lang::Character$UnicodeBlock * CYRILLIC; + static ::java::lang::Character$UnicodeBlock * CYRILLIC_SUPPLEMENTARY; + static ::java::lang::Character$UnicodeBlock * ARMENIAN; + static ::java::lang::Character$UnicodeBlock * HEBREW; + static ::java::lang::Character$UnicodeBlock * ARABIC; + static ::java::lang::Character$UnicodeBlock * SYRIAC; + static ::java::lang::Character$UnicodeBlock * THAANA; + static ::java::lang::Character$UnicodeBlock * DEVANAGARI; + static ::java::lang::Character$UnicodeBlock * BENGALI; + static ::java::lang::Character$UnicodeBlock * GURMUKHI; + static ::java::lang::Character$UnicodeBlock * GUJARATI; + static ::java::lang::Character$UnicodeBlock * ORIYA; + static ::java::lang::Character$UnicodeBlock * TAMIL; + static ::java::lang::Character$UnicodeBlock * TELUGU; + static ::java::lang::Character$UnicodeBlock * KANNADA; + static ::java::lang::Character$UnicodeBlock * MALAYALAM; + static ::java::lang::Character$UnicodeBlock * SINHALA; + static ::java::lang::Character$UnicodeBlock * THAI; + static ::java::lang::Character$UnicodeBlock * LAO; + static ::java::lang::Character$UnicodeBlock * TIBETAN; + static ::java::lang::Character$UnicodeBlock * MYANMAR; + static ::java::lang::Character$UnicodeBlock * GEORGIAN; + static ::java::lang::Character$UnicodeBlock * HANGUL_JAMO; + static ::java::lang::Character$UnicodeBlock * ETHIOPIC; + static ::java::lang::Character$UnicodeBlock * CHEROKEE; + static ::java::lang::Character$UnicodeBlock * UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS; + static ::java::lang::Character$UnicodeBlock * OGHAM; + static ::java::lang::Character$UnicodeBlock * RUNIC; + static ::java::lang::Character$UnicodeBlock * TAGALOG; + static ::java::lang::Character$UnicodeBlock * HANUNOO; + static ::java::lang::Character$UnicodeBlock * BUHID; + static ::java::lang::Character$UnicodeBlock * TAGBANWA; + static ::java::lang::Character$UnicodeBlock * KHMER; + static ::java::lang::Character$UnicodeBlock * MONGOLIAN; + static ::java::lang::Character$UnicodeBlock * LIMBU; + static ::java::lang::Character$UnicodeBlock * TAI_LE; + static ::java::lang::Character$UnicodeBlock * KHMER_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * PHONETIC_EXTENSIONS; + static ::java::lang::Character$UnicodeBlock * LATIN_EXTENDED_ADDITIONAL; + static ::java::lang::Character$UnicodeBlock * GREEK_EXTENDED; + static ::java::lang::Character$UnicodeBlock * GENERAL_PUNCTUATION; + static ::java::lang::Character$UnicodeBlock * SUPERSCRIPTS_AND_SUBSCRIPTS; + static ::java::lang::Character$UnicodeBlock * CURRENCY_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * COMBINING_MARKS_FOR_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * LETTERLIKE_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * NUMBER_FORMS; + static ::java::lang::Character$UnicodeBlock * ARROWS; + static ::java::lang::Character$UnicodeBlock * MATHEMATICAL_OPERATORS; + static ::java::lang::Character$UnicodeBlock * MISCELLANEOUS_TECHNICAL; + static ::java::lang::Character$UnicodeBlock * CONTROL_PICTURES; + static ::java::lang::Character$UnicodeBlock * OPTICAL_CHARACTER_RECOGNITION; + static ::java::lang::Character$UnicodeBlock * ENCLOSED_ALPHANUMERICS; + static ::java::lang::Character$UnicodeBlock * BOX_DRAWING; + static ::java::lang::Character$UnicodeBlock * BLOCK_ELEMENTS; + static ::java::lang::Character$UnicodeBlock * GEOMETRIC_SHAPES; + static ::java::lang::Character$UnicodeBlock * MISCELLANEOUS_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * DINGBATS; + static ::java::lang::Character$UnicodeBlock * MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A; + static ::java::lang::Character$UnicodeBlock * SUPPLEMENTAL_ARROWS_A; + static ::java::lang::Character$UnicodeBlock * BRAILLE_PATTERNS; + static ::java::lang::Character$UnicodeBlock * SUPPLEMENTAL_ARROWS_B; + static ::java::lang::Character$UnicodeBlock * MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B; + static ::java::lang::Character$UnicodeBlock * SUPPLEMENTAL_MATHEMATICAL_OPERATORS; + static ::java::lang::Character$UnicodeBlock * MISCELLANEOUS_SYMBOLS_AND_ARROWS; + static ::java::lang::Character$UnicodeBlock * CJK_RADICALS_SUPPLEMENT; + static ::java::lang::Character$UnicodeBlock * KANGXI_RADICALS; + static ::java::lang::Character$UnicodeBlock * IDEOGRAPHIC_DESCRIPTION_CHARACTERS; + static ::java::lang::Character$UnicodeBlock * CJK_SYMBOLS_AND_PUNCTUATION; + static ::java::lang::Character$UnicodeBlock * HIRAGANA; + static ::java::lang::Character$UnicodeBlock * KATAKANA; + static ::java::lang::Character$UnicodeBlock * BOPOMOFO; + static ::java::lang::Character$UnicodeBlock * HANGUL_COMPATIBILITY_JAMO; + static ::java::lang::Character$UnicodeBlock * KANBUN; + static ::java::lang::Character$UnicodeBlock * BOPOMOFO_EXTENDED; + static ::java::lang::Character$UnicodeBlock * KATAKANA_PHONETIC_EXTENSIONS; + static ::java::lang::Character$UnicodeBlock * ENCLOSED_CJK_LETTERS_AND_MONTHS; + static ::java::lang::Character$UnicodeBlock * CJK_COMPATIBILITY; + static ::java::lang::Character$UnicodeBlock * CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A; + static ::java::lang::Character$UnicodeBlock * YIJING_HEXAGRAM_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * CJK_UNIFIED_IDEOGRAPHS; + static ::java::lang::Character$UnicodeBlock * YI_SYLLABLES; + static ::java::lang::Character$UnicodeBlock * YI_RADICALS; + static ::java::lang::Character$UnicodeBlock * HANGUL_SYLLABLES; + static ::java::lang::Character$UnicodeBlock * HIGH_SURROGATES; + static ::java::lang::Character$UnicodeBlock * HIGH_PRIVATE_USE_SURROGATES; + static ::java::lang::Character$UnicodeBlock * LOW_SURROGATES; + static ::java::lang::Character$UnicodeBlock * PRIVATE_USE_AREA; + static ::java::lang::Character$UnicodeBlock * CJK_COMPATIBILITY_IDEOGRAPHS; + static ::java::lang::Character$UnicodeBlock * ALPHABETIC_PRESENTATION_FORMS; + static ::java::lang::Character$UnicodeBlock * ARABIC_PRESENTATION_FORMS_A; + static ::java::lang::Character$UnicodeBlock * VARIATION_SELECTORS; + static ::java::lang::Character$UnicodeBlock * COMBINING_HALF_MARKS; + static ::java::lang::Character$UnicodeBlock * CJK_COMPATIBILITY_FORMS; + static ::java::lang::Character$UnicodeBlock * SMALL_FORM_VARIANTS; + static ::java::lang::Character$UnicodeBlock * ARABIC_PRESENTATION_FORMS_B; + static ::java::lang::Character$UnicodeBlock * HALFWIDTH_AND_FULLWIDTH_FORMS; + static ::java::lang::Character$UnicodeBlock * SPECIALS; + static ::java::lang::Character$UnicodeBlock * LINEAR_B_SYLLABARY; + static ::java::lang::Character$UnicodeBlock * LINEAR_B_IDEOGRAMS; + static ::java::lang::Character$UnicodeBlock * AEGEAN_NUMBERS; + static ::java::lang::Character$UnicodeBlock * OLD_ITALIC; + static ::java::lang::Character$UnicodeBlock * GOTHIC; + static ::java::lang::Character$UnicodeBlock * UGARITIC; + static ::java::lang::Character$UnicodeBlock * DESERET; + static ::java::lang::Character$UnicodeBlock * SHAVIAN; + static ::java::lang::Character$UnicodeBlock * OSMANYA; + static ::java::lang::Character$UnicodeBlock * CYPRIOT_SYLLABARY; + static ::java::lang::Character$UnicodeBlock * BYZANTINE_MUSICAL_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * MUSICAL_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * TAI_XUAN_JING_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * MATHEMATICAL_ALPHANUMERIC_SYMBOLS; + static ::java::lang::Character$UnicodeBlock * CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B; + static ::java::lang::Character$UnicodeBlock * CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT; + static ::java::lang::Character$UnicodeBlock * TAGS; + static ::java::lang::Character$UnicodeBlock * VARIATION_SELECTORS_SUPPLEMENT; + static ::java::lang::Character$UnicodeBlock * SUPPLEMENTARY_PRIVATE_USE_AREA_A; + static ::java::lang::Character$UnicodeBlock * SUPPLEMENTARY_PRIVATE_USE_AREA_B; + static ::java::lang::Character$UnicodeBlock * SURROGATES_AREA; +private: + static JArray< ::java::lang::Character$UnicodeBlock * > * sets; + static JArray< jint > * $SWITCH_TABLE$java$lang$Character$UnicodeBlock$NameType__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Character$UnicodeBlock__ diff --git a/libjava/java/lang/Character.h b/libjava/java/lang/Character.h new file mode 100644 index 000000000..a21447098 --- /dev/null +++ b/libjava/java/lang/Character.h @@ -0,0 +1,179 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Character__ +#define __java_lang_Character__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::Character : public ::java::lang::Object +{ + + static jchar readChar(jchar); + static jchar readCodePoint(jint); +public: + Character(jchar); + jchar charValue(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + ::java::lang::String * toString(); + static ::java::lang::String * toString(jchar); + static jboolean isLowerCase(jchar); + static jboolean isLowerCase(jint); + static jboolean isUpperCase(jchar); + static jboolean isUpperCase(jint); + static jboolean isTitleCase(jchar); + static jboolean isTitleCase(jint); + static jboolean isDigit(jchar); + static jboolean isDigit(jint); + static jboolean isDefined(jchar); + static jboolean isDefined(jint); + static jboolean isLetter(jchar); + static jboolean isLetter(jint); + static jint offsetByCodePoints(::java::lang::CharSequence *, jint, jint); + static jint offsetByCodePoints(JArray< jchar > *, jint, jint, jint, jint); + static jint codePointCount(::java::lang::CharSequence *, jint, jint); + static jint codePointCount(JArray< jchar > *, jint, jint); + static jboolean isLetterOrDigit(jchar); + static jboolean isLetterOrDigit(jint); + static jboolean isJavaLetter(jchar); + static jboolean isJavaIdentifierStart(jint); + static jboolean isJavaLetterOrDigit(jchar); + static jboolean isJavaIdentifierStart(jchar); + static jboolean isJavaIdentifierPart(jchar); + static jboolean isJavaIdentifierPart(jint); + static jboolean isUnicodeIdentifierStart(jchar); + static jboolean isUnicodeIdentifierStart(jint); + static jboolean isUnicodeIdentifierPart(jchar); + static jboolean isUnicodeIdentifierPart(jint); + static jboolean isIdentifierIgnorable(jchar); + static jboolean isIdentifierIgnorable(jint); + static jchar toLowerCase(jchar); + static jint toLowerCase(jint); + static jchar toUpperCase(jchar); + static jint toUpperCase(jint); + static jchar toTitleCase(jchar); + static jint toTitleCase(jint); + static jint digit(jchar, jint); + static jint digit(jint, jint); + static jint getNumericValue(jchar); + static jint getNumericValue(jint); + static jboolean isSpace(jchar); + static jboolean isSpaceChar(jchar); + static jboolean isSpaceChar(jint); + static jboolean isWhitespace(jchar); + static jboolean isWhitespace(jint); + static jboolean isISOControl(jchar); + static jboolean isISOControl(jint); + static jint getType(jchar); + static jint getType(jint); + static jchar forDigit(jint, jint); + static jbyte getDirectionality(jchar); + static jbyte getDirectionality(jint); + static jboolean isMirrored(jchar); + static jboolean isMirrored(jint); + jint Character$compareTo(::java::lang::Character *); + static ::java::lang::Character * valueOf(jchar); + static jchar reverseBytes(jchar); + static JArray< jchar > * toChars(jint); + static jint toChars(jint, JArray< jchar > *, jint); + static jint charCount(jint); + static jboolean isSupplementaryCodePoint(jint); + static jboolean isValidCodePoint(jint); + static jboolean isHighSurrogate(jchar); + static jboolean isLowSurrogate(jchar); + static jboolean isSurrogatePair(jchar, jchar); + static jint toCodePoint(jchar, jchar); + static jint codePointAt(::java::lang::CharSequence *, jint); + static jint codePointAt(JArray< jchar > *, jint); + static jint codePointAt(JArray< jchar > *, jint, jint); + static jint codePointBefore(JArray< jchar > *, jint); + static jint codePointBefore(JArray< jchar > *, jint, jint); + static jint codePointBefore(::java::lang::CharSequence *, jint); + jint compareTo(::java::lang::Object *); +private: + jchar __attribute__((aligned(__alignof__( ::java::lang::Object)))) value; + static const jlong serialVersionUID = 3786198910865385080LL; +public: + static const jint MIN_RADIX = 2; + static const jint MAX_RADIX = 36; + static const jchar MIN_VALUE = 0; + static const jchar MAX_VALUE = 65535; + static const jint MIN_CODE_POINT = 0; + static const jint MAX_CODE_POINT = 1114111; + static const jchar MIN_HIGH_SURROGATE = 55296; + static const jchar MAX_HIGH_SURROGATE = 56319; + static const jchar MIN_LOW_SURROGATE = 56320; + static const jchar MAX_LOW_SURROGATE = 57343; + static const jchar MIN_SURROGATE = 55296; + static const jchar MAX_SURROGATE = 57343; + static const jint MIN_SUPPLEMENTARY_CODE_POINT = 65536; + static ::java::lang::Class * TYPE; + static const jint SIZE = 16; +private: + static const jint MAX_CACHE = 127; + static JArray< ::java::lang::Character * > * charCache; +public: + static const jbyte UPPERCASE_LETTER = 1; + static const jbyte LOWERCASE_LETTER = 2; + static const jbyte TITLECASE_LETTER = 3; + static const jbyte NON_SPACING_MARK = 6; + static const jbyte COMBINING_SPACING_MARK = 8; + static const jbyte ENCLOSING_MARK = 7; + static const jbyte DECIMAL_DIGIT_NUMBER = 9; + static const jbyte LETTER_NUMBER = 10; + static const jbyte OTHER_NUMBER = 11; + static const jbyte SPACE_SEPARATOR = 12; + static const jbyte LINE_SEPARATOR = 13; + static const jbyte PARAGRAPH_SEPARATOR = 14; + static const jbyte CONTROL = 15; + static const jbyte FORMAT = 16; + static const jbyte SURROGATE = 19; + static const jbyte PRIVATE_USE = 18; + static const jbyte UNASSIGNED = 0; + static const jbyte MODIFIER_LETTER = 4; + static const jbyte OTHER_LETTER = 5; + static const jbyte CONNECTOR_PUNCTUATION = 23; + static const jbyte DASH_PUNCTUATION = 20; + static const jbyte START_PUNCTUATION = 21; + static const jbyte END_PUNCTUATION = 22; + static const jbyte INITIAL_QUOTE_PUNCTUATION = 29; + static const jbyte FINAL_QUOTE_PUNCTUATION = 30; + static const jbyte OTHER_PUNCTUATION = 24; + static const jbyte MATH_SYMBOL = 25; + static const jbyte CURRENCY_SYMBOL = 26; + static const jbyte MODIFIER_SYMBOL = 27; + static const jbyte OTHER_SYMBOL = 28; + static const jbyte DIRECTIONALITY_UNDEFINED = -1; + static const jbyte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + static const jbyte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + static const jbyte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + static const jbyte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + static const jbyte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + static const jbyte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + static const jbyte DIRECTIONALITY_ARABIC_NUMBER = 6; + static const jbyte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + static const jbyte DIRECTIONALITY_NONSPACING_MARK = 8; + static const jbyte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + static const jbyte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + static const jbyte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + static const jbyte DIRECTIONALITY_WHITESPACE = 12; + static const jbyte DIRECTIONALITY_OTHER_NEUTRALS = 13; + static const jbyte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + static const jbyte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + static const jbyte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + static const jbyte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + static const jbyte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; +private: + static const jint TYPE_MASK = 31; + static const jint NO_BREAK_MASK = 32; + static const jint MIRROR_MASK = 64; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Character__ diff --git a/libjava/java/lang/Character.java b/libjava/java/lang/Character.java new file mode 100644 index 000000000..2edf72e67 --- /dev/null +++ b/libjava/java/lang/Character.java @@ -0,0 +1,4051 @@ +/* java.lang.Character -- Wrapper class for char, and Unicode subsets + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006, 2007 + 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. */ + +/* + * Note: This class must not be merged with Classpath. Gcj uses C-style + * arrays (see include/java-chartables.h) to store the Unicode character + * database, whereas Classpath uses Java objects (char[] extracted from + * String constants) in gnu.java.lang.CharData. Gcj's approach is more + * efficient, because there is no vtable or data relocation to worry about. + * However, despite the difference in the database interface, the two + * versions share identical algorithms. + */ + +package java.lang; + +import java.io.Serializable; +import java.text.Collator; +import java.util.Locale; + +/** + * Wrapper class for the primitive char data type. In addition, this class + * allows one to retrieve property information and perform transformations + * on the defined characters in the Unicode Standard, Version 4.0.0. + * java.lang.Character is designed to be very dynamic, and as such, it + * retrieves information on the Unicode character set from a separate + * database, gnu.java.lang.CharData, which can be easily upgraded. + * + * <p>For predicates, boundaries are used to describe + * the set of characters for which the method will return true. + * This syntax uses fairly normal regular expression notation. + * See 5.13 of the Unicode Standard, Version 4.0, for the + * boundary specification. + * + * <p>See <a href="http://www.unicode.org">http://www.unicode.org</a> + * for more information on the Unicode Standard. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Paul N. Fisher + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.0 + * @status partly updated to 1.5; some things still missing + */ +public final class Character implements Serializable, Comparable<Character> +{ + /** + * A subset of Unicode blocks. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Subset + { + /** The name of the subset. */ + private final String name; + + /** + * Construct a new subset of characters. + * + * @param name the name of the subset + * @throws NullPointerException if name is null + */ + protected Subset(String name) + { + // Note that name.toString() is name, unless name was null. + this.name = name.toString(); + } + + /** + * Compares two Subsets for equality. This is <code>final</code>, and + * restricts the comparison on the <code>==</code> operator, so it returns + * true only for the same object. + * + * @param o the object to compare + * @return true if o is this + */ + public final boolean equals(Object o) + { + return o == this; + } + + /** + * Makes the original hashCode of Object final, to be consistent with + * equals. + * + * @return the hash code for this object + */ + public final int hashCode() + { + return super.hashCode(); + } + + /** + * Returns the name of the subset. + * + * @return the name + */ + public final String toString() + { + return name; + } + } // class Subset + + /** + * A family of character subsets in the Unicode specification. A character + * is in at most one of these blocks. + * + * This inner class was generated automatically from + * <code>libjava/gnu/gcj/convert/Blocks-3.txt</code>, by some perl scripts. + * This Unicode definition file can be found on the + * <a href="http://www.unicode.org">http://www.unicode.org</a> website. + * JDK 1.4 uses Unicode version 3.0.0. + * + * @author scripts/unicode-blocks.pl (written by Eric Blake) + * @since 1.2 + */ + public static final class UnicodeBlock extends Subset + { + /** The start of the subset. */ + private final int start; + + /** The end of the subset. */ + private final int end; + + /** The canonical name of the block according to the Unicode standard. */ + private final String canonicalName; + + /** Enumeration for the <code>forName()</code> method */ + private enum NameType { CANONICAL, NO_SPACES, CONSTANT; } + + /** + * Constructor for strictly defined blocks. + * + * @param start the start character of the range + * @param end the end character of the range + * @param name the block name + */ + private UnicodeBlock(int start, int end, String name, + String canonicalName) + { + super(name); + this.start = start; + this.end = end; + this.canonicalName = canonicalName; + } + + /** + * Returns the Unicode character block which a character belongs to. + * <strong>Note</strong>: This method does not support the use of + * supplementary characters. For such support, <code>of(int)</code> + * should be used instead. + * + * @param ch the character to look up + * @return the set it belongs to, or null if it is not in one + */ + public static UnicodeBlock of(char ch) + { + return of((int) ch); + } + + /** + * Returns the Unicode character block which a code point belongs to. + * + * @param codePoint the character to look up + * @return the set it belongs to, or null if it is not in one. + * @throws IllegalArgumentException if the specified code point is + * invalid. + * @since 1.5 + */ + public static UnicodeBlock of(int codePoint) + { + if (codePoint > MAX_CODE_POINT) + throw new IllegalArgumentException("The supplied integer value is " + + "too large to be a codepoint."); + // Simple binary search for the correct block. + int low = 0; + int hi = sets.length - 1; + while (low <= hi) + { + int mid = (low + hi) >> 1; + UnicodeBlock b = sets[mid]; + if (codePoint < b.start) + hi = mid - 1; + else if (codePoint > b.end) + low = mid + 1; + else + return b; + } + return null; + } + + /** + * <p> + * Returns the <code>UnicodeBlock</code> with the given name, as defined + * by the Unicode standard. The version of Unicode in use is defined by + * the <code>Character</code> class, and the names are given in the + * <code>Blocks-<version>.txt</code> file corresponding to that version. + * The name may be specified in one of three ways: + * </p> + * <ol> + * <li>The canonical, human-readable name used by the Unicode standard. + * This is the name with all spaces and hyphens retained. For example, + * `Basic Latin' retrieves the block, UnicodeBlock.BASIC_LATIN.</li> + * <li>The canonical name with all spaces removed e.g. `BasicLatin'.</li> + * <li>The name used for the constants specified by this class, which + * is the canonical name with all spaces and hyphens replaced with + * underscores e.g. `BASIC_LATIN'</li> + * </ol> + * <p> + * The names are compared case-insensitively using the case comparison + * associated with the U.S. English locale. The method recognises the + * previous names used for blocks as well as the current ones. At + * present, this simply means that the deprecated `SURROGATES_AREA' + * will be recognised by this method (the <code>of()</code> methods + * only return one of the three new surrogate blocks). + * </p> + * + * @param blockName the name of the block to look up. + * @return the specified block. + * @throws NullPointerException if the <code>blockName</code> is + * <code>null</code>. + * @throws IllegalArgumentException if the name does not match any Unicode + * block. + * @since 1.5 + */ + public static final UnicodeBlock forName(String blockName) + { + NameType type; + if (blockName.indexOf(' ') != -1) + type = NameType.CANONICAL; + else if (blockName.indexOf('_') != -1) + type = NameType.CONSTANT; + else + type = NameType.NO_SPACES; + Collator usCollator = Collator.getInstance(Locale.US); + usCollator.setStrength(Collator.PRIMARY); + /* Special case for deprecated blocks not in sets */ + switch (type) + { + case CANONICAL: + if (usCollator.compare(blockName, "Surrogates Area") == 0) + return SURROGATES_AREA; + break; + case NO_SPACES: + if (usCollator.compare(blockName, "SurrogatesArea") == 0) + return SURROGATES_AREA; + break; + case CONSTANT: + if (usCollator.compare(blockName, "SURROGATES_AREA") == 0) + return SURROGATES_AREA; + break; + } + /* Other cases */ + switch (type) + { + case CANONICAL: + for (UnicodeBlock block : sets) + if (usCollator.compare(blockName, block.canonicalName) == 0) + return block; + break; + case NO_SPACES: + for (UnicodeBlock block : sets) + { + String nsName = block.canonicalName.replaceAll(" ",""); + if (usCollator.compare(blockName, nsName) == 0) + return block; + } + break; + case CONSTANT: + for (UnicodeBlock block : sets) + if (usCollator.compare(blockName, block.toString()) == 0) + return block; + break; + } + throw new IllegalArgumentException("No Unicode block found for " + + blockName + "."); + } + + /** + * Basic Latin. + * 0x0000 - 0x007F. + */ + public static final UnicodeBlock BASIC_LATIN + = new UnicodeBlock(0x0000, 0x007F, + "BASIC_LATIN", + "Basic Latin"); + + /** + * Latin-1 Supplement. + * 0x0080 - 0x00FF. + */ + public static final UnicodeBlock LATIN_1_SUPPLEMENT + = new UnicodeBlock(0x0080, 0x00FF, + "LATIN_1_SUPPLEMENT", + "Latin-1 Supplement"); + + /** + * Latin Extended-A. + * 0x0100 - 0x017F. + */ + public static final UnicodeBlock LATIN_EXTENDED_A + = new UnicodeBlock(0x0100, 0x017F, + "LATIN_EXTENDED_A", + "Latin Extended-A"); + + /** + * Latin Extended-B. + * 0x0180 - 0x024F. + */ + public static final UnicodeBlock LATIN_EXTENDED_B + = new UnicodeBlock(0x0180, 0x024F, + "LATIN_EXTENDED_B", + "Latin Extended-B"); + + /** + * IPA Extensions. + * 0x0250 - 0x02AF. + */ + public static final UnicodeBlock IPA_EXTENSIONS + = new UnicodeBlock(0x0250, 0x02AF, + "IPA_EXTENSIONS", + "IPA Extensions"); + + /** + * Spacing Modifier Letters. + * 0x02B0 - 0x02FF. + */ + public static final UnicodeBlock SPACING_MODIFIER_LETTERS + = new UnicodeBlock(0x02B0, 0x02FF, + "SPACING_MODIFIER_LETTERS", + "Spacing Modifier Letters"); + + /** + * Combining Diacritical Marks. + * 0x0300 - 0x036F. + */ + public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS + = new UnicodeBlock(0x0300, 0x036F, + "COMBINING_DIACRITICAL_MARKS", + "Combining Diacritical Marks"); + + /** + * Greek. + * 0x0370 - 0x03FF. + */ + public static final UnicodeBlock GREEK + = new UnicodeBlock(0x0370, 0x03FF, + "GREEK", + "Greek"); + + /** + * Cyrillic. + * 0x0400 - 0x04FF. + */ + public static final UnicodeBlock CYRILLIC + = new UnicodeBlock(0x0400, 0x04FF, + "CYRILLIC", + "Cyrillic"); + + /** + * Cyrillic Supplementary. + * 0x0500 - 0x052F. + * @since 1.5 + */ + public static final UnicodeBlock CYRILLIC_SUPPLEMENTARY + = new UnicodeBlock(0x0500, 0x052F, + "CYRILLIC_SUPPLEMENTARY", + "Cyrillic Supplementary"); + + /** + * Armenian. + * 0x0530 - 0x058F. + */ + public static final UnicodeBlock ARMENIAN + = new UnicodeBlock(0x0530, 0x058F, + "ARMENIAN", + "Armenian"); + + /** + * Hebrew. + * 0x0590 - 0x05FF. + */ + public static final UnicodeBlock HEBREW + = new UnicodeBlock(0x0590, 0x05FF, + "HEBREW", + "Hebrew"); + + /** + * Arabic. + * 0x0600 - 0x06FF. + */ + public static final UnicodeBlock ARABIC + = new UnicodeBlock(0x0600, 0x06FF, + "ARABIC", + "Arabic"); + + /** + * Syriac. + * 0x0700 - 0x074F. + * @since 1.4 + */ + public static final UnicodeBlock SYRIAC + = new UnicodeBlock(0x0700, 0x074F, + "SYRIAC", + "Syriac"); + + /** + * Thaana. + * 0x0780 - 0x07BF. + * @since 1.4 + */ + public static final UnicodeBlock THAANA + = new UnicodeBlock(0x0780, 0x07BF, + "THAANA", + "Thaana"); + + /** + * Devanagari. + * 0x0900 - 0x097F. + */ + public static final UnicodeBlock DEVANAGARI + = new UnicodeBlock(0x0900, 0x097F, + "DEVANAGARI", + "Devanagari"); + + /** + * Bengali. + * 0x0980 - 0x09FF. + */ + public static final UnicodeBlock BENGALI + = new UnicodeBlock(0x0980, 0x09FF, + "BENGALI", + "Bengali"); + + /** + * Gurmukhi. + * 0x0A00 - 0x0A7F. + */ + public static final UnicodeBlock GURMUKHI + = new UnicodeBlock(0x0A00, 0x0A7F, + "GURMUKHI", + "Gurmukhi"); + + /** + * Gujarati. + * 0x0A80 - 0x0AFF. + */ + public static final UnicodeBlock GUJARATI + = new UnicodeBlock(0x0A80, 0x0AFF, + "GUJARATI", + "Gujarati"); + + /** + * Oriya. + * 0x0B00 - 0x0B7F. + */ + public static final UnicodeBlock ORIYA + = new UnicodeBlock(0x0B00, 0x0B7F, + "ORIYA", + "Oriya"); + + /** + * Tamil. + * 0x0B80 - 0x0BFF. + */ + public static final UnicodeBlock TAMIL + = new UnicodeBlock(0x0B80, 0x0BFF, + "TAMIL", + "Tamil"); + + /** + * Telugu. + * 0x0C00 - 0x0C7F. + */ + public static final UnicodeBlock TELUGU + = new UnicodeBlock(0x0C00, 0x0C7F, + "TELUGU", + "Telugu"); + + /** + * Kannada. + * 0x0C80 - 0x0CFF. + */ + public static final UnicodeBlock KANNADA + = new UnicodeBlock(0x0C80, 0x0CFF, + "KANNADA", + "Kannada"); + + /** + * Malayalam. + * 0x0D00 - 0x0D7F. + */ + public static final UnicodeBlock MALAYALAM + = new UnicodeBlock(0x0D00, 0x0D7F, + "MALAYALAM", + "Malayalam"); + + /** + * Sinhala. + * 0x0D80 - 0x0DFF. + * @since 1.4 + */ + public static final UnicodeBlock SINHALA + = new UnicodeBlock(0x0D80, 0x0DFF, + "SINHALA", + "Sinhala"); + + /** + * Thai. + * 0x0E00 - 0x0E7F. + */ + public static final UnicodeBlock THAI + = new UnicodeBlock(0x0E00, 0x0E7F, + "THAI", + "Thai"); + + /** + * Lao. + * 0x0E80 - 0x0EFF. + */ + public static final UnicodeBlock LAO + = new UnicodeBlock(0x0E80, 0x0EFF, + "LAO", + "Lao"); + + /** + * Tibetan. + * 0x0F00 - 0x0FFF. + */ + public static final UnicodeBlock TIBETAN + = new UnicodeBlock(0x0F00, 0x0FFF, + "TIBETAN", + "Tibetan"); + + /** + * Myanmar. + * 0x1000 - 0x109F. + * @since 1.4 + */ + public static final UnicodeBlock MYANMAR + = new UnicodeBlock(0x1000, 0x109F, + "MYANMAR", + "Myanmar"); + + /** + * Georgian. + * 0x10A0 - 0x10FF. + */ + public static final UnicodeBlock GEORGIAN + = new UnicodeBlock(0x10A0, 0x10FF, + "GEORGIAN", + "Georgian"); + + /** + * Hangul Jamo. + * 0x1100 - 0x11FF. + */ + public static final UnicodeBlock HANGUL_JAMO + = new UnicodeBlock(0x1100, 0x11FF, + "HANGUL_JAMO", + "Hangul Jamo"); + + /** + * Ethiopic. + * 0x1200 - 0x137F. + * @since 1.4 + */ + public static final UnicodeBlock ETHIOPIC + = new UnicodeBlock(0x1200, 0x137F, + "ETHIOPIC", + "Ethiopic"); + + /** + * Cherokee. + * 0x13A0 - 0x13FF. + * @since 1.4 + */ + public static final UnicodeBlock CHEROKEE + = new UnicodeBlock(0x13A0, 0x13FF, + "CHEROKEE", + "Cherokee"); + + /** + * Unified Canadian Aboriginal Syllabics. + * 0x1400 - 0x167F. + * @since 1.4 + */ + public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS + = new UnicodeBlock(0x1400, 0x167F, + "UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS", + "Unified Canadian Aboriginal Syllabics"); + + /** + * Ogham. + * 0x1680 - 0x169F. + * @since 1.4 + */ + public static final UnicodeBlock OGHAM + = new UnicodeBlock(0x1680, 0x169F, + "OGHAM", + "Ogham"); + + /** + * Runic. + * 0x16A0 - 0x16FF. + * @since 1.4 + */ + public static final UnicodeBlock RUNIC + = new UnicodeBlock(0x16A0, 0x16FF, + "RUNIC", + "Runic"); + + /** + * Tagalog. + * 0x1700 - 0x171F. + * @since 1.5 + */ + public static final UnicodeBlock TAGALOG + = new UnicodeBlock(0x1700, 0x171F, + "TAGALOG", + "Tagalog"); + + /** + * Hanunoo. + * 0x1720 - 0x173F. + * @since 1.5 + */ + public static final UnicodeBlock HANUNOO + = new UnicodeBlock(0x1720, 0x173F, + "HANUNOO", + "Hanunoo"); + + /** + * Buhid. + * 0x1740 - 0x175F. + * @since 1.5 + */ + public static final UnicodeBlock BUHID + = new UnicodeBlock(0x1740, 0x175F, + "BUHID", + "Buhid"); + + /** + * Tagbanwa. + * 0x1760 - 0x177F. + * @since 1.5 + */ + public static final UnicodeBlock TAGBANWA + = new UnicodeBlock(0x1760, 0x177F, + "TAGBANWA", + "Tagbanwa"); + + /** + * Khmer. + * 0x1780 - 0x17FF. + * @since 1.4 + */ + public static final UnicodeBlock KHMER + = new UnicodeBlock(0x1780, 0x17FF, + "KHMER", + "Khmer"); + + /** + * Mongolian. + * 0x1800 - 0x18AF. + * @since 1.4 + */ + public static final UnicodeBlock MONGOLIAN + = new UnicodeBlock(0x1800, 0x18AF, + "MONGOLIAN", + "Mongolian"); + + /** + * Limbu. + * 0x1900 - 0x194F. + * @since 1.5 + */ + public static final UnicodeBlock LIMBU + = new UnicodeBlock(0x1900, 0x194F, + "LIMBU", + "Limbu"); + + /** + * Tai Le. + * 0x1950 - 0x197F. + * @since 1.5 + */ + public static final UnicodeBlock TAI_LE + = new UnicodeBlock(0x1950, 0x197F, + "TAI_LE", + "Tai Le"); + + /** + * Khmer Symbols. + * 0x19E0 - 0x19FF. + * @since 1.5 + */ + public static final UnicodeBlock KHMER_SYMBOLS + = new UnicodeBlock(0x19E0, 0x19FF, + "KHMER_SYMBOLS", + "Khmer Symbols"); + + /** + * Phonetic Extensions. + * 0x1D00 - 0x1D7F. + * @since 1.5 + */ + public static final UnicodeBlock PHONETIC_EXTENSIONS + = new UnicodeBlock(0x1D00, 0x1D7F, + "PHONETIC_EXTENSIONS", + "Phonetic Extensions"); + + /** + * Latin Extended Additional. + * 0x1E00 - 0x1EFF. + */ + public static final UnicodeBlock LATIN_EXTENDED_ADDITIONAL + = new UnicodeBlock(0x1E00, 0x1EFF, + "LATIN_EXTENDED_ADDITIONAL", + "Latin Extended Additional"); + + /** + * Greek Extended. + * 0x1F00 - 0x1FFF. + */ + public static final UnicodeBlock GREEK_EXTENDED + = new UnicodeBlock(0x1F00, 0x1FFF, + "GREEK_EXTENDED", + "Greek Extended"); + + /** + * General Punctuation. + * 0x2000 - 0x206F. + */ + public static final UnicodeBlock GENERAL_PUNCTUATION + = new UnicodeBlock(0x2000, 0x206F, + "GENERAL_PUNCTUATION", + "General Punctuation"); + + /** + * Superscripts and Subscripts. + * 0x2070 - 0x209F. + */ + public static final UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS + = new UnicodeBlock(0x2070, 0x209F, + "SUPERSCRIPTS_AND_SUBSCRIPTS", + "Superscripts and Subscripts"); + + /** + * Currency Symbols. + * 0x20A0 - 0x20CF. + */ + public static final UnicodeBlock CURRENCY_SYMBOLS + = new UnicodeBlock(0x20A0, 0x20CF, + "CURRENCY_SYMBOLS", + "Currency Symbols"); + + /** + * Combining Marks for Symbols. + * 0x20D0 - 0x20FF. + */ + public static final UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS + = new UnicodeBlock(0x20D0, 0x20FF, + "COMBINING_MARKS_FOR_SYMBOLS", + "Combining Marks for Symbols"); + + /** + * Letterlike Symbols. + * 0x2100 - 0x214F. + */ + public static final UnicodeBlock LETTERLIKE_SYMBOLS + = new UnicodeBlock(0x2100, 0x214F, + "LETTERLIKE_SYMBOLS", + "Letterlike Symbols"); + + /** + * Number Forms. + * 0x2150 - 0x218F. + */ + public static final UnicodeBlock NUMBER_FORMS + = new UnicodeBlock(0x2150, 0x218F, + "NUMBER_FORMS", + "Number Forms"); + + /** + * Arrows. + * 0x2190 - 0x21FF. + */ + public static final UnicodeBlock ARROWS + = new UnicodeBlock(0x2190, 0x21FF, + "ARROWS", + "Arrows"); + + /** + * Mathematical Operators. + * 0x2200 - 0x22FF. + */ + public static final UnicodeBlock MATHEMATICAL_OPERATORS + = new UnicodeBlock(0x2200, 0x22FF, + "MATHEMATICAL_OPERATORS", + "Mathematical Operators"); + + /** + * Miscellaneous Technical. + * 0x2300 - 0x23FF. + */ + public static final UnicodeBlock MISCELLANEOUS_TECHNICAL + = new UnicodeBlock(0x2300, 0x23FF, + "MISCELLANEOUS_TECHNICAL", + "Miscellaneous Technical"); + + /** + * Control Pictures. + * 0x2400 - 0x243F. + */ + public static final UnicodeBlock CONTROL_PICTURES + = new UnicodeBlock(0x2400, 0x243F, + "CONTROL_PICTURES", + "Control Pictures"); + + /** + * Optical Character Recognition. + * 0x2440 - 0x245F. + */ + public static final UnicodeBlock OPTICAL_CHARACTER_RECOGNITION + = new UnicodeBlock(0x2440, 0x245F, + "OPTICAL_CHARACTER_RECOGNITION", + "Optical Character Recognition"); + + /** + * Enclosed Alphanumerics. + * 0x2460 - 0x24FF. + */ + public static final UnicodeBlock ENCLOSED_ALPHANUMERICS + = new UnicodeBlock(0x2460, 0x24FF, + "ENCLOSED_ALPHANUMERICS", + "Enclosed Alphanumerics"); + + /** + * Box Drawing. + * 0x2500 - 0x257F. + */ + public static final UnicodeBlock BOX_DRAWING + = new UnicodeBlock(0x2500, 0x257F, + "BOX_DRAWING", + "Box Drawing"); + + /** + * Block Elements. + * 0x2580 - 0x259F. + */ + public static final UnicodeBlock BLOCK_ELEMENTS + = new UnicodeBlock(0x2580, 0x259F, + "BLOCK_ELEMENTS", + "Block Elements"); + + /** + * Geometric Shapes. + * 0x25A0 - 0x25FF. + */ + public static final UnicodeBlock GEOMETRIC_SHAPES + = new UnicodeBlock(0x25A0, 0x25FF, + "GEOMETRIC_SHAPES", + "Geometric Shapes"); + + /** + * Miscellaneous Symbols. + * 0x2600 - 0x26FF. + */ + public static final UnicodeBlock MISCELLANEOUS_SYMBOLS + = new UnicodeBlock(0x2600, 0x26FF, + "MISCELLANEOUS_SYMBOLS", + "Miscellaneous Symbols"); + + /** + * Dingbats. + * 0x2700 - 0x27BF. + */ + public static final UnicodeBlock DINGBATS + = new UnicodeBlock(0x2700, 0x27BF, + "DINGBATS", + "Dingbats"); + + /** + * Miscellaneous Mathematical Symbols-A. + * 0x27C0 - 0x27EF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A + = new UnicodeBlock(0x27C0, 0x27EF, + "MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A", + "Miscellaneous Mathematical Symbols-A"); + + /** + * Supplemental Arrows-A. + * 0x27F0 - 0x27FF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_ARROWS_A + = new UnicodeBlock(0x27F0, 0x27FF, + "SUPPLEMENTAL_ARROWS_A", + "Supplemental Arrows-A"); + + /** + * Braille Patterns. + * 0x2800 - 0x28FF. + * @since 1.4 + */ + public static final UnicodeBlock BRAILLE_PATTERNS + = new UnicodeBlock(0x2800, 0x28FF, + "BRAILLE_PATTERNS", + "Braille Patterns"); + + /** + * Supplemental Arrows-B. + * 0x2900 - 0x297F. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_ARROWS_B + = new UnicodeBlock(0x2900, 0x297F, + "SUPPLEMENTAL_ARROWS_B", + "Supplemental Arrows-B"); + + /** + * Miscellaneous Mathematical Symbols-B. + * 0x2980 - 0x29FF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B + = new UnicodeBlock(0x2980, 0x29FF, + "MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B", + "Miscellaneous Mathematical Symbols-B"); + + /** + * Supplemental Mathematical Operators. + * 0x2A00 - 0x2AFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS + = new UnicodeBlock(0x2A00, 0x2AFF, + "SUPPLEMENTAL_MATHEMATICAL_OPERATORS", + "Supplemental Mathematical Operators"); + + /** + * Miscellaneous Symbols and Arrows. + * 0x2B00 - 0x2BFF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS + = new UnicodeBlock(0x2B00, 0x2BFF, + "MISCELLANEOUS_SYMBOLS_AND_ARROWS", + "Miscellaneous Symbols and Arrows"); + + /** + * CJK Radicals Supplement. + * 0x2E80 - 0x2EFF. + * @since 1.4 + */ + public static final UnicodeBlock CJK_RADICALS_SUPPLEMENT + = new UnicodeBlock(0x2E80, 0x2EFF, + "CJK_RADICALS_SUPPLEMENT", + "CJK Radicals Supplement"); + + /** + * Kangxi Radicals. + * 0x2F00 - 0x2FDF. + * @since 1.4 + */ + public static final UnicodeBlock KANGXI_RADICALS + = new UnicodeBlock(0x2F00, 0x2FDF, + "KANGXI_RADICALS", + "Kangxi Radicals"); + + /** + * Ideographic Description Characters. + * 0x2FF0 - 0x2FFF. + * @since 1.4 + */ + public static final UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS + = new UnicodeBlock(0x2FF0, 0x2FFF, + "IDEOGRAPHIC_DESCRIPTION_CHARACTERS", + "Ideographic Description Characters"); + + /** + * CJK Symbols and Punctuation. + * 0x3000 - 0x303F. + */ + public static final UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION + = new UnicodeBlock(0x3000, 0x303F, + "CJK_SYMBOLS_AND_PUNCTUATION", + "CJK Symbols and Punctuation"); + + /** + * Hiragana. + * 0x3040 - 0x309F. + */ + public static final UnicodeBlock HIRAGANA + = new UnicodeBlock(0x3040, 0x309F, + "HIRAGANA", + "Hiragana"); + + /** + * Katakana. + * 0x30A0 - 0x30FF. + */ + public static final UnicodeBlock KATAKANA + = new UnicodeBlock(0x30A0, 0x30FF, + "KATAKANA", + "Katakana"); + + /** + * Bopomofo. + * 0x3100 - 0x312F. + */ + public static final UnicodeBlock BOPOMOFO + = new UnicodeBlock(0x3100, 0x312F, + "BOPOMOFO", + "Bopomofo"); + + /** + * Hangul Compatibility Jamo. + * 0x3130 - 0x318F. + */ + public static final UnicodeBlock HANGUL_COMPATIBILITY_JAMO + = new UnicodeBlock(0x3130, 0x318F, + "HANGUL_COMPATIBILITY_JAMO", + "Hangul Compatibility Jamo"); + + /** + * Kanbun. + * 0x3190 - 0x319F. + */ + public static final UnicodeBlock KANBUN + = new UnicodeBlock(0x3190, 0x319F, + "KANBUN", + "Kanbun"); + + /** + * Bopomofo Extended. + * 0x31A0 - 0x31BF. + * @since 1.4 + */ + public static final UnicodeBlock BOPOMOFO_EXTENDED + = new UnicodeBlock(0x31A0, 0x31BF, + "BOPOMOFO_EXTENDED", + "Bopomofo Extended"); + + /** + * Katakana Phonetic Extensions. + * 0x31F0 - 0x31FF. + * @since 1.5 + */ + public static final UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS + = new UnicodeBlock(0x31F0, 0x31FF, + "KATAKANA_PHONETIC_EXTENSIONS", + "Katakana Phonetic Extensions"); + + /** + * Enclosed CJK Letters and Months. + * 0x3200 - 0x32FF. + */ + public static final UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS + = new UnicodeBlock(0x3200, 0x32FF, + "ENCLOSED_CJK_LETTERS_AND_MONTHS", + "Enclosed CJK Letters and Months"); + + /** + * CJK Compatibility. + * 0x3300 - 0x33FF. + */ + public static final UnicodeBlock CJK_COMPATIBILITY + = new UnicodeBlock(0x3300, 0x33FF, + "CJK_COMPATIBILITY", + "CJK Compatibility"); + + /** + * CJK Unified Ideographs Extension A. + * 0x3400 - 0x4DBF. + * @since 1.4 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + = new UnicodeBlock(0x3400, 0x4DBF, + "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A", + "CJK Unified Ideographs Extension A"); + + /** + * Yijing Hexagram Symbols. + * 0x4DC0 - 0x4DFF. + * @since 1.5 + */ + public static final UnicodeBlock YIJING_HEXAGRAM_SYMBOLS + = new UnicodeBlock(0x4DC0, 0x4DFF, + "YIJING_HEXAGRAM_SYMBOLS", + "Yijing Hexagram Symbols"); + + /** + * CJK Unified Ideographs. + * 0x4E00 - 0x9FFF. + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS + = new UnicodeBlock(0x4E00, 0x9FFF, + "CJK_UNIFIED_IDEOGRAPHS", + "CJK Unified Ideographs"); + + /** + * Yi Syllables. + * 0xA000 - 0xA48F. + * @since 1.4 + */ + public static final UnicodeBlock YI_SYLLABLES + = new UnicodeBlock(0xA000, 0xA48F, + "YI_SYLLABLES", + "Yi Syllables"); + + /** + * Yi Radicals. + * 0xA490 - 0xA4CF. + * @since 1.4 + */ + public static final UnicodeBlock YI_RADICALS + = new UnicodeBlock(0xA490, 0xA4CF, + "YI_RADICALS", + "Yi Radicals"); + + /** + * Hangul Syllables. + * 0xAC00 - 0xD7AF. + */ + public static final UnicodeBlock HANGUL_SYLLABLES + = new UnicodeBlock(0xAC00, 0xD7AF, + "HANGUL_SYLLABLES", + "Hangul Syllables"); + + /** + * High Surrogates. + * 0xD800 - 0xDB7F. + * @since 1.5 + */ + public static final UnicodeBlock HIGH_SURROGATES + = new UnicodeBlock(0xD800, 0xDB7F, + "HIGH_SURROGATES", + "High Surrogates"); + + /** + * High Private Use Surrogates. + * 0xDB80 - 0xDBFF. + * @since 1.5 + */ + public static final UnicodeBlock HIGH_PRIVATE_USE_SURROGATES + = new UnicodeBlock(0xDB80, 0xDBFF, + "HIGH_PRIVATE_USE_SURROGATES", + "High Private Use Surrogates"); + + /** + * Low Surrogates. + * 0xDC00 - 0xDFFF. + * @since 1.5 + */ + public static final UnicodeBlock LOW_SURROGATES + = new UnicodeBlock(0xDC00, 0xDFFF, + "LOW_SURROGATES", + "Low Surrogates"); + + /** + * Private Use Area. + * 0xE000 - 0xF8FF. + */ + public static final UnicodeBlock PRIVATE_USE_AREA + = new UnicodeBlock(0xE000, 0xF8FF, + "PRIVATE_USE_AREA", + "Private Use Area"); + + /** + * CJK Compatibility Ideographs. + * 0xF900 - 0xFAFF. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS + = new UnicodeBlock(0xF900, 0xFAFF, + "CJK_COMPATIBILITY_IDEOGRAPHS", + "CJK Compatibility Ideographs"); + + /** + * Alphabetic Presentation Forms. + * 0xFB00 - 0xFB4F. + */ + public static final UnicodeBlock ALPHABETIC_PRESENTATION_FORMS + = new UnicodeBlock(0xFB00, 0xFB4F, + "ALPHABETIC_PRESENTATION_FORMS", + "Alphabetic Presentation Forms"); + + /** + * Arabic Presentation Forms-A. + * 0xFB50 - 0xFDFF. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_A + = new UnicodeBlock(0xFB50, 0xFDFF, + "ARABIC_PRESENTATION_FORMS_A", + "Arabic Presentation Forms-A"); + + /** + * Variation Selectors. + * 0xFE00 - 0xFE0F. + * @since 1.5 + */ + public static final UnicodeBlock VARIATION_SELECTORS + = new UnicodeBlock(0xFE00, 0xFE0F, + "VARIATION_SELECTORS", + "Variation Selectors"); + + /** + * Combining Half Marks. + * 0xFE20 - 0xFE2F. + */ + public static final UnicodeBlock COMBINING_HALF_MARKS + = new UnicodeBlock(0xFE20, 0xFE2F, + "COMBINING_HALF_MARKS", + "Combining Half Marks"); + + /** + * CJK Compatibility Forms. + * 0xFE30 - 0xFE4F. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_FORMS + = new UnicodeBlock(0xFE30, 0xFE4F, + "CJK_COMPATIBILITY_FORMS", + "CJK Compatibility Forms"); + + /** + * Small Form Variants. + * 0xFE50 - 0xFE6F. + */ + public static final UnicodeBlock SMALL_FORM_VARIANTS + = new UnicodeBlock(0xFE50, 0xFE6F, + "SMALL_FORM_VARIANTS", + "Small Form Variants"); + + /** + * Arabic Presentation Forms-B. + * 0xFE70 - 0xFEFF. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_B + = new UnicodeBlock(0xFE70, 0xFEFF, + "ARABIC_PRESENTATION_FORMS_B", + "Arabic Presentation Forms-B"); + + /** + * Halfwidth and Fullwidth Forms. + * 0xFF00 - 0xFFEF. + */ + public static final UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS + = new UnicodeBlock(0xFF00, 0xFFEF, + "HALFWIDTH_AND_FULLWIDTH_FORMS", + "Halfwidth and Fullwidth Forms"); + + /** + * Specials. + * 0xFFF0 - 0xFFFF. + */ + public static final UnicodeBlock SPECIALS + = new UnicodeBlock(0xFFF0, 0xFFFF, + "SPECIALS", + "Specials"); + + /** + * Linear B Syllabary. + * 0x10000 - 0x1007F. + * @since 1.5 + */ + public static final UnicodeBlock LINEAR_B_SYLLABARY + = new UnicodeBlock(0x10000, 0x1007F, + "LINEAR_B_SYLLABARY", + "Linear B Syllabary"); + + /** + * Linear B Ideograms. + * 0x10080 - 0x100FF. + * @since 1.5 + */ + public static final UnicodeBlock LINEAR_B_IDEOGRAMS + = new UnicodeBlock(0x10080, 0x100FF, + "LINEAR_B_IDEOGRAMS", + "Linear B Ideograms"); + + /** + * Aegean Numbers. + * 0x10100 - 0x1013F. + * @since 1.5 + */ + public static final UnicodeBlock AEGEAN_NUMBERS + = new UnicodeBlock(0x10100, 0x1013F, + "AEGEAN_NUMBERS", + "Aegean Numbers"); + + /** + * Old Italic. + * 0x10300 - 0x1032F. + * @since 1.5 + */ + public static final UnicodeBlock OLD_ITALIC + = new UnicodeBlock(0x10300, 0x1032F, + "OLD_ITALIC", + "Old Italic"); + + /** + * Gothic. + * 0x10330 - 0x1034F. + * @since 1.5 + */ + public static final UnicodeBlock GOTHIC + = new UnicodeBlock(0x10330, 0x1034F, + "GOTHIC", + "Gothic"); + + /** + * Ugaritic. + * 0x10380 - 0x1039F. + * @since 1.5 + */ + public static final UnicodeBlock UGARITIC + = new UnicodeBlock(0x10380, 0x1039F, + "UGARITIC", + "Ugaritic"); + + /** + * Deseret. + * 0x10400 - 0x1044F. + * @since 1.5 + */ + public static final UnicodeBlock DESERET + = new UnicodeBlock(0x10400, 0x1044F, + "DESERET", + "Deseret"); + + /** + * Shavian. + * 0x10450 - 0x1047F. + * @since 1.5 + */ + public static final UnicodeBlock SHAVIAN + = new UnicodeBlock(0x10450, 0x1047F, + "SHAVIAN", + "Shavian"); + + /** + * Osmanya. + * 0x10480 - 0x104AF. + * @since 1.5 + */ + public static final UnicodeBlock OSMANYA + = new UnicodeBlock(0x10480, 0x104AF, + "OSMANYA", + "Osmanya"); + + /** + * Cypriot Syllabary. + * 0x10800 - 0x1083F. + * @since 1.5 + */ + public static final UnicodeBlock CYPRIOT_SYLLABARY + = new UnicodeBlock(0x10800, 0x1083F, + "CYPRIOT_SYLLABARY", + "Cypriot Syllabary"); + + /** + * Byzantine Musical Symbols. + * 0x1D000 - 0x1D0FF. + * @since 1.5 + */ + public static final UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS + = new UnicodeBlock(0x1D000, 0x1D0FF, + "BYZANTINE_MUSICAL_SYMBOLS", + "Byzantine Musical Symbols"); + + /** + * Musical Symbols. + * 0x1D100 - 0x1D1FF. + * @since 1.5 + */ + public static final UnicodeBlock MUSICAL_SYMBOLS + = new UnicodeBlock(0x1D100, 0x1D1FF, + "MUSICAL_SYMBOLS", + "Musical Symbols"); + + /** + * Tai Xuan Jing Symbols. + * 0x1D300 - 0x1D35F. + * @since 1.5 + */ + public static final UnicodeBlock TAI_XUAN_JING_SYMBOLS + = new UnicodeBlock(0x1D300, 0x1D35F, + "TAI_XUAN_JING_SYMBOLS", + "Tai Xuan Jing Symbols"); + + /** + * Mathematical Alphanumeric Symbols. + * 0x1D400 - 0x1D7FF. + * @since 1.5 + */ + public static final UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS + = new UnicodeBlock(0x1D400, 0x1D7FF, + "MATHEMATICAL_ALPHANUMERIC_SYMBOLS", + "Mathematical Alphanumeric Symbols"); + + /** + * CJK Unified Ideographs Extension B. + * 0x20000 - 0x2A6DF. + * @since 1.5 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B + = new UnicodeBlock(0x20000, 0x2A6DF, + "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B", + "CJK Unified Ideographs Extension B"); + + /** + * CJK Compatibility Ideographs Supplement. + * 0x2F800 - 0x2FA1F. + * @since 1.5 + */ + public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT + = new UnicodeBlock(0x2F800, 0x2FA1F, + "CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT", + "CJK Compatibility Ideographs Supplement"); + + /** + * Tags. + * 0xE0000 - 0xE007F. + * @since 1.5 + */ + public static final UnicodeBlock TAGS + = new UnicodeBlock(0xE0000, 0xE007F, + "TAGS", + "Tags"); + + /** + * Variation Selectors Supplement. + * 0xE0100 - 0xE01EF. + * @since 1.5 + */ + public static final UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT + = new UnicodeBlock(0xE0100, 0xE01EF, + "VARIATION_SELECTORS_SUPPLEMENT", + "Variation Selectors Supplement"); + + /** + * Supplementary Private Use Area-A. + * 0xF0000 - 0xFFFFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A + = new UnicodeBlock(0xF0000, 0xFFFFF, + "SUPPLEMENTARY_PRIVATE_USE_AREA_A", + "Supplementary Private Use Area-A"); + + /** + * Supplementary Private Use Area-B. + * 0x100000 - 0x10FFFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B + = new UnicodeBlock(0x100000, 0x10FFFF, + "SUPPLEMENTARY_PRIVATE_USE_AREA_B", + "Supplementary Private Use Area-B"); + + /** + * Surrogates Area. + * 'D800' - 'DFFF'. + * @deprecated As of 1.5, the three areas, + * <a href="#HIGH_SURROGATES">HIGH_SURROGATES</a>, + * <a href="#HIGH_PRIVATE_USE_SURROGATES">HIGH_PRIVATE_USE_SURROGATES</a> + * and <a href="#LOW_SURROGATES">LOW_SURROGATES</a>, as defined + * by the Unicode standard, should be used in preference to + * this. These are also returned from calls to <code>of(int)</code> + * and <code>of(char)</code>. + */ + @Deprecated + public static final UnicodeBlock SURROGATES_AREA + = new UnicodeBlock(0xD800, 0xDFFF, + "SURROGATES_AREA", + "Surrogates Area"); + + /** + * The defined subsets. + */ + private static final UnicodeBlock sets[] = { + BASIC_LATIN, + LATIN_1_SUPPLEMENT, + LATIN_EXTENDED_A, + LATIN_EXTENDED_B, + IPA_EXTENSIONS, + SPACING_MODIFIER_LETTERS, + COMBINING_DIACRITICAL_MARKS, + GREEK, + CYRILLIC, + CYRILLIC_SUPPLEMENTARY, + ARMENIAN, + HEBREW, + ARABIC, + SYRIAC, + THAANA, + DEVANAGARI, + BENGALI, + GURMUKHI, + GUJARATI, + ORIYA, + TAMIL, + TELUGU, + KANNADA, + MALAYALAM, + SINHALA, + THAI, + LAO, + TIBETAN, + MYANMAR, + GEORGIAN, + HANGUL_JAMO, + ETHIOPIC, + CHEROKEE, + UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS, + OGHAM, + RUNIC, + TAGALOG, + HANUNOO, + BUHID, + TAGBANWA, + KHMER, + MONGOLIAN, + LIMBU, + TAI_LE, + KHMER_SYMBOLS, + PHONETIC_EXTENSIONS, + LATIN_EXTENDED_ADDITIONAL, + GREEK_EXTENDED, + GENERAL_PUNCTUATION, + SUPERSCRIPTS_AND_SUBSCRIPTS, + CURRENCY_SYMBOLS, + COMBINING_MARKS_FOR_SYMBOLS, + LETTERLIKE_SYMBOLS, + NUMBER_FORMS, + ARROWS, + MATHEMATICAL_OPERATORS, + MISCELLANEOUS_TECHNICAL, + CONTROL_PICTURES, + OPTICAL_CHARACTER_RECOGNITION, + ENCLOSED_ALPHANUMERICS, + BOX_DRAWING, + BLOCK_ELEMENTS, + GEOMETRIC_SHAPES, + MISCELLANEOUS_SYMBOLS, + DINGBATS, + MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A, + SUPPLEMENTAL_ARROWS_A, + BRAILLE_PATTERNS, + SUPPLEMENTAL_ARROWS_B, + MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B, + SUPPLEMENTAL_MATHEMATICAL_OPERATORS, + MISCELLANEOUS_SYMBOLS_AND_ARROWS, + CJK_RADICALS_SUPPLEMENT, + KANGXI_RADICALS, + IDEOGRAPHIC_DESCRIPTION_CHARACTERS, + CJK_SYMBOLS_AND_PUNCTUATION, + HIRAGANA, + KATAKANA, + BOPOMOFO, + HANGUL_COMPATIBILITY_JAMO, + KANBUN, + BOPOMOFO_EXTENDED, + KATAKANA_PHONETIC_EXTENSIONS, + ENCLOSED_CJK_LETTERS_AND_MONTHS, + CJK_COMPATIBILITY, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A, + YIJING_HEXAGRAM_SYMBOLS, + CJK_UNIFIED_IDEOGRAPHS, + YI_SYLLABLES, + YI_RADICALS, + HANGUL_SYLLABLES, + HIGH_SURROGATES, + HIGH_PRIVATE_USE_SURROGATES, + LOW_SURROGATES, + PRIVATE_USE_AREA, + CJK_COMPATIBILITY_IDEOGRAPHS, + ALPHABETIC_PRESENTATION_FORMS, + ARABIC_PRESENTATION_FORMS_A, + VARIATION_SELECTORS, + COMBINING_HALF_MARKS, + CJK_COMPATIBILITY_FORMS, + SMALL_FORM_VARIANTS, + ARABIC_PRESENTATION_FORMS_B, + HALFWIDTH_AND_FULLWIDTH_FORMS, + SPECIALS, + LINEAR_B_SYLLABARY, + LINEAR_B_IDEOGRAMS, + AEGEAN_NUMBERS, + OLD_ITALIC, + GOTHIC, + UGARITIC, + DESERET, + SHAVIAN, + OSMANYA, + CYPRIOT_SYLLABARY, + BYZANTINE_MUSICAL_SYMBOLS, + MUSICAL_SYMBOLS, + TAI_XUAN_JING_SYMBOLS, + MATHEMATICAL_ALPHANUMERIC_SYMBOLS, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, + CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, + TAGS, + VARIATION_SELECTORS_SUPPLEMENT, + SUPPLEMENTARY_PRIVATE_USE_AREA_A, + SUPPLEMENTARY_PRIVATE_USE_AREA_B, + }; + } // class UnicodeBlock + + /** + * The immutable value of this Character. + * + * @serial the value of this Character + */ + private final char value; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3786198910865385080L; + + /** + * Smallest value allowed for radix arguments in Java. This value is 2. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MIN_RADIX = 2; + + /** + * Largest value allowed for radix arguments in Java. This value is 36. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MAX_RADIX = 36; + + /** + * The minimum value the char data type can hold. + * This value is <code>'\\u0000'</code>. + */ + public static final char MIN_VALUE = '\u0000'; + + /** + * The maximum value the char data type can hold. + * This value is <code>'\\uFFFF'</code>. + */ + public static final char MAX_VALUE = '\uFFFF'; + + /** + * The minimum Unicode 4.0 code point. This value is <code>0</code>. + * @since 1.5 + */ + public static final int MIN_CODE_POINT = 0; + + /** + * The maximum Unicode 4.0 code point, which is greater than the range + * of the char data type. + * This value is <code>0x10FFFF</code>. + * @since 1.5 + */ + public static final int MAX_CODE_POINT = 0x10FFFF; + + /** + * The minimum Unicode high surrogate code unit, or + * <emph>leading-surrogate</emph>, in the UTF-16 character encoding. + * This value is <code>'\uD800'</code>. + * @since 1.5 + */ + public static final char MIN_HIGH_SURROGATE = '\uD800'; + + /** + * The maximum Unicode high surrogate code unit, or + * <emph>leading-surrogate</emph>, in the UTF-16 character encoding. + * This value is <code>'\uDBFF'</code>. + * @since 1.5 + */ + public static final char MAX_HIGH_SURROGATE = '\uDBFF'; + + /** + * The minimum Unicode low surrogate code unit, or + * <emph>trailing-surrogate</emph>, in the UTF-16 character encoding. + * This value is <code>'\uDC00'</code>. + * @since 1.5 + */ + public static final char MIN_LOW_SURROGATE = '\uDC00'; + + /** + * The maximum Unicode low surrogate code unit, or + * <emph>trailing-surrogate</emph>, in the UTF-16 character encoding. + * This value is <code>'\uDFFF'</code>. + * @since 1.5 + */ + public static final char MAX_LOW_SURROGATE = '\uDFFF'; + + /** + * The minimum Unicode surrogate code unit in the UTF-16 character encoding. + * This value is <code>'\uD800'</code>. + * @since 1.5 + */ + public static final char MIN_SURROGATE = MIN_HIGH_SURROGATE; + + /** + * The maximum Unicode surrogate code unit in the UTF-16 character encoding. + * This value is <code>'\uDFFF'</code>. + * @since 1.5 + */ + public static final char MAX_SURROGATE = MAX_LOW_SURROGATE; + + /** + * The lowest possible supplementary Unicode code point (the first code + * point outside the basic multilingual plane (BMP)). + * This value is <code>0x10000</code>. + */ + public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x10000; + + /** + * Class object representing the primitive char data type. + * + * @since 1.1 + */ + public static final Class<Character> TYPE = (Class<Character>) VMClassLoader.getPrimitiveClass('C'); + + /** + * The number of bits needed to represent a <code>char</code>. + * @since 1.5 + */ + public static final int SIZE = 16; + + // This caches some Character values, and is used by boxing + // conversions via valueOf(). We must cache at least 0..127; + // this constant controls how much we actually cache. + private static final int MAX_CACHE = 127; + private static Character[] charCache = new Character[MAX_CACHE + 1]; + + /** + * Lu = Letter, Uppercase (Informative). + * + * @since 1.1 + */ + public static final byte UPPERCASE_LETTER = 1; + + /** + * Ll = Letter, Lowercase (Informative). + * + * @since 1.1 + */ + public static final byte LOWERCASE_LETTER = 2; + + /** + * Lt = Letter, Titlecase (Informative). + * + * @since 1.1 + */ + public static final byte TITLECASE_LETTER = 3; + + /** + * Mn = Mark, Non-Spacing (Normative). + * + * @since 1.1 + */ + public static final byte NON_SPACING_MARK = 6; + + /** + * Mc = Mark, Spacing Combining (Normative). + * + * @since 1.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + + /** + * Me = Mark, Enclosing (Normative). + * + * @since 1.1 + */ + public static final byte ENCLOSING_MARK = 7; + + /** + * Nd = Number, Decimal Digit (Normative). + * + * @since 1.1 + */ + public static final byte DECIMAL_DIGIT_NUMBER = 9; + + /** + * Nl = Number, Letter (Normative). + * + * @since 1.1 + */ + public static final byte LETTER_NUMBER = 10; + + /** + * No = Number, Other (Normative). + * + * @since 1.1 + */ + public static final byte OTHER_NUMBER = 11; + + /** + * Zs = Separator, Space (Normative). + * + * @since 1.1 + */ + public static final byte SPACE_SEPARATOR = 12; + + /** + * Zl = Separator, Line (Normative). + * + * @since 1.1 + */ + public static final byte LINE_SEPARATOR = 13; + + /** + * Zp = Separator, Paragraph (Normative). + * + * @since 1.1 + */ + public static final byte PARAGRAPH_SEPARATOR = 14; + + /** + * Cc = Other, Control (Normative). + * + * @since 1.1 + */ + public static final byte CONTROL = 15; + + /** + * Cf = Other, Format (Normative). + * + * @since 1.1 + */ + public static final byte FORMAT = 16; + + /** + * Cs = Other, Surrogate (Normative). + * + * @since 1.1 + */ + public static final byte SURROGATE = 19; + + /** + * Co = Other, Private Use (Normative). + * + * @since 1.1 + */ + public static final byte PRIVATE_USE = 18; + + /** + * Cn = Other, Not Assigned (Normative). + * + * @since 1.1 + */ + public static final byte UNASSIGNED = 0; + + /** + * Lm = Letter, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_LETTER = 4; + + /** + * Lo = Letter, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_LETTER = 5; + + /** + * Pc = Punctuation, Connector (Informative). + * + * @since 1.1 + */ + public static final byte CONNECTOR_PUNCTUATION = 23; + + /** + * Pd = Punctuation, Dash (Informative). + * + * @since 1.1 + */ + public static final byte DASH_PUNCTUATION = 20; + + /** + * Ps = Punctuation, Open (Informative). + * + * @since 1.1 + */ + public static final byte START_PUNCTUATION = 21; + + /** + * Pe = Punctuation, Close (Informative). + * + * @since 1.1 + */ + public static final byte END_PUNCTUATION = 22; + + /** + * Pi = Punctuation, Initial Quote (Informative). + * + * @since 1.4 + */ + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + + /** + * Pf = Punctuation, Final Quote (Informative). + * + * @since 1.4 + */ + public static final byte FINAL_QUOTE_PUNCTUATION = 30; + + /** + * Po = Punctuation, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_PUNCTUATION = 24; + + /** + * Sm = Symbol, Math (Informative). + * + * @since 1.1 + */ + public static final byte MATH_SYMBOL = 25; + + /** + * Sc = Symbol, Currency (Informative). + * + * @since 1.1 + */ + public static final byte CURRENCY_SYMBOL = 26; + + /** + * Sk = Symbol, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_SYMBOL = 27; + + /** + * So = Symbol, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_SYMBOL = 28; + + /** + * Undefined bidirectional character type. Undefined char values have + * undefined directionality in the Unicode specification. + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_UNDEFINED = -1; + + /** + * Strong bidirectional character type "L". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + + /** + * Strong bidirectional character type "R". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + + /** + * Strong bidirectional character type "AL". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + + /** + * Weak bidirectional character type "EN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + + /** + * Weak bidirectional character type "ES". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + + /** + * Weak bidirectional character type "ET". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + + /** + * Weak bidirectional character type "AN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; + + /** + * Weak bidirectional character type "CS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + + /** + * Weak bidirectional character type "NSM". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; + + /** + * Weak bidirectional character type "BN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + + /** + * Neutral bidirectional character type "B". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + + /** + * Neutral bidirectional character type "S". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + + /** + * Strong bidirectional character type "WS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_WHITESPACE = 12; + + /** + * Neutral bidirectional character type "ON". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; + + /** + * Strong bidirectional character type "LRE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + + /** + * Strong bidirectional character type "LRO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + + /** + * Strong bidirectional character type "RLE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + + /** + * Strong bidirectional character type "RLO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + + /** + * Weak bidirectional character type "PDF". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + + /** + * Mask for grabbing the type out of the result of readChar. + * @see #readChar(char) + */ + private static final int TYPE_MASK = 0x1F; + + /** + * Mask for grabbing the non-breaking space flag out of the result of + * readChar. + * @see #readChar(char) + */ + private static final int NO_BREAK_MASK = 0x20; + + /** + * Mask for grabbing the mirrored directionality flag out of the result + * of readChar. + * @see #readChar(char) + */ + private static final int MIRROR_MASK = 0x40; + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. Note that the top 9 + * bits are meaningless in this context; they are useful only in the native + * code. + * + * @param ch the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + */ + private static native char readChar(char ch); + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. Note that the top 9 + * bits are meaningless in this context; they are useful only in the native + * code. + * + * @param codePoint the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + */ + private static native char readCodePoint(int codePoint); + + /** + * Wraps up a character. + * + * @param value the character to wrap + */ + public Character(char value) + { + this.value = value; + } + + /** + * Returns the character which has been wrapped by this class. + * + * @return the character wrapped + */ + public char charValue() + { + return value; + } + + /** + * Returns the numerical value (unsigned) of the wrapped character. + * Range of returned values: 0x0000-0xFFFF. + * + * @return the value of the wrapped character + */ + public int hashCode() + { + return value; + } + + /** + * Determines if an object is equal to this object. This is only true for + * another Character object wrapping the same value. + * + * @param o object to compare + * @return true if o is a Character with the same value + */ + public boolean equals(Object o) + { + return o instanceof Character && value == ((Character) o).value; + } + + /** + * Converts the wrapped character into a String. + * + * @return a String containing one character -- the wrapped character + * of this instance + */ + public String toString() + { + // This assumes that String.valueOf(char) can create a single-character + // String more efficiently than through the public API. + return String.valueOf(value); + } + + /** + * Returns a String of length 1 representing the specified character. + * + * @param ch the character to convert + * @return a String containing the character + * @since 1.4 + */ + public static String toString(char ch) + { + // This assumes that String.valueOf(char) can create a single-character + // String more efficiently than through the public API. + return String.valueOf(ch); + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * <code>'a'</code> is lowercase. + * <br> + * lowercase = [Ll] + * + * @param ch character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + */ + public static boolean isLowerCase(char ch) + { + return getType(ch) == LOWERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * <code>'a'</code> is lowercase. Unlike isLowerCase(char), this method + * supports supplementary Unicode code points. + * <br> + * lowercase = [Ll] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode lowercase letter, else false + * @see #isUpperCase(int) + * @see #isTitleCase(int) + * @see #toLowerCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isLowerCase(int codePoint) + { + return getType(codePoint) == LOWERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * <code>'A'</code> is uppercase. + * <br> + * uppercase = [Lu] + * + * @param ch character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + */ + public static boolean isUpperCase(char ch) + { + return getType(ch) == UPPERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * <code>'A'</code> is uppercase. Unlike isUpperCase(char), this method + * supports supplementary Unicode code points. + * <br> + * uppercase = [Lu] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode uppercase letter, else false + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #toUpperCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isUpperCase(int codePoint) + { + return getType(codePoint) == UPPERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * <br> + * titlecase = [Lt] + * + * @param ch character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + */ + public static boolean isTitleCase(char ch) + { + return getType(ch) == TITLECASE_LETTER; + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * Unlike isTitleCase(char), this method supports supplementary Unicode + * code points. + * <br> + * titlecase = [Lt] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode titlecase letter, else false + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toTitleCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isTitleCase(int codePoint) + { + return getType(codePoint) == TITLECASE_LETTER; + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * <code>'0'</code> is a digit. + * <br> + * Unicode decimal digit = [Nd] + * + * @param ch character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + */ + public static boolean isDigit(char ch) + { + return getType(ch) == DECIMAL_DIGIT_NUMBER; + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * <code>'0'</code> is a digit. Unlike isDigit(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode decimal digit = [Nd] + * + * @param codePoint character to test + * @return true if ccodePoint is a Unicode decimal digit, else false + * @see #digit(int, int) + * @see #forDigit(int, int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isDigit(int codePoint) + { + return getType(codePoint) == DECIMAL_DIGIT_NUMBER; + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + * <br> + * defined = not [Cn] + * + * @param ch character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + */ + public static boolean isDefined(char ch) + { + return getType(ch) != UNASSIGNED; + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. Unlike + * isDefined(char), this method supports supplementary Unicode code points. + * <br> + * defined = not [Cn] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode character, else false + * @see #isDigit(int) + * @see #isLetter(int) + * @see #isLetterOrDigit(int) + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #isUpperCase(int) + * @since 1.5 + */ + public static boolean isDefined(int codePoint) + { + return getType(codePoint) != UNASSIGNED; + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * <br> + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param ch character to test + * @return true if ch is a Unicode letter, else false + * @see #isDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + */ + public static boolean isLetter(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * Unlike isLetter(char), this method supports supplementary Unicode code + * points. + * <br> + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode letter, else false + * @see #isDigit(int) + * @see #isJavaIdentifierStart(int) + * @see #isJavaLetter(int) + * @see #isJavaLetterOrDigit(int) + * @see #isLetterOrDigit(int) + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #isUnicodeIdentifierStart(int) + * @see #isUpperCase(int) + * @since 1.5 + */ + public static boolean isLetter(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + } + + /** + * Returns the index into the given CharSequence that is offset + * <code>codePointOffset</code> code points from <code>index</code>. + * @param seq the CharSequence + * @param index the start position in the CharSequence + * @param codePointOffset the number of code points offset from the start + * position + * @return the index into the CharSequence that is codePointOffset code + * points offset from index + * + * @throws NullPointerException if seq is null + * @throws IndexOutOfBoundsException if index is negative or greater than the + * length of the sequence. + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * subsequence from index to the end of seq has fewer than codePointOffset + * code points + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * subsequence from the start of seq to index has fewer than + * (-codePointOffset) code points + * @since 1.5 + */ + public static int offsetByCodePoints(CharSequence seq, + int index, + int codePointOffset) + { + int len = seq.length(); + if (index < 0 || index > len) + throw new IndexOutOfBoundsException(); + + int numToGo = codePointOffset; + int offset = index; + int adjust = 1; + if (numToGo >= 0) + { + for (; numToGo > 0; offset++) + { + numToGo--; + if (Character.isHighSurrogate(seq.charAt(offset)) + && (offset + 1) < len + && Character.isLowSurrogate(seq.charAt(offset + 1))) + offset++; + } + return offset; + } + else + { + numToGo *= -1; + for (; numToGo > 0;) + { + numToGo--; + offset--; + if (Character.isLowSurrogate(seq.charAt(offset)) + && (offset - 1) >= 0 + && Character.isHighSurrogate(seq.charAt(offset - 1))) + offset--; + } + return offset; + } + } + + /** + * Returns the index into the given char subarray that is offset + * <code>codePointOffset</code> code points from <code>index</code>. + * @param a the char array + * @param start the start index of the subarray + * @param count the length of the subarray + * @param index the index to be offset + * @param codePointOffset the number of code points offset from <code>index + * </code> + * @return the index into the char array + * + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if start or count is negative or if + * start + count is greater than the length of the array + * @throws IndexOutOfBoundsException if index is less than start or larger + * than start + count + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * subarray from index to start + count - 1 has fewer than codePointOffset + * code points. + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * subarray from start to index - 1 has fewer than (-codePointOffset) code + * points + * @since 1.5 + + */ + public static int offsetByCodePoints(char[] a, + int start, + int count, + int index, + int codePointOffset) + { + int len = a.length; + int end = start + count; + if (start < 0 || count < 0 || end > len || index < start || index > end) + throw new IndexOutOfBoundsException(); + + int numToGo = codePointOffset; + int offset = index; + int adjust = 1; + if (numToGo >= 0) + { + for (; numToGo > 0; offset++) + { + numToGo--; + if (Character.isHighSurrogate(a[offset]) + && (offset + 1) < len + && Character.isLowSurrogate(a[offset + 1])) + offset++; + } + return offset; + } + else + { + numToGo *= -1; + for (; numToGo > 0;) + { + numToGo--; + offset--; + if (Character.isLowSurrogate(a[offset]) + && (offset - 1) >= 0 + && Character.isHighSurrogate(a[offset - 1])) + offset--; + if (offset < start) + throw new IndexOutOfBoundsException(); + } + return offset; + } + + } + + /** + * Returns the number of Unicode code points in the specified range of the + * given CharSequence. The first char in the range is at position + * beginIndex and the last one is at position endIndex - 1. Paired + * surrogates (supplementary characters are represented by a pair of chars - + * one from the high surrogates and one from the low surrogates) + * count as just one code point. + * @param seq the CharSequence to inspect + * @param beginIndex the beginning of the range + * @param endIndex the end of the range + * @return the number of Unicode code points in the given range of the + * sequence + * @throws NullPointerException if seq is null + * @throws IndexOutOfBoundsException if beginIndex is negative, endIndex is + * larger than the length of seq, or if beginIndex is greater than endIndex. + * @since 1.5 + */ + public static int codePointCount(CharSequence seq, int beginIndex, + int endIndex) + { + int len = seq.length(); + if (beginIndex < 0 || endIndex > len || beginIndex > endIndex) + throw new IndexOutOfBoundsException(); + + int count = 0; + for (int i = beginIndex; i < endIndex; i++) + { + count++; + // If there is a pairing, count it only once. + if (isHighSurrogate(seq.charAt(i)) && (i + 1) < endIndex + && isLowSurrogate(seq.charAt(i + 1))) + i ++; + } + return count; + } + + /** + * Returns the number of Unicode code points in the specified range of the + * given char array. The first char in the range is at position + * offset and the length of the range is count. Paired surrogates + * (supplementary characters are represented by a pair of chars - + * one from the high surrogates and one from the low surrogates) + * count as just one code point. + * @param a the char array to inspect + * @param offset the beginning of the range + * @param count the length of the range + * @return the number of Unicode code points in the given range of the + * array + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if offset or count is negative or if + * offset + countendIndex is larger than the length of a. + * @since 1.5 + */ + public static int codePointCount(char[] a, int offset, + int count) + { + int len = a.length; + int end = offset + count; + if (offset < 0 || count < 0 || end > len) + throw new IndexOutOfBoundsException(); + + int counter = 0; + for (int i = offset; i < end; i++) + { + counter++; + // If there is a pairing, count it only once. + if (isHighSurrogate(a[i]) && (i + 1) < end + && isLowSurrogate(a[i + 1])) + i ++; + } + return counter; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + * <br> + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param ch character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + */ + public static boolean isLetterOrDigit(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. Unlike isLetterOrDigit(char), + * this method supports supplementary Unicode code points. + * <br> + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode letter or a Unicode digit, else false + * @see #isDigit(int) + * @see #isJavaIdentifierPart(int) + * @see #isJavaLetter(int) + * @see #isJavaLetterOrDigit(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isLetterOrDigit(int codePoint) + { + return ((1 << getType(codePoint) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} + * @see #isJavaLetterOrDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + */ + public static boolean isJavaLetter(char ch) + { + return isJavaIdentifierStart(ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). Unlike isJavaIdentifierStart(char), this method supports + * supplementary Unicode code points. + * <br> + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param codePoint character to test + * @return true if codePoint can start a Java identifier, else false + * @see #isJavaIdentifierPart(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierStart(int) + * @since 1.5 + */ + public static boolean isJavaIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @deprecated Replaced by {@link #isJavaIdentifierPart(char)} + * @see #isJavaLetter(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @see #isIdentifierIgnorable(char) + */ + public static boolean isJavaLetterOrDigit(char ch) + { + return isJavaIdentifierPart(ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * <br> + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * <br> + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. Unlike isJavaIdentifierPart(char), this method + * supports supplementary Unicode code points. + * <br> + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(int) + * @see #isJavaIdentifierStart(int) + * @see #isLetterOrDigit(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isJavaIdentifierPart(int codePoint) + { + int category = getType(codePoint); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + * <br> + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param ch character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. Unlike isUnicodeIdentifierStart(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param codePoint character to test + * @return true if codePoint can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + * <br> + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. Unlike isUnicodeIdentifierPart(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint can follow the first letter in a Unicode + * identifier + * @see #isIdentifierIgnorable(int) + * @see #isJavaIdentifierPart(int) + * @see #isLetterOrDigit(int) + * @see #isUnicodeIdentifierStart(int) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierPart(int codePoint) + { + int category = getType(codePoint); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters (<code>'\u0000'</code> + * through <code>'\u0008'</code>, <code>'\u000E'</code> through + * <code>'\u001B'</code>, and <code>'\u007F'</code> through + * <code>'\u009F'</code>), and FORMAT characters. + * <br> + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param ch character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isIdentifierIgnorable(char ch) + { + return (ch <= '\u009F' && (ch < '\t' || ch >= '\u007F' + || (ch <= '\u001B' && ch >= '\u000E'))) + || getType(ch) == FORMAT; + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters (<code>'\u0000'</code> + * through <code>'\u0008'</code>, <code>'\u000E'</code> through + * <code>'\u001B'</code>, and <code>'\u007F'</code> through + * <code>'\u009F'</code>), and FORMAT characters. Unlike + * isIdentifierIgnorable(char), this method supports supplementary Unicode + * code points. + * <br> + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isIdentifierIgnorable(int codePoint) + { + return ((codePoint >= 0 && codePoint <= 0x0008) + || (codePoint >= 0x000E && codePoint <= 0x001B) + || (codePoint >= 0x007F && codePoint <= 0x009F) + || getType(codePoint) == FORMAT); + } + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(ch)) does not always return true. + * + * @param ch character to convert to lowercase + * @return lowercase mapping of ch, or ch if lowercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #toUpperCase(char) + */ + public static native char toLowerCase(char ch); + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(codePoint)) does not always return true. + * Unlike toLowerCase(char), this method supports supplementary Unicode + * code points. + * + * @param codePoint character to convert to lowercase + * @return lowercase mapping of codePoint, or codePoint if lowercase + * mapping does not exist + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toTitleCase(int) + * @see #toUpperCase(int) + * @since 1.5 + */ + public static native int toLowerCase(int codePoint); + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(ch)) does not always return true. + * + * @param ch character to convert to uppercase + * @return uppercase mapping of ch, or ch if uppercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toLowerCase(char) + * @see #toTitleCase(char) + */ + public static native char toUpperCase(char ch); + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(codePoint)) does not always return true. + * Unlike toUpperCase(char), this method supports supplementary + * Unicode code points. + * + * @param codePoint character to convert to uppercase + * @return uppercase mapping of codePoint, or codePoint if uppercase + * mapping does not exist + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toLowerCase(int) + * @see #toTitleCase(int) + * @since 1.5 + */ + public static native int toUpperCase(int codePoint); + + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(ch)) does not always return true. + * + * @param ch character to convert to titlecase + * @return titlecase mapping of ch, or ch if titlecase mapping does + * not exist + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #toUpperCase(char) + */ + public static native char toTitleCase(char ch); + + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(codePoint)) does not always return true. + * Unlike toTitleCase(char), this method supports supplementary + * Unicode code points. + * + * @param codePoint character to convert to titlecase + * @return titlecase mapping of codePoint, or codePoint if titlecase + * mapping does not exist + * @see #isTitleCase(int) + * @see #toLowerCase(int) + * @see #toUpperCase(int) + * @since 1.5 + */ + public static native int toTitleCase(int codePoint); + + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) + * exceeds the radix, or if ch is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. + * <br> + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character to convert into a digit + * @param radix radix in which ch is a digit + * @return digit which ch represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(char) + * @see #getNumericValue(char) + */ + public static native int digit(char ch, int radix); + + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(int) + * exceeds the radix, or if codePoint is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. Unlike digit(char, int), + * this method supports supplementary Unicode code points. + * <br> + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character to convert into a digit + * @param radix radix in which codePoint is a digit + * @return digit which codePoint represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(int) + * @see #getNumericValue(int) + * @since 1.5 + */ + public static native int digit(int codePoint, int radix); + + /** + * Returns the Unicode numeric value property of a character. For example, + * <code>'\\u216C'</code> (the Roman numeral fifty) returns 50. + * + * <p>This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: <code>'\u0041'</code> + * through <code>'\u005A'</code> (uppercase); <code>'\u0061'</code> + * through <code>'\u007A'</code> (lowercase); and <code>'\uFF21'</code> + * through <code>'\uFF3A'</code>, <code>'\uFF41'</code> through + * <code>'\uFF5A'</code> (full width variants). + * + * <p>If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character from which the numeric value property will + * be retrieved + * @return the numeric value property of ch, or -1 if it does not exist, or + * -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(char, int) + * @see #isDigit(char) + * @since 1.1 + */ + public static native int getNumericValue(char ch); + + /** + * Returns the Unicode numeric value property of a character. For example, + * <code>'\\u216C'</code> (the Roman numeral fifty) returns 50. + * + * <p>This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: <code>'\u0041'</code> + * through <code>'\u005A'</code> (uppercase); <code>'\u0061'</code> + * through <code>'\u007A'</code> (lowercase); and <code>'\uFF21'</code> + * through <code>'\uFF3A'</code>, <code>'\uFF41'</code> through + * <code>'\uFF5A'</code> (full width variants). + * + * <p>If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * Unlike getNumericValue(char), this method supports supplementary Unicode + * code points. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character from which the numeric value property will + * be retrieved + * @return the numeric value property of codePoint, or -1 if it does not + * exist, or -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(int, int) + * @see #isDigit(int) + * @since 1.5 + */ + public static native int getNumericValue(int codePoint); + + /** + * Determines if a character is a ISO-LATIN-1 space. This is only the five + * characters <code>'\t'</code>, <code>'\n'</code>, <code>'\f'</code>, + * <code>'\r'</code>, and <code>' '</code>. + * <br> + * Java space = U+0020|U+0009|U+000A|U+000C|U+000D + * + * @param ch character to test + * @return true if ch is a space, else false + * @deprecated Replaced by {@link #isWhitespace(char)} + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + */ + public static boolean isSpace(char ch) + { + // Performing the subtraction up front alleviates need to compare longs. + return ch-- <= ' ' && ((1 << ch) + & ((1 << (' ' - 1)) + | (1 << ('\t' - 1)) + | (1 << ('\n' - 1)) + | (1 << ('\r' - 1)) + | (1 << ('\f' - 1)))) != 0; + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + * <br> + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param ch character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isSpaceChar(char ch) + { + return ((1 << getType(ch)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. Unlike + * isSpaceChar(char), this method supports supplementary Unicode code points. + * <br> + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode space, else false + * @see #isWhitespace(int) + * @since 1.5 + */ + public static boolean isSpaceChar(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * (<code>'\u00A0'</code>, <code>'\u2007'</code>, and <code>'\u202F'</code>); + * and these characters: <code>'\u0009'</code>, <code>'\u000A'</code>, + * <code>'\u000B'</code>, <code>'\u000C'</code>, <code>'\u000D'</code>, + * <code>'\u001C'</code>, <code>'\u001D'</code>, <code>'\u001E'</code>, + * and <code>'\u001F'</code>. + * <br> + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param ch character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.1 + */ + public static boolean isWhitespace(char ch) + { + int attr = readChar(ch); + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (ch <= '\u001F' && ((1 << ch) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * (<code>'\u00A0'</code>, <code>'\u2007'</code>, and <code>'\u202F'</code>); + * and these characters: <code>'\u0009'</code>, <code>'\u000A'</code>, + * <code>'\u000B'</code>, <code>'\u000C'</code>, <code>'\u000D'</code>, + * <code>'\u001C'</code>, <code>'\u001D'</code>, <code>'\u001E'</code>, + * and <code>'\u001F'</code>. Unlike isWhitespace(char), this method + * supports supplementary Unicode code points. + * <br> + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param codePoint character to test + * @return true if codePoint is Java whitespace, else false + * @see #isSpaceChar(int) + * @since 1.5 + */ + public static boolean isWhitespace(int codePoint) + { + int plane = codePoint >>> 16; + if (plane > 2 && plane != 14) + return false; + int attr = readCodePoint(codePoint); + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (codePoint <= '\u001F' && ((1 << codePoint) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + } + + /** + * Determines if a character has the ISO Control property. + * <br> + * ISO Control = [Cc] + * + * @param ch character to test + * @return true if ch is an ISO Control character, else false + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isISOControl(char ch) + { + return getType(ch) == CONTROL; + } + + /** + * Determines if a character has the ISO Control property. Unlike + * isISOControl(char), this method supports supplementary unicode + * code points. + * <br> + * ISO Control = [Cc] + * + * @param codePoint character to test + * @return true if codePoint is an ISO Control character, else false + * @see #isSpaceChar(int) + * @see #isWhitespace(int) + * @since 1.5 + */ + public static boolean isISOControl(int codePoint) + { + return getType(codePoint) == CONTROL; + } + + /** + * Returns the Unicode general category property of a character. + * + * @param ch character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.1 + */ + public static native int getType(char ch); + + /** + * Returns the Unicode general category property of a character. Supports + * supplementary Unicode code points. + * + * @param codePoint character from which the general category property will + * be retrieved + * @return the character category property of codePoint as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.5 + */ + public static native int getType(int codePoint); + + /** + * Converts a digit into a character which represents that digit + * in a specified radix. If the radix exceeds MIN_RADIX or MAX_RADIX, + * or the digit exceeds the radix, then the null character <code>'\0'</code> + * is returned. Otherwise the return value is in '0'-'9' and 'a'-'z'. + * <br> + * return value boundary = U+0030-U+0039|U+0061-U+007A + * + * @param digit digit to be converted into a character + * @param radix radix of digit + * @return character representing digit in radix, or '\0' + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #digit(char, int) + */ + public static char forDigit(int digit, int radix) + { + if (radix < MIN_RADIX || radix > MAX_RADIX + || digit < 0 || digit >= radix) + return '\0'; + return (char) (digit < 10 ? ('0' + digit) : ('a' - 10 + digit)); + } + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. + * + * @param ch the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.4 + */ + public static native byte getDirectionality(char ch); + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. Unlike getDirectionality(char), + * this method supports supplementary Unicode code points. + * + * @param codePoint the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.5 + */ + public static native byte getDirectionality(int codePoint); + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, <code>\u0028</code> (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param ch the character to look up + * @return true if the character is mirrored + * @since 1.4 + */ + public static boolean isMirrored(char ch) + { + return (readChar(ch) & MIRROR_MASK) != 0; + } + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, <code>\u0028</code> (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. Unlike + * isMirrored(char), this method supports supplementary Unicode code points. + * + * @param codePoint the character to look up + * @return true if the character is mirrored + * @since 1.5 + */ + public static boolean isMirrored(int codePoint) + { + int plane = codePoint >>> 16; + if (plane > 2 && plane != 14) + return false; + return (readCodePoint(codePoint) & MIRROR_MASK) != 0; + } + + /** + * Compares another Character to this Character, numerically. + * + * @param anotherCharacter Character to compare with this Character + * @return a negative integer if this Character is less than + * anotherCharacter, zero if this Character is equal, and + * a positive integer if this Character is greater + * @throws NullPointerException if anotherCharacter is null + * @since 1.2 + */ + public int compareTo(Character anotherCharacter) + { + return value - anotherCharacter.value; + } + + /** + * Returns an <code>Character</code> object wrapping the value. + * In contrast to the <code>Character</code> constructor, this method + * will cache some values. It is used by boxing conversion. + * + * @param val the value to wrap + * @return the <code>Character</code> + * + * @since 1.5 + */ + public static Character valueOf(char val) + { + if (val > MAX_CACHE) + return new Character(val); + synchronized (charCache) + { + if (charCache[val - MIN_VALUE] == null) + charCache[val - MIN_VALUE] = new Character(val); + return charCache[val - MIN_VALUE]; + } + } + + /** + * Reverse the bytes in val. + * @since 1.5 + */ + public static char reverseBytes(char val) + { + return (char) (((val >> 8) & 0xff) | ((val << 8) & 0xff00)); + } + + /** + * Converts a unicode code point to a UTF-16 representation of that + * code point. + * + * @param codePoint the unicode code point + * + * @return the UTF-16 representation of that code point + * + * @throws IllegalArgumentException if the code point is not a valid + * unicode code point + * + * @since 1.5 + */ + public static char[] toChars(int codePoint) + { + if (!isValidCodePoint(codePoint)) + throw new IllegalArgumentException("Illegal Unicode code point : " + + codePoint); + char[] result = new char[charCount(codePoint)]; + int ignore = toChars(codePoint, result, 0); + return result; + } + + /** + * Converts a unicode code point to its UTF-16 representation. + * + * @param codePoint the unicode code point + * @param dst the target char array + * @param dstIndex the start index for the target + * + * @return number of characters written to <code>dst</code> + * + * @throws IllegalArgumentException if <code>codePoint</code> is not a + * valid unicode code point + * @throws NullPointerException if <code>dst</code> is <code>null</code> + * @throws IndexOutOfBoundsException if <code>dstIndex</code> is not valid + * in <code>dst</code> or if the UTF-16 representation does not + * fit into <code>dst</code> + * + * @since 1.5 + */ + public static int toChars(int codePoint, char[] dst, int dstIndex) + { + if (!isValidCodePoint(codePoint)) + { + throw new IllegalArgumentException("not a valid code point: " + + codePoint); + } + + int result; + if (isSupplementaryCodePoint(codePoint)) + { + // Write second char first to cause IndexOutOfBoundsException + // immediately. + final int cp2 = codePoint - 0x10000; + dst[dstIndex + 1] = (char) ((cp2 % 0x400) + (int) MIN_LOW_SURROGATE); + dst[dstIndex] = (char) ((cp2 / 0x400) + (int) MIN_HIGH_SURROGATE); + result = 2; + } + else + { + dst[dstIndex] = (char) codePoint; + result = 1; + } + return result; + } + + /** + * Return number of 16-bit characters required to represent the given + * code point. + * + * @param codePoint a unicode code point + * + * @return 2 if codePoint >= 0x10000, 1 otherwise. + * + * @since 1.5 + */ + public static int charCount(int codePoint) + { + return + (codePoint >= MIN_SUPPLEMENTARY_CODE_POINT) + ? 2 + : 1; + } + + /** + * Determines whether the specified code point is + * in the range 0x10000 .. 0x10FFFF, i.e. the character is within the Unicode + * supplementary character range. + * + * @param codePoint a Unicode code point + * + * @return <code>true</code> if code point is in supplementary range + * + * @since 1.5 + */ + public static boolean isSupplementaryCodePoint(int codePoint) + { + return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT + && codePoint <= MAX_CODE_POINT; + } + + /** + * Determines whether the specified code point is + * in the range 0x0000 .. 0x10FFFF, i.e. it is a valid Unicode code point. + * + * @param codePoint a Unicode code point + * + * @return <code>true</code> if code point is valid + * + * @since 1.5 + */ + public static boolean isValidCodePoint(int codePoint) + { + return codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT; + } + + /** + * Return true if the given character is a high surrogate. + * @param ch the character + * @return true if the character is a high surrogate character + * + * @since 1.5 + */ + public static boolean isHighSurrogate(char ch) + { + return ch >= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE; + } + + /** + * Return true if the given character is a low surrogate. + * @param ch the character + * @return true if the character is a low surrogate character + * + * @since 1.5 + */ + public static boolean isLowSurrogate(char ch) + { + return ch >= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE; + } + + /** + * Return true if the given characters compose a surrogate pair. + * This is true if the first character is a high surrogate and the + * second character is a low surrogate. + * @param ch1 the first character + * @param ch2 the first character + * @return true if the characters compose a surrogate pair + * + * @since 1.5 + */ + public static boolean isSurrogatePair(char ch1, char ch2) + { + return isHighSurrogate(ch1) && isLowSurrogate(ch2); + } + + /** + * Given a valid surrogate pair, this returns the corresponding + * code point. + * @param high the high character of the pair + * @param low the low character of the pair + * @return the corresponding code point + * + * @since 1.5 + */ + public static int toCodePoint(char high, char low) + { + return ((high - MIN_HIGH_SURROGATE) * 0x400) + + (low - MIN_LOW_SURROGATE) + 0x10000; + } + + /** + * Get the code point at the specified index in the CharSequence. + * This is like CharSequence#charAt(int), but if the character is + * the start of a surrogate pair, and there is a following + * character, and this character completes the pair, then the + * corresponding supplementary code point is returned. Otherwise, + * the character at the index is returned. + * + * @param sequence the CharSequence + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointAt(CharSequence sequence, int index) + { + int len = sequence.length(); + if (index < 0 || index >= len) + throw new IndexOutOfBoundsException(); + char high = sequence.charAt(index); + if (! isHighSurrogate(high) || ++index >= len) + return high; + char low = sequence.charAt(index); + if (! isLowSurrogate(low)) + return high; + return toCodePoint(high, low); + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character, and this character completes the pair, then + * the corresponding supplementary code point is returned. + * Otherwise, the character at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index) + { + return codePointAt(chars, index, chars.length); + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character within the specified range, and this + * character completes the pair, then the corresponding + * supplementary code point is returned. Otherwise, the character + * at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @param limit the limit past which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= + * limit, or if limit is negative or >= the length of the array + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index, int limit) + { + if (index < 0 || index >= limit || limit < 0 || limit > chars.length) + throw new IndexOutOfBoundsException(); + char high = chars[index]; + if (! isHighSurrogate(high) || ++index >= limit) + return high; + char low = chars[index]; + if (! isLowSurrogate(low)) + return high; + return toCodePoint(high, low); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index) + { + return codePointBefore(chars, index, 1); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. The start parameter is used to + * limit the range of the array which may be examined. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @param start the index before which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is > start or > + * the length of the array, or if limit is negative or >= the + * length of the array + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index, int start) + { + if (index < start || index > chars.length + || start < 0 || start >= chars.length) + throw new IndexOutOfBoundsException(); + --index; + char low = chars[index]; + if (! isLowSurrogate(low) || --index < start) + return low; + char high = chars[index]; + if (! isHighSurrogate(high)) + return low; + return toCodePoint(high, low); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(CharSequence, int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. + * + * @param sequence the CharSequence + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointBefore(CharSequence sequence, int index) + { + int len = sequence.length(); + if (index < 1 || index > len) + throw new IndexOutOfBoundsException(); + --index; + char low = sequence.charAt(index); + if (! isLowSurrogate(low) || --index < 0) + return low; + char high = sequence.charAt(index); + if (! isHighSurrogate(high)) + return low; + return toCodePoint(high, low); + } +} // class Character diff --git a/libjava/java/lang/Class$1.h b/libjava/java/lang/Class$1.h new file mode 100644 index 000000000..7c18cbb4e --- /dev/null +++ b/libjava/java/lang/Class$1.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Class$1__ +#define __java_lang_Class$1__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Class$1 : public ::java::lang::Object +{ + +public: // actually package-private + Class$1(::java::lang::reflect::AccessibleObject *); +public: + virtual ::java::lang::Object * run(); +private: + ::java::lang::reflect::AccessibleObject * __attribute__((aligned(__alignof__( ::java::lang::Object)))) val$obj; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Class$1__ diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h new file mode 100644 index 000000000..d4a918483 --- /dev/null +++ b/libjava/java/lang/Class.h @@ -0,0 +1,758 @@ +// Class.h - Header file for java.lang.Class. -*- c++ -*- + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written primary using compiler source and Class.java as guides. +#ifndef __JAVA_LANG_CLASS_H__ +#define __JAVA_LANG_CLASS_H__ + +#pragma interface + +#include <stddef.h> +#include <java/lang/Object.h> +#include <java/lang/String.h> +#include <java/net/URL.h> +#include <java/lang/reflect/Modifier.h> +#include <java/security/ProtectionDomain.h> +#include <java/lang/Package.h> + +// Avoid including SystemClassLoader.h. +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace runtime + { + class SystemClassLoader; + } + } + } +} + +// We declare these here to avoid including gcj/cni.h. +extern "C" void _Jv_InitClass (jclass klass); +extern "C" jclass _Jv_NewClassFromInitializer + (const char *class_initializer); +extern "C" void _Jv_RegisterNewClasses (char **classes); +extern "C" void _Jv_RegisterClasses (const jclass *classes); +extern "C" void _Jv_RegisterClasses_Counted (const jclass *classes, + size_t count); + +// This must be predefined with "C" linkage. +extern "C" void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, + int meth_idx); +extern "C" void *_Jv_ResolvePoolEntry (jclass this_class, jint index); + +// These are the possible values for the `state' field of the class +// structure. Note that ordering is important here. Whenever the +// state changes, one should notify all waiters of this class. +enum +{ + JV_STATE_NOTHING = 0, // Set by compiler. + + JV_STATE_PRELOADING = 1, // Can do _Jv_FindClass. + + // There is an invariant through libgcj that a class will always be + // at a state greater than or equal to JV_STATE_LOADING when it is + // returned by a class loader to user code. Hence, defineclass.cc + // installs supers before returning a class, C++-ABI-compiled + // classes are created with supers installed, and BC-ABI-compiled + // classes are linked to this state before being returned by their + // class loader. + JV_STATE_LOADING = 3, // Has super installed. + JV_STATE_READ = 4, // Has been completely defined. + JV_STATE_LOADED = 5, // Has Miranda methods defined. + + JV_STATE_COMPILED = 6, // This was a compiled class. + + JV_STATE_PREPARED = 7, // Layout & static init done. + JV_STATE_LINKED = 9, // Strings interned. + + JV_STATE_IN_PROGRESS = 10, // <clinit> running. + + JV_STATE_ERROR = 12, + + JV_STATE_PHANTOM = 13, // Bytecode is missing. In many cases we can + // work around that. If not, throw a + // NoClassDefFoundError. + + JV_STATE_DONE = 14, // Must be last. + + +}; + +struct _Jv_Field; +struct _Jv_VTable; +union _Jv_word; +struct _Jv_ArrayVTable; +class _Jv_Linker; +class _Jv_ExecutionEngine; +class _Jv_CompiledEngine; +class _Jv_IndirectCompiledEngine; + +#ifdef INTERPRETER +class _Jv_InterpreterEngine; +class _Jv_ClassReader; +class _Jv_InterpClass; +class _Jv_InterpMethod; +#endif + +class _Jv_ClosureList +{ + _Jv_ClosureList *next; + void *ptr; +public: + void registerClosure (jclass klass, void *ptr); + static void releaseClosures (_Jv_ClosureList **closures); +}; + +struct _Jv_Constants +{ + jint size; + jbyte *tags; + _Jv_word *data; +}; + +struct _Jv_Method +{ + // Method name. + _Jv_Utf8Const *name; + // Method signature. + _Jv_Utf8Const *signature; + // Access flags. + _Jv_ushort accflags; + // Method's index in the vtable. + _Jv_ushort index; + // Pointer to underlying function. + void *ncode; + // NULL-terminated list of exception class names; can be NULL if + // there are none such. + _Jv_Utf8Const **throws; + + _Jv_Method *getNextMethod () + { return this + 1; } +}; + +// The table used to resolve interface calls. +struct _Jv_IDispatchTable +{ + // Index into interface's ioffsets. + jshort iindex; + jshort itable_length; + // Class Interface dispatch table. + void *itable[0]; +}; + +// Used by _Jv_Linker::get_interfaces () +struct _Jv_ifaces +{ + jclass *list; + jshort len; + jshort count; +}; + +struct _Jv_MethodSymbol +{ + _Jv_Utf8Const *class_name; + _Jv_Utf8Const *name; + _Jv_Utf8Const *signature; +}; + +struct _Jv_OffsetTable +{ + jint state; + jint offsets[]; +}; + +struct _Jv_AddressTable +{ + jint state; + void *addresses[]; +}; + +struct _Jv_CatchClass +{ + java::lang::Class **address; + _Jv_Utf8Const *classname; +}; + +// Possible values for the assertion_code field in the type assertion table. +enum +{ + JV_ASSERT_END_OF_TABLE = 0, + JV_ASSERT_TYPES_COMPATIBLE = 1, + JV_ASSERT_IS_INSTANTIABLE = 2 +}; + +// Entry in the type assertion table, used to validate type constraints +// for binary compatibility. +struct _Jv_TypeAssertion +{ + jint assertion_code; + _Jv_Utf8Const *op1; + _Jv_Utf8Const *op2; +}; + +typedef enum +{ + JV_CLASS_ATTR, + JV_METHOD_ATTR, + JV_FIELD_ATTR, + JV_DONE_ATTR +} jv_attr_type; + +typedef enum +{ + JV_INNER_CLASSES_KIND, + JV_ENCLOSING_METHOD_KIND, + JV_SIGNATURE_KIND, + JV_ANNOTATIONS_KIND, + JV_PARAMETER_ANNOTATIONS_KIND, + JV_ANNOTATION_DEFAULT_KIND +} jv_attr_kind; + +#define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) + +#define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) + +// Forward declarations for friends of java::lang::Class + +// Friend functions implemented in natClass.cc. +_Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); +jboolean _Jv_IsAssignableFrom (jclass, jclass); +jboolean _Jv_IsAssignableFromSlow (jclass, jclass); +jboolean _Jv_InterfaceAssignableFrom (jclass, jclass); + +_Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*, jclass * = NULL); +java::lang::reflect::Method *_Jv_GetReflectedMethod (jclass klass, + _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); +jfieldID JvGetFirstInstanceField (jclass); +jint JvNumInstanceFields (jclass); +jfieldID JvGetFirstStaticField (jclass); +jint JvNumStaticFields (jclass); + +jobject _Jv_AllocObject (jclass); +void *_Jv_AllocObj (jint, jclass); +void *_Jv_AllocPtrFreeObj (jint, jclass); +void *_Jv_AllocArray (jint, jclass); + +bool _Jv_getInterfaceMethod(jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); + +jobject _Jv_JNI_ToReflectedField (_Jv_JNIEnv *, jclass, jfieldID, + jboolean); +jobject _Jv_JNI_ToReflectedMethod (_Jv_JNIEnv *, jclass, jmethodID, + jboolean); +jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *); + +jmethodID _Jv_FromReflectedMethod (java::lang::reflect::Method *); +jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *); +jint JvNumMethods (jclass); +jmethodID JvGetFirstMethod (jclass); +_Jv_Utf8Const *_Jv_GetClassNameUtf8 (jclass); + +#ifdef INTERPRETER +// Finds a desired interpreter method in the given class or NULL if not found +class _Jv_MethodBase; +_Jv_MethodBase *_Jv_FindInterpreterMethod (jclass, jmethodID); +jstring _Jv_GetInterpClassSourceFile (jclass); +#endif + +jbyte _Jv_GetClassState (jclass); + +void _Jv_RegisterClassHookDefault (jclass klass); +void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); +void _Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); +void _Jv_UnregisterClass (jclass); +jclass _Jv_FindClassNoException (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); +jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); +jclass _Jv_FindClassInCache (_Jv_Utf8Const *name); +jclass _Jv_PopClass (void); +void _Jv_PushClass (jclass k); +void _Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable = 0); +jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); +void _Jv_InitNewClassFields (jclass klass); + +// Friend functions and classes in prims.cc +void _Jv_InitPrimClass (jclass, const char *, char, int); +jstring _Jv_GetMethodString (jclass, _Jv_Method *, jclass = NULL); + +jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, + jint flags); +jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader); + +jboolean _Jv_IsInterpretedClass (jclass); +jboolean _Jv_IsBinaryCompatibilityABI (jclass); + +jboolean _Jv_IsPhantomClass (jclass); + +void _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); + +#ifdef INTERPRETER +void _Jv_InitField (jobject, jclass, int); +#endif + +class _Jv_StackTrace; +class _Jv_BytecodeVerifier; + +void _Jv_sharedlib_register_hook (jclass klass); + +/* Find the class that defines the given method. Returns NULL + if it cannot be found. Searches both interpreted and native + classes. */ +jclass _Jv_GetMethodDeclaringClass (jmethodID method); + +class java::lang::Class : public java::lang::Object +{ +public: + static jclass forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader); + static jclass forName (jstring className); + JArray<jclass> *getClasses (void); + + java::lang::ClassLoader *getClassLoader (void); +private: + java::lang::ClassLoader *getClassLoader (jclass caller); +public: + // This is an internal method that circumvents the usual security + // checks when getting the class loader. + java::lang::ClassLoader *getClassLoaderInternal (void) + { + return loader; + } + + java::lang::reflect::Constructor *getConstructor (JArray<jclass> *); + JArray<java::lang::reflect::Constructor *> *getConstructors (void); + java::lang::reflect::Constructor *getDeclaredConstructor (JArray<jclass> *); + JArray<java::lang::reflect::Constructor *> *getDeclaredConstructors (jboolean); + java::lang::reflect::Field *getDeclaredField (jstring); + JArray<java::lang::reflect::Field *> *getDeclaredFields (); + JArray<java::lang::reflect::Field *> *getDeclaredFields (jboolean); + java::lang::reflect::Method *getDeclaredMethod (jstring, JArray<jclass> *); + JArray<java::lang::reflect::Method *> *getDeclaredMethods (void); + + JArray<jclass> *getDeclaredClasses (void); + JArray<jclass> *getDeclaredClasses (jboolean); + jclass getDeclaringClass (void); + + java::lang::reflect::Field *getField (jstring); +private: + JArray<java::lang::reflect::Field *> internalGetFields (); + java::lang::reflect::Field *getField (jstring, jint); + jint _getMethods (JArray<java::lang::reflect::Method *> *result, + jint offset); + java::lang::reflect::Field *getPrivateField (jstring); + java::lang::reflect::Method *getPrivateMethod (jstring, JArray<jclass> *); + java::security::ProtectionDomain *getProtectionDomain0 (); + + java::lang::reflect::Method *_getMethod (jstring, JArray<jclass> *); + java::lang::reflect::Method *_getDeclaredMethod (jstring, JArray<jclass> *); + + jstring getReflectionSignature (jint /*jv_attr_type*/ type, + jint obj_index); + jstring getReflectionSignature (::java::lang::reflect::Method *); + jstring getReflectionSignature (::java::lang::reflect::Constructor *); + jstring getReflectionSignature (::java::lang::reflect::Field *); + + jstring getClassSignature(); + jobject getMethodDefaultValue (::java::lang::reflect::Method *); + +public: + JArray<java::lang::reflect::Field *> *getFields (void); + + JArray<jclass> *getInterfaces (void); + + void getSignature (java::lang::StringBuffer *buffer); + static jstring getSignature (JArray<jclass> *, jboolean is_constructor); + JArray<java::lang::reflect::Method *> *getMethods (void); + + inline jint getModifiers (void) + { + return accflags & java::lang::reflect::Modifier::ALL_FLAGS; + } + + jstring getName (void); + + java::net::URL *getResource (jstring resourceName); + java::io::InputStream *getResourceAsStream (jstring resourceName); + JArray<jobject> *getSigners (void); + void setSigners(JArray<jobject> *); + + inline jclass getSuperclass (void) + { + return superclass; + } + + inline jclass getInterface (jint n) + { + return interfaces[n]; + } + + inline jboolean isArray (void) + { + return name->first() == '['; + } + + inline jclass getComponentType (void) + { + return isArray () ? element_type : 0; + } + + jboolean isAssignableFrom (jclass cls); + jboolean isInstance (jobject obj); + + inline jboolean isInterface (void) + { + return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0; + } + + inline jboolean isPrimitive (void) + { + return vtable == JV_PRIMITIVE_VTABLE; + } + + jobject newInstance (void); + java::security::ProtectionDomain *getProtectionDomain (void); + java::lang::Package *getPackage (void); + jstring toString (void); + jboolean desiredAssertionStatus (void); + + JArray<java::lang::reflect::TypeVariable *> *getTypeParameters (void); + + jint getEnclosingMethodData(void); + java::lang::Class *getEnclosingClass (void); + java::lang::reflect::Constructor *getEnclosingConstructor (void); + java::lang::reflect::Method *getEnclosingMethod (void); + jobjectArray getDeclaredAnnotations(jint, jint, jint); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Method *, + jboolean); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Constructor *, + jboolean); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Field *); + JArray< ::java::lang::annotation::Annotation *> *getDeclaredAnnotationsInternal(); + + jboolean isEnum (void) + { + return (accflags & 0x4000) != 0; + } + jboolean isSynthetic (void) + { + return (accflags & 0x1000) != 0; + } + jboolean isAnnotation (void) + { + return (accflags & 0x2000) != 0; + } + + jboolean isAnonymousClass(); + jboolean isLocalClass(); + jboolean isMemberClass(); + + // FIXME: this probably shouldn't be public. + jint size (void) + { + return size_in_bytes; + } + + // The index of the first method we declare ourself (as opposed to + // inheriting). + inline jint firstMethodIndex (void) + { + return vtable_method_count - method_count; + } + + // finalization + void finalize (); + + // This constructor is used to create Class object for the primitive + // types. See prims.cc. + Class (); + + // Given the BC ABI version, return the size of an Class initializer. + static jlong initializerSize (jlong ABI) + { + unsigned long version = ABI & 0xfffff; + int abi_rev = version % 100; + + // The reflection_data field was added by abi_rev 1. + if (abi_rev == 0) + return ((char*)(&::java::lang::Class::class$.reflection_data) + - (char*)&::java::lang::Class::class$); + + return sizeof (::java::lang::Class); + } + + static java::lang::Class class$; + +private: + + void memberAccessCheck (jint flags); + + void initializeClass (void); + + static jstring getPackagePortion (jstring); + + void set_state (jint nstate) + { + state = nstate; + notifyAll (); + } + + jint findInnerClassAttribute(); + jint findDeclaredClasses(JArray<jclass> *, jboolean, jint); + + // Friend functions implemented in natClass.cc. + friend _Jv_Method *::_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); + friend jboolean (::_Jv_IsAssignableFrom) (jclass, jclass); + friend jboolean (::_Jv_IsAssignableFromSlow) (jclass, jclass); + friend jboolean (::_Jv_InterfaceAssignableFrom) (jclass, jclass); + friend void *::_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, + int method_idx); + + friend void ::_Jv_InitClass (jclass klass); + friend java::lang::Class* ::_Jv_NewClassFromInitializer (const char *class_initializer); + friend void _Jv_RegisterNewClasses (void **classes); + + friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*, jclass *); + friend java::lang::reflect::Method* ::_Jv_GetReflectedMethod (jclass klass, + _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); + friend jfieldID (::JvGetFirstInstanceField) (jclass); + friend jint (::JvNumInstanceFields) (jclass); + friend jfieldID (::JvGetFirstStaticField) (jclass); + friend jint (::JvNumStaticFields) (jclass); + + friend jobject (::_Jv_AllocObject) (jclass); + friend void *::_Jv_AllocObj (jint, jclass); + friend void *::_Jv_AllocPtrFreeObj (jint, jclass); + friend void *::_Jv_AllocArray (jint, jclass); + + friend jobject (::_Jv_JNI_ToReflectedField) (_Jv_JNIEnv *, jclass, jfieldID, + jboolean); + friend jobject (::_Jv_JNI_ToReflectedMethod) (_Jv_JNIEnv *, jclass, jmethodID, + jboolean); + friend jfieldID (::_Jv_FromReflectedField) (java::lang::reflect::Field *); + + friend jmethodID (::_Jv_FromReflectedMethod) (java::lang::reflect::Method *); + friend jmethodID (::_Jv_FromReflectedConstructor) (java::lang::reflect::Constructor *); + friend jint (::JvNumMethods) (jclass); + friend jmethodID (::JvGetFirstMethod) (jclass); + friend _Jv_Utf8Const *::_Jv_GetClassNameUtf8 (jclass); +#ifdef INTERPRETER + friend _Jv_MethodBase *(::_Jv_FindInterpreterMethod) (jclass klass, + jmethodID desired_method); + friend jstring ::_Jv_GetInterpClassSourceFile (jclass); +#endif + friend jbyte (::_Jv_GetClassState) (jclass klass); + + // Friends classes and functions to implement the ClassLoader + friend class java::lang::ClassLoader; + friend class java::lang::VMClassLoader; + + friend class java::io::ObjectOutputStream; + friend class java::io::ObjectInputStream; + friend class java::io::ObjectStreamClass; + + friend void ::_Jv_RegisterClasses (const jclass *classes); + friend void ::_Jv_RegisterClasses_Counted (const jclass *classes, + size_t count); + friend void ::_Jv_RegisterClassHookDefault (jclass klass); + friend void ::_Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void ::_Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void ::_Jv_UnregisterClass (jclass); + friend jclass (::_Jv_FindClassNoException) (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name); + friend jclass (::_Jv_PopClass) (void); + friend void ::_Jv_PushClass (jclass k); + friend void ::_Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable); + friend jclass (::_Jv_NewClass) (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); + friend void ::_Jv_InitNewClassFields (jclass klass); + + // in prims.cc + friend void ::_Jv_InitPrimClass (jclass, const char *, char, int); + + friend jstring (::_Jv_GetMethodString) (jclass, _Jv_Method *, jclass); + + friend jboolean (::_Jv_CheckAccess) (jclass self_klass, jclass other_klass, + jint flags); + + friend bool (::_Jv_getInterfaceMethod) (jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); + + friend jclass (::_Jv_GetArrayClass) (jclass klass, + java::lang::ClassLoader *loader); + + friend jboolean (::_Jv_IsInterpretedClass) (jclass); + friend jboolean (::_Jv_IsBinaryCompatibilityABI) (jclass); + + friend jboolean (::_Jv_IsPhantomClass) (jclass); + +#ifdef INTERPRETER + friend void ::_Jv_InitField (jobject, jclass, int); + + friend class ::_Jv_ClassReader; + friend class ::_Jv_InterpClass; + friend class ::_Jv_InterpMethod; + friend class ::_Jv_InterpreterEngine; +#endif + friend class ::_Jv_StackTrace; + +#ifdef JV_MARKOBJ_DECL + friend JV_MARKOBJ_DECL; +#endif + + friend class ::_Jv_BytecodeVerifier; + friend class java::io::VMObjectStreamClass; + + friend class ::_Jv_Linker; + friend class ::_Jv_ExecutionEngine; + friend class ::_Jv_CompiledEngine; + friend class ::_Jv_IndirectCompiledEngine; + friend class ::_Jv_ClosureList; + + friend void ::_Jv_sharedlib_register_hook (jclass klass); + + friend void *::_Jv_ResolvePoolEntry (jclass this_class, jint index); + + friend void ::_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); + + friend class java::lang::reflect::Field; + friend class java::lang::reflect::Method; + friend class java::lang::reflect::Constructor; + friend class java::lang::reflect::VMProxy; + + // Chain for class pool. This also doubles as the ABI version + // number. It is only used for this purpose at class registration + // time, and only for precompiled classes. + jclass next_or_version; + // Name of class. + _Jv_Utf8Const *name; + // Access flags for class. + _Jv_ushort accflags; + // The superclass, or null for Object. + jclass superclass; + // Class constants. + _Jv_Constants constants; + // Methods. If this is an array class, then this field holds a + // pointer to the element type. + union + { + _Jv_Method *methods; + jclass element_type; + }; + // Number of methods. If this class is primitive, this holds the + // character used to represent this type in a signature. + jshort method_count; + // Number of methods in the vtable. + jshort vtable_method_count; + // The fields. + _Jv_Field *fields; + // Size of instance fields, in bytes. + jint size_in_bytes; + // Total number of fields (instance and static). + jshort field_count; + // Number of static fields. + jshort static_field_count; + // The vtbl for all objects of this class. + _Jv_VTable *vtable; + // Virtual method offset table. + _Jv_OffsetTable *otable; + // Offset table symbols. + _Jv_MethodSymbol *otable_syms; + // Address table + _Jv_AddressTable *atable; + _Jv_MethodSymbol *atable_syms; + // Interface table + _Jv_AddressTable *itable; + _Jv_MethodSymbol *itable_syms; + _Jv_CatchClass *catch_classes; + // Interfaces implemented by this class. + jclass *interfaces; + // The class loader for this class. + java::lang::ClassLoader *loader; + // Number of interfaces. + jshort interface_count; + // State of this class. + jbyte state; + // The thread which has locked this class. Used during class + // initialization. + java::lang::Thread *thread; + // How many levels of "extends" this class is removed from Object. + jshort depth; + // Vector of this class's superclasses, ordered by decreasing depth. + jclass *ancestors; + // In a regular class, this field points to the Class Interface Dispatch + // Table. In an interface, it points to the ioffsets table. + union + { + _Jv_IDispatchTable *idt; + jshort *ioffsets; + }; + // Pointer to the class that represents an array of this class. + jclass arrayclass; + // Security Domain to which this class belongs (or null). + java::security::ProtectionDomain *protectionDomain; + // Pointer to the type assertion table for this class. + _Jv_TypeAssertion *assertion_table; + // Signers of this class (or null). + JArray<jobject> *hack_signers; + // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace. + jclass chain; + // Additional data, specific to the generator (JIT, native, + // interpreter) of this class. + void *aux_info; + // Execution engine. + _Jv_ExecutionEngine *engine; + // Reflection data. + unsigned char *reflection_data; +}; + +// Inline functions that are friends of java::lang::Class + +inline void _Jv_InitClass (jclass klass) +{ + if (__builtin_expect (klass->state == JV_STATE_DONE, true)) + return; + klass->initializeClass (); +} + +// Return array class corresponding to element type KLASS, creating it if +// necessary. +inline jclass +_Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader) +{ + extern void _Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable = 0); + if (__builtin_expect (!klass->arrayclass, false)) + _Jv_NewArrayClass (klass, loader); + return klass->arrayclass; +} + +#endif /* __JAVA_LANG_CLASS_H__ */ diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java new file mode 100644 index 000000000..a4e8ee592 --- /dev/null +++ b/libjava/java/lang/Class.java @@ -0,0 +1,1430 @@ +/* Class.java -- Representation of a Java class. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 + 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.reflect.ClassSignatureParser; +import java.io.InputStream; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.HashMap; +import java.util.Collection; +import java.lang.reflect.AnnotatedElement; +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.reflect.AccessibleObject; + +/** + * 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. + * + * <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 (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.0 + * @see ClassLoader + */ +public final class Class<T> + implements Type, AnnotatedElement, GenericDeclaration, Serializable +{ + /** + * Class is non-instantiable from Java code; only the VM can create + * instances of this class. + */ + private Class () + { + } + + // Initialize the class. + private native void initializeClass (); + + // finalization + protected native void finalize () throws Throwable; + + /** + * Use the classloader of the current class to load, link, and initialize + * a class. This is equivalent to your code calling + * <code>Class.forName(name, true, getClass().getClassLoader())</code>. + * + * @param name the name of the class to find + * @return the Class object representing the class + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + */ + public static native Class<?> forName (String className) + throws ClassNotFoundException; + + // A private internal method that is called by compiler-generated code. + private static Class forName (String className, Class caller) + throws ClassNotFoundException + { + return forName(className, true, caller.getClassLoaderInternal()); + } + + + /** + * Use the specified classloader to load and link a class. If the loader + * is null, this uses the bootstrap class loader (provide the security + * check succeeds). Unfortunately, this method cannot be used to obtain + * the Class objects for primitive types or for void, you have to use + * the fields in the appropriate java.lang wrapper classes. + * + * <p>Calls <code>classloader.loadclass(name, initialize)</code>. + * + * @param name the name of the class to find + * @param initialize whether or not to initialize the class at this time + * @param classloader the classloader to use to find the class; null means + * to use the bootstrap class loader + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + * @throws SecurityException if the <code>classloader</code> argument + * is <code>null</code> and the caller does not have the + * <code>RuntimePermission("getClassLoader")</code> permission + * @see ClassLoader + * @since 1.2 + */ + public static native Class<?> forName (String className, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException; + + /** + * Get all the public member classes and interfaces declared in this + * class or inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class<?>[] getClasses() + { + memberAccessCheck(Member.PUBLIC); + return internalGetClasses(); + } + + /** + * Like <code>getClasses()</code> but without the security checks. + */ + private Class<?>[] internalGetClasses() + { + ArrayList<Class> list = new ArrayList<Class>(); + list.addAll(Arrays.asList(getDeclaredClasses(true))); + Class superClass = getSuperclass(); + if (superClass != null) + list.addAll(Arrays.asList(superClass.internalGetClasses())); + return list.toArray(new Class<?>[list.size()]); + } + + /** + * Get the ClassLoader that loaded this class. If the class was loaded + * by the bootstrap classloader, this method will return null. + * If there is a security manager, and the caller's class loader is not + * an ancestor of the requested one, a security check of + * <code>RuntimePermission("getClassLoader")</code> + * must first succeed. Primitive types and void return null. + * + * @return the ClassLoader that loaded this class + * @throws SecurityException if the security check fails + * @see ClassLoader + * @see RuntimePermission + */ + public native ClassLoader getClassLoader (); + + // A private internal method that is called by compiler-generated code. + private final native ClassLoader getClassLoader (Class caller); + + /** + * Internal method that circumvents the usual security checks when + * getting the class loader. + */ + private native ClassLoader getClassLoaderInternal (); + + /** + * If this is an array, get the Class representing the type of array. + * Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and + * calling getComponentType on that would give "java.lang.String". If + * this is not an array, returns null. + * + * @return the array type of this class, or null + * @see Array + * @since 1.1 + */ + public native Class<?> getComponentType (); + + /** + * Get a public constructor declared in this class. If the constructor takes + * no argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getConstructors() + * @since 1.1 + */ + public native Constructor<T> getConstructor(Class<?>... args) + throws NoSuchMethodException; + + /** + * Get all the public constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with <code>checkMemberAccess(this, Member.PUBLIC)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return all public constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor<?>[] getConstructors() + { + memberAccessCheck(Member.PUBLIC); + return getDeclaredConstructors(true); + } + + /** + * Get a constructor declared in this class. If the constructor takes no + * argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredConstructors() + * @since 1.1 + */ + public native Constructor<T> getDeclaredConstructor(Class<?>... args) + throws NoSuchMethodException; + + /** + * Get all the declared member classes and interfaces in this class, but + * not those inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class<?>[] getDeclaredClasses() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredClasses(false); + } + + native Class<?>[] getDeclaredClasses (boolean publicOnly); + + /** + * Get all the declared constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with <code>checkMemberAccess(this, Member.DECLARED)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return all constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor<?>[] getDeclaredConstructors() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredConstructors(false); + } + + native Constructor<?>[] getDeclaredConstructors (boolean publicOnly); + + /** + * Get a field declared in this class, where name is its simple name. The + * implicit length field of arrays is not available. A security check may + * be performed, with <code>checkMemberAccess(this, Member.DECLARED)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @param name the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredFields() + * @since 1.1 + */ + public native Field getDeclaredField(String fieldName) + throws NoSuchFieldException; + + /** + * Get all the declared fields in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getDeclaredFields() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredFields(false); + } + + native Field[] getDeclaredFields (boolean publicOnly); + + private native Method _getDeclaredMethod(String methodName, Class[] args); + + /** + * Get a method declared in this class, where name is its simple name. The + * implicit methods of Object are not available from arrays or interfaces. + * Constructors (named "<init>" in the class file) and class initializers + * (name "<clinit>") are not available. The Virtual Machine allows + * multiple methods with the same signature but differing return types; in + * such a case the most specific return types are favored, then the final + * choice is arbitrary. If the method takes no argument, an array of zero + * elements and null are equivalent for the types argument. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredMethods() + * @since 1.1 + */ + public Method getDeclaredMethod(String methodName, Class<?>... args) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + + if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) + throw new NoSuchMethodException(methodName); + + Method match = _getDeclaredMethod(methodName, args); + if (match == null) + throw new NoSuchMethodException(methodName); + return match; + } + + /** + * Get all the declared methods in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does include the implicit methods of + * arrays and interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public native Method[] getDeclaredMethods(); + + /** + * If this is a nested or inner class, return the class that declared it. + * If not, return null. + * + * @return the declaring class of this class + * @since 1.1 + */ + // This is marked as unimplemented in the JCL book. + public native Class<?> getDeclaringClass (); + + private native Field getField (String fieldName, int hash) + throws NoSuchFieldException; + + /** + * Get a public field declared or inherited in this class, where name is + * its simple name. If the class contains multiple accessible fields by + * that name, an arbitrary one is returned. The implicit length field of + * arrays is not available. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param fieldName the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getFields() + * @since 1.1 + */ + public Field getField(String fieldName) + throws NoSuchFieldException + { + memberAccessCheck(Member.PUBLIC); + Field field = getField(fieldName, fieldName.hashCode()); + if (field == null) + throw new NoSuchFieldException(fieldName); + return field; + } + + /** + * Get all the public fields declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getFields() + { + memberAccessCheck(Member.PUBLIC); + return internalGetFields(); + } + + /** + * Like <code>getFields()</code> but without the security checks. + */ + private Field[] internalGetFields() + { + LinkedHashSet set = new LinkedHashSet(); + set.addAll(Arrays.asList(getDeclaredFields(true))); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].internalGetFields())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.internalGetFields())); + return (Field[])set.toArray(new Field[set.size()]); + } + + /** + * Returns the <code>Package</code> in which this class is defined + * Returns null when this information is not available from the + * classloader of this class. + * + * @return the package for this class, if it is available + * @since 1.2 + */ + public Package getPackage() + { + ClassLoader cl = getClassLoaderInternal(); + if (cl != null) + return cl.getPackage(getPackagePortion(getName())); + else + return VMClassLoader.getPackage(getPackagePortion(getName())); + } + + /** + * Get the interfaces this class <em>directly</em> implements, in the + * order that they were declared. This returns an empty array, not null, + * for Object, primitives, void, and classes or interfaces with no direct + * superinterface. Array types return Cloneable and Serializable. + * + * @return the interfaces this class directly implements + */ + public native Class<?>[] getInterfaces (); + + private final native void getSignature(StringBuffer buffer); + private static final native String getSignature(Class[] args, + boolean is_construtor); + + public native Method _getMethod(String methodName, Class[] args); + + /** + * Get a public method declared or inherited in this class, where name is + * its simple name. The implicit methods of Object are not available from + * interfaces. Constructors (named "<init>" in the class file) and class + * initializers (name "<clinit>") are not available. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types, and the class can inherit multiple methods of the same + * return type; in such a case the most specific return types are favored, + * then the final choice is arbitrary. If the method takes no argument, an + * array of zero elements and null are equivalent for the types argument. + * A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getMethods() + * @since 1.1 + */ + public Method getMethod(String methodName, Class<?>... args) + throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + + if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) + throw new NoSuchMethodException(methodName); + + Method method = _getMethod(methodName, args); + if (method == null) + throw new NoSuchMethodException(methodName); + return method; + } + + private native int _getMethods (Method[] result, int offset); + + /** + * Get all the public methods declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does not include the implicit + * methods of interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public native Method[] getMethods(); + + /** + * Get the modifiers of this class. These can be decoded using Modifier, + * and is limited to one of public, protected, or private, and any of + * final, static, abstract, or interface. An array class has the same + * public, protected, or private modifier as its component type, and is + * marked final but not an interface. Primitive types and void are marked + * public and final, but not an interface. + * + * @return the modifiers of this class + * @see Modifer + * @since 1.1 + */ + public native int getModifiers (); + + /** + * Get the name of this class, separated by dots for package separators. + * If the class represents a primitive type, or void, then the + * name of the type as it appears in the Java programming language + * is returned. For instance, <code>Byte.TYPE.getName()</code> + * returns "byte". + * + * Arrays are specially encoded as shown on this table. + * <pre> + * array type [<em>element type</em> + * (note that the element type is encoded per + * this table) + * boolean Z + * byte B + * char C + * short S + * int I + * long J + * float F + * double D + * void V + * class or interface, alone: <dotted name> + * class or interface, as element type: L<dotted name>; + * </pre> + * + * @return the name of this class + */ + public native String getName (); + + /** + * Get a resource URL using this class's package using the + * getClassLoader().getResource() method. If this class was loaded using + * the system classloader, ClassLoader.getSystemResource() is used instead. + * + * <p>If the name you supply is absolute (it starts with a <code>/</code>), + * then the leading <code>/</code> is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * <code>.</code>'s are replaced with <code>/</code>. + * + * <p>The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return the URL to the resource + * @throws NullPointerException if name is null + * @since 1.1 + */ + public URL getResource(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoaderInternal(); + if (loader == null) + return ClassLoader.getSystemResource(name); + return loader.getResource(name); + } + + /** + * Get a resource using this class's package using the + * getClassLoader().getResourceAsStream() method. If this class was loaded + * using the system classloader, ClassLoader.getSystemResource() is used + * instead. + * + * <p>If the name you supply is absolute (it starts with a <code>/</code>), + * then the leading <code>/</code> is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * <code>.</code>'s are replaced with <code>/</code>. + * + * <p>The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return an InputStream with the contents of the resource in it, or null + * @throws NullPointerException if name is null + * @since 1.1 + */ + public InputStream getResourceAsStream(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoaderInternal(); + if (loader == null) + return ClassLoader.getSystemResourceAsStream(name); + return loader.getResourceAsStream(name); + } + + private String resourcePath(String resourceName) + { + if (resourceName.length() > 0) + { + if (resourceName.charAt(0) != '/') + { + String pkg = getPackagePortion(getName()); + if (pkg.length() > 0) + resourceName = pkg.replace('.','/') + '/' + resourceName; + } + else + { + resourceName = resourceName.substring(1); + } + } + return resourceName; + } + + /** + * Get the signers of this class. This returns null if there are no signers, + * such as for primitive types or void. + * + * @return the signers of this class + * @since 1.1 + */ + public native Object[] getSigners (); + + /** + * Set the signers of this class. + * + * @param signers the signers of this class + */ + native void setSigners(Object[] signers); + + /** + * Get the direct superclass of this class. If this is an interface, + * Object, a primitive type, or void, it will return null. If this is an + * array type, it will return Object. + * + * @return the direct superclass of this class + */ + public native Class<? super T> getSuperclass (); + + /** + * Return whether this class is an array type. + * + * @return whether this class is an array type + * @since 1.1 + */ + public native boolean isArray (); + + /** + * Discover whether an instance of the Class parameter would be an + * instance of this Class as well. Think of doing + * <code>isInstance(c.newInstance())</code> or even + * <code>c.newInstance() instanceof (this class)</code>. While this + * checks widening conversions for objects, it must be exact for primitive + * types. + * + * @param c the class to check + * @return whether an instance of c would be an instance of this class + * as well + * @throws NullPointerException if c is null + * @since 1.1 + */ + public native boolean isAssignableFrom (Class<?> c); + + /** + * Discover whether an Object is an instance of this Class. Think of it + * as almost like <code>o instanceof (this class)</code>. + * + * @param o the Object to check + * @return whether o is an instance of this class + * @since 1.1 + */ + public native boolean isInstance (Object o); + + /** + * Check whether this class is an interface or not. Array types are not + * interfaces. + * + * @return whether this class is an interface or not + */ + public native boolean isInterface (); + + /** + * Return whether this class is a primitive type. A primitive type class + * is a class representing a kind of "placeholder" for the various + * primitive types, or void. You can access the various primitive type + * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., + * or through boolean.class, int.class, etc. + * + * @return whether this class is a primitive type + * @see Boolean#TYPE + * @see Byte#TYPE + * @see Character#TYPE + * @see Short#TYPE + * @see Integer#TYPE + * @see Long#TYPE + * @see Float#TYPE + * @see Double#TYPE + * @see Void#TYPE + * @since 1.1 + */ + public native boolean isPrimitive (); + + /** + * Get a new instance of this class by calling the no-argument constructor. + * The class is initialized if it has not been already. A security check + * may be performed, with <code>checkMemberAccess(this, Member.PUBLIC)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return a new instance of this class + * @throws InstantiationException if there is not a no-arg constructor + * for this class, including interfaces, abstract classes, arrays, + * primitive types, and void; or if an exception occurred during + * the constructor + * @throws IllegalAccessException if you are not allowed to access the + * no-arg constructor because of scoping reasons + * @throws SecurityException if the security check fails + * @throws ExceptionInInitializerError if class initialization caused by + * this call fails with an exception + */ + public native T newInstance () + throws InstantiationException, IllegalAccessException; + + // We need a native method to retrieve the protection domain, because we + // can't add fields to java.lang.Class that are accessible from Java. + private native ProtectionDomain getProtectionDomain0(); + + /** + * Returns the protection domain of this class. If the classloader did not + * record the protection domain when creating this class the unknown + * protection domain is returned which has a <code>null</code> code source + * and all permissions. A security check may be performed, with + * <code>RuntimePermission("getProtectionDomain")</code>. + * + * @return the protection domain + * @throws SecurityException if the security manager exists and the caller + * does not have <code>RuntimePermission("getProtectionDomain")</code>. + * @see RuntimePermission + * @since 1.2 + */ + public ProtectionDomain getProtectionDomain() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(VMClassLoader.protectionDomainPermission); + + ProtectionDomain protectionDomain = getProtectionDomain0(); + + if (protectionDomain == null) + return VMClassLoader.unknownProtectionDomain; + else + return protectionDomain; + } + + /** + * Return the human-readable form of this Object. For an object, this + * is either "interface " or "class " followed by <code>getName()</code>, + * for primitive types and void it is just <code>getName()</code>. + * + * @return the human-readable form of this Object + */ + public String toString() + { + if (isPrimitive()) + return getName(); + return (isInterface() ? "interface " : "class ") + getName(); + } + + /** + * Returns the desired assertion status of this class, if it were to be + * initialized at this moment. The class assertion status, if set, is + * returned; the backup is the default package status; then if there is + * a class loader, that default is returned; and finally the system default + * is returned. This method seldom needs calling in user code, but exists + * for compilers to implement the assert statement. Note that there is no + * guarantee that the result of this method matches the class's actual + * assertion status. + * + * @return the desired assertion status + * @see ClassLoader#setClassAssertionStatus(String, boolean) + * @see ClassLoader#setPackageAssertionStatus(String, boolean) + * @see ClassLoader#setDefaultAssertionStatus(boolean) + * @since 1.4 + */ + public boolean desiredAssertionStatus() + { + ClassLoader c = getClassLoaderInternal(); + Object status; + if (c == null) + return VMClassLoader.defaultAssertionStatus(); + if (c.classAssertionStatus != null) + synchronized (c) + { + status = c.classAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + status = ClassLoader.systemClassAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + if (c.packageAssertionStatus != null) + synchronized (c) + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = c.packageAssertionStatus.get(null); + else + do + { + status = c.packageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = ClassLoader.systemPackageAssertionStatus.get(null); + else + do + { + status = ClassLoader.systemPackageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + return c.defaultAssertionStatus; + } + + /** + * Strip the last portion of the name (after the last dot). + * + * @param name the name to get package of + * @return the package name, or "" if no package + */ + private static String getPackagePortion(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return ""; + return name.substring(0, lastInd); + } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } + + + /** + * <p> + * Casts this class to represent a subclass of the specified class. + * This method is useful for `narrowing' the type of a class so that + * the class object, and instances of that class, can match the contract + * of a more restrictive method. For example, if this class has the + * static type of <code>Class<Object></code>, and a dynamic type of + * <code>Class<Rectangle></code>, then, assuming <code>Shape</code> is + * a superclass of <code>Rectangle</code>, this method can be used on + * this class with the parameter, <code>Class<Shape></code>, to retain + * the same instance but with the type + * <code>Class<? extends Shape></code>. + * </p> + * <p> + * If this class can be converted to an instance which is parameterised + * over a subtype of the supplied type, <code>U</code>, then this method + * returns an appropriately cast reference to this object. Otherwise, + * a <code>ClassCastException</code> is thrown. + * </p> + * + * @param klass the class object, the parameterized type (<code>U</code>) of + * which should be a superclass of the parameterized type of + * this instance. + * @return a reference to this object, appropriately cast. + * @throws ClassCastException if this class can not be converted to one + * which represents a subclass of the specified + * type, <code>U</code>. + * @since 1.5 + */ + public <U> Class<? extends U> asSubclass(Class<U> klass) + { + if (! klass.isAssignableFrom(this)) + throw new ClassCastException(); + return (Class<? extends U>) this; + } + + /** + * Returns the specified object, cast to this <code>Class</code>' type. + * + * @param obj the object to cast + * @throws ClassCastException if obj is not an instance of this class + * @since 1.5 + */ + public T cast(Object obj) + { + if (obj != null && ! isInstance(obj)) + throw new ClassCastException(); + return (T) obj; + } + + /** + * Returns the enumeration constants of this class, or + * null if this class is not an <code>Enum</code>. + * + * @return an array of <code>Enum</code> constants + * associated with this class, or null if this + * class is not an <code>enum</code>. + * @since 1.5 + */ + public T[] getEnumConstants() + { + if (isEnum()) + { + try + { + Method m = getMethod("values"); + setAccessible(m); + return (T[]) m.invoke(null); + } + catch (NoSuchMethodException exception) + { + throw new Error("Enum lacks values() method"); + } + catch (IllegalAccessException exception) + { + throw new Error("Unable to access Enum class"); + } + catch (InvocationTargetException exception) + { + throw new + RuntimeException("The values method threw an exception", + exception); + } + } + else + { + return null; + } + } + + /** + * Returns true if this class is an <code>Enum</code>. + * + * @return true if this is an enumeration class. + * @since 1.5 + */ + public native boolean isEnum(); + + + /** + * Returns true if this class is a synthetic class, generated by + * the compiler. + * + * @return true if this is a synthetic class. + * @since 1.5 + */ + public native boolean isSynthetic(); + + + /** + * Returns true if this class is an <code>Annotation</code>. + * + * @return true if this is an annotation class. + * @since 1.5 + */ + public native boolean isAnnotation(); + + + /** + * Returns the simple name for this class, as used in the source + * code. For normal classes, this is the content returned by + * <code>getName()</code> which follows the last ".". Anonymous + * classes have no name, and so the result of calling this method is + * "". The simple name of an array consists of the simple name of + * its component type, followed by "[]". Thus, an array with the + * component type of an anonymous class has a simple name of simply + * "[]". + * + * @return the simple name for this class. + * @since 1.5 + */ + public String getSimpleName() + { + if (isAnonymousClass()) + return ""; + if (isArray()) + return getComponentType().getSimpleName() + "[]"; + + String fullName = getName(); + Class enclosingClass = getEnclosingClass(); + if (enclosingClass == null) + // It's a top level class. + return fullName.substring(fullName.lastIndexOf(".") + 1); + + fullName = fullName.substring(enclosingClass.getName().length()); + + // We've carved off the enclosing class name; now we must have '$' + // followed optionally by digits, followed by the class name. + int pos = 1; + while (Character.isDigit(fullName.charAt(pos))) + ++pos; + fullName = fullName.substring(pos); + + return fullName; + } + + /** + * Returns the class which immediately encloses this class. If this class + * is a top-level class, this method returns <code>null</code>. + * + * @return the immediate enclosing class, or <code>null</code> if this is + * a top-level class. + * @since 1.5 + */ + public native Class<?> getEnclosingClass(); + + /** + * Returns the constructor which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing constructor if this class is + * declared within a constructor. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + public native Constructor<T> getEnclosingConstructor(); + + /** + * Returns the method which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing method if this class is + * declared within a method. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + public native Method getEnclosingMethod(); + + private native String getClassSignature(); + + /** + * <p> + * Returns an array of <code>Type</code> objects which represent the + * interfaces directly implemented by this class or extended by this + * interface. + * </p> + * <p> + * If one of the superinterfaces is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the <code>ParameterizedType</code> + * interface, and only if an instance has not already been created. + * </p> + * <p> + * The order of the interfaces in the array matches the order in which + * the interfaces are declared. For classes which represent an array, + * an array of two interfaces, <code>Cloneable</code> and + * <code>Serializable</code>, is always returned, with the objects in + * that order. A class representing a primitive type or void always + * returns an array of zero size. + * </p> + * + * @return an array of interfaces implemented or extended by this class. + * @throws GenericSignatureFormatError if the generic signature of one + * of the interfaces does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if any of the superinterfaces refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if any of the interfaces + * refer to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type[] getGenericInterfaces() + { + if (isPrimitive()) + return new Type[0]; + + String sig = getClassSignature(); + if (sig == null) + return getInterfaces(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getInterfaceTypes(); + } + + /** + * <p> + * Returns a <code>Type</code> object representing the direct superclass, + * whether class, interface, primitive type or void, of this class. + * If this class is an array class, then a class instance representing + * the <code>Object</code> class is returned. If this class is primitive, + * an interface, or a representation of either the <code>Object</code> + * class or void, then <code>null</code> is returned. + * </p> + * <p> + * If the superclass is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the <code>ParameterizedType</code> + * interface, and only if an instance has not already been created. + * </p> + * + * @return the superclass of this class. + * @throws GenericSignatureFormatError if the generic signature of the + * class does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if the superclass refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if the superclass + * refers to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type getGenericSuperclass() + { + if (isArray()) + return Object.class; + + if (isPrimitive() || isInterface() || this == Object.class) + return null; + + String sig = getClassSignature(); + if (sig == null) + return getSuperclass(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getSuperclassType(); + } + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this class, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public TypeVariable<Class<T>>[] getTypeParameters() + { + String sig = getClassSignature(); + if (sig == null) + return (TypeVariable<Class<T>>[])new TypeVariable[0]; + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Returns this class' annotation for the specified annotation type, + * or <code>null</code> if no such annotation exists. + * + * @param annotationClass the type of annotation to look for. + * @return this class' annotation for the specified type, or + * <code>null</code> if no such annotation exists. + * @since 1.5 + */ + public <A extends Annotation> A getAnnotation(Class<A> annotationClass) + { + A foundAnnotation = null; + Annotation[] annotations = getAnnotations(); + for (Annotation annotation : annotations) + if (annotation.annotationType() == annotationClass) + foundAnnotation = (A) annotation; + return foundAnnotation; + } + + /** + * Returns all annotations associated with this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return this class' annotations. + * @since 1.5 + */ + public Annotation[] getAnnotations() + { + HashMap<Class, Annotation> map = new HashMap<Class, Annotation>(); + for (Annotation a : getDeclaredAnnotations()) + map.put((Class) a.annotationType(), a); + for (Class<? super T> s = getSuperclass(); + s != null; + s = s.getSuperclass()) + { + for (Annotation a : s.getDeclaredAnnotations()) + { + Class k = (Class) a.annotationType(); + if (! map.containsKey(k) && k.isAnnotationPresent(Inherited.class)) + map.put(k, a); + } + } + Collection<Annotation> v = map.values(); + return v.toArray(new Annotation[v.size()]); + } + + /** + * <p> + * Returns the canonical name of this class, as defined by section + * 6.7 of the Java language specification. Each package, top-level class, + * top-level interface and primitive type has a canonical name. A member + * class has a canonical name, if its parent class has one. Likewise, + * an array type has a canonical name, if its component type does. + * Local or anonymous classes do not have canonical names. + * </p> + * <p> + * The canonical name for top-level classes, top-level interfaces and + * primitive types is always the same as the fully-qualified name. + * For array types, the canonical name is the canonical name of its + * component type with `[]' appended. + * </p> + * <p> + * The canonical name of a member class always refers to the place where + * the class was defined, and is composed of the canonical name of the + * defining class and the simple name of the member class, joined by `.'. + * For example, if a <code>Person</code> class has an inner class, + * <code>M</code>, then both its fully-qualified name and canonical name + * is <code>Person.M</code>. A subclass, <code>Staff</code>, of + * <code>Person</code> refers to the same inner class by the fully-qualified + * name of <code>Staff.M</code>, but its canonical name is still + * <code>Person.M</code>. + * </p> + * <p> + * Where no canonical name is present, <code>null</code> is returned. + * </p> + * + * @return the canonical name of the class, or <code>null</code> if the + * class doesn't have a canonical name. + * @since 1.5 + */ + public String getCanonicalName() + { + if (isArray()) + { + String componentName = getComponentType().getCanonicalName(); + if (componentName != null) + return componentName + "[]"; + } + if (isMemberClass()) + { + String memberName = getDeclaringClass().getCanonicalName(); + if (memberName != null) + return memberName + "." + getSimpleName(); + } + if (isLocalClass() || isAnonymousClass()) + return null; + return getName(); + } + + /** + * Returns all annotations directly defined by this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return the annotations directly defined by this class. + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + + /** + * Returns true if an annotation for the specified type is associated + * with this class. This is primarily a short-hand for using marker + * annotations. + * + * @param annotationClass the type of annotation to look for. + * @return true if an annotation exists for the specified type. + * @since 1.5 + */ + public boolean isAnnotationPresent(Class<? extends Annotation> + annotationClass) + { + return getAnnotation(annotationClass) != null; + } + + /** + * Returns true if this object represents an anonymous class. + * + * @return true if this object represents an anonymous class. + * @since 1.5 + */ + public native boolean isAnonymousClass(); + + /** + * Returns true if this object represents an local class. + * + * @return true if this object represents an local class. + * @since 1.5 + */ + public native boolean isLocalClass(); + + /** + * Returns true if this object represents an member class. + * + * @return true if this object represents an member class. + * @since 1.5 + */ + public native boolean isMemberClass(); + + /** + * Utility method for use by classes in this package. + */ + static void setAccessible(final AccessibleObject obj) + { + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + obj.setAccessible(true); + return null; + } + }); + } +} diff --git a/libjava/java/lang/ClassCastException.h b/libjava/java/lang/ClassCastException.h new file mode 100644 index 000000000..55c0bcc88 --- /dev/null +++ b/libjava/java/lang/ClassCastException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassCastException__ +#define __java_lang_ClassCastException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::ClassCastException : public ::java::lang::RuntimeException +{ + +public: + ClassCastException(); + ClassCastException(::java::lang::String *); +private: + static const jlong serialVersionUID = -9223365651070458532LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ClassCastException__ diff --git a/libjava/java/lang/ClassCircularityError.h b/libjava/java/lang/ClassCircularityError.h new file mode 100644 index 000000000..81d6f93ad --- /dev/null +++ b/libjava/java/lang/ClassCircularityError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassCircularityError__ +#define __java_lang_ClassCircularityError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::ClassCircularityError : public ::java::lang::LinkageError +{ + +public: + ClassCircularityError(); + ClassCircularityError(::java::lang::String *); +private: + static const jlong serialVersionUID = 1054362542914539689LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ClassCircularityError__ diff --git a/libjava/java/lang/ClassFormatError.h b/libjava/java/lang/ClassFormatError.h new file mode 100644 index 000000000..ee6664f56 --- /dev/null +++ b/libjava/java/lang/ClassFormatError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassFormatError__ +#define __java_lang_ClassFormatError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::ClassFormatError : public ::java::lang::LinkageError +{ + +public: + ClassFormatError(); + ClassFormatError(::java::lang::String *); +private: + static const jlong serialVersionUID = -8420114879011949195LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ClassFormatError__ diff --git a/libjava/java/lang/ClassLoader$AnnotationsKey.h b/libjava/java/lang/ClassLoader$AnnotationsKey.h new file mode 100644 index 000000000..1a395b07b --- /dev/null +++ b/libjava/java/lang/ClassLoader$AnnotationsKey.h @@ -0,0 +1,31 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassLoader$AnnotationsKey__ +#define __java_lang_ClassLoader$AnnotationsKey__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::ClassLoader$AnnotationsKey : public ::java::lang::Object +{ + +public: + ClassLoader$AnnotationsKey(::java::lang::Class *, jint, jint, jint); + jboolean equals(::java::lang::Object *); + jint hashCode(); +public: // actually package-private + jint __attribute__((aligned(__alignof__( ::java::lang::Object)))) member_type; + jint member_index; + jint kind_req; + ::java::lang::Class * declaringClass; + jint hashCode__; +public: + static JArray< ::java::lang::annotation::Annotation * > * NIL; + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ClassLoader$AnnotationsKey__ diff --git a/libjava/java/lang/ClassLoader.h b/libjava/java/lang/ClassLoader.h new file mode 100644 index 000000000..5112eab98 --- /dev/null +++ b/libjava/java/lang/ClassLoader.h @@ -0,0 +1,112 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassLoader__ +#define __java_lang_ClassLoader__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace java + { + namespace net + { + class URL; + } + namespace nio + { + class ByteBuffer; + } + namespace security + { + class ProtectionDomain; + } + } +} + +jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader); +void _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, bool is_jar); + +class java::lang::ClassLoader : public ::java::lang::Object +{ + +public: // actually package-private + virtual JArray< ::java::lang::Object * > * getDeclaredAnnotations(::java::lang::Class *, jint, jint, jint); + virtual JArray< ::java::lang::Object * > * putDeclaredAnnotations(::java::lang::Class *, jint, jint, jint, JArray< ::java::lang::Object * > *); +public: // actually protected + ClassLoader(); + ClassLoader(::java::lang::ClassLoader *); +public: + virtual ::java::lang::Class * loadClass(::java::lang::String *); +private: + ::java::lang::Class * loadClassFromSig(::java::lang::String *); +public: // actually protected + virtual ::java::lang::Class * loadClass(::java::lang::String *, jboolean); + virtual ::java::lang::Class * findClass(::java::lang::String *); + virtual ::java::lang::Class * defineClass(JArray< jbyte > *, jint, jint); + virtual ::java::lang::Class * defineClass(::java::lang::String *, JArray< jbyte > *, jint, jint); + virtual ::java::lang::Class * defineClass(::java::lang::String *, JArray< jbyte > *, jint, jint, ::java::security::ProtectionDomain *); + virtual ::java::lang::Class * defineClass(::java::lang::String *, ::java::nio::ByteBuffer *, ::java::security::ProtectionDomain *); + virtual void resolveClass(::java::lang::Class *); + virtual ::java::lang::Class * findSystemClass(::java::lang::String *); +public: + virtual ::java::lang::ClassLoader * getParent(); +public: // actually protected + virtual void setSigners(::java::lang::Class *, JArray< ::java::lang::Object * > *); + virtual ::java::lang::Class * findLoadedClass(::java::lang::String *); +public: + virtual ::java::net::URL * getResource(::java::lang::String *); + virtual ::java::util::Enumeration * getResources(::java::lang::String *); +public: // actually protected + virtual ::java::util::Enumeration * findResources(::java::lang::String *); + virtual ::java::net::URL * findResource(::java::lang::String *); +public: + static ::java::net::URL * getSystemResource(::java::lang::String *); + static ::java::util::Enumeration * getSystemResources(::java::lang::String *); + virtual ::java::io::InputStream * getResourceAsStream(::java::lang::String *); + static ::java::io::InputStream * getSystemResourceAsStream(::java::lang::String *); + static ::java::lang::ClassLoader * getSystemClassLoader(); +public: // actually protected + virtual ::java::lang::Package * definePackage(::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::net::URL *); + virtual ::java::lang::Package * getPackage(::java::lang::String *); + virtual JArray< ::java::lang::Package * > * getPackages(); + virtual ::java::lang::String * findLibrary(::java::lang::String *); +public: + virtual void setDefaultAssertionStatus(jboolean); + virtual void setPackageAssertionStatus(::java::lang::String *, jboolean); + virtual void setClassAssertionStatus(::java::lang::String *, jboolean); + virtual void clearAssertionStatus(); +public: // actually package-private + virtual jboolean isAncestorOf(::java::lang::ClassLoader *); +private: + void checkInitialized(); +public: // actually package-private + ::java::util::HashMap * __attribute__((aligned(__alignof__( ::java::lang::Object)))) loadedClasses; + ::java::util::HashMap * loadingConstraints; + ::java::util::HashMap * definedPackages; +private: + ::java::lang::ClassLoader * parent; + jboolean initialized; +public: // actually package-private + static ::java::lang::ClassLoader * systemClassLoader; +private: + ::java::util::concurrent::ConcurrentHashMap * declaredAnnotations; +public: // actually package-private + static ::java::security::ProtectionDomain * defaultProtectionDomain; + jboolean defaultAssertionStatus; + static ::java::util::Map * systemPackageAssertionStatus; + ::java::util::Map * packageAssertionStatus; + static ::java::util::Map * systemClassAssertionStatus; + ::java::util::Map * classAssertionStatus; +public: + static ::java::lang::Class class$; + + friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name, java::lang::ClassLoader *loader); + friend void ::_Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, bool is_jar); +}; + +#endif // __java_lang_ClassLoader__ diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java new file mode 100644 index 000000000..d55573095 --- /dev/null +++ b/libjava/java/lang/ClassLoader.java @@ -0,0 +1,1144 @@ +/* ClassLoader.java -- responsible for loading classes into the VM + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 gnu.classpath.SystemProperties; +import gnu.classpath.VMStackWalker; +import gnu.java.util.DoubleEnumeration; +import gnu.java.util.EmptyEnumeration; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import java.util.concurrent.ConcurrentHashMap; +import java.lang.annotation.Annotation; + +/** + * The ClassLoader is a way of customizing the way Java gets its classes + * and loads them into memory. The verifier and other standard Java things + * still run, but the ClassLoader is allowed great flexibility in determining + * where to get the classfiles and when to load and resolve them. For that + * matter, a custom ClassLoader can perform on-the-fly code generation or + * modification! + * + * <p>Every classloader has a parent classloader that is consulted before + * the 'child' classloader when classes or resources should be loaded. + * This is done to make sure that classes can be loaded from an hierarchy of + * multiple classloaders and classloaders do not accidentially redefine + * already loaded classes by classloaders higher in the hierarchy. + * + * <p>The grandparent of all classloaders is the bootstrap classloader, which + * loads all the standard system classes as implemented by GNU Classpath. The + * other special classloader is the system classloader (also called + * application classloader) that loads all classes from the CLASSPATH + * (<code>java.class.path</code> system property). The system classloader + * is responsible for finding the application classes from the classpath, + * and delegates all requests for the standard library classes to its parent + * the bootstrap classloader. Most programs will load all their classes + * through the system classloaders. + * + * <p>The bootstrap classloader in GNU Classpath is implemented as a couple of + * static (native) methods on the package private class + * <code>java.lang.VMClassLoader</code>, the system classloader is an + * instance of <code>gnu.java.lang.SystemClassLoader</code> + * (which is a subclass of <code>java.net.URLClassLoader</code>). + * + * <p>Users of a <code>ClassLoader</code> will normally just use the methods + * <ul> + * <li> <code>loadClass()</code> to load a class.</li> + * <li> <code>getResource()</code> or <code>getResourceAsStream()</code> + * to access a resource.</li> + * <li> <code>getResources()</code> to get an Enumeration of URLs to all + * the resources provided by the classloader and its parents with the + * same name.</li> + * </ul> + * + * <p>Subclasses should implement the methods + * <ul> + * <li> <code>findClass()</code> which is called by <code>loadClass()</code> + * when the parent classloader cannot provide a named class.</li> + * <li> <code>findResource()</code> which is called by + * <code>getResource()</code> when the parent classloader cannot provide + * a named resource.</li> + * <li> <code>findResources()</code> which is called by + * <code>getResource()</code> to combine all the resources with the + * same name from the classloader and its parents.</li> + * <li> <code>findLibrary()</code> which is called by + * <code>Runtime.loadLibrary()</code> when a class defined by the + * classloader wants to load a native library.</li> + * </ul> + * + * @author John Keiser + * @author Mark Wielaard + * @author Eric Blake (ebb9@email.byu.edu) + * @see Class + * @since 1.0 + */ +public abstract class ClassLoader +{ + /** + * All classes loaded by this classloader. VM's may choose to implement + * this cache natively; but it is here available for use if necessary. It + * is not private in order to allow native code (and trusted subclasses) + * access to this field. + */ + final HashMap loadedClasses = new HashMap(); + + /** + * Loading constraints registered with this classloader. This maps + * a class name to a weak reference to a class. When the reference + * is non-null, it means that a reference to the name must resolve + * to the indicated class. + */ + final HashMap<String, WeakReference<Class>> loadingConstraints + = new HashMap<String, WeakReference<Class>>(); + + /** + * All packages defined by this classloader. It is not private in order to + * allow native code (and trusted subclasses) access to this field. + */ + final HashMap definedPackages = new HashMap(); + + /** + * The classloader that is consulted before this classloader. + * If null then the parent is the bootstrap classloader. + */ + private final ClassLoader parent; + + /** + * This is true if this classloader was successfully initialized. + * This flag is needed to avoid a class loader attack: even if the + * security manager rejects an attempt to create a class loader, the + * malicious class could have a finalize method which proceeds to + * define classes. + */ + private final boolean initialized; + + /** + * System/Application classloader: defaults to an instance of + * gnu.java.lang.SystemClassLoader, unless the first invocation of + * getSystemClassLoader loads another class loader because of the + * java.system.class.loader property. The initialization of this field + * is somewhat circular - getSystemClassLoader() checks whether this + * field is null in order to bypass a security check. + */ + static final ClassLoader systemClassLoader = + VMClassLoader.getSystemClassLoader(); + + /** + * This cache maps from a Class to its associated annotations. It's + * declared here so that when this class loader becomes unreachable, + * so will the corresponding cache. + */ + + private final ConcurrentHashMap<AnnotationsKey,Object[]> + declaredAnnotations + = new ConcurrentHashMap<AnnotationsKey,Object[]>(); + + static final class AnnotationsKey + { + final int /* jv_attr_type */ member_type; + final int member_index; + final int /* jv_attr_kind */ kind_req; + final Class declaringClass; + final int hashCode; + + public AnnotationsKey (Class declaringClass, + int member_type, + int member_index, + int kind_req) + { + this.member_type = member_type; + this.member_index = member_index; + this.kind_req = kind_req; + this.declaringClass = declaringClass; + hashCode = (member_type ^ member_index ^ kind_req + ^ declaringClass.hashCode()); + } + + public boolean equals(Object obj) + { + AnnotationsKey other = (AnnotationsKey)obj; + return (this.member_type == other.member_type + && this.member_index == other.member_index + && this.kind_req == other.kind_req + && this.declaringClass == other.declaringClass); + } + + public int hashCode() + { + return hashCode; + } + + public static final Annotation[] NIL = new Annotation[0]; + } + + final Object[] getDeclaredAnnotations(Class declaringClass, + int member_type, + int member_index, + int kind_req) + { + Object[] result + = declaredAnnotations.get (new AnnotationsKey + (declaringClass, + member_type, + member_index, + kind_req)); + if (result != AnnotationsKey.NIL && result != null) + return (Object[])result.clone(); + return null; + } + + final Object[] putDeclaredAnnotations(Class declaringClass, + int member_type, + int member_index, + int kind_req, + Object[] annotations) + { + declaredAnnotations.put + (new AnnotationsKey + (declaringClass, member_type, + member_index, kind_req), + annotations == null ? AnnotationsKey.NIL : annotations); + + return annotations == null ? null : (Object[])annotations.clone(); + } + + static + { + // Find out if we have to install a default security manager. Note + // that this is done here because we potentially need the system + // class loader to load the security manager and note also that we + // don't need the security manager until the system class loader + // is created. If the runtime chooses to use a class loader that + // doesn't have the system class loader as its parent, it is + // responsible for setting up a security manager before doing so. + String secman = SystemProperties.getProperty("java.security.manager"); + if (secman != null && SecurityManager.current == null) + { + if (secman.equals("") || secman.equals("default")) + { + SecurityManager.current = new SecurityManager(); + } + else + { + try + { + Class cl = Class.forName(secman, false, systemClassLoader); + SecurityManager.current = (SecurityManager) cl.newInstance(); + } + catch (Exception x) + { + throw (InternalError) + new InternalError("Unable to create SecurityManager") + .initCause(x); + } + } + } + } + + /** + * The default protection domain, used when defining a class with a null + * paramter for the domain. + */ + static final ProtectionDomain defaultProtectionDomain; + static + { + CodeSource cs = new CodeSource(null, null); + PermissionCollection perm = Policy.getPolicy().getPermissions(cs); + defaultProtectionDomain = new ProtectionDomain(cs, perm); + } + + /** + * The desired assertion status of classes loaded by this loader, if not + * overridden by package or class instructions. + */ + // Package visible for use by Class. + boolean defaultAssertionStatus = VMClassLoader.defaultAssertionStatus(); + + /** + * The command-line state of the package assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemPackageAssertionStatus + = VMClassLoader.packageAssertionStatus(); + + /** + * The map of package assertion status overrides, or null if no package + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE, and the unnamed package is represented + * by the null key. This map must be synchronized on this instance. + */ + // Package visible for use by Class. + Map packageAssertionStatus; + + /** + * The command-line state of the class assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemClassAssertionStatus + = VMClassLoader.classAssertionStatus(); + + /** + * The map of class assertion status overrides, or null if no class + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE. This map must be synchronized on this + * instance. + */ + // Package visible for use by Class. + Map classAssertionStatus; + + /** + * Create a new ClassLoader with as parent the system classloader. There + * may be a security check for <code>checkCreateClassLoader</code>. + * + * @throws SecurityException if the security check fails + */ + protected ClassLoader() throws SecurityException + { + this(systemClassLoader); + } + + /** + * Create a new ClassLoader with the specified parent. The parent will + * be consulted when a class or resource is requested through + * <code>loadClass()</code> or <code>getResource()</code>. Only when the + * parent classloader cannot provide the requested class or resource the + * <code>findClass()</code> or <code>findResource()</code> method + * of this classloader will be called. There may be a security check for + * <code>checkCreateClassLoader</code>. + * + * @param parent the classloader's parent, or null for the bootstrap + * classloader + * @throws SecurityException if the security check fails + * @since 1.2 + */ + protected ClassLoader(ClassLoader parent) + { + // May we create a new classloader? + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkCreateClassLoader(); + this.parent = parent; + this.initialized = true; + } + + /** + * Load a class using this ClassLoader or its parent, without resolving + * it. Calls <code>loadClass(name, false)</code>. + * + * <p>Subclasses should not override this method but should override + * <code>findClass()</code> which is called by this method.</p> + * + * @param name the name of the class relative to this ClassLoader + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + public Class<?> loadClass(String name) throws ClassNotFoundException + { + return loadClass(name, false); + } + + private native Class loadClassFromSig(String name) + throws ClassNotFoundException; + + /** + * Load a class using this ClassLoader or its parent, possibly resolving + * it as well using <code>resolveClass()</code>. It first tries to find + * out if the class has already been loaded through this classloader by + * calling <code>findLoadedClass()</code>. Then it calls + * <code>loadClass()</code> on the parent classloader (or when there is + * no parent it uses the VM bootclassloader). If the class is still + * not loaded it tries to create a new class by calling + * <code>findClass()</code>. Finally when <code>resolve</code> is + * <code>true</code> it also calls <code>resolveClass()</code> on the + * newly loaded class. + * + * <p>Subclasses should not override this method but should override + * <code>findClass()</code> which is called by this method.</p> + * + * @param name the fully qualified name of the class to load + * @param resolve whether or not to resolve the class + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + protected synchronized Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + int lastDot = name.lastIndexOf('.'); + if (lastDot != -1) + sm.checkPackageAccess(name.substring(0, lastDot)); + } + + // Arrays are handled specially. + Class c; + if (name.length() > 0 && name.charAt(0) == '[') + c = loadClassFromSig(name); + else + { + // Have we already loaded this class? + c = findLoadedClass(name); + if (c == null) + { + // Can the class be loaded by a parent? + try + { + if (parent == null) + { + c = VMClassLoader.loadClass(name, resolve); + if (c != null) + return c; + } + else + { + return parent.loadClass(name, resolve); + } + } + catch (ClassNotFoundException e) + { + } + // Still not found, we have to do it ourself. + c = findClass(name); + } + } + if (resolve) + resolveClass(c); + return c; + } + + /** + * Called for every class name that is needed but has not yet been + * defined by this classloader or one of its parents. It is called by + * <code>loadClass()</code> after both <code>findLoadedClass()</code> and + * <code>parent.loadClass()</code> couldn't provide the requested class. + * + * <p>The default implementation throws a + * <code>ClassNotFoundException</code>. Subclasses should override this + * method. An implementation of this method in a subclass should get the + * class bytes of the class (if it can find them), if the package of the + * requested class doesn't exist it should define the package and finally + * it should call define the actual class. It does not have to resolve the + * class. It should look something like the following:<br> + * + * <pre> + * // Get the bytes that describe the requested class + * byte[] classBytes = classLoaderSpecificWayToFindClassBytes(name); + * // Get the package name + * int lastDot = name.lastIndexOf('.'); + * if (lastDot != -1) + * { + * String packageName = name.substring(0, lastDot); + * // Look if the package already exists + * if (getPackage(packageName) == null) + * { + * // define the package + * definePackage(packageName, ...); + * } + * } + * // Define and return the class + * return defineClass(name, classBytes, 0, classBytes.length); + * </pre> + * + * <p><code>loadClass()</code> makes sure that the <code>Class</code> + * returned by <code>findClass()</code> will later be returned by + * <code>findLoadedClass()</code> when the same class name is requested. + * + * @param name class name to find (including the package name) + * @return the requested Class + * @throws ClassNotFoundException when the class can not be found + * @since 1.2 + */ + protected Class<?> findClass(String name) throws ClassNotFoundException + { + throw new ClassNotFoundException(name); + } + + /** + * Helper to define a class using a string of bytes. This version is not + * secure. + * + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @deprecated use {@link #defineClass(String, byte[], int, int)} instead + */ + protected final Class<?> defineClass(byte[] data, int offset, int len) + throws ClassFormatError + { + return defineClass(null, data, offset, len); + } + + /** + * Helper to define a class using a string of bytes without a + * ProtectionDomain. Subclasses should call this method from their + * <code>findClass()</code> implementation. The name should use '.' + * separators, and discard the trailing ".class". The default protection + * domain has the permissions of + * <code>Policy.getPolicy().getPermissions(new CodeSource(null, null))</code>. + * + * @param name the name to give the class, or null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java." + * @since 1.1 + */ + protected final Class<?> defineClass(String name, byte[] data, int offset, + int len) throws ClassFormatError + { + return defineClass(name, data, offset, len, null); + } + + /** + * Helper to define a class using a string of bytes. Subclasses should call + * this method from their <code>findClass()</code> implementation. If the + * domain is null, the default of + * <code>Policy.getPolicy().getPermissions(new CodeSource(null, null))</code> + * is used. Once a class has been defined in a package, all further classes + * in that package must have the same set of certificates or a + * SecurityException is thrown. + * + * @param name the name to give the class. null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @param domain the ProtectionDomain to give to the class, null for the + * default protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java.", or if certificates + * do not match up + * @since 1.2 + */ + protected final synchronized Class<?> defineClass(String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + throws ClassFormatError + { + checkInitialized(); + if (domain == null) + domain = defaultProtectionDomain; + + Class retval = VMClassLoader.defineClass(this, name, data, + offset, len, domain); + loadedClasses.put(retval.getName(), retval); + return retval; + } + + /** + * Helper to define a class using the contents of a byte buffer. If + * the domain is null, the default of + * <code>Policy.getPolicy().getPermissions(new CodeSource(null, + * null))</code> is used. Once a class has been defined in a + * package, all further classes in that package must have the same + * set of certificates or a SecurityException is thrown. + * + * @param name the name to give the class. null if unknown + * @param buf a byte buffer containing bytes that form a class. + * @param domain the ProtectionDomain to give to the class, null for the + * default protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws NoClassDefFoundError if the supplied name is not the same as + * the one specified by the byte buffer. + * @throws SecurityException if name starts with "java.", or if certificates + * do not match up + * @since 1.5 + */ + protected final Class<?> defineClass(String name, ByteBuffer buf, + ProtectionDomain domain) + throws ClassFormatError + { + byte[] data = new byte[buf.remaining()]; + buf.get(data); + return defineClass(name, data, 0, data.length, domain); + } + + /** + * Links the class, if that has not already been done. Linking basically + * resolves all references to other classes made by this class. + * + * @param c the class to resolve + * @throws NullPointerException if c is null + * @throws LinkageError if linking fails + */ + protected final void resolveClass(Class<?> c) + { + checkInitialized(); + VMClassLoader.resolveClass(c); + } + + /** + * Helper to find a Class using the system classloader, possibly loading it. + * A subclass usually does not need to call this, if it correctly + * overrides <code>findClass(String)</code>. + * + * @param name the name of the class to find + * @return the found class + * @throws ClassNotFoundException if the class cannot be found + */ + protected final Class<?> findSystemClass(String name) + throws ClassNotFoundException + { + checkInitialized(); + return Class.forName(name, false, systemClassLoader); + } + + /** + * Returns the parent of this classloader. If the parent of this + * classloader is the bootstrap classloader then this method returns + * <code>null</code>. A security check may be performed on + * <code>RuntimePermission("getClassLoader")</code>. + * + * @return the parent <code>ClassLoader</code> + * @throws SecurityException if the security check fails + * @since 1.2 + */ + public final ClassLoader getParent() + { + // Check if we may return the parent classloader. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && ! cl.isAncestorOf(this)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return parent; + } + + /** + * Helper to set the signers of a class. This should be called after + * defining the class. + * + * @param c the Class to set signers of + * @param signers the signers to set + * @since 1.1 + */ + protected final void setSigners(Class<?> c, Object[] signers) + { + checkInitialized(); + c.setSigners(signers); + } + + /** + * Helper to find an already-loaded class in this ClassLoader. + * + * @param name the name of the class to find + * @return the found Class, or null if it is not found + * @since 1.1 + */ + protected final synchronized Class<?> findLoadedClass(String name) + { + checkInitialized(); + // NOTE: If the VM is keeping its own cache, it may make sense to have + // this method be native. + return (Class) loadedClasses.get(name); + } + + /** + * Get the URL to a resource using this classloader or one of its parents. + * First tries to get the resource by calling <code>getResource()</code> + * on the parent classloader. If the parent classloader returns null then + * it tries finding the resource by calling <code>findResource()</code> on + * this classloader. The resource name should be separated by '/' for path + * elements. + * + * <p>Subclasses should not override this method but should override + * <code>findResource()</code> which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return the URL to the resource or null when not found + */ + public URL getResource(String name) + { + URL result; + + if (parent == null) + result = VMClassLoader.getResource(name); + else + result = parent.getResource(name); + + if (result == null) + result = findResource(name); + return result; + } + + /** + * Returns an Enumeration of all resources with a given name that can + * be found by this classloader and its parents. Certain classloaders + * (such as the URLClassLoader when given multiple jar files) can have + * multiple resources with the same name that come from multiple locations. + * It can also occur that a parent classloader offers a resource with a + * certain name and the child classloader also offers a resource with that + * same name. <code>getResource()</code> only offers the first resource (of the + * parent) with a given name. This method lists all resources with the + * same name. The name should use '/' as path separators. + * + * <p>The Enumeration is created by first calling <code>getResources()</code> + * on the parent classloader and then calling <code>findResources()</code> + * on this classloader.</p> + * + * @param name the resource name + * @return an enumaration of all resources found + * @throws IOException if I/O errors occur in the process + * @since 1.2 + * @specnote this was <code>final</code> prior to 1.5 + */ + public Enumeration<URL> getResources(String name) throws IOException + { + Enumeration<URL> parentResources; + if (parent == null) + parentResources = VMClassLoader.getResources(name); + else + parentResources = parent.getResources(name); + return new DoubleEnumeration<URL>(parentResources, findResources(name)); + } + + /** + * Called whenever all locations of a named resource are needed. + * It is called by <code>getResources()</code> after it has called + * <code>parent.getResources()</code>. The results are combined by + * the <code>getResources()</code> method. + * + * <p>The default implementation always returns an empty Enumeration. + * Subclasses should override it when they can provide an Enumeration of + * URLs (possibly just one element) to the named resource. + * The first URL of the Enumeration should be the same as the one + * returned by <code>findResource</code>. + * + * @param name the name of the resource to be found + * @return a possibly empty Enumeration of URLs to the named resource + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + protected Enumeration<URL> findResources(String name) throws IOException + { + return new EmptyEnumeration<URL>(); + } + + /** + * Called whenever a resource is needed that could not be provided by + * one of the parents of this classloader. It is called by + * <code>getResource()</code> after <code>parent.getResource()</code> + * couldn't provide the requested resource. + * + * <p>The default implementation always returns null. Subclasses should + * override this method when they can provide a way to return a URL + * to a named resource. + * + * @param name the name of the resource to be found + * @return a URL to the named resource or null when not found + * @since 1.2 + */ + protected URL findResource(String name) + { + return null; + } + + /** + * Get the URL to a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return the URL to the resource + * @since 1.1 + */ + public static final URL getSystemResource(String name) + { + return systemClassLoader.getResource(name); + } + + /** + * Get an Enumeration of URLs to resources with a given name using the + * the system classloader. The enumeration firsts lists the resources with + * the given name that can be found by the bootstrap classloader followed + * by the resources with the given name that can be found on the classpath. + * + * @param name the name of the resource relative to the system classloader + * @return an Enumeration of URLs to the resources + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + public static Enumeration<URL> getSystemResources(String name) + throws IOException + { + return systemClassLoader.getResources(name); + } + + /** + * Get a resource as stream using this classloader or one of its parents. + * First calls <code>getResource()</code> and if that returns a URL to + * the resource then it calls and returns the InputStream given by + * <code>URL.openStream()</code>. + * + * <p>Subclasses should not override this method but should override + * <code>findResource()</code> which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return an InputStream to the resource, or null + * @since 1.1 + */ + public InputStream getResourceAsStream(String name) + { + try + { + URL url = getResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Get a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return an input stream for the resource, or null + * @since 1.1 + */ + public static final InputStream getSystemResourceAsStream(String name) + { + try + { + URL url = getSystemResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Returns the system classloader. The system classloader (also called + * the application classloader) is the classloader that is used to + * load the application classes on the classpath (given by the system + * property <code>java.class.path</code>. This is set as the context + * class loader for a thread. The system property + * <code>java.system.class.loader</code>, if defined, is taken to be the + * name of the class to use as the system class loader, which must have + * a public constructor which takes a ClassLoader as a parent. The parent + * class loader passed in the constructor is the default system class + * loader. + * + * <p>Note that this is different from the bootstrap classloader that + * actually loads all the real "system" classes (the bootstrap classloader + * is the parent of the returned system classloader). + * + * <p>A security check will be performed for + * <code>RuntimePermission("getClassLoader")</code> if the calling class + * is not a parent of the system class loader. + * + * @return the system class loader + * @throws SecurityException if the security check fails + * @throws IllegalStateException if this is called recursively + * @throws Error if <code>java.system.class.loader</code> fails to load + * @since 1.2 + */ + public static ClassLoader getSystemClassLoader() + { + // Check if we may return the system classloader + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && cl != systemClassLoader) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + + return systemClassLoader; + } + + /** + * Defines a new package and creates a Package object. The package should + * be defined before any class in the package is defined with + * <code>defineClass()</code>. The package should not yet be defined + * before in this classloader or in one of its parents (which means that + * <code>getPackage()</code> should return <code>null</code>). All + * parameters except the <code>name</code> of the package may be + * <code>null</code>. + * + * <p>Subclasses should call this method from their <code>findClass()</code> + * implementation before calling <code>defineClass()</code> on a Class + * in a not yet defined Package (which can be checked by calling + * <code>getPackage()</code>). + * + * @param name the name of the Package + * @param specTitle the name of the specification + * @param specVendor the name of the specification designer + * @param specVersion the version of this specification + * @param implTitle the name of the implementation + * @param implVendor the vendor that wrote this implementation + * @param implVersion the version of this implementation + * @param sealed if sealed the origin of the package classes + * @return the Package object for the specified package + * @throws IllegalArgumentException if the package name is null or it + * was already defined by this classloader or one of its parents + * @see Package + * @since 1.2 + */ + protected Package definePackage(String name, String specTitle, + String specVendor, String specVersion, + String implTitle, String implVendor, + String implVersion, URL sealed) + { + if (getPackage(name) != null) + throw new IllegalArgumentException("Package " + name + + " already defined"); + Package p = new Package(name, specTitle, specVendor, specVersion, + implTitle, implVendor, implVersion, sealed, this); + synchronized (definedPackages) + { + definedPackages.put(name, p); + } + return p; + } + + /** + * Returns the Package object for the requested package name. It returns + * null when the package is not defined by this classloader or one of its + * parents. + * + * @param name the package name to find + * @return the package, if defined + * @since 1.2 + */ + protected Package getPackage(String name) + { + Package p; + if (parent == null) + p = VMClassLoader.getPackage(name); + else + p = parent.getPackage(name); + + if (p == null) + { + synchronized (definedPackages) + { + p = (Package) definedPackages.get(name); + } + } + return p; + } + + /** + * Returns all Package objects defined by this classloader and its parents. + * + * @return an array of all defined packages + * @since 1.2 + */ + protected Package[] getPackages() + { + // Get all our packages. + Package[] packages; + synchronized(definedPackages) + { + packages = new Package[definedPackages.size()]; + definedPackages.values().toArray(packages); + } + + // If we have a parent get all packages defined by our parents. + Package[] parentPackages; + if (parent == null) + parentPackages = VMClassLoader.getPackages(); + else + parentPackages = parent.getPackages(); + + Package[] allPackages = new Package[parentPackages.length + + packages.length]; + System.arraycopy(parentPackages, 0, allPackages, 0, + parentPackages.length); + System.arraycopy(packages, 0, allPackages, parentPackages.length, + packages.length); + return allPackages; + } + + /** + * Called by <code>Runtime.loadLibrary()</code> to get an absolute path + * to a (system specific) library that was requested by a class loaded + * by this classloader. The default implementation returns + * <code>null</code>. It should be implemented by subclasses when they + * have a way to find the absolute path to a library. If this method + * returns null the library is searched for in the default locations + * (the directories listed in the <code>java.library.path</code> system + * property). + * + * @param name the (system specific) name of the requested library + * @return the full pathname to the requested library, or null + * @see Runtime#loadLibrary(String) + * @since 1.2 + */ + protected String findLibrary(String name) + { + return null; + } + + /** + * Set the default assertion status for classes loaded by this classloader, + * used unless overridden by a package or class request. + * + * @param enabled true to set the default to enabled + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public void setDefaultAssertionStatus(boolean enabled) + { + defaultAssertionStatus = enabled; + } + + /** + * Set the default assertion status for packages, used unless overridden + * by a class request. This default also covers subpackages, unless they + * are also specified. The unnamed package should use null for the name. + * + * @param name the package (and subpackages) to affect + * @param enabled true to set the default to enabled + * @see #setDefaultAssertionStatus(boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setPackageAssertionStatus(String name, + boolean enabled) + { + if (packageAssertionStatus == null) + packageAssertionStatus + = new HashMap(systemPackageAssertionStatus); + packageAssertionStatus.put(name, Boolean.valueOf(enabled)); + } + + /** + * Set the default assertion status for a class. This only affects the + * status of top-level classes, any other string is harmless. + * + * @param name the class to affect + * @param enabled true to set the default to enabled + * @throws NullPointerException if name is null + * @see #setDefaultAssertionStatus(boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setClassAssertionStatus(String name, + boolean enabled) + { + if (classAssertionStatus == null) + classAssertionStatus = new HashMap(systemClassAssertionStatus); + // The toString() hack catches null, as required. + classAssertionStatus.put(name.toString(), Boolean.valueOf(enabled)); + } + + /** + * Resets the default assertion status of this classloader, its packages + * and classes, all to false. This allows overriding defaults inherited + * from the command line. + * + * @see #setDefaultAssertionStatus(boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @since 1.4 + */ + public synchronized void clearAssertionStatus() + { + defaultAssertionStatus = false; + packageAssertionStatus = new HashMap(); + classAssertionStatus = new HashMap(); + } + + /** + * Return true if this loader is either the specified class loader + * or an ancestor thereof. + * @param loader the class loader to check + */ + final boolean isAncestorOf(ClassLoader loader) + { + while (loader != null) + { + if (this == loader) + return true; + loader = loader.parent; + } + return false; + } + + /** + * Before doing anything "dangerous" please call this method to make sure + * this class loader instance was properly constructed (and not obtained + * by exploiting the finalizer attack) + * @see #initialized + */ + private void checkInitialized() + { + if (! initialized) + throw new SecurityException("attempt to use uninitialized class loader"); + } +} diff --git a/libjava/java/lang/ClassNotFoundException.h b/libjava/java/lang/ClassNotFoundException.h new file mode 100644 index 000000000..c0ab78158 --- /dev/null +++ b/libjava/java/lang/ClassNotFoundException.h @@ -0,0 +1,27 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ClassNotFoundException__ +#define __java_lang_ClassNotFoundException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::ClassNotFoundException : public ::java::lang::Exception +{ + +public: + ClassNotFoundException(); + ClassNotFoundException(::java::lang::String *); + ClassNotFoundException(::java::lang::String *, ::java::lang::Throwable *); + virtual ::java::lang::Throwable * getException(); + virtual ::java::lang::Throwable * getCause(); +private: + static const jlong serialVersionUID = 9176873029745254542LL; + ::java::lang::Throwable * __attribute__((aligned(__alignof__( ::java::lang::Exception)))) ex; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ClassNotFoundException__ diff --git a/libjava/java/lang/CloneNotSupportedException.h b/libjava/java/lang/CloneNotSupportedException.h new file mode 100644 index 000000000..19fa2124a --- /dev/null +++ b/libjava/java/lang/CloneNotSupportedException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_CloneNotSupportedException__ +#define __java_lang_CloneNotSupportedException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::CloneNotSupportedException : public ::java::lang::Exception +{ + +public: + CloneNotSupportedException(); + CloneNotSupportedException(::java::lang::String *); +private: + static const jlong serialVersionUID = 5195511250079656443LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_CloneNotSupportedException__ diff --git a/libjava/java/lang/Cloneable.h b/libjava/java/lang/Cloneable.h new file mode 100644 index 000000000..ff5db98d0 --- /dev/null +++ b/libjava/java/lang/Cloneable.h @@ -0,0 +1,18 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Cloneable__ +#define __java_lang_Cloneable__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Cloneable : public ::java::lang::Object +{ + +public: + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Cloneable__ diff --git a/libjava/java/lang/Comparable.h b/libjava/java/lang/Comparable.h new file mode 100644 index 000000000..b594e2ddc --- /dev/null +++ b/libjava/java/lang/Comparable.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Comparable__ +#define __java_lang_Comparable__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Comparable : public ::java::lang::Object +{ + +public: + virtual jint compareTo(::java::lang::Object *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Comparable__ diff --git a/libjava/java/lang/Compiler.h b/libjava/java/lang/Compiler.h new file mode 100644 index 000000000..e21d90300 --- /dev/null +++ b/libjava/java/lang/Compiler.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Compiler__ +#define __java_lang_Compiler__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Compiler : public ::java::lang::Object +{ + + Compiler(); +public: + static jboolean compileClass(::java::lang::Class *); + static jboolean compileClasses(::java::lang::String *); + static ::java::lang::Object * command(::java::lang::Object *); + static void enable(); + static void disable(); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Compiler__ diff --git a/libjava/java/lang/Deprecated.h b/libjava/java/lang/Deprecated.h new file mode 100644 index 000000000..6ab34f11a --- /dev/null +++ b/libjava/java/lang/Deprecated.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Deprecated__ +#define __java_lang_Deprecated__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Deprecated : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Deprecated__ diff --git a/libjava/java/lang/Double.h b/libjava/java/lang/Double.h new file mode 100644 index 000000000..54eb42b50 --- /dev/null +++ b/libjava/java/lang/Double.h @@ -0,0 +1,59 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Double__ +#define __java_lang_Double__ + +#pragma interface + +#include <java/lang/Number.h> + +class java::lang::Double : public ::java::lang::Number +{ + +public: + Double(jdouble); + Double(::java::lang::String *); + static ::java::lang::String * toString(jdouble); + static ::java::lang::String * toHexString(jdouble); + static ::java::lang::Double * valueOf(jdouble); + static ::java::lang::Double * valueOf(::java::lang::String *); + static jdouble parseDouble(::java::lang::String *); + static jboolean isNaN(jdouble); + static jboolean isInfinite(jdouble); + jboolean isNaN(); + jboolean isInfinite(); + ::java::lang::String * toString(); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + static jlong doubleToLongBits(jdouble); + static jlong doubleToRawLongBits(jdouble); + static jdouble longBitsToDouble(jlong); + jint Double$compareTo(::java::lang::Double *); + static jint compare(jdouble, jdouble); + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -9172774392245257468LL; +public: + static jdouble MAX_VALUE; + static jdouble MIN_VALUE; + static jdouble NEGATIVE_INFINITY; + static jdouble POSITIVE_INFINITY; + static jdouble NaN; + static const jint SIZE = 64; + static ::java::lang::Class * TYPE; +private: + static ::java::lang::Double * ZERO; + static ::java::lang::Double * ONE; + jdouble __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Double__ diff --git a/libjava/java/lang/EcosProcess.h b/libjava/java/lang/EcosProcess.h new file mode 100644 index 000000000..a0173c30a --- /dev/null +++ b/libjava/java/lang/EcosProcess.h @@ -0,0 +1,27 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_EcosProcess__ +#define __java_lang_EcosProcess__ + +#pragma interface + +#include <java/lang/Process.h> +#include <gcj/array.h> + + +class java::lang::EcosProcess : public ::java::lang::Process +{ + +public: + void destroy(); + jint exitValue(); + ::java::io::InputStream * getErrorStream(); + ::java::io::InputStream * getInputStream(); + ::java::io::OutputStream * getOutputStream(); + jint waitFor(); + EcosProcess(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_EcosProcess__ diff --git a/libjava/java/lang/EcosProcess.java b/libjava/java/lang/EcosProcess.java new file mode 100644 index 000000000..79c2f12a5 --- /dev/null +++ b/libjava/java/lang/EcosProcess.java @@ -0,0 +1,60 @@ +// EcosProcess.java - Subclass of Process for eCos systems. + +/* Copyright (C) 1998, 1999, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Tom Tromey <tromey@cygnus.com> + * @date May 11, 1999 + */ + +// This is entirely internal to our implementation. + +final class EcosProcess extends Process +{ + // See natEcosProcess.cc to understand why this is native. + public native void destroy (); + + public int exitValue () + { + return 0; + } + public InputStream getErrorStream () + { + return null; + } + + public InputStream getInputStream () + { + return null; + } + + public OutputStream getOutputStream () + { + return null; + } + + public int waitFor () throws InterruptedException + { + return 0; + } + + public EcosProcess (String[] progarray, String[] envp, File dir, + boolean redirect) + throws IOException + { + throw new IOException ("eCos processes unimplemented"); + } +} diff --git a/libjava/java/lang/Enum.h b/libjava/java/lang/Enum.h new file mode 100644 index 000000000..15ccb1615 --- /dev/null +++ b/libjava/java/lang/Enum.h @@ -0,0 +1,41 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Enum__ +#define __java_lang_Enum__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Enum : public ::java::lang::Object +{ + +public: // actually protected + Enum(::java::lang::String *, jint); +public: + static ::java::lang::Enum * valueOf(::java::lang::Class *, ::java::lang::String *); + virtual jboolean equals(::java::lang::Object *); + virtual jint hashCode(); + virtual ::java::lang::String * toString(); + virtual jint Enum$compareTo(::java::lang::Enum *); +public: // actually protected + virtual ::java::lang::Object * clone(); +public: + virtual ::java::lang::String * name(); + virtual jint ordinal(); + virtual ::java::lang::Class * getDeclaringClass(); +public: // actually protected + virtual void finalize(); +public: + virtual jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -4300926546619394005LL; +public: // actually package-private + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) name__; + jint ordinal__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Enum__ diff --git a/libjava/java/lang/EnumConstantNotPresentException.h b/libjava/java/lang/EnumConstantNotPresentException.h new file mode 100644 index 000000000..b3bc11b28 --- /dev/null +++ b/libjava/java/lang/EnumConstantNotPresentException.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_EnumConstantNotPresentException__ +#define __java_lang_EnumConstantNotPresentException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::EnumConstantNotPresentException : public ::java::lang::RuntimeException +{ + +public: + EnumConstantNotPresentException(::java::lang::Class *, ::java::lang::String *); + virtual ::java::lang::String * constantName(); + virtual ::java::lang::Class * enumType(); +private: + static const jlong serialVersionUID = -6046998521960521108LL; + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::RuntimeException)))) enumType__; + ::java::lang::String * constantName__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_EnumConstantNotPresentException__ diff --git a/libjava/java/lang/Error.h b/libjava/java/lang/Error.h new file mode 100644 index 000000000..9cb6019b4 --- /dev/null +++ b/libjava/java/lang/Error.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Error__ +#define __java_lang_Error__ + +#pragma interface + +#include <java/lang/Throwable.h> + +class java::lang::Error : public ::java::lang::Throwable +{ + +public: + Error(); + Error(::java::lang::String *); + Error(::java::lang::String *, ::java::lang::Throwable *); + Error(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = 4980196508277280342LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Error__ diff --git a/libjava/java/lang/Exception.h b/libjava/java/lang/Exception.h new file mode 100644 index 000000000..9f3ab43a5 --- /dev/null +++ b/libjava/java/lang/Exception.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Exception__ +#define __java_lang_Exception__ + +#pragma interface + +#include <java/lang/Throwable.h> + +class java::lang::Exception : public ::java::lang::Throwable +{ + +public: + Exception(); + Exception(::java::lang::String *); + Exception(::java::lang::String *, ::java::lang::Throwable *); + Exception(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -3387516993124229948LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Exception__ diff --git a/libjava/java/lang/ExceptionInInitializerError.h b/libjava/java/lang/ExceptionInInitializerError.h new file mode 100644 index 000000000..89fbaee7c --- /dev/null +++ b/libjava/java/lang/ExceptionInInitializerError.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ExceptionInInitializerError__ +#define __java_lang_ExceptionInInitializerError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::ExceptionInInitializerError : public ::java::lang::LinkageError +{ + +public: + ExceptionInInitializerError(); + ExceptionInInitializerError(::java::lang::String *); + ExceptionInInitializerError(::java::lang::Throwable *); + virtual ::java::lang::Throwable * getException(); + virtual ::java::lang::Throwable * getCause(); +public: // actually package-private + static const jlong serialVersionUID = 1521711792217232256LL; +private: + ::java::lang::Throwable * __attribute__((aligned(__alignof__( ::java::lang::LinkageError)))) exception; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ExceptionInInitializerError__ diff --git a/libjava/java/lang/Float.h b/libjava/java/lang/Float.h new file mode 100644 index 000000000..603da6dd1 --- /dev/null +++ b/libjava/java/lang/Float.h @@ -0,0 +1,60 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Float__ +#define __java_lang_Float__ + +#pragma interface + +#include <java/lang/Number.h> + +class java::lang::Float : public ::java::lang::Number +{ + +public: + Float(jfloat); + Float(jdouble); + Float(::java::lang::String *); + static ::java::lang::String * toString(jfloat); + static ::java::lang::String * toHexString(jfloat); + static ::java::lang::Float * valueOf(::java::lang::String *); + static ::java::lang::Float * valueOf(jfloat); + static jfloat parseFloat(::java::lang::String *); + static jboolean isNaN(jfloat); + static jboolean isInfinite(jfloat); + jboolean isNaN(); + jboolean isInfinite(); + ::java::lang::String * toString(); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + static jint floatToIntBits(jfloat); + static jint floatToRawIntBits(jfloat); + static jfloat intBitsToFloat(jint); + jint Float$compareTo(::java::lang::Float *); + static jint compare(jfloat, jfloat); + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -2671257302660747028LL; +public: + static jfloat MAX_VALUE; + static jfloat MIN_VALUE; + static jfloat NEGATIVE_INFINITY; + static jfloat POSITIVE_INFINITY; + static jfloat NaN; + static ::java::lang::Class * TYPE; + static const jint SIZE = 32; +private: + static ::java::lang::Float * ZERO; + static ::java::lang::Float * ONE; + jfloat __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Float__ diff --git a/libjava/java/lang/IllegalAccessError.h b/libjava/java/lang/IllegalAccessError.h new file mode 100644 index 000000000..12b8747c4 --- /dev/null +++ b/libjava/java/lang/IllegalAccessError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalAccessError__ +#define __java_lang_IllegalAccessError__ + +#pragma interface + +#include <java/lang/IncompatibleClassChangeError.h> + +class java::lang::IllegalAccessError : public ::java::lang::IncompatibleClassChangeError +{ + +public: + IllegalAccessError(); + IllegalAccessError(::java::lang::String *); +private: + static const jlong serialVersionUID = -8988904074992417891LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalAccessError__ diff --git a/libjava/java/lang/IllegalAccessException.h b/libjava/java/lang/IllegalAccessException.h new file mode 100644 index 000000000..c09174756 --- /dev/null +++ b/libjava/java/lang/IllegalAccessException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalAccessException__ +#define __java_lang_IllegalAccessException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::IllegalAccessException : public ::java::lang::Exception +{ + +public: + IllegalAccessException(); + IllegalAccessException(::java::lang::String *); +private: + static const jlong serialVersionUID = 6616958222490762034LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalAccessException__ diff --git a/libjava/java/lang/IllegalArgumentException.h b/libjava/java/lang/IllegalArgumentException.h new file mode 100644 index 000000000..187e430c1 --- /dev/null +++ b/libjava/java/lang/IllegalArgumentException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalArgumentException__ +#define __java_lang_IllegalArgumentException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::IllegalArgumentException : public ::java::lang::RuntimeException +{ + +public: + IllegalArgumentException(); + IllegalArgumentException(::java::lang::String *); + IllegalArgumentException(::java::lang::String *, ::java::lang::Throwable *); + IllegalArgumentException(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -5365630128856068164LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalArgumentException__ diff --git a/libjava/java/lang/IllegalMonitorStateException.h b/libjava/java/lang/IllegalMonitorStateException.h new file mode 100644 index 000000000..ad9cb5902 --- /dev/null +++ b/libjava/java/lang/IllegalMonitorStateException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalMonitorStateException__ +#define __java_lang_IllegalMonitorStateException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::IllegalMonitorStateException : public ::java::lang::RuntimeException +{ + +public: + IllegalMonitorStateException(); + IllegalMonitorStateException(::java::lang::String *); +private: + static const jlong serialVersionUID = 3713306369498869069LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalMonitorStateException__ diff --git a/libjava/java/lang/IllegalStateException.h b/libjava/java/lang/IllegalStateException.h new file mode 100644 index 000000000..e79bced81 --- /dev/null +++ b/libjava/java/lang/IllegalStateException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalStateException__ +#define __java_lang_IllegalStateException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::IllegalStateException : public ::java::lang::RuntimeException +{ + +public: + IllegalStateException(); + IllegalStateException(::java::lang::String *); + IllegalStateException(::java::lang::String *, ::java::lang::Throwable *); + IllegalStateException(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -1848914673093119416LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalStateException__ diff --git a/libjava/java/lang/IllegalThreadStateException.h b/libjava/java/lang/IllegalThreadStateException.h new file mode 100644 index 000000000..066eb92cd --- /dev/null +++ b/libjava/java/lang/IllegalThreadStateException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IllegalThreadStateException__ +#define __java_lang_IllegalThreadStateException__ + +#pragma interface + +#include <java/lang/IllegalArgumentException.h> + +class java::lang::IllegalThreadStateException : public ::java::lang::IllegalArgumentException +{ + +public: + IllegalThreadStateException(); + IllegalThreadStateException(::java::lang::String *); +private: + static const jlong serialVersionUID = -7626246362397460174LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IllegalThreadStateException__ diff --git a/libjava/java/lang/IncompatibleClassChangeError.h b/libjava/java/lang/IncompatibleClassChangeError.h new file mode 100644 index 000000000..ca4099194 --- /dev/null +++ b/libjava/java/lang/IncompatibleClassChangeError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IncompatibleClassChangeError__ +#define __java_lang_IncompatibleClassChangeError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::IncompatibleClassChangeError : public ::java::lang::LinkageError +{ + +public: + IncompatibleClassChangeError(); + IncompatibleClassChangeError(::java::lang::String *); +private: + static const jlong serialVersionUID = -4914975503642802119LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IncompatibleClassChangeError__ diff --git a/libjava/java/lang/IndexOutOfBoundsException.h b/libjava/java/lang/IndexOutOfBoundsException.h new file mode 100644 index 000000000..4cd4184a7 --- /dev/null +++ b/libjava/java/lang/IndexOutOfBoundsException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_IndexOutOfBoundsException__ +#define __java_lang_IndexOutOfBoundsException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::IndexOutOfBoundsException : public ::java::lang::RuntimeException +{ + +public: + IndexOutOfBoundsException(); + IndexOutOfBoundsException(::java::lang::String *); +private: + static const jlong serialVersionUID = 234122996006267687LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_IndexOutOfBoundsException__ diff --git a/libjava/java/lang/InheritableThreadLocal.h b/libjava/java/lang/InheritableThreadLocal.h new file mode 100644 index 000000000..9caf6f3df --- /dev/null +++ b/libjava/java/lang/InheritableThreadLocal.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_InheritableThreadLocal__ +#define __java_lang_InheritableThreadLocal__ + +#pragma interface + +#include <java/lang/ThreadLocal.h> + +class java::lang::InheritableThreadLocal : public ::java::lang::ThreadLocal +{ + +public: + InheritableThreadLocal(); +public: // actually protected + virtual ::java::lang::Object * childValue(::java::lang::Object *); +public: // actually package-private + static void newChildThread(::java::lang::Thread *); +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_InheritableThreadLocal__ diff --git a/libjava/java/lang/InstantiationError.h b/libjava/java/lang/InstantiationError.h new file mode 100644 index 000000000..4b817d2b3 --- /dev/null +++ b/libjava/java/lang/InstantiationError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_InstantiationError__ +#define __java_lang_InstantiationError__ + +#pragma interface + +#include <java/lang/IncompatibleClassChangeError.h> + +class java::lang::InstantiationError : public ::java::lang::IncompatibleClassChangeError +{ + +public: + InstantiationError(); + InstantiationError(::java::lang::String *); +private: + static const jlong serialVersionUID = -4885810657349421204LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_InstantiationError__ diff --git a/libjava/java/lang/InstantiationException.h b/libjava/java/lang/InstantiationException.h new file mode 100644 index 000000000..805ab3c70 --- /dev/null +++ b/libjava/java/lang/InstantiationException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_InstantiationException__ +#define __java_lang_InstantiationException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::InstantiationException : public ::java::lang::Exception +{ + +public: + InstantiationException(); + InstantiationException(::java::lang::String *); +private: + static const jlong serialVersionUID = -8441929162975509110LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_InstantiationException__ diff --git a/libjava/java/lang/Integer.h b/libjava/java/lang/Integer.h new file mode 100644 index 000000000..f1bd11bdb --- /dev/null +++ b/libjava/java/lang/Integer.h @@ -0,0 +1,77 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Integer__ +#define __java_lang_Integer__ + +#pragma interface + +#include <java/lang/Number.h> +#include <gcj/array.h> + + +class java::lang::Integer : public ::java::lang::Number +{ + +public: + Integer(jint); + Integer(::java::lang::String *); +private: + static jint stringSize(jint, jint); +public: + static ::java::lang::String * toString(jint, jint); + static ::java::lang::String * toHexString(jint); + static ::java::lang::String * toOctalString(jint); + static ::java::lang::String * toBinaryString(jint); + static ::java::lang::String * toString(jint); + static jint parseInt(::java::lang::String *, jint); + static jint parseInt(::java::lang::String *); + static ::java::lang::Integer * valueOf(::java::lang::String *, jint); + static ::java::lang::Integer * valueOf(::java::lang::String *); + static ::java::lang::Integer * valueOf(jint); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + ::java::lang::String * toString(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + static ::java::lang::Integer * getInteger(::java::lang::String *); + static ::java::lang::Integer * getInteger(::java::lang::String *, jint); + static ::java::lang::Integer * getInteger(::java::lang::String *, ::java::lang::Integer *); + static ::java::lang::Integer * decode(::java::lang::String *); + jint Integer$compareTo(::java::lang::Integer *); + static jint bitCount(jint); + static jint rotateLeft(jint, jint); + static jint rotateRight(jint, jint); + static jint highestOneBit(jint); + static jint numberOfLeadingZeros(jint); + static jint lowestOneBit(jint); + static jint numberOfTrailingZeros(jint); + static jint signum(jint); + static jint reverseBytes(jint); + static jint reverse(jint); +public: // actually package-private + static ::java::lang::String * toUnsignedString(jint, jint); + static jint parseInt(::java::lang::String *, jint, jboolean); +public: + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = 1360826667806852920LL; +public: + static const jint MIN_VALUE = -2147483647 - 1; + static const jint MAX_VALUE = 2147483647; + static ::java::lang::Class * TYPE; + static const jint SIZE = 32; +private: + static const jint MIN_CACHE = -128; + static const jint MAX_CACHE = 127; + static JArray< ::java::lang::Integer * > * intCache; + jint __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Integer__ diff --git a/libjava/java/lang/InternalError.h b/libjava/java/lang/InternalError.h new file mode 100644 index 000000000..b0477bbe6 --- /dev/null +++ b/libjava/java/lang/InternalError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_InternalError__ +#define __java_lang_InternalError__ + +#pragma interface + +#include <java/lang/VirtualMachineError.h> + +class java::lang::InternalError : public ::java::lang::VirtualMachineError +{ + +public: + InternalError(); + InternalError(::java::lang::String *); +private: + static const jlong serialVersionUID = -9062593416125562365LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_InternalError__ diff --git a/libjava/java/lang/InterruptedException.h b/libjava/java/lang/InterruptedException.h new file mode 100644 index 000000000..c452de6b5 --- /dev/null +++ b/libjava/java/lang/InterruptedException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_InterruptedException__ +#define __java_lang_InterruptedException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::InterruptedException : public ::java::lang::Exception +{ + +public: + InterruptedException(); + InterruptedException(::java::lang::String *); +private: + static const jlong serialVersionUID = 6700697376100628473LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_InterruptedException__ diff --git a/libjava/java/lang/Iterable.h b/libjava/java/lang/Iterable.h new file mode 100644 index 000000000..3bdb2543b --- /dev/null +++ b/libjava/java/lang/Iterable.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Iterable__ +#define __java_lang_Iterable__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Iterable : public ::java::lang::Object +{ + +public: + virtual ::java::util::Iterator * iterator() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Iterable__ diff --git a/libjava/java/lang/LinkageError.h b/libjava/java/lang/LinkageError.h new file mode 100644 index 000000000..4368d8b9f --- /dev/null +++ b/libjava/java/lang/LinkageError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_LinkageError__ +#define __java_lang_LinkageError__ + +#pragma interface + +#include <java/lang/Error.h> + +class java::lang::LinkageError : public ::java::lang::Error +{ + +public: + LinkageError(); + LinkageError(::java::lang::String *); +private: + static const jlong serialVersionUID = 3579600108157160122LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_LinkageError__ diff --git a/libjava/java/lang/Long.h b/libjava/java/lang/Long.h new file mode 100644 index 000000000..60c0d2437 --- /dev/null +++ b/libjava/java/lang/Long.h @@ -0,0 +1,77 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Long__ +#define __java_lang_Long__ + +#pragma interface + +#include <java/lang/Number.h> +#include <gcj/array.h> + + +class java::lang::Long : public ::java::lang::Number +{ + +public: + Long(jlong); + Long(::java::lang::String *); +private: + static jint stringSize(jlong, jint); +public: + static ::java::lang::String * toString(jlong, jint); + static ::java::lang::String * toHexString(jlong); + static ::java::lang::String * toOctalString(jlong); + static ::java::lang::String * toBinaryString(jlong); + static ::java::lang::String * toString(jlong); + static jlong parseLong(::java::lang::String *, jint); + static jlong parseLong(::java::lang::String *); + static ::java::lang::Long * valueOf(::java::lang::String *, jint); + static ::java::lang::Long * valueOf(::java::lang::String *); + static ::java::lang::Long * valueOf(jlong); + static ::java::lang::Long * decode(::java::lang::String *); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + ::java::lang::String * toString(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + static ::java::lang::Long * getLong(::java::lang::String *); + static ::java::lang::Long * getLong(::java::lang::String *, jlong); + static ::java::lang::Long * getLong(::java::lang::String *, ::java::lang::Long *); + jint Long$compareTo(::java::lang::Long *); + static jint bitCount(jlong); + static jlong rotateLeft(jlong, jint); + static jlong rotateRight(jlong, jint); + static jlong highestOneBit(jlong); + static jint numberOfLeadingZeros(jlong); + static jlong lowestOneBit(jlong); + static jint numberOfTrailingZeros(jlong); + static jint signum(jlong); + static jlong reverseBytes(jlong); + static jlong reverse(jlong); +private: + static ::java::lang::String * toUnsignedString(jlong, jint); + static jlong parseLong(::java::lang::String *, jint, jboolean); +public: + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = 4290774380558885855LL; +public: + static const jlong MIN_VALUE = -9223372036854775807LL - 1; + static const jlong MAX_VALUE = 9223372036854775807LL; + static ::java::lang::Class * TYPE; + static const jint SIZE = 64; +private: + static const jint MIN_CACHE = -128; + static const jint MAX_CACHE = 127; + static JArray< ::java::lang::Long * > * longCache; + jlong __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Long__ diff --git a/libjava/java/lang/Math.h b/libjava/java/lang/Math.h new file mode 100644 index 000000000..32707e9f8 --- /dev/null +++ b/libjava/java/lang/Math.h @@ -0,0 +1,68 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Math__ +#define __java_lang_Math__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Math : public ::java::lang::Object +{ + + Math(); +public: + static jint abs(jint); + static jlong abs(jlong); + static jfloat abs(jfloat); + static jdouble abs(jdouble); + static jint min(jint, jint); + static jlong min(jlong, jlong); + static jfloat min(jfloat, jfloat); + static jdouble min(jdouble, jdouble); + static jint max(jint, jint); + static jlong max(jlong, jlong); + static jfloat max(jfloat, jfloat); + static jdouble max(jdouble, jdouble); + static jdouble sin(jdouble); + static jdouble cos(jdouble); + static jdouble tan(jdouble); + static jdouble asin(jdouble); + static jdouble acos(jdouble); + static jdouble atan(jdouble); + static jdouble atan2(jdouble, jdouble); + static jdouble exp(jdouble); + static jdouble log(jdouble); + static jdouble sqrt(jdouble); + static jdouble pow(jdouble, jdouble); + static jdouble IEEEremainder(jdouble, jdouble); + static jdouble ceil(jdouble); + static jdouble floor(jdouble); + static jdouble rint(jdouble); + static jint round(jfloat); + static jlong round(jdouble); + static jdouble random(); + static jdouble toRadians(jdouble); + static jdouble toDegrees(jdouble); + static jdouble cbrt(jdouble); + static jdouble cosh(jdouble); + static jdouble expm1(jdouble); + static jdouble hypot(jdouble, jdouble); + static jdouble log10(jdouble); + static jdouble log1p(jdouble); + static jdouble signum(jdouble); + static jfloat signum(jfloat); + static jdouble sinh(jdouble); + static jdouble tanh(jdouble); + static jdouble ulp(jdouble); + static jfloat ulp(jfloat); +private: + static ::java::util::Random * rand; +public: + static jdouble E; + static jdouble PI; + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Math__ diff --git a/libjava/java/lang/Math.java b/libjava/java/lang/Math.java new file mode 100644 index 000000000..836b8bd86 --- /dev/null +++ b/libjava/java/lang/Math.java @@ -0,0 +1,973 @@ +/* java.lang.Math -- common mathematical functions, native allowed + Copyright (C) 1998, 2001, 2002, 2003, 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 java.lang; + +import gnu.classpath.Configuration; + +import java.util.Random; + +/** + * Helper class containing useful mathematical functions and constants. + * <P> + * + * Note that angles are specified in radians. Conversion functions are + * provided for your convenience. + * + * @author Paul Fisher + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + */ +public final class Math +{ + /** + * Math is non-instantiable + */ + private Math() + { + } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalang"); + } + } + + /** + * A random number generator, initialized on first use. + */ + private static Random rand; + + /** + * The most accurate approximation to the mathematical constant <em>e</em>: + * <code>2.718281828459045</code>. Used in natural log and exp. + * + * @see #log(double) + * @see #exp(double) + */ + public static final double E = 2.718281828459045; + + /** + * The most accurate approximation to the mathematical constant <em>pi</em>: + * <code>3.141592653589793</code>. This is the ratio of a circle's diameter + * to its circumference. + */ + public static final double PI = 3.141592653589793; + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * Note that the the largest negative value (Integer.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a <em>negative</em> value. You have been warned. + * + * @param i the number to take the absolute value of + * @return the absolute value + * @see Integer#MIN_VALUE + */ + public static int abs(int i) + { + return (i < 0) ? -i : i; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * Note that the the largest negative value (Long.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a <em>negative</em> value. You have been warned. + * + * @param l the number to take the absolute value of + * @return the absolute value + * @see Long#MIN_VALUE + */ + public static long abs(long l) + { + return (l < 0) ? -l : l; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * This is equivalent, but faster than, calling + * <code>Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))</code>. + * + * @param f the number to take the absolute value of + * @return the absolute value + */ + public static float abs(float f) + { + return (f <= 0) ? 0 - f : f; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * + * This is equivalent, but faster than, calling + * <code>Double.longBitsToDouble(Double.doubleToLongBits(a) + * << 1) >>> 1);</code>. + * + * @param d the number to take the absolute value of + * @return the absolute value + */ + public static double abs(double d) + { + return (d <= 0) ? 0 - d : d; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static int min(int a, int b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static long min(long a, long b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static float min(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static double min(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static int max(int a, int b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static long max(long a, long b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static float max(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static double max(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * The trigonometric function <em>sin</em>. The sine of NaN or infinity is + * NaN, and the sine of 0 retains its sign. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the angle (in radians) + * @return sin(a) + */ + public static native double sin(double a); + + /** + * The trigonometric function <em>cos</em>. The cosine of NaN or infinity is + * NaN. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return cos(a) + */ + public static native double cos(double a); + + /** + * The trigonometric function <em>tan</em>. The tangent of NaN or infinity + * is NaN, and the tangent of 0 retains its sign. This is accurate within 1 + * ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return tan(a) + */ + public static native double tan(double a); + + /** + * The trigonometric function <em>arcsin</em>. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN; and the arcsine of + * 0 retains its sign. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the sin to turn back into an angle + * @return arcsin(a) + */ + public static native double asin(double a); + + /** + * The trigonometric function <em>arccos</em>. The range of angles returned + * is 0 to pi radians (0 to 180 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the cos to turn back into an angle + * @return arccos(a) + */ + public static native double acos(double a); + + /** + * The trigonometric function <em>arcsin</em>. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the + * result is NaN; and the arctangent of 0 retains its sign. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the tan to turn back into an angle + * @return arcsin(a) + * @see #atan2(double, double) + */ + public static native double atan(double a); + + /** + * A special version of the trigonometric function <em>arctan</em>, for + * converting rectangular coordinates <em>(x, y)</em> to polar + * <em>(r, theta)</em>. This computes the arctangent of x/y in the range + * of -pi to pi radians (-180 to 180 degrees). Special cases:<ul> + * <li>If either argument is NaN, the result is NaN.</li> + * <li>If the first argument is positive zero and the second argument is + * positive, or the first argument is positive and finite and the second + * argument is positive infinity, then the result is positive zero.</li> + * <li>If the first argument is negative zero and the second argument is + * positive, or the first argument is negative and finite and the second + * argument is positive infinity, then the result is negative zero.</li> + * <li>If the first argument is positive zero and the second argument is + * negative, or the first argument is positive and finite and the second + * argument is negative infinity, then the result is the double value + * closest to pi.</li> + * <li>If the first argument is negative zero and the second argument is + * negative, or the first argument is negative and finite and the second + * argument is negative infinity, then the result is the double value + * closest to -pi.</li> + * <li>If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * double value closest to pi/2.</li> + * <li>If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * double value closest to -pi/2.</li> + * <li>If both arguments are positive infinity, then the result is the + * double value closest to pi/4.</li> + * <li>If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the double value closest to + * 3*pi/4.</li> + * <li>If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the double value closest to + * -pi/4.</li> + * <li>If both arguments are negative infinity, then the result is the + * double value closest to -3*pi/4.</li> + * + * </ul><p>This is accurate within 2 ulps, and is semi-monotonic. To get r, + * use sqrt(x*x+y*y). + * + * @param y the y position + * @param x the x position + * @return <em>theta</em> in the conversion of (x, y) to (r, theta) + * @see #atan(double) + */ + public static native double atan2(double y, double x); + + /** + * 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 + * infinity, the result is positive zero. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the number to raise to the power + * @return the number raised to the power of <em>e</em> + * @see #log(double) + * @see #pow(double, double) + */ + public static native double exp(double a); + + /** + * 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 + * is either zero, the result is negative infinity. This is accurate within + * 1 ulp, and is semi-monotonic. + * + * <p>Note that the way to get log<sub>b</sub>(a) is to do this: + * <code>ln(a) / ln(b)</code>. + * + * @param a the number to take the natural log of + * @return the natural log of <code>a</code> + * @see #exp(double) + */ + public static native double log(double a); + + /** + * Take a square root. 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 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). + * + * @param a the numeric argument + * @return the square root of the argument + * @see #pow(double, double) + */ + public static native double sqrt(double a); + + /** + * Raise a number to a power. Special cases:<ul> + * <li>If the second argument is positive or negative zero, then the result + * is 1.0.</li> + * <li>If the second argument is 1.0, then the result is the same as the + * first argument.</li> + * <li>If the second argument is NaN, then the result is NaN.</li> + * <li>If the first argument is NaN and the second argument is nonzero, + * then the result is NaN.</li> + * <li>If the absolute value of the first argument is greater than 1 and + * the second argument is positive infinity, or the absolute value of the + * first argument is less than 1 and the second argument is negative + * infinity, then the result is positive infinity.</li> + * <li>If the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, then the result is positive zero.</li> + * <li>If the absolute value of the first argument equals 1 and the second + * argument is infinite, then the result is NaN.</li> + * <li>If the first argument is positive zero and the second argument is + * greater than zero, or the first argument is positive infinity and the + * second argument is less than zero, then the result is positive zero.</li> + * <li>If the first argument is positive zero and the second argument is + * less than zero, or the first argument is positive infinity and the + * second argument is greater than zero, then the result is positive + * infinity.</li> + * <li>If the first argument is negative zero and the second argument is + * greater than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is less than zero but not a + * finite odd integer, then the result is positive zero.</li> + * <li>If the first argument is negative zero and the second argument is a + * positive finite odd integer, or the first argument is negative infinity + * and the second argument is a negative finite odd integer, then the result + * is negative zero.</li> + * <li>If the first argument is negative zero and the second argument is + * less than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is greater than zero but not a + * finite odd integer, then the result is positive infinity.</li> + * <li>If the first argument is negative zero and the second argument is a + * negative finite odd integer, or the first argument is negative infinity + * and the second argument is a positive finite odd integer, then the result + * is negative infinity.</li> + * <li>If the first argument is less than zero and the second argument is a + * finite even integer, then the result is equal to the result of raising + * the absolute value of the first argument to the power of the second + * argument.</li> + * <li>If the first argument is less than zero and the second argument is a + * finite odd integer, then the result is equal to the negative of the + * result of raising the absolute value of the first argument to the power + * of the second argument.</li> + * <li>If the first argument is finite and less than zero and the second + * argument is finite and not an integer, then the result is NaN.</li> + * <li>If both arguments are integers, then the result is exactly equal to + * the mathematical result of raising the first argument to the power of + * the second argument if that result can in fact be represented exactly as + * a double value.</li> + * + * </ul><p>(In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is a fixed point of the + * method {@link #ceil(double)} or, equivalently, a fixed point of the + * method {@link #floor(double)}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the value is + * equal to the value.) This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the number to raise + * @param b the power to raise it to + * @return a<sup>b</sup> + */ + public static native double pow(double a, double b); + + /** + * Get the IEEE 754 floating point remainder on two numbers. This is the + * value of <code>x - y * <em>n</em></code>, where <em>n</em> is the closest + * double to <code>x / y</code> (ties go to the even n); for a zero + * remainder, the sign is that of <code>x</code>. If either argument is NaN, + * the first argument is infinite, or the second argument is zero, the result + * is NaN; if x is finite but y is infinite, the result is x. This is + * accurate within the limits of doubles. + * + * @param x the dividend (the top half) + * @param y the divisor (the bottom half) + * @return the IEEE 754-defined floating point remainder of x/y + * @see #rint(double) + */ + public static native double IEEEremainder(double x, double y); + + /** + * Take the nearest integer that is that is greater than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same; if the argument is between -1 and 0, the result is negative zero. + * Note that <code>Math.ceil(x) == -Math.floor(-x)</code>. + * + * @param a the value to act upon + * @return the nearest integer >= <code>a</code> + */ + public static native double ceil(double a); + + /** + * Take the nearest integer that is that is less than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same. Note that <code>Math.ceil(x) == -Math.floor(-x)</code>. + * + * @param a the value to act upon + * @return the nearest integer <= <code>a</code> + */ + public static native double floor(double a); + + /** + * Take the nearest integer to the argument. If it is exactly between + * two integers, the even integer is taken. If the argument is NaN, + * infinite, or zero, the result is the same. + * + * @param a the value to act upon + * @return the nearest integer to <code>a</code> + */ + public static native double rint(double a); + + /** + * Take the nearest integer to the argument. This is equivalent to + * <code>(int) Math.floor(a + 0.5f)</code>. If the argument is NaN, the result + * is 0; otherwise if the argument is outside the range of int, the result + * will be Integer.MIN_VALUE or Integer.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest integer to the argument + * @see Integer#MIN_VALUE + * @see Integer#MAX_VALUE + */ + public static int round(float a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (int) floor(a + 0.5f); + } + + /** + * Take the nearest long to the argument. This is equivalent to + * <code>(long) Math.floor(a + 0.5)</code>. If the argument is NaN, the + * result is 0; otherwise if the argument is outside the range of long, the + * result will be Long.MIN_VALUE or Long.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest long to the argument + * @see Long#MIN_VALUE + * @see Long#MAX_VALUE + */ + public static long round(double a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (long) floor(a + 0.5d); + } + + /** + * Get a random number. This behaves like Random.nextDouble(), seeded by + * System.currentTimeMillis() when first called. In other words, the number + * is from a pseudorandom sequence, and lies in the range [+0.0, 1.0). + * This random sequence is only used by this method, and is threadsafe, + * although you may want your own random number generator if it is shared + * among threads. + * + * @return a random number + * @see Random#nextDouble() + * @see System#currentTimeMillis() + */ + public static synchronized double random() + { + if (rand == null) + rand = new Random(); + return rand.nextDouble(); + } + + /** + * Convert from degrees to radians. The formula for this is + * radians = degrees * (pi/180); however it is not always exact given the + * limitations of floating point numbers. + * + * @param degrees an angle in degrees + * @return the angle in radians + * @since 1.2 + */ + public static double toRadians(double degrees) + { + return (degrees * PI) / 180; + } + + /** + * Convert from radians to degrees. The formula for this is + * degrees = radians * (180/pi); however it is not always exact given the + * limitations of floating point numbers. + * + * @param rads an angle in radians + * @return the angle in degrees + * @since 1.2 + */ + public static double toDegrees(double rads) + { + return (rads * 180) / PI; + } + + /** + * <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 native double cbrt(double 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 native double cosh(double 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 native double expm1(double 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 native double hypot(double a, double 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. + * </p> + * <p> + * Arguments of either <code>NaN</code> or less than zero return + * <code>NaN</code>. An argument of positive infinity returns positive + * infinity. Negative infinity is returned if either positive or negative + * zero is supplied. Where the argument is the result of + * <code>10<sup>n</sup</code>, then <code>n</code> is returned. + * </p> + * + * @param a the numeric argument. + * @return the base 10 logarithm of <code>a</code>. + * @since 1.5 + */ + public static native double log10(double a); + + /** + * <p> + * Returns the natural logarithm resulting from the sum of the argument, + * <code>a</code> and 1. For values close to 0, the + * result of <code>log1p(a)</code> tend to be much closer to the + * exact result than simply <code>log(1.0+a)</code>. The returned + * result is within 1 ulp of the exact result, and the results are + * semi-monotonic. + * </p> + * <p> + * Arguments of either <code>NaN</code> or less than -1 return + * <code>NaN</code>. An argument of positive infinity or zero + * returns the original argument. Negative infinity is returned from an + * argument of -1. + * </p> + * + * @param a the numeric argument. + * @return the natural logarithm of <code>a</code> + 1. + * @since 1.5 + */ + public static native double log1p(double 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.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) + { + if (Double.isNaN(a)) + return Double.NaN; + if (a > 0) + return 1.0; + if (a < 0) + return -1.0; + return 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) + { + if (Float.isNaN(a)) + return Float.NaN; + if (a > 0) + return 1.0f; + if (a < 0) + 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 native double sinh(double 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 native double tanh(double 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) + { + if (Double.isNaN(d)) + return d; + if (Double.isInfinite(d)) + return Double.POSITIVE_INFINITY; + // This handles both +0.0 and -0.0. + if (d == 0.0) + return Double.MIN_VALUE; + long bits = Double.doubleToLongBits(d); + final int mantissaBits = 52; + final int exponentBits = 11; + final long mantMask = (1L << mantissaBits) - 1; + long mantissa = bits & mantMask; + final long expMask = (1L << exponentBits) - 1; + long exponent = (bits >>> mantissaBits) & expMask; + + // Denormal number, so the answer is easy. + if (exponent == 0) + { + long result = (exponent << mantissaBits) | 1L; + return Double.longBitsToDouble(result); + } + + // Conceptually we want to have '1' as the mantissa. Then we would + // shift the mantissa over to make a normal number. If this underflows + // the exponent, we will make a denormal result. + long newExponent = exponent - mantissaBits; + long newMantissa; + if (newExponent > 0) + newMantissa = 0; + else + { + newMantissa = 1L << -(newExponent - 1); + newExponent = 0; + } + return Double.longBitsToDouble((newExponent << mantissaBits) | newMantissa); + } + + /** + * 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) + { + if (Float.isNaN(f)) + return f; + if (Float.isInfinite(f)) + return Float.POSITIVE_INFINITY; + // This handles both +0.0 and -0.0. + if (f == 0.0) + return Float.MIN_VALUE; + int bits = Float.floatToIntBits(f); + final int mantissaBits = 23; + final int exponentBits = 8; + final int mantMask = (1 << mantissaBits) - 1; + int mantissa = bits & mantMask; + final int expMask = (1 << exponentBits) - 1; + int exponent = (bits >>> mantissaBits) & expMask; + + // Denormal number, so the answer is easy. + if (exponent == 0) + { + int result = (exponent << mantissaBits) | 1; + return Float.intBitsToFloat(result); + } + + // Conceptually we want to have '1' as the mantissa. Then we would + // shift the mantissa over to make a normal number. If this underflows + // the exponent, we will make a denormal result. + int newExponent = exponent - mantissaBits; + int newMantissa; + if (newExponent > 0) + newMantissa = 0; + else + { + newMantissa = 1 << -(newExponent - 1); + newExponent = 0; + } + return Float.intBitsToFloat((newExponent << mantissaBits) | newMantissa); + } +} diff --git a/libjava/java/lang/NegativeArraySizeException.h b/libjava/java/lang/NegativeArraySizeException.h new file mode 100644 index 000000000..e05f7c515 --- /dev/null +++ b/libjava/java/lang/NegativeArraySizeException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NegativeArraySizeException__ +#define __java_lang_NegativeArraySizeException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::NegativeArraySizeException : public ::java::lang::RuntimeException +{ + +public: + NegativeArraySizeException(); + NegativeArraySizeException(::java::lang::String *); +private: + static const jlong serialVersionUID = -8960118058596991861LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NegativeArraySizeException__ diff --git a/libjava/java/lang/NoClassDefFoundError.h b/libjava/java/lang/NoClassDefFoundError.h new file mode 100644 index 000000000..90790a7b9 --- /dev/null +++ b/libjava/java/lang/NoClassDefFoundError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NoClassDefFoundError__ +#define __java_lang_NoClassDefFoundError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::NoClassDefFoundError : public ::java::lang::LinkageError +{ + +public: + NoClassDefFoundError(); + NoClassDefFoundError(::java::lang::String *); +private: + static const jlong serialVersionUID = 9095859863287012458LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NoClassDefFoundError__ diff --git a/libjava/java/lang/NoSuchFieldError.h b/libjava/java/lang/NoSuchFieldError.h new file mode 100644 index 000000000..65f444e83 --- /dev/null +++ b/libjava/java/lang/NoSuchFieldError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NoSuchFieldError__ +#define __java_lang_NoSuchFieldError__ + +#pragma interface + +#include <java/lang/IncompatibleClassChangeError.h> + +class java::lang::NoSuchFieldError : public ::java::lang::IncompatibleClassChangeError +{ + +public: + NoSuchFieldError(); + NoSuchFieldError(::java::lang::String *); +private: + static const jlong serialVersionUID = -3456430195886129035LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NoSuchFieldError__ diff --git a/libjava/java/lang/NoSuchFieldException.h b/libjava/java/lang/NoSuchFieldException.h new file mode 100644 index 000000000..36fe841ed --- /dev/null +++ b/libjava/java/lang/NoSuchFieldException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NoSuchFieldException__ +#define __java_lang_NoSuchFieldException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::NoSuchFieldException : public ::java::lang::Exception +{ + +public: + NoSuchFieldException(); + NoSuchFieldException(::java::lang::String *); +private: + static const jlong serialVersionUID = -6143714805279938260LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NoSuchFieldException__ diff --git a/libjava/java/lang/NoSuchMethodError.h b/libjava/java/lang/NoSuchMethodError.h new file mode 100644 index 000000000..5db0a040e --- /dev/null +++ b/libjava/java/lang/NoSuchMethodError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NoSuchMethodError__ +#define __java_lang_NoSuchMethodError__ + +#pragma interface + +#include <java/lang/IncompatibleClassChangeError.h> + +class java::lang::NoSuchMethodError : public ::java::lang::IncompatibleClassChangeError +{ + +public: + NoSuchMethodError(); + NoSuchMethodError(::java::lang::String *); +public: // actually package-private + static const jlong serialVersionUID = -3765521442372831335LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NoSuchMethodError__ diff --git a/libjava/java/lang/NoSuchMethodException.h b/libjava/java/lang/NoSuchMethodException.h new file mode 100644 index 000000000..dc905d67f --- /dev/null +++ b/libjava/java/lang/NoSuchMethodException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NoSuchMethodException__ +#define __java_lang_NoSuchMethodException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::NoSuchMethodException : public ::java::lang::Exception +{ + +public: + NoSuchMethodException(); + NoSuchMethodException(::java::lang::String *); +private: + static const jlong serialVersionUID = 5034388446362600923LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NoSuchMethodException__ diff --git a/libjava/java/lang/NullPointerException.h b/libjava/java/lang/NullPointerException.h new file mode 100644 index 000000000..4af582cf4 --- /dev/null +++ b/libjava/java/lang/NullPointerException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NullPointerException__ +#define __java_lang_NullPointerException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::NullPointerException : public ::java::lang::RuntimeException +{ + +public: + NullPointerException(); + NullPointerException(::java::lang::String *); +private: + static const jlong serialVersionUID = 5162710183389028792LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NullPointerException__ diff --git a/libjava/java/lang/Number.h b/libjava/java/lang/Number.h new file mode 100644 index 000000000..65ba92019 --- /dev/null +++ b/libjava/java/lang/Number.h @@ -0,0 +1,32 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Number__ +#define __java_lang_Number__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::Number : public ::java::lang::Object +{ + +public: + Number(); + virtual jint intValue() = 0; + virtual jlong longValue() = 0; + virtual jfloat floatValue() = 0; + virtual jdouble doubleValue() = 0; + virtual jbyte byteValue(); + virtual jshort shortValue(); +private: + static const jlong serialVersionUID = -8742448824652078965LL; +public: // actually package-private + static JArray< jchar > * digits; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Number__ diff --git a/libjava/java/lang/NumberFormatException.h b/libjava/java/lang/NumberFormatException.h new file mode 100644 index 000000000..34bd4d678 --- /dev/null +++ b/libjava/java/lang/NumberFormatException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_NumberFormatException__ +#define __java_lang_NumberFormatException__ + +#pragma interface + +#include <java/lang/IllegalArgumentException.h> + +class java::lang::NumberFormatException : public ::java::lang::IllegalArgumentException +{ + +public: + NumberFormatException(); + NumberFormatException(::java::lang::String *); +private: + static const jlong serialVersionUID = -2848938806368998894LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_NumberFormatException__ diff --git a/libjava/java/lang/Object.h b/libjava/java/lang/Object.h new file mode 100644 index 000000000..54fd447d1 --- /dev/null +++ b/libjava/java/lang/Object.h @@ -0,0 +1,91 @@ +// Object.h - Header file for java.lang.Object. -*- c++ -*- + +/* Copyright (C) 1998, 1999, 2000, 2001, 2004, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#ifndef __JAVA_LANG_OBJECT_H__ +#define __JAVA_LANG_OBJECT_H__ + +#pragma interface + +#include <gcj/javaprims.h> + +extern "Java" +{ +// This class is mainly here as a kludge to get G++ to allocate two +// extra entries in each vtable. +struct _JvObjectPrefix +{ +protected: + // New ABI Compatibility Dummy, #1 and 2. + virtual void nacd_1 (void) {}; // This slot really contains the Class pointer. + // For IA64, the GC descriptor goes into the second word of the nacd1 descr. +# ifndef __ia64__ + virtual void nacd_2 (void) {}; // Actually the GC bitmap marking descriptor. +# endif +}; +} + +// Forward declarations for friends of java::lang::Object +void _Jv_MonitorEnter (jobject obj); +void _Jv_MonitorExit (jobject obj); +void _Jv_InitializeSyncMutex (void); +void _Jv_FinalizeObject (jobject obj); +bool _Jv_ObjectCheckMonitor (jobject obj); + +class java::lang::Object : public _JvObjectPrefix +{ +protected: + virtual void finalize (void); +public: + // Order must match order in Object.java. + jclass getClass (void); + virtual jint hashCode (void); + void notify (void); + void notifyAll (void); + void wait (jlong timeout, jint nanos); + virtual jboolean equals (jobject obj); + Object (void); + virtual jstring toString (void); + void wait (void); + void wait (jlong timeout); + + friend void ::_Jv_MonitorEnter (jobject obj); + friend void ::_Jv_MonitorExit (jobject obj); + friend void ::_Jv_InitializeSyncMutex (void); + friend void ::_Jv_FinalizeObject (jobject obj); + friend bool ::_Jv_ObjectCheckMonitor (jobject obj); + +#ifdef JV_MARKOBJ_DECL + friend JV_MARKOBJ_DECL; +#endif +#ifdef JV_MARKARRAY_DECL + friend JV_MARKARRAY_DECL; +#endif + + static java::lang::Class class$; + +protected: + virtual jobject clone (void); + +private: + // This does not actually refer to a Java object. Instead it is a + // placeholder for a piece of internal data (the synchronization + // information). +# ifndef JV_HASH_SYNCHRONIZATION + jobject sync_info; +# endif + + // Initialize the sync_info field. Not called with JV_HASH_SYNCHRONIZATION. + void sync_init (void); + +public: + virtual void throwNoSuchMethodError (void); +}; + +#endif /* __JAVA_LANG_OBJECT_H__ */ diff --git a/libjava/java/lang/Object.java b/libjava/java/lang/Object.java new file mode 100644 index 000000000..740a7c78e --- /dev/null +++ b/libjava/java/lang/Object.java @@ -0,0 +1,519 @@ +/* java.lang.Object - The universal superclass in Java + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2007 + 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; + +/* 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. + * plus gcj compiler sources (to determine object layout) + * Status: Complete to version 1.1 + */ + +/** + * Object is the ultimate superclass of every class + * (excepting interfaces). When you define a class that + * does not extend any other class, it implicitly extends + * java.lang.Object. Also, an anonymous class based on + * an interface will extend Object. + * + * <p>It provides general-purpose methods that every single + * Object, regardless of race, sex or creed, implements. + * All of the public methods may be invoked on arrays or + * interfaces. The protected methods <code>clone</code> + * and <code>finalize</code> are not accessible on arrays + * or interfaces, but all array types have a public version + * of <code>clone</code> which is accessible. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class Object +{ + /** + * Called on an object by the Virtual Machine at most once, + * at some point after the Object is determined unreachable + * but before it is destroyed. You would think that this + * means it eventually is called on every Object, but this is + * not necessarily the case. If execution terminates + * abnormally, garbage collection does not always happen. + * Thus you cannot rely on this method to always work. + * For finer control over garbage collection, use references + * from the {@link java.lang.ref} package. + * + * <p>Virtual Machines are free to not call this method if + * they can determine that it does nothing important; for + * example, if your class extends Object and overrides + * finalize to do simply <code>super.finalize()</code>. + * + * <p>finalize() will be called by a {@link Thread} that has no + * locks on any Objects, and may be called concurrently. + * There are no guarantees on the order in which multiple + * objects are finalized. This means that finalize() is + * usually unsuited for performing actions that must be + * thread-safe, and that your implementation must be + * use defensive programming if it is to always work. + * + * <p>If an Exception is thrown from finalize() during garbage + * collection, it will be patently ignored and the Object will + * still be destroyed. + * + * <p>It is allowed, although not typical, for user code to call + * finalize() directly. User invocation does not affect whether + * automatic invocation will occur. It is also permitted, + * although not recommended, for a finalize() method to "revive" + * an object by making it reachable from normal code again. + * + * <p>Unlike constructors, finalize() does not get called + * for an object's superclass unless the implementation + * specifically calls <code>super.finalize()</code>. + * + * <p>The default implementation does nothing. + * + * @throws Throwable permits a subclass to throw anything in an + * overridden version; but the default throws nothing + * @see System#gc() + * @see System#runFinalizersOnExit(boolean) + * @see java.lang.ref + */ + // This must come first. See _JvObjectPrefix in Object.h. + protected void finalize () throws Throwable + { + } + + /** + * Returns the runtime {@link Class} of this Object. + * + * <p>The class object can also be obtained without a runtime + * instance by using the class literal, as in: + * <code>Foo.class</code>. Notice that the class literal + * also works on primitive types, making it useful for + * reflection purposes. + * + * @return the class of this Object + */ + public final native Class<? extends Object> getClass(); + + /** + * Get a value that represents this Object, as uniquely as + * possible within the confines of an int. + * + * <p>There are some requirements on this method which + * subclasses must follow:<br> + * + * <ul> + * <li>Semantic equality implies identical hashcodes. In other + * words, if <code>a.equals(b)</code> is true, then + * <code>a.hashCode() == b.hashCode()</code> must be as well. + * However, the reverse is not necessarily true, and two + * objects may have the same hashcode without being equal.</li> + * <li>It must be consistent. Whichever value o.hashCode() + * returns on the first invocation must be the value + * returned on all later invocations as long as the object + * exists. Notice, however, that the result of hashCode may + * change between separate executions of a Virtual Machine, + * because it is not invoked on the same object.</li> + * </ul> + * + * <p>Notice that since <code>hashCode</code> is used in + * {@link java.util.Hashtable} and other hashing classes, + * a poor implementation will degrade the performance of hashing + * (so don't blindly implement it as returning a constant!). Also, + * if calculating the hash is time-consuming, a class may consider + * caching the results. + * + * <p>The default implementation returns + * <code>System.identityHashCode(this)</code> + * + * @return the hash code for this Object + * @see #equals(Object) + * @see System#identityHashCode(Object) + */ + public native int hashCode(); + + /** + * Wakes up one of the {@link Thread}s that has called + * <code>wait</code> on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a <code>synchronized</code> method or statement. + * + * <p>The Thread to wake up is chosen arbitrarily. The + * awakened thread is not guaranteed to be the next thread + * to actually obtain the lock on this object. + * + * <p>This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that the newly awakened thread can actually resume. The + * awakened thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final native void notify(); + + /** + * Wakes up all of the {@link Thread}s that have called + * <code>wait</code> on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a <code>synchronized</code> method or statement. + * + * <p>There are no guarantees as to which thread will next + * obtain the lock on the object. + * + * <p>This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that one of the newly awakened threads can actually resume. + * The resuming thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notify() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final native void notifyAll(); + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + * <p>The waiting period is nowhere near as precise as + * nanoseconds; considering that even wait(int) is inaccurate, + * how much can you expect? But on supporting + * implementations, this offers somewhat more granularity + * than milliseconds. + * + * @param ms the number of milliseconds to wait (1,000 + * milliseconds = 1 second) + * @param ns the number of nanoseconds to wait over and + * above ms (1,000,000 nanoseconds = 1 millisecond) + * @throws IllegalArgumentException if ms < 0 or ns is not + * in the range 0 to 999,999 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see Thread + */ + public final native void wait(long timeout, int nanos) + throws InterruptedException; + + /** + * Determine whether this Object is semantically equal + * to another Object. + * + * <p>There are some fairly strict requirements on this + * method which subclasses must follow:<br> + * <ul> + * <li>It must be transitive. If <code>a.equals(b)</code> and + * <code>b.equals(c)</code>, then <code>a.equals(c)</code> + * must be true as well.</li> + * <li>It must be symmetric. <code>a.equals(b)</code> and + * <code>b.equals(a)</code> must have the same value.</li> + * <li>It must be reflexive. <code>a.equals(a)</code> must + * always be true.</li> + * <li>It must be consistent. Whichever value a.equals(b) + * returns on the first invocation must be the value + * returned on all later invocations.</li> + * <li><code>a.equals(null)</code> must be false.</li> + * <li>It must be consistent with hashCode(). That is, + * <code>a.equals(b)</code> must imply + * <code>a.hashCode() == b.hashCode()</code>. + * The reverse is not true; two objects that are not + * equal may have the same hashcode, but that has + * the potential to harm hashing performance.</li> + * </ul> + * + * <p>This is typically overridden to throw a {@link ClassCastException} + * if the argument is not comparable to the class performing + * the comparison, but that is not a requirement. It is legal + * for <code>a.equals(b)</code> to be true even though + * <code>a.getClass() != b.getClass()</code>. Also, it + * is typical to never cause a {@link NullPointerException}. + * + * <p>In general, the Collections API ({@link java.util}) use the + * <code>equals</code> method rather than the <code>==</code> + * operator to compare objects. However, {@link java.util.IdentityHashMap} + * is an exception to this rule, for its own good reasons. + * + * <p>The default implementation returns <code>this == o</code>. + * + * @param obj the Object to compare to + * @return whether this Object is semantically equal to another + * @see #hashCode() + */ + public boolean equals(Object obj) + { + return this == obj; + } + + /** + * The basic constructor. Object is special, because it has no + * superclass, so there is no call to super(). + * + * @throws OutOfMemoryError Technically, this constructor never + * throws an OutOfMemoryError, because the memory has + * already been allocated by this point. But as all + * instance creation expressions eventually trace back + * to this constructor, and creating an object allocates + * memory, we list that possibility here. + */ + public Object() + { + } + + /** + * Convert this Object to a human-readable String. + * There are no limits placed on how long this String + * should be or what it should contain. We suggest you + * make it as intuitive as possible to be able to place + * it into {@link java.io.PrintStream#println() System.out.println()} + * and such. + * + * <p>It is typical, but not required, to ensure that this method + * never completes abruptly with a {@link RuntimeException}. + * + * <p>This method will be called when performing string + * concatenation with this object. If the result is + * <code>null</code>, string concatenation will instead + * use <code>"null"</code>. + * + * <p>The default implementation returns + * <code>getClass().getName() + "@" + + * Integer.toHexString(hashCode())</code>. + * + * @return the String representing this Object, which may be null + * @throws OutOfMemoryError The default implementation creates a new + * String object, therefore it must allocate memory + * @see #getClass() + * @see #hashCode() + * @see Class#getName() + * @see Integer#toHexString(int) + */ + public String toString() + { + return getClass().getName() + '@' + Integer.toHexString(hashCode()); + } + + /** + * Waits indefinitely for notify() or notifyAll() to be + * called on the Object in question. Implementation is + * identical to wait(0). + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>While it is typical that this method will complete abruptly + * with an {@link InterruptedException}, it is not guaranteed. So, + * it is typical to call wait inside an infinite loop:<br> + * + * <pre> + * try + * { + * while (true) + * lock.wait(); + * } + * catch (InterruptedException e) + * { + * } + * </pre> + * + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final void wait() throws InterruptedException + { + wait(0, 0); + } + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + * <p>The waiting period is only *roughly* the amount of time + * you requested. It cannot be exact because of the overhead + * of the call itself. Most Virtual Machiness treat the + * argument as a lower limit on the time spent waiting, but + * even that is not guaranteed. Besides, some other thread + * may hold the lock on the object when the time expires, so + * the current thread may still have to wait to reobtain the + * lock. + * + * @param timeout the minimum number of milliseconds to wait (1000 + * milliseconds = 1 second), or 0 for an indefinite wait + * @throws IllegalArgumentException if ms < 0 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long, int) + * @see Thread + */ + public final void wait(long timeout) throws InterruptedException + { + wait(timeout, 0); + } + + /** + * This method may be called to create a new copy of the + * Object. The typical behavior is as follows:<br> + * <ul> + * <li><code>o == o.clone()</code> is false</li> + * <li><code>o.getClass() == o.clone().getClass()</code> + * is true</li> + * <li><code>o.equals(o)</code> is true</li> + * </ul> + * + * <p>However, these are not strict requirements, and may + * be violated if necessary. Of the three requirements, the + * last is the most commonly violated, particularly if the + * subclass does not override {@link #equals(Object)}. + * + * <p>If the Object you call clone() on does not implement + * {@link Cloneable} (which is a placeholder interface), then + * a CloneNotSupportedException is thrown. Notice that + * Object does not implement Cloneable; this method exists + * as a convenience for subclasses that do. + * + * <p>Object's implementation of clone allocates space for the + * new Object using the correct class, without calling any + * constructors, and then fills in all of the new field values + * with the old field values. Thus, it is a shallow copy. + * However, subclasses are permitted to make a deep copy. + * + * <p>All array types implement Cloneable, and override + * this method as follows (it should never fail):<br> + * <pre> + * public Object clone() + * { + * try + * { + * super.clone(); + * } + * catch (CloneNotSupportedException e) + * { + * throw new InternalError(e.getMessage()); + * } + * } + * </pre> + * + * @return a copy of the Object + * @throws CloneNotSupportedException If this Object does not + * implement Cloneable + * @throws OutOfMemoryError Since cloning involves memory allocation, + * even though it may bypass constructors, you might run + * out of memory + * @see Cloneable + */ + protected native Object clone() throws CloneNotSupportedException; + + // This initializes the sync_info member. It is here for + // completeness (some day we'll be able to auto-generate Object.h). + private final native void sync_init(); + + // If we fail to find a method at class loading time we put the + // vtable index of this method in its place: any attempt to call + // that method will result in an error. + void throwNoSuchMethodError() + { + throw new NoSuchMethodError("in " + getClass()); + } + + // Note that we don't mention the sync_info field here. If we do, + // jc1 will not work correctly. +} diff --git a/libjava/java/lang/OutOfMemoryError.h b/libjava/java/lang/OutOfMemoryError.h new file mode 100644 index 000000000..7fac1f5a0 --- /dev/null +++ b/libjava/java/lang/OutOfMemoryError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_OutOfMemoryError__ +#define __java_lang_OutOfMemoryError__ + +#pragma interface + +#include <java/lang/VirtualMachineError.h> + +class java::lang::OutOfMemoryError : public ::java::lang::VirtualMachineError +{ + +public: + OutOfMemoryError(); + OutOfMemoryError(::java::lang::String *); +private: + static const jlong serialVersionUID = 8228564086184010517LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_OutOfMemoryError__ diff --git a/libjava/java/lang/Override.h b/libjava/java/lang/Override.h new file mode 100644 index 000000000..e6424ee6a --- /dev/null +++ b/libjava/java/lang/Override.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Override__ +#define __java_lang_Override__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Override : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Override__ diff --git a/libjava/java/lang/Package.h b/libjava/java/lang/Package.h new file mode 100644 index 000000000..6d12d9f36 --- /dev/null +++ b/libjava/java/lang/Package.h @@ -0,0 +1,62 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Package__ +#define __java_lang_Package__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace java + { + namespace net + { + class URL; + } + } +} + +class java::lang::Package : public ::java::lang::Object +{ + +public: // actually package-private + Package(::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::net::URL *); + Package(::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *, ::java::net::URL *, ::java::lang::ClassLoader *); +public: + virtual ::java::lang::String * getName(); + virtual ::java::lang::String * getSpecificationTitle(); + virtual ::java::lang::String * getSpecificationVersion(); + virtual ::java::lang::String * getSpecificationVendor(); + virtual ::java::lang::String * getImplementationTitle(); + virtual ::java::lang::String * getImplementationVersion(); + virtual ::java::lang::String * getImplementationVendor(); + virtual jboolean isSealed(); + virtual jboolean isSealed(::java::net::URL *); + virtual jboolean isCompatibleWith(::java::lang::String *); + static ::java::lang::Package * getPackage(::java::lang::String *); + static JArray< ::java::lang::Package * > * getPackages(); + virtual jint hashCode(); + virtual ::java::lang::String * toString(); + virtual ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *); + virtual JArray< ::java::lang::annotation::Annotation * > * getAnnotations(); + virtual JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations(); + virtual jboolean isAnnotationPresent(::java::lang::Class *); +private: + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) name; + ::java::lang::String * implTitle; + ::java::lang::String * implVendor; + ::java::lang::String * implVersion; + ::java::lang::String * specTitle; + ::java::lang::String * specVendor; + ::java::lang::String * specVersion; + ::java::net::URL * sealed; + ::java::lang::ClassLoader * loader; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Package__ diff --git a/libjava/java/lang/PosixProcess$EOFInputStream.h b/libjava/java/lang/PosixProcess$EOFInputStream.h new file mode 100644 index 000000000..bda16533a --- /dev/null +++ b/libjava/java/lang/PosixProcess$EOFInputStream.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_PosixProcess$EOFInputStream__ +#define __java_lang_PosixProcess$EOFInputStream__ + +#pragma interface + +#include <java/io/InputStream.h> + +class java::lang::PosixProcess$EOFInputStream : public ::java::io::InputStream +{ + +public: // actually package-private + PosixProcess$EOFInputStream(); +public: + virtual jint read(); +public: // actually package-private + static ::java::lang::PosixProcess$EOFInputStream * instance; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_PosixProcess$EOFInputStream__ diff --git a/libjava/java/lang/PosixProcess$ProcessManager.h b/libjava/java/lang/PosixProcess$ProcessManager.h new file mode 100644 index 000000000..4b3b62e13 --- /dev/null +++ b/libjava/java/lang/PosixProcess$ProcessManager.h @@ -0,0 +1,45 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_PosixProcess$ProcessManager__ +#define __java_lang_PosixProcess$ProcessManager__ + +#pragma interface + +#include <java/lang/Thread.h> +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawDataManaged; + } + } +} + +class java::lang::PosixProcess$ProcessManager : public ::java::lang::Thread +{ + +public: // actually package-private + PosixProcess$ProcessManager(); + void addToLiveProcesses(::java::lang::PosixProcess *); + void startExecuting(::java::lang::PosixProcess *); + void waitUntilReady(); +public: + void run(); +private: + void init(); + void waitForSignal(); + jboolean reap(::java::lang::PosixProcess *); + void signalReaper(); + ::java::util::LinkedList * __attribute__((aligned(__alignof__( ::java::lang::Thread)))) queue; + ::java::util::LinkedList * liveProcesses; + jboolean ready; +public: // actually package-private + static ::gnu::gcj::RawDataManaged * nativeData; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_PosixProcess$ProcessManager__ diff --git a/libjava/java/lang/PosixProcess.h b/libjava/java/lang/PosixProcess.h new file mode 100644 index 000000000..3254f5224 --- /dev/null +++ b/libjava/java/lang/PosixProcess.h @@ -0,0 +1,62 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_PosixProcess__ +#define __java_lang_PosixProcess__ + +#pragma interface + +#include <java/lang/Process.h> +#include <gcj/array.h> + + +class java::lang::PosixProcess : public ::java::lang::Process +{ + +public: + void destroy(); +private: + void nativeDestroy(); +public: + jint exitValue(); +public: // actually package-private + void processTerminationCleanup(); +public: + ::java::io::InputStream * getErrorStream(); + ::java::io::InputStream * getInputStream(); + ::java::io::OutputStream * getOutputStream(); + jint waitFor(); +public: // actually package-private + void spawn(::java::lang::PosixProcess$ProcessManager *); +private: + void nativeSpawn(); +public: // actually package-private + PosixProcess(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); + static ::java::lang::Object * access$0(); + static void access$1(::java::lang::PosixProcess$ProcessManager *); +private: + JArray< ::java::lang::String * > * __attribute__((aligned(__alignof__( ::java::lang::Process)))) progarray; + JArray< ::java::lang::String * > * envp; + ::java::io::File * dir; + jboolean redirect; + ::java::lang::Throwable * exception; +public: // actually package-private + jlong pid; + static const jint STATE_WAITING_TO_START = 0; + static const jint STATE_RUNNING = 1; + static const jint STATE_TERMINATED = 2; + jint state; + jint status; +private: + ::java::io::InputStream * errorStream; + ::java::io::InputStream * inputStream; + ::java::io::OutputStream * outputStream; + ::java::io::InputStream * returnedErrorStream; + ::java::io::InputStream * returnedInputStream; + static ::java::lang::Object * queueLock; + static ::java::lang::PosixProcess$ProcessManager * processManager; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_PosixProcess__ diff --git a/libjava/java/lang/PosixProcess.java b/libjava/java/lang/PosixProcess.java new file mode 100644 index 000000000..dd59e7b93 --- /dev/null +++ b/libjava/java/lang/PosixProcess.java @@ -0,0 +1,470 @@ +// PosixProcess.java - Subclass of Process for POSIX systems. +/* Copyright (C) 1998, 1999, 2004, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.LinkedList; + +import gnu.gcj.RawDataManaged; + +/** + * @author Tom Tromey <tromey@cygnus.com> + * @date May 3, 1999 + * @author David Daney <ddaney@avtrex.com> Rewrote using + * ProcessManager + */ +final class PosixProcess extends Process +{ + static final class ProcessManager extends Thread + { + /** + * A list of {@link PosixProcess PosixProcesses} to be + * started. The queueLock object is used as the lock Object + * for all process related operations. To avoid dead lock + * ensure queueLock is obtained before PosixProcess. + */ + private LinkedList<PosixProcess> queue = new LinkedList<PosixProcess>(); + private LinkedList<PosixProcess> liveProcesses = + new LinkedList<PosixProcess>(); + private boolean ready = false; + + static RawDataManaged nativeData; + + ProcessManager() + { + // Use package private Thread constructor to place us in the + // root ThreadGroup with no InheritableThreadLocal. If the + // InheritableThreadLocals were allowed to initialize, they could + // cause a Runtime.exec() to be called causing infinite + // recursion. + super("ProcessManager", true); + // Don't keep the (main) process from exiting on our account. + this.setDaemon(true); + } + + /** + * Add a process to the list of running processes. This must only + * be called with the queueLock held. + * + * @param p The PosixProcess. + */ + void addToLiveProcesses(PosixProcess p) + { + liveProcesses.add(p); + } + + /** + * Queue up the PosixProcess and awake the ProcessManager. + * The ProcessManager will start the PosixProcess from its + * thread so it can be reaped when it terminates. + * + * @param p The PosixProcess. + */ + void startExecuting(PosixProcess p) + { + synchronized (queueLock) + { + queue.add(p); + signalReaper(); // If blocked in waitForSignal(). + queueLock.notifyAll(); // If blocked in wait(); + } + } + + /** + * Block until the ProcessManager thread is ready to accept + * commands. + */ + void waitUntilReady() + { + synchronized (this) + { + try + { + while (! ready) + wait(); + } + catch (InterruptedException ie) + { + // Ignore. + } + } + } + + /** + * Main Process starting/reaping loop. + */ + public void run() + { + init(); + // Now ready to accept requests. + synchronized (this) + { + ready = true; + this.notifyAll(); + } + + for (;;) + { + try + { + synchronized (queueLock) + { + Iterator<PosixProcess> processIterator = + liveProcesses.iterator(); + while (processIterator.hasNext()) + { + boolean reaped = reap(processIterator.next()); + if (reaped) + processIterator.remove(); + } + if (liveProcesses.size() == 0 && queue.size() == 0) + { + // This reaper thread could exit, but we keep it + // alive for a while in case someone wants to + // start more Processes. + try + { + queueLock.wait(1000L); + if (queue.size() == 0) + { + processManager = null; + return; // Timed out. + } + } + catch (InterruptedException ie) + { + // Ignore and exit the thread. + return; + } + } + while (queue.size() > 0) + { + PosixProcess p = queue.remove(0); + p.spawn(this); + } + } + + // Wait for a SIGCHLD from either an exiting process or + // the startExecuting() method. This is done outside of + // the synchronized block to allow other threads to + // enter and submit more jobs. + waitForSignal(); + } + catch (Exception ex) + { + ex.printStackTrace(System.err); + } + } + } + + /** + * Setup native signal handlers and other housekeeping things. + */ + private native void init(); + + /** + * Block waiting for SIGCHLD. + * + */ + private native void waitForSignal(); + + /** + * Try to reap the specified child without blocking. + * + * @param p the process to try to reap. + * + * @return true if the process terminated. + * + */ + private native boolean reap(PosixProcess p); + + /** + * Send SIGCHLD to the reaper thread. + */ + private native void signalReaper(); + } + + public void destroy() + { + // Synchronized on the queueLock. This ensures that the reaper + // thread cannot be doing a wait() on the child. + // Otherwise there would be a race where the OS could + // create a process with the same pid between the wait() + // and the update of the state which would cause a kill to + // the wrong process. + synchronized (queueLock) + { + synchronized (this) + { + // If there is no ProcessManager we cannot kill. + if (state != STATE_TERMINATED) + { + if (processManager == null) + throw new InternalError(); + nativeDestroy(); + } + } + } + } + + private native void nativeDestroy(); + + public int exitValue() + { + synchronized (this) + { + if (state != STATE_TERMINATED) + throw new IllegalThreadStateException("Process has not exited"); + } + return status; + } + + /** + * Called by native code when process exits. + * + * Already synchronized (this). Close any streams that we can to + * conserve file descriptors. + * + * The outputStream can be closed as any future writes will + * generate an IOException due to EPIPE. + * + * The inputStream and errorStream can only be closed if the user + * has not obtained a reference to them AND they have no bytes + * available. Since the process has terminated they will never have + * any more data available and can safely be replaced by + * EOFInputStreams. + */ + void processTerminationCleanup() + { + try + { + outputStream.close(); + } + catch (IOException ioe) + { + // Ignore. + } + try + { + if (returnedErrorStream == null && errorStream.available() == 0) + { + errorStream.close(); + errorStream = null; + } + } + catch (IOException ioe) + { + // Ignore. + } + try + { + if (returnedInputStream == null && inputStream.available() == 0) + { + inputStream.close(); + inputStream = null; + } + } + catch (IOException ioe) + { + // Ignore. + } + } + + public synchronized InputStream getErrorStream() + { + if (returnedErrorStream != null) + return returnedErrorStream; + + if (errorStream == null) + returnedErrorStream = EOFInputStream.instance; + else + returnedErrorStream = errorStream; + + return returnedErrorStream; + } + + public synchronized InputStream getInputStream() + { + if (returnedInputStream != null) + return returnedInputStream; + + if (inputStream == null) + returnedInputStream = EOFInputStream.instance; + else + returnedInputStream = inputStream; + + return returnedInputStream; + } + + public OutputStream getOutputStream() + { + return outputStream; + } + + public int waitFor() throws InterruptedException + { + synchronized (this) + { + while (state != STATE_TERMINATED) + wait(); + } + return status; + } + + /** + * Start this process running. This should only be called by the + * ProcessManager with the queueLock held. + * + * @param pm The ProcessManager that made the call. + */ + void spawn(ProcessManager pm) + { + synchronized (this) + { + // Do the fork/exec magic. + nativeSpawn(); + // There is no race with reap() in the pidToProcess map + // because this is always called from the same thread + // doing the reaping. + pm.addToLiveProcesses(this); + state = STATE_RUNNING; + // Notify anybody waiting on state change. + this.notifyAll(); + } + } + + /** + * Do the fork and exec. + */ + private native void nativeSpawn(); + + PosixProcess(String[] progarray, String[] envp, File dir, boolean redirect) + throws IOException + { + // Check to ensure there is something to run, and avoid + // dereferencing null pointers in native code. + if (progarray[0] == null) + throw new NullPointerException(); + + this.progarray = progarray; + this.envp = envp; + this.dir = dir; + this.redirect = redirect; + + // Start a ProcessManager if there is not one already running. + synchronized (queueLock) + { + if (processManager == null) + { + processManager = new ProcessManager(); + processManager.start(); + processManager.waitUntilReady(); + } + + // Queue this PosixProcess for starting by the ProcessManager. + processManager.startExecuting(this); + } + + // Wait until ProcessManager has started us. + synchronized (this) + { + while (state == STATE_WAITING_TO_START) + { + try + { + wait(); + } + catch (InterruptedException ie) + { + // FIXME: What to do when interrupted while blocking in a constructor? + // Ignore. + } + } + } + + // If there was a problem, re-throw it. + if (exception != null) + { + if (exception instanceof IOException) + { + IOException ioe = new IOException(exception.toString()); + ioe.initCause(exception); + throw ioe; + } + + // Not an IOException. Something bad happened. + InternalError ie = new InternalError(exception.toString()); + ie.initCause(exception); + throw ie; + } + + // If we get here, all is well, the Process has started. + } + + private String[] progarray; + private String[] envp; + private File dir; + private boolean redirect; + + /** Set by the ProcessManager on problems starting. */ + private Throwable exception; + + /** The process id. This is cast to a pid_t on the native side. */ + long pid; + + // FIXME: Why doesn't the friend declaration in PosixProcess.h + // allow PosixProcess$ProcessManager native code access these + // when they are private? + + /** Before the process is forked. */ + static final int STATE_WAITING_TO_START = 0; + + /** After the fork. */ + static final int STATE_RUNNING = 1; + + /** After exit code has been collected. */ + static final int STATE_TERMINATED = 2; + + /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */ + int state; + + /** The exit status, if the child has exited. */ + int status; + + /** The streams. */ + private InputStream errorStream; + private InputStream inputStream; + private OutputStream outputStream; + + /** InputStreams obtained by the user. Not null indicates that the + * user has obtained the stream. + */ + private InputStream returnedErrorStream; + private InputStream returnedInputStream; + + /** + * Lock Object for all processManager related locking. + */ + private static Object queueLock = new Object(); + private static ProcessManager processManager; + + static class EOFInputStream extends InputStream + { + static EOFInputStream instance = new EOFInputStream(); + public int read() + { + return -1; + } + } +} diff --git a/libjava/java/lang/Process.h b/libjava/java/lang/Process.h new file mode 100644 index 000000000..f363feb50 --- /dev/null +++ b/libjava/java/lang/Process.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Process__ +#define __java_lang_Process__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Process : public ::java::lang::Object +{ + +public: + Process(); + virtual ::java::io::OutputStream * getOutputStream() = 0; + virtual ::java::io::InputStream * getInputStream() = 0; + virtual ::java::io::InputStream * getErrorStream() = 0; + virtual jint waitFor() = 0; + virtual jint exitValue() = 0; + virtual void destroy() = 0; + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Process__ diff --git a/libjava/java/lang/ProcessBuilder.h b/libjava/java/lang/ProcessBuilder.h new file mode 100644 index 000000000..fd6029df0 --- /dev/null +++ b/libjava/java/lang/ProcessBuilder.h @@ -0,0 +1,37 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ProcessBuilder__ +#define __java_lang_ProcessBuilder__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::ProcessBuilder : public ::java::lang::Object +{ + +public: + ProcessBuilder(::java::util::List *); + ProcessBuilder(JArray< ::java::lang::String * > *); + ::java::util::List * command(); + ::java::lang::ProcessBuilder * command(::java::util::List *); + ::java::lang::ProcessBuilder * command(JArray< ::java::lang::String * > *); + ::java::io::File * directory(); + ::java::lang::ProcessBuilder * directory(::java::io::File *); + ::java::util::Map * environment(); + jboolean redirectErrorStream(); + ::java::lang::ProcessBuilder * redirectErrorStream(jboolean); + ::java::lang::Process * start(); +private: + ::java::io::File * __attribute__((aligned(__alignof__( ::java::lang::Object)))) directory__; + ::java::util::List * command__; + ::java::util::Map * environment__; + jboolean redirect; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ProcessBuilder__ diff --git a/libjava/java/lang/Readable.h b/libjava/java/lang/Readable.h new file mode 100644 index 000000000..d8e7d2185 --- /dev/null +++ b/libjava/java/lang/Readable.h @@ -0,0 +1,29 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Readable__ +#define __java_lang_Readable__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace java + { + namespace nio + { + class CharBuffer; + } + } +} + +class java::lang::Readable : public ::java::lang::Object +{ + +public: + virtual jint read(::java::nio::CharBuffer *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Readable__ diff --git a/libjava/java/lang/Runnable.h b/libjava/java/lang/Runnable.h new file mode 100644 index 000000000..ba5985cbf --- /dev/null +++ b/libjava/java/lang/Runnable.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Runnable__ +#define __java_lang_Runnable__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Runnable : public ::java::lang::Object +{ + +public: + virtual void run() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Runnable__ diff --git a/libjava/java/lang/Runtime.h b/libjava/java/lang/Runtime.h new file mode 100644 index 000000000..4679cc0b1 --- /dev/null +++ b/libjava/java/lang/Runtime.h @@ -0,0 +1,69 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Runtime__ +#define __java_lang_Runtime__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::Runtime : public ::java::lang::Object +{ + + Runtime(); +public: + static ::java::lang::Runtime * getRuntime(); + virtual void exit(jint); +public: // actually package-private + static void exitNoChecksAccessor(jint); +private: + void exitNoChecks(jint); +public: // actually package-private + virtual jboolean runShutdownHooks(); +public: + virtual void addShutdownHook(::java::lang::Thread *); + virtual jboolean removeShutdownHook(::java::lang::Thread *); + virtual void halt(jint); + static void runFinalizersOnExit(jboolean); + virtual ::java::lang::Process * exec(::java::lang::String *); + virtual ::java::lang::Process * exec(::java::lang::String *, JArray< ::java::lang::String * > *); + virtual ::java::lang::Process * exec(::java::lang::String *, JArray< ::java::lang::String * > *, ::java::io::File *); + virtual ::java::lang::Process * exec(JArray< ::java::lang::String * > *); + virtual ::java::lang::Process * exec(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *); + virtual ::java::lang::Process * exec(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *); + virtual jint availableProcessors(); + virtual jlong freeMemory(); + virtual jlong totalMemory(); + virtual jlong maxMemory(); + virtual void gc(); + virtual void runFinalization(); + virtual void traceInstructions(jboolean); + virtual void traceMethodCalls(jboolean); + virtual void load(::java::lang::String *); + virtual void loadLibrary(::java::lang::String *); + virtual ::java::io::InputStream * getLocalizedInputStream(::java::io::InputStream *); + virtual ::java::io::OutputStream * getLocalizedOutputStream(::java::io::OutputStream *); +public: // actually package-private + virtual void exitInternal(jint); + virtual void _load(::java::lang::String *, jboolean); + virtual jboolean loadLibraryInternal(::java::lang::String *); +private: + static void init(); + void runFinalizationForExit(); +public: // actually package-private + static ::java::lang::String * nativeGetLibname(::java::lang::String *, ::java::lang::String *); + virtual ::java::lang::Process * execInternal(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *); +private: + JArray< ::java::lang::String * > * __attribute__((aligned(__alignof__( ::java::lang::Object)))) libpath; + ::java::lang::Thread * exitSequence; + ::java::util::Set * shutdownHooks; + jboolean finalizeOnExit; + static ::java::lang::Runtime * current; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Runtime__ diff --git a/libjava/java/lang/Runtime.java b/libjava/java/lang/Runtime.java new file mode 100644 index 000000000..3466f19f2 --- /dev/null +++ b/libjava/java/lang/Runtime.java @@ -0,0 +1,747 @@ +/* Runtime.java -- access to the VM process + Copyright (C) 1998, 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.classpath.SystemProperties; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * Runtime represents the Virtual Machine. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Jeroen Frijters + */ +// No idea why this class isn't final, since you can't build a subclass! +public class Runtime +{ + /** + * The library path, to search when loading libraries. We can also safely use + * this as a lock for synchronization. + */ + private final String[] libpath; + + static + { + init(); + } + + /** + * The thread that started the exit sequence. Access to this field must + * be thread-safe; lock on libpath to avoid deadlock with user code. + * <code>runFinalization()</code> may want to look at this to see if ALL + * finalizers should be run, because the virtual machine is about to halt. + */ + private Thread exitSequence; + + /** + * All shutdown hooks. This is initialized lazily, and set to null once all + * shutdown hooks have run. Access to this field must be thread-safe; lock + * on libpath to avoid deadlock with user code. + */ + private Set shutdownHooks; + + /** True if we should finalize on exit. */ + private boolean finalizeOnExit; + + /** + * The one and only runtime instance. + */ + private static final Runtime current = new Runtime(); + + /** + * Not instantiable by a user, this should only create one instance. + */ + private Runtime() + { + if (current != null) + throw new InternalError("Attempt to recreate Runtime"); + + // We don't use libpath in the libgcj implementation. We still + // set it to something to allow the various synchronizations to + // work. + libpath = new String[0]; + } + + /** + * Get the current Runtime object for this JVM. This is necessary to access + * the many instance methods of this class. + * + * @return the current Runtime object + */ + public static Runtime getRuntime() + { + return current; + } + + /** + * Exit the Java runtime. This method will either throw a SecurityException + * or it will never return. The status code is returned to the system; often + * a non-zero status code indicates an abnormal exit. Of course, there is a + * security check, <code>checkExit(status)</code>. + * + * <p>First, all shutdown hooks are run, in unspecified order, and + * concurrently. Next, if finalization on exit has been enabled, all pending + * finalizers are run. Finally, the system calls <code>halt</code>.</p> + * + * <p>If this is run a second time after shutdown has already started, there + * are two actions. If shutdown hooks are still executing, it blocks + * indefinitely. Otherwise, if the status is nonzero it halts immediately; + * if it is zero, it blocks indefinitely. This is typically called by + * <code>System.exit</code>.</p> + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @see #addShutdownHook(Thread) + * @see #runFinalizersOnExit(boolean) + * @see #runFinalization() + * @see #halt(int) + */ + public void exit(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + exitNoChecks(status); + } + + // Accessor to avoid adding a vtable slot. + static void exitNoChecksAccessor(int status) + { + current.exitNoChecks(status); + } + + // Private since we can't add a vtable slot in 4.1.x. + private void exitNoChecks(int status) + { + if (runShutdownHooks()) + exitInternal(status); + + // Someone else already called runShutdownHooks(). + // Make sure we are not/no longer in the shutdownHooks set. + // And wait till the thread that is calling runShutdownHooks() finishes. + synchronized (libpath) + { + if (shutdownHooks != null) + { + shutdownHooks.remove(Thread.currentThread()); + // Interrupt the exit sequence thread, in case it was waiting + // inside a join on our thread. + exitSequence.interrupt(); + // Shutdown hooks are still running, so we clear status to + // make sure we don't halt. + status = 0; + } + } + + // If exit() is called again after the shutdown hooks have run, but + // while finalization for exit is going on and the status is non-zero + // we halt immediately. + if (status != 0) + exitInternal(status); + + while (true) + try + { + exitSequence.join(); + } + catch (InterruptedException e) + { + // Ignore, we've suspended indefinitely to let all shutdown + // hooks complete, and to let any non-zero exits through, because + // this is a duplicate call to exit(0). + } + } + + /** + * On first invocation, run all the shutdown hooks and return true. + * Any subsequent invocations will simply return false. + * Note that it is package accessible so that VMRuntime can call it + * when VM exit is not triggered by a call to Runtime.exit(). + * + * @return was the current thread the first one to call this method? + */ + boolean runShutdownHooks() + { + boolean first = false; + synchronized (libpath) // Synch on libpath, not this, to avoid deadlock. + { + if (exitSequence == null) + { + first = true; + exitSequence = Thread.currentThread(); + if (shutdownHooks != null) + { + Iterator i = shutdownHooks.iterator(); + while (i.hasNext()) // Start all shutdown hooks. + try + { + ((Thread) i.next()).start(); + } + catch (IllegalThreadStateException e) + { + i.remove(); + } + } + } + } + if (first) + { + if (shutdownHooks != null) + { + // Check progress of all shutdown hooks. As a hook completes, + // remove it from the set. If a hook calls exit, it removes + // itself from the set, then waits indefinitely on the + // exitSequence thread. Once the set is empty, set it to null to + // signal all finalizer threads that halt may be called. + while (true) + { + Thread[] hooks; + synchronized (libpath) + { + hooks = new Thread[shutdownHooks.size()]; + shutdownHooks.toArray(hooks); + } + if (hooks.length == 0) + break; + for (int i = 0; i < hooks.length; i++) + { + try + { + synchronized (libpath) + { + if (!shutdownHooks.contains(hooks[i])) + continue; + } + hooks[i].join(); + synchronized (libpath) + { + shutdownHooks.remove(hooks[i]); + } + } + catch (InterruptedException x) + { + // continue waiting on the next thread + } + } + } + synchronized (libpath) + { + shutdownHooks = null; + } + } + // Run finalization on all finalizable objects (even if they are + // still reachable). + runFinalizationForExit(); + } + return first; + } + + /** + * Register a new shutdown hook. This is invoked when the program exits + * normally (because all non-daemon threads ended, or because + * <code>System.exit</code> was invoked), or when the user terminates + * the virtual machine (such as by typing ^C, or logging off). There is + * a security check to add hooks, + * <code>RuntimePermission("shutdownHooks")</code>. + * + * <p>The hook must be an initialized, but unstarted Thread. The threads + * are run concurrently, and started in an arbitrary order; and user + * threads or daemons may still be running. Once shutdown hooks have + * started, they must all complete, or else you must use <code>halt</code>, + * to actually finish the shutdown sequence. Attempts to modify hooks + * after shutdown has started result in IllegalStateExceptions.</p> + * + * <p>It is imperative that you code shutdown hooks defensively, as you + * do not want to deadlock, and have no idea what other hooks will be + * running concurrently. It is also a good idea to finish quickly, as the + * virtual machine really wants to shut down!</p> + * + * <p>There are no guarantees that such hooks will run, as there are ways + * to forcibly kill a process. But in such a drastic case, shutdown hooks + * would do little for you in the first place.</p> + * + * @param hook an initialized, unstarted Thread + * @throws IllegalArgumentException if the hook is already registered or run + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #removeShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public void addShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + if (hook.isAlive() || hook.getThreadGroup() == null) + throw new IllegalArgumentException("The hook thread " + hook + " must not have been already run or started"); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException("The Virtual Machine is exiting. It is not possible anymore to add any hooks"); + if (shutdownHooks == null) + shutdownHooks = new HashSet(); // Lazy initialization. + if (! shutdownHooks.add(hook)) + throw new IllegalArgumentException(hook.toString() + " had already been inserted"); + } + } + + /** + * De-register a shutdown hook. As when you registered it, there is a + * security check to remove hooks, + * <code>RuntimePermission("shutdownHooks")</code>. + * + * @param hook the hook to remove + * @return true if the hook was successfully removed, false if it was not + * registered in the first place + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #addShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public boolean removeShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException(); + if (shutdownHooks != null) + return shutdownHooks.remove(hook); + } + return false; + } + + /** + * Forcibly terminate the virtual machine. This call never returns. It is + * much more severe than <code>exit</code>, as it bypasses all shutdown + * hooks and initializers. Use caution in calling this! Of course, there is + * a security check, <code>checkExit(status)</code>. + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #exit(int) + * @see #addShutdownHook(Thread) + */ + public void halt(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + exitInternal(status); + } + + /** + * Tell the VM to run the finalize() method on every single Object before + * it exits. Note that the JVM may still exit abnormally and not perform + * this, so you still don't have a guarantee. And besides that, this is + * inherently unsafe in multi-threaded code, as it may result in deadlock + * as multiple threads compete to manipulate objects. This value defaults to + * <code>false</code>. There is a security check, <code>checkExit(0)</code>. + * + * @param finalizeOnExit whether to finalize all Objects on exit + * @throws SecurityException if permission is denied + * @see #exit(int) + * @see #gc() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(0); + current.finalizeOnExit = finalizeOnExit; + } + + /** + * Create a new subprocess with the specified command line. Calls + * <code>exec(cmdline, null, null)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmdline the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline) throws IOException + { + return exec(cmdline, null, null); + } + + /** + * Create a new subprocess with the specified command line and environment. + * If the environment is null, the process inherits the environment of + * this process. Calls <code>exec(cmdline, env, null)</code>. A security + * check is performed, <code>checkExec</code>. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline, String[] env) throws IOException + { + return exec(cmdline, env, null); + } + + /** + * Create a new subprocess with the specified command line, environment, and + * working directory. If the environment is null, the process inherits the + * environment of this process. If the directory is null, the process uses + * the current working directory. This splits cmdline into an array, using + * the default StringTokenizer, then calls + * <code>exec(cmdArray, env, dir)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + * @since 1.3 + */ + public Process exec(String cmdline, String[] env, File dir) + throws IOException + { + StringTokenizer t = new StringTokenizer(cmdline); + String[] cmd = new String[t.countTokens()]; + for (int i = 0; i < cmd.length; i++) + cmd[i] = t.nextToken(); + return exec(cmd, env, dir); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized. Calls <code>exec(cmd, null, null)</code>. A security check + * is performed, <code>checkExec</code>. + * + * @param cmd the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or has null entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd) throws IOException + { + return exec(cmd, null, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and specified environment. If the environment is null, the + * process inherits the environment of this process. Calls + * <code>exec(cmd, env, null)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd, String[] env) throws IOException + { + return exec(cmd, env, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and the specified environment and working directory. If the + * environment is null, the process inherits the environment of this + * process. If the directory is null, the process uses the current working + * directory. A security check is performed, <code>checkExec</code>. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + * @since 1.3 + */ + public Process exec(String[] cmd, String[] env, File dir) + throws IOException + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExec(cmd[0]); + return execInternal(cmd, env, dir); + } + + /** + * Returns the number of available processors currently available to the + * virtual machine. This number may change over time; so a multi-processor + * program want to poll this to determine maximal resource usage. + * + * @return the number of processors available, at least 1 + */ + public native int availableProcessors(); + + /** + * Find out how much memory is still free for allocating Objects on the heap. + * + * @return the number of bytes of free memory for more Objects + */ + public native long freeMemory(); + + /** + * Find out how much memory total is available on the heap for allocating + * Objects. + * + * @return the total number of bytes of memory for Objects + */ + public native long totalMemory(); + + /** + * Returns the maximum amount of memory the virtual machine can attempt to + * use. This may be <code>Long.MAX_VALUE</code> if there is no inherent + * limit (or if you really do have a 8 exabyte memory!). + * + * @return the maximum number of bytes the virtual machine will attempt + * to allocate + */ + public native long maxMemory(); + + /** + * Run the garbage collector. This method is more of a suggestion than + * anything. All this method guarantees is that the garbage collector will + * have "done its best" by the time it returns. Notice that garbage + * collection takes place even without calling this method. + */ + public native void gc(); + + /** + * Run finalization on all Objects that are waiting to be finalized. Again, + * a suggestion, though a stronger one than {@link #gc()}. This calls the + * <code>finalize</code> method of all objects waiting to be collected. + * + * @see #finalize() + */ + public native void runFinalization(); + + /** + * Tell the VM to trace every bytecode instruction that executes (print out + * a trace of it). No guarantees are made as to where it will be printed, + * and the VM is allowed to ignore this request. + * + * @param on whether to turn instruction tracing on + */ + public native void traceInstructions(boolean on); + + /** + * Tell the VM to trace every method call that executes (print out a trace + * of it). No guarantees are made as to where it will be printed, and the + * VM is allowed to ignore this request. + * + * @param on whether to turn method tracing on + */ + public native void traceMethodCalls(boolean on); + + /** + * Load a native library using the system-dependent filename. This is similar + * to loadLibrary, except the only name mangling done is inserting "_g" + * before the final ".so" if the VM was invoked by the name "java_g". There + * may be a security check, of <code>checkLink</code>. + * + * @param filename the file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + */ + public void load(String filename) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(filename); + _load(filename, false); + } + + /** + * Load a native library using a system-independent "short name" for the + * library. It will be transformed to a correct filename in a + * system-dependent manner (for example, in Windows, "mylib" will be turned + * into "mylib.dll"). This is done as follows: if the context that called + * load has a ClassLoader cl, then <code>cl.findLibrary(libpath)</code> is + * used to convert the name. If that result was null, or there was no class + * loader, this searches each directory of the system property + * <code>java.library.path</code> for a file named + * <code>System.mapLibraryName(libname)</code>. There may be a security + * check, of <code>checkLink</code>. + * + * @param libname the library to load + * + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + * + * @see System#mapLibraryName(String) + * @see ClassLoader#findLibrary(String) + */ + public void loadLibrary(String libname) + { + // This is different from the Classpath implementation, but I + // believe it is more correct. + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(libname); + _load(libname, true); + } + + /** + * Return a localized version of this InputStream, meaning all characters + * are localized before they come out the other end. + * + * @param in the stream to localize + * @return the localized stream + * @deprecated <code>InputStreamReader</code> is the preferred way to read + * local encodings + */ + public InputStream getLocalizedInputStream(InputStream in) + { + return in; + } + + /** + * Return a localized version of this OutputStream, meaning all characters + * are localized before they are sent to the other end. + * + * @param out the stream to localize + * @return the localized stream + * @deprecated <code>OutputStreamWriter</code> is the preferred way to write + * local encodings + */ + public OutputStream getLocalizedOutputStream(OutputStream out) + { + return out; + } + + /** + * Native method that actually shuts down the virtual machine. + * + * @param status the status to end the process with + */ + native void exitInternal(int status); + + /** + * Load a file. If it has already been loaded, do nothing. The name has + * already been mapped to a true filename. + * + * @param filename the file to load + * @param do_search True if we should search the load path for the file + */ + native void _load(String filename, boolean do_search); + + /** + *This is a helper function for the ClassLoader which can load + * compiled libraries. Returns true if library (which is just the + * base name -- path searching is done by this function) was loaded, + * false otherwise. + */ + native boolean loadLibraryInternal(String libname); + + /** + * A helper for Runtime static initializer which does some internal native + * initialization. + */ + private static native void init (); + + /** + * Run finalizers when exiting. + */ + private native void runFinalizationForExit(); + + /** + * Map a system-independent "short name" to the full file name, and append + * it to the path. + * XXX This method is being replaced by System.mapLibraryName. + * + * @param pathname the path + * @param libname the short version of the library name + * @return the full filename + */ + static native String nativeGetLibname(String pathname, String libname); + + /** + * Execute a process. The command line has already been tokenized, and + * the environment should contain name=value mappings. If directory is null, + * use the current working directory; otherwise start the process in that + * directory. + * + * @param cmd the non-null command tokens + * @param env the non-null environment setup + * @param dir the directory to use, may be null + * @return the newly created process + * @throws NullPointerException if cmd or env have null elements + * @throws IOException if the exec fails + */ + native Process execInternal(String[] cmd, String[] env, File dir) + throws IOException; +} // class Runtime diff --git a/libjava/java/lang/RuntimeException.h b/libjava/java/lang/RuntimeException.h new file mode 100644 index 000000000..0bce089c7 --- /dev/null +++ b/libjava/java/lang/RuntimeException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_RuntimeException__ +#define __java_lang_RuntimeException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::RuntimeException : public ::java::lang::Exception +{ + +public: + RuntimeException(); + RuntimeException(::java::lang::String *); + RuntimeException(::java::lang::String *, ::java::lang::Throwable *); + RuntimeException(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -7034897190745766939LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_RuntimeException__ diff --git a/libjava/java/lang/RuntimePermission.h b/libjava/java/lang/RuntimePermission.h new file mode 100644 index 000000000..8b4817545 --- /dev/null +++ b/libjava/java/lang/RuntimePermission.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_RuntimePermission__ +#define __java_lang_RuntimePermission__ + +#pragma interface + +#include <java/security/BasicPermission.h> + +class java::lang::RuntimePermission : public ::java::security::BasicPermission +{ + +public: + RuntimePermission(::java::lang::String *); + RuntimePermission(::java::lang::String *, ::java::lang::String *); +private: + static const jlong serialVersionUID = 7399184964622342223LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_RuntimePermission__ diff --git a/libjava/java/lang/SecurityException.h b/libjava/java/lang/SecurityException.h new file mode 100644 index 000000000..3b19ba203 --- /dev/null +++ b/libjava/java/lang/SecurityException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_SecurityException__ +#define __java_lang_SecurityException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::SecurityException : public ::java::lang::RuntimeException +{ + +public: + SecurityException(); + SecurityException(::java::lang::String *); + SecurityException(::java::lang::String *, ::java::lang::Throwable *); + SecurityException(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = 6878364983674394167LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_SecurityException__ diff --git a/libjava/java/lang/SecurityManager$1.h b/libjava/java/lang/SecurityManager$1.h new file mode 100644 index 000000000..4e5787541 --- /dev/null +++ b/libjava/java/lang/SecurityManager$1.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_SecurityManager$1__ +#define __java_lang_SecurityManager$1__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::SecurityManager$1 : public ::java::lang::Object +{ + +public: // actually package-private + SecurityManager$1(::java::lang::SecurityManager *, ::java::lang::String *); +public: + virtual ::java::lang::Object * run(); +public: // actually package-private + ::java::lang::SecurityManager * __attribute__((aligned(__alignof__( ::java::lang::Object)))) this$0; +private: + ::java::lang::String * val$restriction; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_SecurityManager$1__ diff --git a/libjava/java/lang/SecurityManager.h b/libjava/java/lang/SecurityManager.h new file mode 100644 index 000000000..8abaa6a7e --- /dev/null +++ b/libjava/java/lang/SecurityManager.h @@ -0,0 +1,84 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_SecurityManager__ +#define __java_lang_SecurityManager__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace java + { + namespace net + { + class InetAddress; + } + namespace security + { + class Permission; + } + } +} + +class java::lang::SecurityManager : public ::java::lang::Object +{ + +public: + SecurityManager(); + virtual jboolean getInCheck(); +public: // actually protected + virtual JArray< ::java::lang::Class * > * getClassContext(); + virtual ::java::lang::ClassLoader * currentClassLoader(); + virtual ::java::lang::Class * currentLoadedClass(); + virtual jint classDepth(::java::lang::String *); + virtual jint classLoaderDepth(); + virtual jboolean inClass(::java::lang::String *); + virtual jboolean inClassLoader(); +public: + virtual ::java::lang::Object * getSecurityContext(); + virtual void checkPermission(::java::security::Permission *); + virtual void checkPermission(::java::security::Permission *, ::java::lang::Object *); + virtual void checkCreateClassLoader(); + virtual void checkAccess(::java::lang::Thread *); + virtual void checkAccess(::java::lang::ThreadGroup *); + virtual void checkExit(jint); + virtual void checkExec(::java::lang::String *); + virtual void checkLink(::java::lang::String *); + virtual void checkRead(::java::io::FileDescriptor *); + virtual void checkRead(::java::lang::String *); + virtual void checkRead(::java::lang::String *, ::java::lang::Object *); + virtual void checkWrite(::java::io::FileDescriptor *); + virtual void checkWrite(::java::lang::String *); + virtual void checkDelete(::java::lang::String *); + virtual void checkConnect(::java::lang::String *, jint); + virtual void checkConnect(::java::lang::String *, jint, ::java::lang::Object *); + virtual void checkListen(jint); + virtual void checkAccept(::java::lang::String *, jint); + virtual void checkMulticast(::java::net::InetAddress *); + virtual void checkMulticast(::java::net::InetAddress *, jbyte); + virtual void checkPropertiesAccess(); + virtual void checkPropertyAccess(::java::lang::String *); + virtual jboolean checkTopLevelWindow(::java::lang::Object *); + virtual void checkPrintJobAccess(); + virtual void checkSystemClipboardAccess(); + virtual void checkAwtEventQueueAccess(); + virtual void checkPackageAccess(::java::lang::String *); + virtual void checkPackageDefinition(::java::lang::String *); + virtual void checkSetFactory(); + virtual void checkMemberAccess(::java::lang::Class *, jint); + virtual void checkSecurityAccess(::java::lang::String *); + virtual ::java::lang::ThreadGroup * getThreadGroup(); +public: // actually package-private + virtual void checkPackageList(::java::lang::String *, ::java::lang::String *, ::java::lang::String *); + static ::java::lang::SecurityManager * volatile current; +public: // actually protected + jboolean __attribute__((aligned(__alignof__( ::java::lang::Object)))) inCheck; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_SecurityManager__ diff --git a/libjava/java/lang/Short.h b/libjava/java/lang/Short.h new file mode 100644 index 000000000..4858db52f --- /dev/null +++ b/libjava/java/lang/Short.h @@ -0,0 +1,54 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Short__ +#define __java_lang_Short__ + +#pragma interface + +#include <java/lang/Number.h> +#include <gcj/array.h> + + +class java::lang::Short : public ::java::lang::Number +{ + +public: + Short(jshort); + Short(::java::lang::String *); + static ::java::lang::String * toString(jshort); + static jshort parseShort(::java::lang::String *); + static jshort parseShort(::java::lang::String *, jint); + static ::java::lang::Short * valueOf(::java::lang::String *, jint); + static ::java::lang::Short * valueOf(::java::lang::String *); + static ::java::lang::Short * valueOf(jshort); + static ::java::lang::Short * decode(::java::lang::String *); + jbyte byteValue(); + jshort shortValue(); + jint intValue(); + jlong longValue(); + jfloat floatValue(); + jdouble doubleValue(); + ::java::lang::String * toString(); + jint hashCode(); + jboolean equals(::java::lang::Object *); + jint Short$compareTo(::java::lang::Short *); + static jshort reverseBytes(jshort); + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = 7515723908773894738LL; +public: + static const jshort MIN_VALUE = -32768; + static const jshort MAX_VALUE = 32767; + static ::java::lang::Class * TYPE; + static const jint SIZE = 16; +private: + static const jint MIN_CACHE = -128; + static const jint MAX_CACHE = 127; + static JArray< ::java::lang::Short * > * shortCache; + jshort __attribute__((aligned(__alignof__( ::java::lang::Number)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Short__ diff --git a/libjava/java/lang/StackOverflowError.h b/libjava/java/lang/StackOverflowError.h new file mode 100644 index 000000000..6d1e06f65 --- /dev/null +++ b/libjava/java/lang/StackOverflowError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StackOverflowError__ +#define __java_lang_StackOverflowError__ + +#pragma interface + +#include <java/lang/VirtualMachineError.h> + +class java::lang::StackOverflowError : public ::java::lang::VirtualMachineError +{ + +public: + StackOverflowError(); + StackOverflowError(::java::lang::String *); +private: + static const jlong serialVersionUID = 8609175038441759607LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StackOverflowError__ diff --git a/libjava/java/lang/StackTraceElement.h b/libjava/java/lang/StackTraceElement.h new file mode 100644 index 000000000..7adf3dc31 --- /dev/null +++ b/libjava/java/lang/StackTraceElement.h @@ -0,0 +1,39 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StackTraceElement__ +#define __java_lang_StackTraceElement__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::StackTraceElement : public ::java::lang::Object +{ + +public: // actually package-private + StackTraceElement(::java::lang::String *, jint, ::java::lang::String *, ::java::lang::String *, jboolean); +public: + StackTraceElement(::java::lang::String *, ::java::lang::String *, ::java::lang::String *, jint); + ::java::lang::String * getFileName(); + jint getLineNumber(); + ::java::lang::String * getClassName(); + ::java::lang::String * getMethodName(); + jboolean isNativeMethod(); + ::java::lang::String * toString(); + jboolean equals(::java::lang::Object *); + jint hashCode(); +private: + static jboolean equals(::java::lang::Object *, ::java::lang::Object *); + static jint hashCode(::java::lang::Object *); + static const jlong serialVersionUID = 6992337162326171013LL; + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) fileName; + jint lineNumber; + ::java::lang::String * declaringClass; + ::java::lang::String * methodName; + jboolean isNative; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StackTraceElement__ diff --git a/libjava/java/lang/StrictMath.h b/libjava/java/lang/StrictMath.h new file mode 100644 index 000000000..d37d5d668 --- /dev/null +++ b/libjava/java/lang/StrictMath.h @@ -0,0 +1,203 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StrictMath__ +#define __java_lang_StrictMath__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::StrictMath : public ::java::lang::Object +{ + + StrictMath(); +public: + static jint abs(jint); + static jlong abs(jlong); + static jfloat abs(jfloat); + static jdouble abs(jdouble); + static jint min(jint, jint); + static jlong min(jlong, jlong); + static jfloat min(jfloat, jfloat); + static jdouble min(jdouble, jdouble); + static jint max(jint, jint); + static jlong max(jlong, jlong); + static jfloat max(jfloat, jfloat); + static jdouble max(jdouble, jdouble); + static jdouble sin(jdouble); + static jdouble cos(jdouble); + static jdouble tan(jdouble); + static jdouble asin(jdouble); + static jdouble acos(jdouble); + static jdouble atan(jdouble); + static jdouble atan2(jdouble, jdouble); + static jdouble sinh(jdouble); + static jdouble cosh(jdouble); + static jdouble tanh(jdouble); +private: + static jlong getLowDWord(jlong); + static jlong getHighDWord(jlong); + static jdouble buildDouble(jlong, jlong); +public: + static jdouble cbrt(jdouble); + static jdouble exp(jdouble); + static jdouble expm1(jdouble); + static jdouble log(jdouble); + static jdouble sqrt(jdouble); + static jdouble pow(jdouble, jdouble); + static jdouble IEEEremainder(jdouble, jdouble); + static jdouble ceil(jdouble); + static jdouble floor(jdouble); + static jdouble rint(jdouble); + static jint round(jfloat); + static jlong round(jdouble); + static jdouble random(); + static jdouble toRadians(jdouble); + static jdouble toDegrees(jdouble); +private: + static jint remPiOver2(jdouble, JArray< jdouble > *); + static jint remPiOver2(JArray< jdouble > *, JArray< jdouble > *, jint, jint); + static jdouble scale(jdouble, jint); + static jdouble sin(jdouble, jdouble); + static jdouble cos(jdouble, jdouble); + static jdouble tan(jdouble, jdouble, jboolean); +public: + static jdouble signum(jdouble); + static jfloat signum(jfloat); + static jdouble ulp(jdouble); + static jfloat ulp(jfloat); +private: + static ::java::util::Random * rand; +public: + static jdouble E; + static jdouble PI; +private: + static jdouble TWO_16; + static jdouble TWO_20; + static jdouble TWO_24; + static jdouble TWO_27; + static jdouble TWO_28; + static jdouble TWO_29; + static jdouble TWO_31; + static jdouble TWO_49; + static jdouble TWO_52; + static jdouble TWO_54; + static jdouble TWO_57; + static jdouble TWO_60; + static jdouble TWO_64; + static jdouble TWO_66; + static jdouble TWO_1023; + static JArray< jint > * TWO_OVER_PI; + static JArray< jdouble > * PI_OVER_TWO; + static jdouble PI_L; + static jdouble PIO2_1; + static jdouble PIO2_1L; + static jdouble PIO2_2; + static jdouble PIO2_2L; + static jdouble PIO2_3; + static jdouble PIO2_3L; + static jdouble SQRT_1_5; + static jdouble SQRT_2; + static jdouble SQRT_3; + static jdouble EXP_LIMIT_H; + static jdouble EXP_LIMIT_L; + static jdouble CP; + static jdouble CP_H; + static jdouble CP_L; + static jdouble LN2; + static jdouble LN2_H; + static jdouble LN2_L; + static jdouble INV_LN2; + static jdouble INV_LN2_H; + static jdouble INV_LN2_L; + static jdouble LG1; + static jdouble LG2; + static jdouble LG3; + static jdouble LG4; + static jdouble LG5; + static jdouble LG6; + static jdouble LG7; + static jdouble L1; + static jdouble L2; + static jdouble L3; + static jdouble L4; + static jdouble L5; + static jdouble L6; + static jdouble P1; + static jdouble P2; + static jdouble P3; + static jdouble P4; + static jdouble P5; + static jdouble DP_H; + static jdouble DP_L; + static jdouble OVT; + static jdouble S1; + static jdouble S2; + static jdouble S3; + static jdouble S4; + static jdouble S5; + static jdouble S6; + static jdouble C1; + static jdouble C2; + static jdouble C3; + static jdouble C4; + static jdouble C5; + static jdouble C6; + static jdouble T0; + static jdouble T1; + static jdouble T2; + static jdouble T3; + static jdouble T4; + static jdouble T5; + static jdouble T6; + static jdouble T7; + static jdouble T8; + static jdouble T9; + static jdouble T10; + static jdouble T11; + static jdouble T12; + static jdouble PS0; + static jdouble PS1; + static jdouble PS2; + static jdouble PS3; + static jdouble PS4; + static jdouble PS5; + static jdouble QS1; + static jdouble QS2; + static jdouble QS3; + static jdouble QS4; + static jdouble ATAN_0_5H; + static jdouble ATAN_0_5L; + static jdouble ATAN_1_5H; + static jdouble ATAN_1_5L; + static jdouble AT0; + static jdouble AT1; + static jdouble AT2; + static jdouble AT3; + static jdouble AT4; + static jdouble AT5; + static jdouble AT6; + static jdouble AT7; + static jdouble AT8; + static jdouble AT9; + static jdouble AT10; + static const jint CBRT_B1 = 715094163; + static const jint CBRT_B2 = 696219795; + static jdouble CBRT_C; + static jdouble CBRT_D; + static jdouble CBRT_E; + static jdouble CBRT_F; + static jdouble CBRT_G; + static jdouble EXPM1_Q1; + static jdouble EXPM1_Q2; + static jdouble EXPM1_Q3; + static jdouble EXPM1_Q4; + static jdouble EXPM1_Q5; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StrictMath__ diff --git a/libjava/java/lang/String$CaseInsensitiveComparator.h b/libjava/java/lang/String$CaseInsensitiveComparator.h new file mode 100644 index 000000000..8a1b121bc --- /dev/null +++ b/libjava/java/lang/String$CaseInsensitiveComparator.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_String$CaseInsensitiveComparator__ +#define __java_lang_String$CaseInsensitiveComparator__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::String$CaseInsensitiveComparator : public ::java::lang::Object +{ + +public: // actually package-private + String$CaseInsensitiveComparator(); +public: + jint String$CaseInsensitiveComparator$compare(::java::lang::String *, ::java::lang::String *); + jint compare(::java::lang::Object *, ::java::lang::Object *); +private: + static const jlong serialVersionUID = 8575799808933029326LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_String$CaseInsensitiveComparator__ diff --git a/libjava/java/lang/String.h b/libjava/java/lang/String.h new file mode 100644 index 000000000..32e0ccdfa --- /dev/null +++ b/libjava/java/lang/String.h @@ -0,0 +1,148 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_String__ +#define __java_lang_String__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace runtime + { + class StringBuffer; + } + } + } +} + +jchar* _Jv_GetStringChars (jstring str); +jstring* _Jv_StringFindSlot (jchar*, jint, jint); +jstring* _Jv_StringGetSlot (jstring); +jstring _Jv_NewStringUtf8Const (_Jv_Utf8Const* str); +jstring _Jv_NewStringLatin1 (const char*, jsize); +jstring _Jv_AllocString (jsize); + +class java::lang::String : public ::java::lang::Object +{ + +public: + String(); + String(::java::lang::String *); + String(JArray< jchar > *); + String(JArray< jchar > *, jint, jint); + String(JArray< jbyte > *, jint, jint, jint); + String(JArray< jbyte > *, jint); + String(JArray< jbyte > *, jint, jint, ::java::lang::String *); + String(JArray< jbyte > *, ::java::lang::String *); + String(JArray< jbyte > *, jint, jint); + String(JArray< jbyte > *); + String(::java::lang::StringBuffer *); + String(::java::lang::StringBuilder *); +public: // actually package-private + String(JArray< jchar > *, jint, jint, jboolean); + String(::gnu::gcj::runtime::StringBuffer *); +public: + jint length(); + jchar charAt(jint); + jint codePointAt(jint); + jint codePointBefore(jint); + void getChars(jint, jint, JArray< jchar > *, jint); + void getBytes(jint, jint, JArray< jbyte > *, jint); + JArray< jbyte > * getBytes(::java::lang::String *); + JArray< jbyte > * getBytes(); + jboolean equals(::java::lang::Object *); + jboolean contentEquals(::java::lang::StringBuffer *); + jboolean contentEquals(::java::lang::CharSequence *); + jboolean equalsIgnoreCase(::java::lang::String *); + jint String$compareTo(::java::lang::String *); +private: + jint nativeCompareTo(::java::lang::String *); +public: + jint compareToIgnoreCase(::java::lang::String *); + jboolean regionMatches(jint, ::java::lang::String *, jint, jint); + jboolean regionMatches(jboolean, jint, ::java::lang::String *, jint, jint); + jboolean startsWith(::java::lang::String *, jint); + jboolean startsWith(::java::lang::String *); + jboolean endsWith(::java::lang::String *); + jint hashCode(); + jint indexOf(jint); + jint indexOf(jint, jint); + jint lastIndexOf(jint); + jint lastIndexOf(jint, jint); + jint indexOf(::java::lang::String *); + jint indexOf(::java::lang::String *, jint); + jint lastIndexOf(::java::lang::String *); + jint lastIndexOf(::java::lang::String *, jint); + ::java::lang::String * substring(jint); + ::java::lang::String * substring(jint, jint); + ::java::lang::CharSequence * subSequence(jint, jint); + ::java::lang::String * concat(::java::lang::String *); + ::java::lang::String * replace(jchar, jchar); + jboolean matches(::java::lang::String *); + ::java::lang::String * replaceFirst(::java::lang::String *, ::java::lang::String *); + ::java::lang::String * replaceAll(::java::lang::String *, ::java::lang::String *); + JArray< ::java::lang::String * > * split(::java::lang::String *, jint); + JArray< ::java::lang::String * > * split(::java::lang::String *); + ::java::lang::String * toLowerCase(::java::util::Locale *); + ::java::lang::String * toLowerCase(); + ::java::lang::String * toUpperCase(::java::util::Locale *); + ::java::lang::String * toUpperCase(); + ::java::lang::String * trim(); + ::java::lang::String * toString(); + JArray< jchar > * toCharArray(); + static ::java::lang::String * valueOf(::java::lang::Object *); + static ::java::lang::String * valueOf(JArray< jchar > *); + static ::java::lang::String * valueOf(JArray< jchar > *, jint, jint); + static ::java::lang::String * copyValueOf(JArray< jchar > *, jint, jint); + static ::java::lang::String * copyValueOf(JArray< jchar > *); + static ::java::lang::String * valueOf(jboolean); + static ::java::lang::String * valueOf(jchar); + static ::java::lang::String * valueOf(jint); + static ::java::lang::String * valueOf(jlong); + static ::java::lang::String * valueOf(jfloat); + static ::java::lang::String * valueOf(jdouble); + static ::java::lang::String * format(::java::util::Locale *, ::java::lang::String *, JArray< ::java::lang::Object * > *); + static ::java::lang::String * format(::java::lang::String *, JArray< ::java::lang::Object * > *); + ::java::lang::String * intern(); + jint codePointCount(jint, jint); + jboolean contains(::java::lang::CharSequence *); + ::java::lang::String * replace(::java::lang::CharSequence *, ::java::lang::CharSequence *); + jint offsetByCodePoints(jint, jint); + jboolean isEmpty(); +private: + static ::java::lang::String * toString(JArray< jchar > *, jint, jint); + void init(JArray< jchar > *, jint, jint, jboolean); + void init(JArray< jbyte > *, jint, jint, jint); + void init(JArray< jbyte > *, jint, jint, ::java::lang::String *); + void init(::gnu::gcj::runtime::StringBuffer *); +public: + jint compareTo(::java::lang::Object *); +private: + static const jlong serialVersionUID = -6849794470754667710LL; + ::java::lang::Object * __attribute__((aligned(__alignof__( ::java::lang::Object)))) data; + jint boffset; +public: // actually package-private + jint count; +private: + jint cachedHashCode; +public: + static ::java::util::Comparator * CASE_INSENSITIVE_ORDER; + static ::java::lang::Class class$; + + friend jchar* ::_Jv_GetStringChars (jstring str); + friend jstring* ::_Jv_StringFindSlot (jchar*, jint, jint); + friend jstring* ::_Jv_StringGetSlot (jstring); + friend jstring (::_Jv_NewStringUtf8Const) (_Jv_Utf8Const* str); + friend jstring (::_Jv_NewStringLatin1) (const char*, jsize); + friend jstring (::_Jv_AllocString) (jsize); +}; + +#endif // __java_lang_String__ diff --git a/libjava/java/lang/String.java b/libjava/java/lang/String.java new file mode 100644 index 000000000..b9ce3c016 --- /dev/null +++ b/libjava/java/lang/String.java @@ -0,0 +1,1457 @@ +/* String.java -- immutable character sequences; the object of string literals + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 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.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Comparator; +import java.text.Collator; +import java.util.Formatter; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Strings represent an immutable set of characters. All String literals + * are instances of this class, and two string literals with the same contents + * refer to the same String object. + * + * <p>This class also includes a number of methods for manipulating the + * contents of strings (of course, creating a new object if there are any + * changes, as String is immutable). Case mapping relies on Unicode 3.0.0 + * standards, where some character sequences have a different number of + * characters in the uppercase version than the lower case. + * + * <p>Strings are special, in that they are the only object with an overloaded + * operator. When you use '+' with at least one String argument, both + * arguments have String conversion performed on them, and another String (not + * guaranteed to be unique) results. + * + * <p>String is special-cased when doing data serialization - rather than + * listing the fields of this class, a String object is converted to a string + * literal in the object stream. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.0 + * @status updated to 1.4 + */ +public final class String + implements Serializable, Comparable<String>, CharSequence +{ + // WARNING: String is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * This is probably not necessary because this class is special cased already + * but it will avoid showing up as a discrepancy when comparing SUIDs. + */ + private static final long serialVersionUID = -6849794470754667710L; + + /** + * This is the object that holds the characters that make up the + * String. It might be a char[], or it could be String. It could + * even be `this'. The actual characters can't be located using + * pure Java code. + * @see #boffset + */ + private Object data; + + /** + * This is a <emph>byte</emph> offset of the actual characters from + * the start of the character-holding object. Don't use this field + * in Java code. + */ + private int boffset; + + /** + * Holds the number of characters in value. Package visible for use + * by trusted code. + */ + int count; + + /** + * Caches the result of hashCode(). If this value is zero, the hashcode + * is considered uncached (even if 0 is the correct hash value). + */ + private int cachedHashCode; + + /** + * An implementation for {@link #CASE_INSENSITIVE_ORDER}. + * This must be {@link Serializable}. The class name is dictated by + * compatibility with Sun's JDK. + */ + private static final class CaseInsensitiveComparator + implements Comparator<String>, Serializable + { + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 8575799808933029326L; + + /** + * The default private constructor generates unnecessary overhead. + */ + CaseInsensitiveComparator() {} + + /** + * Compares to Strings, using + * <code>String.compareToIgnoreCase(String)</code>. + * + * @param o1 the first string + * @param o2 the second string + * @return < 0, 0, or > 0 depending on the case-insensitive + * comparison of the two strings. + * @throws NullPointerException if either argument is null + * @throws ClassCastException if either argument is not a String + * @see #compareToIgnoreCase(String) + */ + public int compare(String o1, String o2) + { + return o1.compareToIgnoreCase(o2); + } + } // class CaseInsensitiveComparator + + /** + * A Comparator that uses <code>String.compareToIgnoreCase(String)</code>. + * This comparator is {@link Serializable}. Note that it ignores Locale, + * for that, you want a Collator. + * + * @see Collator#compare(String, String) + * @since 1.2 + */ + public static final Comparator<String> CASE_INSENSITIVE_ORDER + = new CaseInsensitiveComparator(); + + /** + * Creates an empty String (length 0). Unless you really need a new object, + * consider using <code>""</code> instead. + */ + public String() + { + data = "".data; + boffset = 0; + count = 0; + } + + /** + * Copies the contents of a String to a new String. Since Strings are + * immutable, only a shallow copy is performed. + * + * @param str String to copy + * @throws NullPointerException if value is null + */ + public String(String str) + { + data = str.data; + boffset = str.boffset; + count = str.count; + cachedHashCode = str.cachedHashCode; + } + + /** + * Creates a new String using the character sequence of the char array. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @throws NullPointerException if data is null + */ + public String(char[] data) + { + init(data, 0, data.length, false); + } + + /** + * Creates a new String using the character sequence of a subarray of + * characters. The string starts at offset, and copies count chars. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count < 0 (overflow) + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String(char[] data, int offset, int count) + { + init(data, offset, count, false); + } + + /** + * Creates a new String using an 8-bit array of integer values, starting at + * an offset, and copying up to the count. Each character c, using + * corresponding byte b, is created in the new String as if by performing: + * + * <pre> + * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) + * </pre> + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @param offset position (base 0) to start copying out of ascii + * @param count the number of characters from ascii to copy + * @throws NullPointerException if ascii is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count < 0 (overflow) + * || offset + count > ascii.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @deprecated use {@link #String(byte[], int, int, String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte, int offset, int count) + { + init(ascii, hibyte, offset, count); + } + + /** + * Creates a new String using an 8-bit array of integer values. Each + * character c, using corresponding byte b, is created in the new String + * as if by performing: + * + * <pre> + * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) + * </pre> + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @throws NullPointerException if ascii is null + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @see #String(byte[], int, int, int) + * @deprecated use {@link #String(byte[], String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte) + { + init(ascii, hibyte, 0, ascii.length); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the specified encoding type + * to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of bytes in the array to use + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @since 1.1 + */ + public String(byte[] data, int offset, int count, String encoding) + throws UnsupportedEncodingException + { + init (data, offset, count, encoding); + } + + /** + * Creates a new String using the byte array. Uses the specified encoding + * type to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, String encoding) + throws UnsupportedEncodingException + { + this(data, 0, data.length, encoding); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the encoding of the platform's + * default charset, so the resulting string may be longer or shorter than + * the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified + * if the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of bytes in the array to use + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, int offset, int count) + { + try + { + init (data, offset, count, + System.getProperty("file.encoding", "8859_1")); + } + catch (UnsupportedEncodingException x1) + { + // Maybe the default encoding is bad. + try + { + init (data, offset, count, "8859_1"); + } + catch (UnsupportedEncodingException x2) + { + // We know this can't happen. + } + } + } + + /** + * Creates a new String using the byte array. Uses the encoding of the + * platform's default charset, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified + * if the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @throws NullPointerException if data is null + * @throws Error if the decoding fails + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data) + { + this(data, 0, data.length); + } + + /** + * Creates a new String using the character sequence represented by + * the StringBuffer. Subsequent changes to buf do not affect the String. + * + * @param buffer StringBuffer to copy + * @throws NullPointerException if buffer is null + */ + public String(StringBuffer buffer) + { + synchronized (buffer) + { + // Share unless buffer is 3/4 empty. + boolean should_copy = ((buffer.count << 2) < buffer.value.length); + if (! should_copy) + buffer.shared = true; + init (buffer.value, 0, buffer.count, ! should_copy); + } + } + + /** + * Creates a new String using the character sequence represented by + * the StringBuilder. Subsequent changes to buf do not affect the String. + * + * @param buffer StringBuilder to copy + * @throws NullPointerException if buffer is null + */ + public String(StringBuilder buffer) + { + this(buffer.value, 0, buffer.count); + } + + /** + * Special constructor which can share an array when safe to do so. + * + * @param data the characters to copy + * @param offset the location to start from + * @param count the number of characters to use + * @param dont_copy true if the array is trusted, and need not be copied + * @throws NullPointerException if chars is null + * @throws StringIndexOutOfBoundsException if bounds check fails + */ + String(char[] data, int offset, int count, boolean dont_copy) + { + init(data, offset, count, dont_copy); + } + + // This is used by gnu.gcj.runtime.StringBuffer, so it must have + // package-private protection. It is accessed via CNI and so avoids + // ordinary protection mechanisms. + String(gnu.gcj.runtime.StringBuffer buffer) + { + // No need to synchronize or mark the buffer, since we know it is + // only used once. + init (buffer); + } + + /** + * Returns the number of characters contained in this String. + * + * @return the length of this String + */ + public int length() + { + return count; + } + + /** + * Returns the character located at the specified index within this String. + * + * @param index position of character to return (base 0) + * @return character located at position index + * @throws IndexOutOfBoundsException if index < 0 || index >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public native char charAt(int index); + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointAt(int index) + { + // Use the CharSequence overload as we get better range checking + // this way. + return Character.codePointAt(this, index); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at <code>index-1</code> and + * <code>index-2</code> to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @since 1.5 + */ + public synchronized int codePointBefore(int index) + { + // Use the CharSequence overload as we get better range checking + // this way. + return Character.codePointBefore(this, index); + } + + /** + * Copies characters from this String starting at a specified start index, + * ending at a specified stop index, to a character array starting at + * a specified destination begin index. + * + * @param srcBegin index to begin copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst character array which this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + */ + public native void getChars(int srcBegin, int srcEnd, + char[] dst, int dstBegin); + + /** + * Copies the low byte of each character from this String starting at a + * specified start index, ending at a specified stop index, to a byte array + * starting at a specified destination begin index. + * + * @param srcBegin index to being copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst byte array which each low byte of this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null and copy length is non-zero + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + * @see #getBytes() + * @see #getBytes(String) + * @deprecated use {@link #getBytes()}, which uses a char to byte encoder + */ + public native void getBytes(int srcBegin, int srcEnd, + byte[] dst, int dstBegin); + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * specified encoding method, so the result may be longer or shorter than + * the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the encoder encounters a problem; this implementation returns null. + * + * @param enc encoding name + * @return the resulting byte array, or null on a problem + * @throws NullPointerException if enc is null + * @throws UnsupportedEncodingException if encoding is not supported + * @since 1.1 + */ + public native byte[] getBytes(String enc) + throws UnsupportedEncodingException; + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * encoding of the platform's default charset, so the result may be longer + * or shorter than the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}. The behavior is not specified if + * the encoder encounters a problem; this implementation returns null. + * + * @return the resulting byte array, or null on a problem + * @since 1.1 + */ + public byte[] getBytes() + { + try + { + return getBytes (System.getProperty("file.encoding", "8859_1")); + } + catch (UnsupportedEncodingException x) + { + // This probably shouldn't happen, but could if file.encoding + // is somehow changed to a value we don't understand. + try + { + return getBytes ("8859_1"); + } + catch (UnsupportedEncodingException x2) + { + // This really shouldn't happen, because the 8859_1 + // encoding should always be available. + throw new InternalError ("couldn't find 8859_1 encoder"); + } + } + } + + /** + * Predicate which compares anObject to this. This is true only for Strings + * with the same character sequence. + * + * @param anObject the object to compare + * @return true if anObject is semantically equal to this + * @see #compareTo(String) + * @see #equalsIgnoreCase(String) + */ + public native boolean equals(Object anObject); + + /** + * Compares the given StringBuffer to this String. This is true if the + * StringBuffer has the same content as this String at this moment. + * + * @param buffer the StringBuffer to compare to + * @return true if StringBuffer has the same character sequence + * @throws NullPointerException if the given StringBuffer is null + * @since 1.4 + */ + public native boolean contentEquals(StringBuffer buffer); + + /** + * Compares the given CharSequence to this String. This is true if + * the CharSequence has the same content as this String at this + * moment. + * + * @param seq the CharSequence to compare to + * @return true if CharSequence has the same character sequence + * @throws NullPointerException if the given CharSequence is null + * @since 1.5 + */ + public native boolean contentEquals(CharSequence seq); + + /** + * Compares a String to this String, ignoring case. This does not handle + * multi-character capitalization exceptions; instead the comparison is + * made on a character-by-character basis, and is true if:<br><ul> + * <li><code>c1 == c2</code></li> + * <li><code>Character.toUpperCase(c1) + * == Character.toUpperCase(c2)</code></li> + * <li><code>Character.toLowerCase(c1) + * == Character.toLowerCase(c2)</code></li> + * </ul> + * + * @param anotherString String to compare to this String + * @return true if anotherString is equal, ignoring case + * @see #equals(Object) + * @see Character#toUpperCase(char) + * @see Character#toLowerCase(char) + */ + public native boolean equalsIgnoreCase(String anotherString); + + /** + * Compares this String and another String (case sensitive, + * lexicographically). The result is less than 0 if this string sorts + * before the other, 0 if they are equal, and greater than 0 otherwise. + * After any common starting sequence is skipped, the result is + * <code>this.charAt(k) - anotherString.charAt(k)</code> if both strings + * have characters remaining, or + * <code>this.length() - anotherString.length()</code> if one string is + * a subsequence of the other. + * + * @param anotherString the String to compare against + * @return the comparison + * @throws NullPointerException if anotherString is null + */ + public int compareTo(String anotherString) + { + return nativeCompareTo(anotherString); + } + + /** + * The native implementation of compareTo(). Must be named different + * since cni doesn't understand the bridge method generated from + * the compareTo() method because of the Comparable<String> interface. + */ + private native int nativeCompareTo(String anotherString); + + /** + * Compares this String and another String (case insensitive). This + * comparison is <em>similar</em> to equalsIgnoreCase, in that it ignores + * locale and multi-characater capitalization, and compares characters + * after performing + * <code>Character.toLowerCase(Character.toUpperCase(c))</code> on each + * character of the string. This is unsatisfactory for locale-based + * comparison, in which case you should use {@link java.text.Collator}. + * + * @param str the string to compare against + * @return the comparison + * @see Collator#compare(String, String) + * @since 1.2 + */ + public int compareToIgnoreCase(String str) + { + return this.toUpperCase().toLowerCase().compareTo( + str.toUpperCase().toLowerCase()); + } + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length. Indices out of bounds are harmless, and give + * a false result. + * + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param ooffset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match (case sensitive) + * @throws NullPointerException if other is null + */ + public native boolean regionMatches(int toffset, + String other, int ooffset, int len); + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length, optionally ignoring case. Indices out of bounds + * are harmless, and give a false result. Case comparisons are based on + * <code>Character.toLowerCase()</code> and + * <code>Character.toUpperCase()</code>, not on multi-character + * capitalization expansions. + * + * @param ignoreCase true if case should be ignored in comparision + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param ooffset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match, false otherwise + * @throws NullPointerException if other is null + */ + public native boolean regionMatches(boolean ignoreCase, int toffset, + String other, int ooffset, int len); + + /** + * Predicate which determines if this String contains the given prefix, + * beginning comparison at toffset. The result is false if toffset is + * negative or greater than this.length(), otherwise it is the same as + * <code>this.substring(toffset).startsWith(prefix)</code>. + * + * @param prefix String to compare + * @param toffset offset for this String where comparison starts + * @return true if this String starts with prefix + * @throws NullPointerException if prefix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public native boolean startsWith(String prefix, int toffset); + + /** + * Predicate which determines if this String starts with a given prefix. + * If the prefix is an empty String, true is returned. + * + * @param prefix String to compare + * @return true if this String starts with the prefix + * @throws NullPointerException if prefix is null + * @see #startsWith(String, int) + */ + public boolean startsWith(String prefix) + { + return startsWith (prefix, 0); + } + + /** + * Predicate which determines if this String ends with a given suffix. + * If the suffix is an empty String, true is returned. + * + * @param suffix String to compare + * @return true if this String ends with the suffix + * @throws NullPointerException if suffix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public boolean endsWith(String suffix) + { + return regionMatches (this.count - suffix.count, suffix, 0, suffix.count); + } + + /** + * Computes the hashcode for this String. This is done with int arithmetic, + * where ** represents exponentiation, by this formula:<br> + * <code>s[0]*31**(n-1) + s[1]*31**(n-2) + ... + s[n-1]</code>. + * + * @return hashcode value of this String + */ + public native int hashCode(); + + /** + * Finds the first instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int indexOf(int ch) + { + return indexOf(ch, 0); + } + + /** + * Finds the first instance of a character in this String, starting at + * a given index. If starting index is less than 0, the search + * starts at the beginning of this String. If the starting index + * is greater than the length of this String, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public native int indexOf(int ch, int fromIndex); + + /** + * Finds the last instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int lastIndexOf(int ch) + { + return lastIndexOf(ch, count - 1); + } + + /** + * Finds the last instance of a character in this String, starting at + * a given index. If starting index is greater than the maximum valid + * index, then the search begins at the end of this String. If the + * starting index is less than zero, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public native int lastIndexOf(int ch, int fromIndex); + + /** + * Finds the first instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this String, starting at + * a given index. If starting index is less than 0, the search + * starts at the beginning of this String. If the starting index + * is greater than the length of this String, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public native int indexOf(String str, int fromIndex); + + /** + * Finds the last instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this String, starting at + * a given index. If starting index is greater than the maximum valid + * index, then the search begins at the end of this String. If the + * starting index is less than zero, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str, int fromIndex) + { + if (fromIndex >= count) + fromIndex = count - str.count; + for (;; --fromIndex) + { + if (fromIndex < 0) + return -1; + if (startsWith(str, fromIndex)) + return fromIndex; + } + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at the end of this String. + * + * @param begin index to start substring (base 0) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || begin > length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String substring(int begin) + { + return substring(begin, count); + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. + * + * @param begin index to start substring (inclusive, base 0) + * @param end index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end (while unspecified, this is a + * StringIndexOutOfBoundsException) + */ + public native String substring(int begin, int end); + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. This behaves like + * <code>substring(begin, end)</code>. + * + * @param begin index to start substring (inclusive, base 0) + * @param end index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end + * @since 1.4 + */ + public CharSequence subSequence(int begin, int end) + { + return substring(begin, end); + } + + /** + * Concatenates a String to this String. This results in a new string unless + * one of the two originals is "". + * + * @param str String to append to this String + * @return newly concatenated String + * @throws NullPointerException if str is null + */ + public native String concat(String str); + + /** + * Replaces every instance of a character in this String with a new + * character. If no replacements occur, this is returned. + * + * @param oldChar the old character to replace + * @param newChar the new character + * @return new String with all instances of oldChar replaced with newChar + */ + public native String replace(char oldChar, char newChar); + + /** + * Test if this String matches a regular expression. This is shorthand for + * <code>{@link Pattern}.matches(regex, this)</code>. + * + * @param regex the pattern to match + * @return true if the pattern matches + * @throws NullPointerException if regex is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#matches(String, CharSequence) + * @since 1.4 + */ + public boolean matches(String regex) + { + return Pattern.matches(regex, this); + } + + /** + * Replaces the first substring match of the regular expression with a + * given replacement. This is shorthand for <code>{@link Pattern} + * .compile(regex).matcher(this).replaceFirst(replacement)</code>. + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceAll(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceFirst(String) + * @since 1.4 + */ + public String replaceFirst(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceFirst(replacement); + } + + /** + * Replaces all matching substrings of the regular expression with a + * given replacement. This is shorthand for <code>{@link Pattern} + * .compile(regex).matcher(this).replaceAll(replacement)</code>. + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceFirst(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceAll(String) + * @since 1.4 + */ + public String replaceAll(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceAll(replacement); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * + * <p>The limit affects the length of the array. If it is positive, the + * array will contain at most n elements (n - 1 pattern matches). If + * negative, the array length is unlimited, but there can be trailing empty + * entries. if 0, the array length is unlimited, and trailing empty entries + * are discarded. + * + * <p>For example, splitting "boo:and:foo" yields:<br> + * <table border=0> + * <th><td>Regex</td> <td>Limit</td> <td>Result</td></th> + * <tr><td>":"</td> <td>2</td> <td>{ "boo", "and:foo" }</td></tr> + * <tr><td>":"</td> <td>t</td> <td>{ "boo", "and", "foo" }</td></tr> + * <tr><td>":"</td> <td>-2</td> <td>{ "boo", "and", "foo" }</td></tr> + * <tr><td>"o"</td> <td>5</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> + * <tr><td>"o"</td> <td>-2</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> + * <tr><td>"o"</td> <td>0</td> <td>{ "b", "", ":and:f" }</td></tr> + * </table> + * + * <p>This is shorthand for + * <code>{@link Pattern}.compile(regex).split(this, limit)</code>. + * + * @param regex the pattern to match + * @param limit the limit threshold + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex, int limit) + { + return Pattern.compile(regex).split(this, limit); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * The array length is unlimited, and trailing empty entries are discarded, + * as though calling <code>split(regex, 0)</code>. + * + * @param regex the pattern to match + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #split(String, int) + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex) + { + return Pattern.compile(regex).split(this, 0); + } + + /** + * Lowercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new lowercased String, or this if no characters were lowercased + * @throws NullPointerException if loc is null + * @see #toUpperCase(Locale) + * @since 1.1 + */ + public native String toLowerCase(Locale locale); + + /** + * Lowercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new lowercased String, or this if no characters were lowercased + * @see #toLowerCase(Locale) + * @see #toUpperCase() + */ + public String toLowerCase() + { + // The JDK is a bit confused about what to do here. If we pass in + // the default Locale then special Locale handling might be + // invoked. However, the docs also say that Character.toLowerCase + // rules here. We go with the latter. + return toLowerCase (null); + } + + /** + * Uppercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new uppercased String, or this if no characters were uppercased + * @throws NullPointerException if loc is null + * @see #toLowerCase(Locale) + * @since 1.1 + */ + public native String toUpperCase(Locale locale); + + /** + * Uppercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new uppercased String, or this if no characters were uppercased + * @see #toUpperCase(Locale) + * @see #toLowerCase() + */ + public String toUpperCase() + { + // The JDK is a bit confused about what to do here. If we pass in + // the default Locale then special Locale handling might be + // invoked. However, the docs also say that Character.toLowerCase + // rules here. We go with the latter. + return toUpperCase (null); + } + + /** + * Trims all characters less than or equal to <code>'\u0020'</code> + * (<code>' '</code>) from the beginning and end of this String. This + * includes many, but not all, ASCII control characters, and all + * {@link Character#isWhitespace(char)}. + * + * @return new trimmed String, or this if nothing trimmed + */ + public native String trim(); + + /** + * Returns this, as it is already a String! + * + * @return this + */ + public String toString() + { + return this; + } + + /** + * Copies the contents of this String into a character array. Subsequent + * changes to the array do not affect the String. + * + * @return character array copying the String + */ + public native char[] toCharArray(); + + /** + * Returns a String representation of an Object. This is "null" if the + * object is null, otherwise it is <code>obj.toString()</code> (which + * can be null). + * + * @param obj the Object + * @return the string conversion of obj + */ + public static String valueOf(Object obj) + { + return obj == null ? "null" : obj.toString(); + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #valueOf(char[], int, int) + * @see #String(char[]) + */ + public static String valueOf(char[] data) + { + return valueOf (data, 0, data.length); + } + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static native String valueOf(char[] data, int offset, int count); + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count < 0 (overflow) + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static String copyValueOf(char[] data, int offset, int count) + { + String r = new String (); + r.init(data, offset, count, false); + return r; + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #copyValueOf(char[], int, int) + * @see #String(char[]) + */ + public static String copyValueOf(char[] data) + { + return copyValueOf (data, 0, data.length); + } + + /** + * Returns a String representing a boolean. + * + * @param b the boolean + * @return "true" if b is true, else "false" + */ + public static String valueOf(boolean b) + { + return b ? "true" : "false"; + } + + /** + * Returns a String representing a character. + * + * @param c the character + * @return String containing the single character c + */ + public static native String valueOf(char c); + + /** + * Returns a String representing an integer. + * + * @param i the integer + * @return String containing the integer in base 10 + * @see Integer#toString(int) + */ + public static native String valueOf(int i); + + /** + * Returns a String representing a long. + * + * @param l the long + * @return String containing the long in base 10 + * @see Long#toString(long) + */ + public static String valueOf(long l) + { + return Long.toString(l); + } + + /** + * Returns a String representing a float. + * + * @param f the float + * @return String containing the float + * @see Float#toString(float) + */ + public static String valueOf(float f) + { + return Float.toString(f); + } + + /** + * Returns a String representing a double. + * + * @param d the double + * @return String containing the double + * @see Double#toString(double) + */ + public static String valueOf(double d) + { + return Double.toString(d); + } + + + /** @since 1.5 */ + public static String format(Locale locale, String format, Object... args) + { + Formatter f = new Formatter(locale); + return f.format(format, args).toString(); + } + + /** @since 1.5 */ + public static String format(String format, Object... args) + { + return format(Locale.getDefault(), format, args); + } + + /** + * Fetches this String from the intern hashtable. + * If two Strings are considered equal, by the equals() method, + * then intern() will return the same String instance. ie. + * if (s1.equals(s2)) then (s1.intern() == s2.intern()). + * All string literals and string-valued constant expressions + * are already interned. + * + * @return the interned String + */ + public native String intern(); + + /** + * Return the number of code points between two indices in the + * <code>String</code>. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public synchronized int codePointCount(int start, int end) + { + if (start < 0 || end > count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = charAt(start); + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || charAt(start + 1) < Character.MIN_LOW_SURROGATE + || charAt(start + 1) > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Returns true iff this String contains the sequence of Characters + * described in s. + * @param s the CharSequence + * @return true iff this String contains s + * + * @since 1.5 + */ + public boolean contains (CharSequence s) + { + return this.indexOf(s.toString()) != -1; + } + + /** + * Returns a string that is this string with all instances of the sequence + * represented by <code>target</code> replaced by the sequence in + * <code>replacement</code>. + * @param target the sequence to be replaced + * @param replacement the sequence used as the replacement + * @return the string constructed as above + */ + public String replace (CharSequence target, CharSequence replacement) + { + String targetString = target.toString(); + String replaceString = replacement.toString(); + int targetLength = target.length(); + int replaceLength = replacement.length(); + + int startPos = this.indexOf(targetString); + StringBuilder result = new StringBuilder(this); + while (startPos != -1) + { + // Replace the target with the replacement + result.replace(startPos, startPos + targetLength, replaceString); + + // Search for a new occurrence of the target + startPos = result.indexOf(targetString, startPos + replaceLength); + } + return result.toString(); + } + + /** + * Return the index into this String that is offset from the given index by + * <code>codePointOffset</code> code points. + * @param index the index at which to start + * @param codePointOffset the number of code points to offset + * @return the index into this String that is <code>codePointOffset</code> + * code points offset from <code>index</code>. + * + * @throws IndexOutOfBoundsException if index is negative or larger than the + * length of this string. + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * substring starting with index has fewer than codePointOffset code points. + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * substring ending with index has fewer than (-codePointOffset) code points. + * @since 1.5 + */ + public int offsetByCodePoints(int index, int codePointOffset) + { + if (index < 0 || index > count) + throw new IndexOutOfBoundsException(); + + return Character.offsetByCodePoints(this, index, codePointOffset); + } + + /** + * Returns true if, and only if, {@link #length()} + * is <code>0</code>. + * + * @return true if the length of the string is zero. + * @since 1.6 + */ + public boolean isEmpty() + { + return count == 0; + } + + // Generate a String that shares the value array: subsequent changes + // to this array will affect the String. A private internal method + // that is called from CPStringBuilder by compiler-generated code. + private static String toString(char[] value, int startIndex, int count) + { + return new String(value, startIndex, count, true); + } + + private native void init(char[] chars, int offset, int count, + boolean dont_copy); + private native void init(byte[] chars, int hibyte, int offset, int count); + private native void init(byte[] chars, int offset, int count, String enc) + throws UnsupportedEncodingException; + private native void init(gnu.gcj.runtime.StringBuffer buffer); +} diff --git a/libjava/java/lang/StringBuffer.h b/libjava/java/lang/StringBuffer.h new file mode 100644 index 000000000..487e2fcd3 --- /dev/null +++ b/libjava/java/lang/StringBuffer.h @@ -0,0 +1,115 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StringBuffer__ +#define __java_lang_StringBuffer__ + +#pragma interface + +#include <java/lang/AbstractStringBuffer.h> +#include <gcj/array.h> + + +class java::lang::StringBuffer : public ::java::lang::AbstractStringBuffer +{ + +public: + StringBuffer(); + StringBuffer(jint); + StringBuffer(::java::lang::String *); + StringBuffer(::java::lang::CharSequence *); + jint length(); + jint capacity(); + void ensureCapacity(jint); + void setLength(jint); + jchar charAt(jint); + jint codePointAt(jint); + jint codePointBefore(jint); + void getChars(jint, jint, JArray< jchar > *, jint); + void setCharAt(jint, jchar); + ::java::lang::StringBuffer * StringBuffer$append(::java::lang::Object *); + ::java::lang::StringBuffer * StringBuffer$append(::java::lang::String *); + ::java::lang::StringBuffer * StringBuffer$append(::java::lang::StringBuffer *); + ::java::lang::StringBuffer * StringBuffer$append(JArray< jchar > *); + ::java::lang::StringBuffer * StringBuffer$append(JArray< jchar > *, jint, jint); + ::java::lang::StringBuffer * StringBuffer$append(jboolean); + ::java::lang::StringBuffer * StringBuffer$append(jchar); + ::java::lang::StringBuffer * StringBuffer$append(::java::lang::CharSequence *); + ::java::lang::StringBuffer * StringBuffer$append(::java::lang::CharSequence *, jint, jint); + ::java::lang::StringBuffer * StringBuffer$append(jint); + ::java::lang::StringBuffer * StringBuffer$append(jlong); + ::java::lang::StringBuffer * StringBuffer$append(jfloat); + ::java::lang::StringBuffer * StringBuffer$append(jdouble); + ::java::lang::StringBuffer * StringBuffer$appendCodePoint(jint); + ::java::lang::StringBuffer * StringBuffer$delete(jint, jint); + ::java::lang::StringBuffer * StringBuffer$deleteCharAt(jint); + ::java::lang::StringBuffer * StringBuffer$replace(jint, jint, ::java::lang::String *); + ::java::lang::String * substring(jint); + ::java::lang::CharSequence * subSequence(jint, jint); + ::java::lang::String * substring(jint, jint); + ::java::lang::StringBuffer * StringBuffer$insert(jint, JArray< jchar > *, jint, jint); + ::java::lang::StringBuffer * StringBuffer$insert(jint, ::java::lang::Object *); + ::java::lang::StringBuffer * StringBuffer$insert(jint, ::java::lang::String *); + ::java::lang::StringBuffer * StringBuffer$insert(jint, ::java::lang::CharSequence *); + ::java::lang::StringBuffer * StringBuffer$insert(jint, ::java::lang::CharSequence *, jint, jint); + ::java::lang::StringBuffer * StringBuffer$insert(jint, JArray< jchar > *); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jboolean); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jchar); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jint); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jlong); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jfloat); + ::java::lang::StringBuffer * StringBuffer$insert(jint, jdouble); + jint indexOf(::java::lang::String *); + jint indexOf(::java::lang::String *, jint); + jint lastIndexOf(::java::lang::String *); + jint lastIndexOf(::java::lang::String *, jint); + ::java::lang::StringBuffer * StringBuffer$reverse(); + ::java::lang::String * toString(); + void trimToSize(); + jint codePointCount(jint, jint); + jint offsetByCodePoints(jint, jint); +public: // actually package-private + void ensureCapacity_unsynchronized(jint); +public: + ::java::lang::AbstractStringBuffer * reverse(); + ::java::lang::AbstractStringBuffer * deleteCharAt(jint); + ::java::lang::AbstractStringBuffer * replace(jint, jint, ::java::lang::String *); + ::java::lang::AbstractStringBuffer * delete$(jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, jdouble); + ::java::lang::AbstractStringBuffer * insert(jint, jfloat); + ::java::lang::AbstractStringBuffer * insert(jint, jlong); + ::java::lang::AbstractStringBuffer * insert(jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, jchar); + ::java::lang::AbstractStringBuffer * insert(jint, jboolean); + ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *, jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::String *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::Object *); + ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *, jint, jint); + ::java::lang::AbstractStringBuffer * append(jdouble); + ::java::lang::AbstractStringBuffer * append(jfloat); + ::java::lang::AbstractStringBuffer * append(jlong); + ::java::lang::AbstractStringBuffer * append(jint); + ::java::lang::Appendable * append(::java::lang::CharSequence *, jint, jint); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *, jint, jint); + ::java::lang::Appendable * append(::java::lang::CharSequence *); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *); + ::java::lang::Appendable * append(jchar); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(jchar); + ::java::lang::AbstractStringBuffer * append(jboolean); + ::java::lang::AbstractStringBuffer * append(JArray< jchar > *, jint, jint); + ::java::lang::AbstractStringBuffer * append(JArray< jchar > *); + ::java::lang::AbstractStringBuffer * append(::java::lang::StringBuffer *); + ::java::lang::AbstractStringBuffer * append(::java::lang::String *); + ::java::lang::AbstractStringBuffer * append(::java::lang::Object *); + ::java::lang::AbstractStringBuffer * appendCodePoint(jint); +private: + static const jlong serialVersionUID = 3388685877147921107LL; +public: // actually package-private + jboolean __attribute__((aligned(__alignof__( ::java::lang::AbstractStringBuffer)))) shared; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StringBuffer__ diff --git a/libjava/java/lang/StringBuffer.java b/libjava/java/lang/StringBuffer.java new file mode 100644 index 000000000..0c61b4d9f --- /dev/null +++ b/libjava/java/lang/StringBuffer.java @@ -0,0 +1,976 @@ +/* StringBuffer.java -- Growable strings + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 + 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.Serializable; + +/** + * <code>StringBuffer</code> represents a changeable <code>String</code>. + * It provides the operations required to modify the + * <code>StringBuffer</code>, including insert, replace, delete, append, + * and reverse. It is thread-safe; meaning that all modifications to a buffer + * are in synchronized methods. + * + * <p><code>StringBuffer</code>s are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. <em>Capacity</em> indicates the number of characters the + * <code>StringBuffer</code> can have in it before it has to grow (growing + * the char array is an expensive operation involving <code>new</code>). + * + * <p>Incidentally, compilers often implement the String operator "+" + * by using a <code>StringBuffer</code> operation:<br> + * <code>a + b</code><br> + * is the same as<br> + * <code>new StringBuffer().append(a).append(b).toString()</code>. + * + * <p>Classpath's StringBuffer is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuffer is converted to a String + * and the StringBuffer is not changed after that (quite common when performing + * string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @since 1.0 + * @status updated to 1.4 + */ +public final class StringBuffer + extends AbstractStringBuffer + 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+. + */ + private static final long serialVersionUID = 3388685877147921107L; + + /** + * True if the buffer is shared with another object (StringBuffer or + * String); this means the buffer must be copied before writing to it again. + * Note that this has permissions set this way so that String can get the + * value. + * + * @serial whether the buffer is shared + */ + boolean shared; + + /** + * Create a new StringBuffer with default capacity 16. + */ + public StringBuffer() + { + super(); + } + + /** + * Create an empty <code>StringBuffer</code> with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuffer(int capacity) + { + super(capacity); + } + + /** + * Create a new <code>StringBuffer</code> with the characters in the + * specified <code>String</code>. Initial capacity will be the size of the + * String plus 16. + * + * @param str the <code>String</code> to convert + * @throws NullPointerException if str is null + */ + public StringBuffer(String str) + { + // Unfortunately, because the size is 16 larger, we cannot share. + super(str); + } + + /** + * Create a new <code>StringBuffer</code> with the characters in the + * specified <code>CharSequence</code>. Initial capacity will be the + * 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 seq the initializing <code>CharSequence</code> + * @throws NullPointerException if str is null + * @since 1.5 + */ + public StringBuffer(CharSequence seq) + { + super(seq); + } + + /** + * Get the length of the <code>String</code> this <code>StringBuffer</code> + * would create. Not to be confused with the <em>capacity</em> of the + * <code>StringBuffer</code>. + * + * @return the length of this <code>StringBuffer</code> + * @see #capacity() + * @see #setLength(int) + */ + public synchronized int length() + { + return count; + } + + /** + * Get the total number of characters this <code>StringBuffer</code> can + * support before it must be grown. Not to be confused with <em>length</em>. + * + * @return the capacity of this <code>StringBuffer</code> + * @see #length() + * @see #ensureCapacity(int) + */ + public synchronized int capacity() + { + return value.length; + } + + /** + * Increase the capacity of this <code>StringBuffer</code>. This will + * ensure that an expensive growing operation will not occur until + * <code>minimumCapacity</code> is reached. The buffer is grown to the + * larger of <code>minimumCapacity</code> and + * <code>capacity() * 2 + 2</code>, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public synchronized void ensureCapacity(int minimumCapacity) + { + ensureCapacity_unsynchronized(minimumCapacity); + } + + /** + * Set the length of this StringBuffer. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first <code>newLength</code> + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public synchronized void setLength(int newLength) + { + super.setLength(newLength); + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public synchronized char charAt(int index) + { + return super.charAt(index); + } + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointAt(int index) + { + return super.codePointAt(index); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at <code>index-1</code> and + * <code>index-2</code> to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointBefore(int index) + { + return super.codePointBefore(index); + } + + /** + * Get the specified array of characters. <code>srcOffset - srcEnd</code> + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public synchronized void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + super.getChars(srcOffset, srcEnd, dst, dstOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public synchronized void setCharAt(int index, char ch) + { + super.setCharAt(index, ch); + } + + /** + * 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>. + * + * @param obj the <code>Object</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(Object) + * @see #append(String) + */ + public synchronized StringBuffer append(Object obj) + { + super.append(obj); + return this; + } + + /** + * Append the <code>String</code> to this <code>StringBuffer</code>. If + * str is null, the String "null" is appended. + * + * @param str the <code>String</code> to append + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer append(String str) + { + super.append(str); + return this; + } + + /** + * Append the <code>StringBuffer</code> value of the argument to this + * <code>StringBuffer</code>. This behaves the same as + * <code>append((Object) stringBuffer)</code>, except it is more efficient. + * + * @param stringBuffer the <code>StringBuffer</code> to convert and append + * @return this <code>StringBuffer</code> + * @see #append(Object) + * @since 1.4 + */ + public synchronized StringBuffer append(StringBuffer stringBuffer) + { + super.append(stringBuffer); + 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. + * + * @param data the <code>char[]</code> to append + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @see #append(char[], int, int) + */ + public synchronized StringBuffer append(char[] data) + { + super.append(data, 0, data.length); + return this; + } + + /** + * Append part of the <code>char</code> array to this + * <code>StringBuffer</code>. This is similar (but more efficient) than + * <code>append(new String(data, offset, count))</code>, except in the case + * of null. + * + * @param data the <code>char[]</code> to append + * @param offset the start location in <code>str</code> + * @param count the number of characters to get from <code>str</code> + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public synchronized StringBuffer append(char[] data, int offset, int count) + { + super.append(data, offset, count); + 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>. + * + * @param bool the <code>boolean</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(boolean) + */ + public synchronized StringBuffer append(boolean bool) + { + super.append(bool); + return this; + } + + /** + * Append the <code>char</code> to this <code>StringBuffer</code>. + * + * @param ch the <code>char</code> to append + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer append(char ch) + { + super.append(ch); + return this; + } + + /** + * Append the characters in the <code>CharSequence</code> to this + * buffer. + * + * @param seq the <code>CharSequence</code> providing the characters + * @return this <code>StringBuffer</code> + * @since 1.5 + */ + public synchronized StringBuffer append(CharSequence seq) + { + super.append(seq, 0, seq.length()); + return this; + } + + /** + * 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) + { + super.append(seq, start, end); + 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>. + * + * @param inum the <code>int</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(int) + */ + // This is native in libgcj, for efficiency. + public synchronized StringBuffer append(int inum) + { + super.append(inum); + 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>. + * + * @param lnum the <code>long</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(long) + */ + public synchronized StringBuffer append(long lnum) + { + super.append(lnum); + 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>. + * + * @param fnum the <code>float</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(float) + */ + public synchronized StringBuffer append(float fnum) + { + super.append(fnum); + 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>. + * + * @param dnum the <code>double</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(double) + */ + public synchronized StringBuffer append(double dnum) + { + super.append(dnum); + return this; + } + + /** + * 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) + { + super.appendCodePoint(code); + return this; + } + + /** + * Delete characters from this <code>StringBuffer</code>. + * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @since 1.2 + */ + public synchronized StringBuffer delete(int start, int end) + { + // This will unshare if required. + super.delete(start, end); + return this; + } + + /** + * Delete a character from this <code>StringBuffer</code>. + * + * @param index the index of the character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if index is out of bounds + * @since 1.2 + */ + public synchronized StringBuffer deleteCharAt(int index) + { + super.deleteCharAt(index); + return this; + } + + /** + * Replace characters between index <code>start</code> (inclusive) and + * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> + * is larger than the size of this StringBuffer, all characters after + * <code>start</code> are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + * @since 1.2 + */ + public synchronized StringBuffer replace(int start, int end, String str) + { + super.replace(start, end, str); + return this; + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at the end of this StringBuffer. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + * @since 1.2 + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as <code>substring(beginIndex, endIndex)</code>, to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuffer + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + * @since 1.4 + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + * @since 1.2 + */ + public synchronized String substring(int beginIndex, int endIndex) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + // Don't copy unless substring is smaller than 1/4 of the buffer. + boolean share_buffer = ((len << 2) >= value.length); + if (share_buffer) + this.shared = true; + // Package constructor avoids an array copy. + return new String(value, beginIndex, len, share_buffer); + } + + /** + * Insert a subarray of the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param str the <code>char[]</code> to insert + * @param str_offset the index in <code>str</code> to start inserting from + * @param len the number of characters to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if any index is out of bounds + * @since 1.2 + */ + public synchronized StringBuffer insert(int offset, + char[] str, int str_offset, int len) + { + super.insert(offset, str, str_offset, len); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param obj the <code>Object</code> to convert and insert + * @return this <code>StringBuffer</code> + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public synchronized StringBuffer insert(int offset, Object obj) + { + super.insert(offset, obj); + return this; + } + + /** + * Insert the <code>String</code> argument into this + * <code>StringBuffer</code>. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public synchronized StringBuffer insert(int offset, String str) + { + super.insert(offset, str); + return this; + } + + /** + * Insert the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset is out of bounds + * @since 1.5 + */ + public synchronized StringBuffer insert(int offset, CharSequence sequence) + { + super.insert(offset, sequence); + return this; + } + + /** + * Insert a subsequence of the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + * @since 1.5 + */ + public synchronized StringBuffer insert(int offset, CharSequence sequence, + int start, int end) + { + super.insert(offset, sequence, start, end); + return this; + } + + /** + * Insert the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param data the <code>char[]</code> to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>data</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public synchronized StringBuffer insert(int offset, char[] data) + { + super.insert(offset, data, 0, data.length); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param bool the <code>boolean</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public synchronized StringBuffer insert(int offset, boolean bool) + { + super.insert(offset, bool); + return this; + } + + /** + * Insert the <code>char</code> argument into this <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param ch the <code>char</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public synchronized StringBuffer insert(int offset, char ch) + { + super.insert(offset, ch); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param inum the <code>int</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public synchronized StringBuffer insert(int offset, int inum) + { + super.insert(offset, inum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param lnum the <code>long</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public synchronized StringBuffer insert(int offset, long lnum) + { + super.insert(offset, lnum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param fnum the <code>float</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public synchronized StringBuffer insert(int offset, float fnum) + { + super.insert(offset, fnum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param dnum the <code>double</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public synchronized StringBuffer insert(int offset, double dnum) + { + super.insert(offset, dnum); + return this; + } + + /** + * Finds the first instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + * @since 1.4 + */ + public synchronized int indexOf(String str) + { + return super.indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuffer, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public synchronized int indexOf(String str, int fromIndex) + { + return super.indexOf(str, fromIndex); + } + + /** + * Finds the last instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + * @since 1.4 + */ + public synchronized int lastIndexOf(String str) + { + return super.lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this StringBuffer, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public synchronized int lastIndexOf(String str, int fromIndex) + { + return super.lastIndexOf(str, fromIndex); + } + + /** + * Reverse the characters in this StringBuffer. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer reverse() + { + super.reverse(); + return this; + } + + /** + * Convert this <code>StringBuffer</code> to a <code>String</code>. The + * String is composed of the characters currently in this StringBuffer. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuffer + */ + public String toString() + { + // The string will set this.shared = true. + return new String(this); + } + + /** + * This may reduce the amount of memory used by the StringBuffer, + * by resizing the internal array to remove unused space. However, + * this method is not required to resize, so this behavior cannot + * be relied upon. + * @since 1.5 + */ + public synchronized void trimToSize() + { + super.trimToSize(); + } + + /** + * Return the number of code points between two indices in the + * <code>StringBuffer</code>. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public synchronized int codePointCount(int start, int end) + { + return super.codePointCount(start, end); + } + + /** + * Starting at the given index, this counts forward by the indicated + * number of code points, and then returns the resulting index. An + * unpaired surrogate counts as a single code point for this + * purpose. + * + * @param start the starting index + * @param codePoints the number of code points + * @return the resulting index + * @since 1.5 + */ + public synchronized int offsetByCodePoints(int start, int codePoints) + { + return super.offsetByCodePoints(start, codePoints); + } + + /** + * An unsynchronized version of ensureCapacity, used internally to avoid + * the cost of a second lock on the same object. This also has the side + * effect of duplicating the array, if it was shared (to form copy-on-write + * semantics). + * + * @param minimumCapacity the minimum capacity + * @see #ensureCapacity(int) + */ + void ensureCapacity_unsynchronized(int minimumCapacity) + { + if (shared || minimumCapacity > value.length) + { + // We don't want to make a larger vector when `shared' is + // set. If we do, then setLength becomes very inefficient + // when repeatedly reusing a StringBuffer in a loop. + int max = (minimumCapacity > value.length + ? value.length * 2 + 2 + : value.length); + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + shared = false; + } + } + +} diff --git a/libjava/java/lang/StringBuilder.h b/libjava/java/lang/StringBuilder.h new file mode 100644 index 000000000..c8b952a41 --- /dev/null +++ b/libjava/java/lang/StringBuilder.h @@ -0,0 +1,96 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StringBuilder__ +#define __java_lang_StringBuilder__ + +#pragma interface + +#include <java/lang/AbstractStringBuffer.h> +#include <gcj/array.h> + + +class java::lang::StringBuilder : public ::java::lang::AbstractStringBuffer +{ + +public: + StringBuilder(); + StringBuilder(jint); + StringBuilder(::java::lang::String *); + StringBuilder(::java::lang::CharSequence *); + jint length(); + jint capacity(); + ::java::lang::StringBuilder * StringBuilder$append(::java::lang::Object *); + ::java::lang::StringBuilder * StringBuilder$append(::java::lang::String *); + ::java::lang::StringBuilder * StringBuilder$append(::java::lang::StringBuffer *); + ::java::lang::StringBuilder * StringBuilder$append(JArray< jchar > *); + ::java::lang::StringBuilder * StringBuilder$append(JArray< jchar > *, jint, jint); + ::java::lang::StringBuilder * StringBuilder$append(jboolean); + ::java::lang::StringBuilder * StringBuilder$append(jchar); + ::java::lang::StringBuilder * StringBuilder$append(::java::lang::CharSequence *); + ::java::lang::StringBuilder * StringBuilder$append(::java::lang::CharSequence *, jint, jint); + ::java::lang::StringBuilder * StringBuilder$append(jint); + ::java::lang::StringBuilder * StringBuilder$append(jlong); + ::java::lang::StringBuilder * StringBuilder$append(jfloat); + ::java::lang::StringBuilder * StringBuilder$append(jdouble); + ::java::lang::StringBuilder * StringBuilder$appendCodePoint(jint); + ::java::lang::StringBuilder * StringBuilder$delete(jint, jint); + ::java::lang::StringBuilder * StringBuilder$deleteCharAt(jint); + ::java::lang::StringBuilder * StringBuilder$replace(jint, jint, ::java::lang::String *); + ::java::lang::String * substring(jint); + ::java::lang::CharSequence * subSequence(jint, jint); + ::java::lang::String * substring(jint, jint); + ::java::lang::StringBuilder * StringBuilder$insert(jint, JArray< jchar > *, jint, jint); + ::java::lang::StringBuilder * StringBuilder$insert(jint, ::java::lang::Object *); + ::java::lang::StringBuilder * StringBuilder$insert(jint, ::java::lang::String *); + ::java::lang::StringBuilder * StringBuilder$insert(jint, ::java::lang::CharSequence *); + ::java::lang::StringBuilder * StringBuilder$insert(jint, ::java::lang::CharSequence *, jint, jint); + ::java::lang::StringBuilder * StringBuilder$insert(jint, JArray< jchar > *); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jboolean); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jchar); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jint); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jlong); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jfloat); + ::java::lang::StringBuilder * StringBuilder$insert(jint, jdouble); + ::java::lang::StringBuilder * StringBuilder$reverse(); + ::java::lang::String * toString(); + ::java::lang::AbstractStringBuffer * reverse(); + ::java::lang::AbstractStringBuffer * deleteCharAt(jint); + ::java::lang::AbstractStringBuffer * replace(jint, jint, ::java::lang::String *); + ::java::lang::AbstractStringBuffer * delete$(jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, jdouble); + ::java::lang::AbstractStringBuffer * insert(jint, jfloat); + ::java::lang::AbstractStringBuffer * insert(jint, jlong); + ::java::lang::AbstractStringBuffer * insert(jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, jchar); + ::java::lang::AbstractStringBuffer * insert(jint, jboolean); + ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *, jint, jint); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::CharSequence *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::String *); + ::java::lang::AbstractStringBuffer * insert(jint, ::java::lang::Object *); + ::java::lang::AbstractStringBuffer * insert(jint, JArray< jchar > *, jint, jint); + ::java::lang::AbstractStringBuffer * append(jdouble); + ::java::lang::AbstractStringBuffer * append(jfloat); + ::java::lang::AbstractStringBuffer * append(jlong); + ::java::lang::AbstractStringBuffer * append(jint); + ::java::lang::Appendable * append(::java::lang::CharSequence *, jint, jint); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *, jint, jint); + ::java::lang::Appendable * append(::java::lang::CharSequence *); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(::java::lang::CharSequence *); + ::java::lang::Appendable * append(jchar); + ::java::lang::AbstractStringBuffer * AbstractStringBuffer$append(jchar); + ::java::lang::AbstractStringBuffer * append(jboolean); + ::java::lang::AbstractStringBuffer * append(JArray< jchar > *, jint, jint); + ::java::lang::AbstractStringBuffer * append(JArray< jchar > *); + ::java::lang::AbstractStringBuffer * append(::java::lang::StringBuffer *); + ::java::lang::AbstractStringBuffer * append(::java::lang::String *); + ::java::lang::AbstractStringBuffer * append(::java::lang::Object *); + ::java::lang::AbstractStringBuffer * appendCodePoint(jint); +private: + static const jlong serialVersionUID = 4383685877147921099LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StringBuilder__ diff --git a/libjava/java/lang/StringBuilder.java b/libjava/java/lang/StringBuilder.java new file mode 100644 index 000000000..aefe9272b --- /dev/null +++ b/libjava/java/lang/StringBuilder.java @@ -0,0 +1,706 @@ +/* StringBuilder.java -- Unsynchronized growable strings + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 + 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.Serializable; + +/** + * <code>StringBuilder</code> represents a changeable <code>String</code>. + * It provides the operations required to modify the + * <code>StringBuilder</code>, including insert, replace, delete, append, + * and reverse. It like <code>StringBuffer</code>, but is not + * synchronized. It is ideal for use when it is known that the + * object will only be used from a single thread. + * + * <p><code>StringBuilder</code>s are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. <em>Capacity</em> indicates the number of characters the + * <code>StringBuilder</code> can have in it before it has to grow (growing + * the char array is an expensive operation involving <code>new</code>). + * + * <p>Incidentally, compilers often implement the String operator "+" + * by using a <code>StringBuilder</code> operation:<br> + * <code>a + b</code><br> + * is the same as<br> + * <code>new StringBuilder().append(a).append(b).toString()</code>. + * + * <p>Classpath's StringBuilder is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuilder is converted to a String + * and the StringBuilder is not changed after that (quite common when + * performing string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @see StringBuffer + * + * @since 1.5 + */ +public final class StringBuilder + extends AbstractStringBuffer + implements Serializable, CharSequence, Appendable +{ + // Implementation note: if you change this class, you usually will + // want to change StringBuffer as well. + + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 4383685877147921099L; + + /** + * Create a new StringBuilder with default capacity 16. + */ + public StringBuilder() + { + super(); + } + + /** + * Create an empty <code>StringBuilder</code> with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuilder(int capacity) + { + super(capacity); + } + + /** + * Create a new <code>StringBuilder</code> with the characters in the + * specified <code>String</code>. Initial capacity will be the size of the + * String plus 16. + * + * @param str the <code>String</code> to convert + * @throws NullPointerException if str is null + */ + public StringBuilder(String str) + { + super(str); + } + + /** + * Create a new <code>StringBuilder</code> with the characters in the + * specified <code>CharSequence</code>. Initial capacity will be the + * 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 seq the initializing <code>CharSequence</code> + * @throws NullPointerException if str is null + */ + public StringBuilder(CharSequence seq) + { + super(seq); + } + + /** + * Get the length of the <code>String</code> this <code>StringBuilder</code> + * would create. Not to be confused with the <em>capacity</em> of the + * <code>StringBuilder</code>. + * + * @return the length of this <code>StringBuilder</code> + * @see #capacity() + * @see #setLength(int) + */ + public int length() + { + return count; + } + + /** + * Get the total number of characters this <code>StringBuilder</code> can + * support before it must be grown. Not to be confused with <em>length</em>. + * + * @return the capacity of this <code>StringBuilder</code> + * @see #length() + * @see #ensureCapacity(int) + */ + public int capacity() + { + return value.length; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param obj the <code>Object</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(Object) + * @see #append(String) + */ + public StringBuilder append(Object obj) + { + super.append(obj); + return this; + } + + /** + * Append the <code>String</code> to this <code>StringBuilder</code>. If + * str is null, the String "null" is appended. + * + * @param str the <code>String</code> to append + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(String str) + { + super.append(str); + return this; + } + + /** + * Append the <code>StringBuilder</code> value of the argument to this + * <code>StringBuilder</code>. This behaves the same as + * <code>append((Object) stringBuffer)</code>, except it is more efficient. + * + * @param stringBuffer the <code>StringBuilder</code> to convert and append + * @return this <code>StringBuilder</code> + * @see #append(Object) + */ + public StringBuilder append(StringBuffer stringBuffer) + { + super.append(stringBuffer); + return this; + } + + /** + * Append the <code>char</code> array to this <code>StringBuilder</code>. + * This is similar (but more efficient) than + * <code>append(new String(data))</code>, except in the case of null. + * + * @param data the <code>char[]</code> to append + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @see #append(char[], int, int) + */ + public StringBuilder append(char[] data) + { + super.append(data, 0, data.length); + return this; + } + + /** + * Append part of the <code>char</code> array to this + * <code>StringBuilder</code>. This is similar (but more efficient) than + * <code>append(new String(data, offset, count))</code>, except in the case + * of null. + * + * @param data the <code>char[]</code> to append + * @param offset the start location in <code>str</code> + * @param count the number of characters to get from <code>str</code> + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public StringBuilder append(char[] data, int offset, int count) + { + super.append(data, offset, count); + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param bool the <code>boolean</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(boolean) + */ + public StringBuilder append(boolean bool) + { + super.append(bool); + return this; + } + + /** + * Append the <code>char</code> to this <code>StringBuilder</code>. + * + * @param ch the <code>char</code> to append + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(char ch) + { + super.append(ch); + return this; + } + + /** + * Append the characters in the <code>CharSequence</code> to this + * buffer. + * + * @param seq the <code>CharSequence</code> providing the characters + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(CharSequence seq) + { + super.append(seq, 0, seq.length()); + return this; + } + + /** + * 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>StringBuilder</code> + */ + public StringBuilder append(CharSequence seq, int start, + int end) + { + super.append(seq, start, end); + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param inum the <code>int</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(int) + */ + // This is native in libgcj, for efficiency. + public StringBuilder append(int inum) + { + super.append(inum); + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param lnum the <code>long</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(long) + */ + public StringBuilder append(long lnum) + { + super.append(lnum); + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param fnum the <code>float</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(float) + */ + public StringBuilder append(float fnum) + { + super.append(fnum); + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param dnum the <code>double</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(double) + */ + public StringBuilder append(double dnum) + { + super.append(dnum); + return this; + } + + /** + * Append the code point to this <code>StringBuilder</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>StringBuilder</code> + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public StringBuilder appendCodePoint(int code) + { + super.appendCodePoint(code); + return this; + } + + /** + * Delete characters from this <code>StringBuilder</code>. + * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + */ + public StringBuilder delete(int start, int end) + { + super.delete(start, end); + return this; + } + + /** + * Delete a character from this <code>StringBuilder</code>. + * + * @param index the index of the character to delete + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if index is out of bounds + */ + public StringBuilder deleteCharAt(int index) + { + super.deleteCharAt(index); + return this; + } + + /** + * Replace characters between index <code>start</code> (inclusive) and + * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> + * is larger than the size of this StringBuilder, all characters after + * <code>start</code> are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new <code>String</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + */ + public StringBuilder replace(int start, int end, String str) + { + super.replace(start, end, str); + return this; + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at the end of this StringBuilder. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as <code>substring(beginIndex, endIndex)</code>, to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + */ + public String substring(int beginIndex, int endIndex) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + return new String(value, beginIndex, len); + } + + /** + * Insert a subarray of the <code>char[]</code> argument into this + * <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param str the <code>char[]</code> to insert + * @param str_offset the index in <code>str</code> to start inserting from + * @param len the number of characters to insert + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if any index is out of bounds + */ + public StringBuilder insert(int offset, + char[] str, int str_offset, int len) + { + super.insert(offset, str, str_offset, len); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param obj the <code>Object</code> to convert and insert + * @return this <code>StringBuilder</code> + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public StringBuilder insert(int offset, Object obj) + { + super.insert(offset, obj); + return this; + } + + /** + * Insert the <code>String</code> argument into this + * <code>StringBuilder</code>. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the <code>String</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, String str) + { + super.insert(offset, str); + return this; + } + + /** + * Insert the <code>CharSequence</code> argument into this + * <code>StringBuilder</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @return this <code>StringBuilder</code> + * @throws IndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, CharSequence sequence) + { + super.insert(offset, sequence); + return this; + } + + /** + * Insert a subsequence of the <code>CharSequence</code> argument into this + * <code>StringBuilder</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this <code>StringBuilder</code> + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + */ + public StringBuilder insert(int offset, CharSequence sequence, + int start, int end) + { + super.insert(offset, sequence, start, end); + return this; + } + + /** + * Insert the <code>char[]</code> argument into this + * <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param data the <code>char[]</code> to insert + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>data</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public StringBuilder insert(int offset, char[] data) + { + super.insert(offset, data); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param bool the <code>boolean</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public StringBuilder insert(int offset, boolean bool) + { + super.insert(offset, bool); + return this; + } + + /** + * Insert the <code>char</code> argument into this <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param ch the <code>char</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, char ch) + { + super.insert(offset, ch); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param inum the <code>int</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public StringBuilder insert(int offset, int inum) + { + super.insert(offset, inum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param lnum the <code>long</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public StringBuilder insert(int offset, long lnum) + { + super.insert(offset, lnum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param fnum the <code>float</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public StringBuilder insert(int offset, float fnum) + { + super.insert(offset, fnum); + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param dnum the <code>double</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public StringBuilder insert(int offset, double dnum) + { + super.insert(offset, dnum); + return this; + } + + /** + * Reverse the characters in this StringBuilder. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this <code>StringBuilder</code> + */ + public StringBuilder reverse() + { + super.reverse(); + return this; + } + + /** + * Convert this <code>StringBuilder</code> to a <code>String</code>. The + * String is composed of the characters currently in this StringBuilder. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuilder + */ + public String toString() + { + return new String(this); + } + +} diff --git a/libjava/java/lang/StringIndexOutOfBoundsException.h b/libjava/java/lang/StringIndexOutOfBoundsException.h new file mode 100644 index 000000000..e3669a0d3 --- /dev/null +++ b/libjava/java/lang/StringIndexOutOfBoundsException.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_StringIndexOutOfBoundsException__ +#define __java_lang_StringIndexOutOfBoundsException__ + +#pragma interface + +#include <java/lang/IndexOutOfBoundsException.h> + +class java::lang::StringIndexOutOfBoundsException : public ::java::lang::IndexOutOfBoundsException +{ + +public: + StringIndexOutOfBoundsException(); + StringIndexOutOfBoundsException(::java::lang::String *); + StringIndexOutOfBoundsException(jint); +private: + static const jlong serialVersionUID = -6762910422159637258LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_StringIndexOutOfBoundsException__ diff --git a/libjava/java/lang/SuppressWarnings.h b/libjava/java/lang/SuppressWarnings.h new file mode 100644 index 000000000..3f28104d9 --- /dev/null +++ b/libjava/java/lang/SuppressWarnings.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_SuppressWarnings__ +#define __java_lang_SuppressWarnings__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::SuppressWarnings : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::String * > * value() = 0; + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_SuppressWarnings__ diff --git a/libjava/java/lang/System$EnvironmentCollection.h b/libjava/java/lang/System$EnvironmentCollection.h new file mode 100644 index 000000000..8392e1782 --- /dev/null +++ b/libjava/java/lang/System$EnvironmentCollection.h @@ -0,0 +1,29 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_System$EnvironmentCollection__ +#define __java_lang_System$EnvironmentCollection__ + +#pragma interface + +#include <java/util/AbstractCollection.h> + +class java::lang::System$EnvironmentCollection : public ::java::util::AbstractCollection +{ + +public: + System$EnvironmentCollection(::java::util::Collection *); + virtual jboolean contains(::java::lang::Object *); + virtual jboolean containsAll(::java::util::Collection *); + virtual ::java::util::Iterator * iterator(); + virtual jboolean remove(::java::lang::Object *); + virtual jboolean removeAll(::java::util::Collection *); + virtual jboolean retainAll(::java::util::Collection *); + virtual jint size(); +public: // actually protected + ::java::util::Collection * __attribute__((aligned(__alignof__( ::java::util::AbstractCollection)))) c; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_System$EnvironmentCollection__ diff --git a/libjava/java/lang/System$EnvironmentMap.h b/libjava/java/lang/System$EnvironmentMap.h new file mode 100644 index 000000000..c8ef8aade --- /dev/null +++ b/libjava/java/lang/System$EnvironmentMap.h @@ -0,0 +1,37 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_System$EnvironmentMap__ +#define __java_lang_System$EnvironmentMap__ + +#pragma interface + +#include <java/util/HashMap.h> + +class java::lang::System$EnvironmentMap : public ::java::util::HashMap +{ + +public: // actually package-private + System$EnvironmentMap(); + System$EnvironmentMap(::java::util::Map *); +public: + virtual jboolean containsKey(::java::lang::Object *); + virtual jboolean containsValue(::java::lang::Object *); + virtual ::java::util::Set * entrySet(); + virtual ::java::lang::String * System$EnvironmentMap$get(::java::lang::Object *); + virtual ::java::util::Set * keySet(); + virtual ::java::lang::String * System$EnvironmentMap$put(::java::lang::String *, ::java::lang::String *); + virtual ::java::lang::String * System$EnvironmentMap$remove(::java::lang::Object *); + virtual ::java::util::Collection * values(); + virtual ::java::lang::Object * get(::java::lang::Object *); + virtual ::java::lang::Object * remove(::java::lang::Object *); + virtual ::java::lang::Object * put(::java::lang::Object *, ::java::lang::Object *); +private: + ::java::util::Set * __attribute__((aligned(__alignof__( ::java::util::HashMap)))) entries; + ::java::util::Set * keys; + ::java::util::Collection * values__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_System$EnvironmentMap__ diff --git a/libjava/java/lang/System$EnvironmentSet.h b/libjava/java/lang/System$EnvironmentSet.h new file mode 100644 index 000000000..9a1e1a65d --- /dev/null +++ b/libjava/java/lang/System$EnvironmentSet.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_System$EnvironmentSet__ +#define __java_lang_System$EnvironmentSet__ + +#pragma interface + +#include <java/lang/System$EnvironmentCollection.h> + +class java::lang::System$EnvironmentSet : public ::java::lang::System$EnvironmentCollection +{ + +public: + System$EnvironmentSet(::java::util::Set *); + virtual jboolean equals(::java::lang::Object *); + virtual jint hashCode(); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_System$EnvironmentSet__ diff --git a/libjava/java/lang/System.h b/libjava/java/lang/System.h new file mode 100644 index 000000000..8a67628b0 --- /dev/null +++ b/libjava/java/lang/System.h @@ -0,0 +1,70 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_System__ +#define __java_lang_System__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace java + { + namespace nio + { + namespace channels + { + class Channel; + } + } + } +} + +class java::lang::System : public ::java::lang::Object +{ + + System(); +public: + static void setIn(::java::io::InputStream *); + static void setOut(::java::io::PrintStream *); + static void setErr(::java::io::PrintStream *); + static void setSecurityManager(::java::lang::SecurityManager *); + static ::java::lang::SecurityManager * getSecurityManager(); + static jlong currentTimeMillis(); + static jlong nanoTime(); + static void arraycopy(::java::lang::Object *, jint, ::java::lang::Object *, jint, jint); + static jint identityHashCode(::java::lang::Object *); + static ::java::util::Properties * getProperties(); + static void setProperties(::java::util::Properties *); + static ::java::lang::String * getProperty(::java::lang::String *); + static ::java::lang::String * getProperty(::java::lang::String *, ::java::lang::String *); + static ::java::lang::String * setProperty(::java::lang::String *, ::java::lang::String *); + static ::java::lang::String * clearProperty(::java::lang::String *); + static ::java::lang::String * getenv(::java::lang::String *); + static ::java::util::Map * getenv(); + static void exit(jint); + static void gc(); + static void runFinalization(); + static void runFinalizersOnExit(jboolean); + static void load(::java::lang::String *); + static void loadLibrary(::java::lang::String *); + static ::java::lang::String * mapLibraryName(::java::lang::String *); +private: + static void setIn0(::java::io::InputStream *); + static void setOut0(::java::io::PrintStream *); + static void setErr0(::java::io::PrintStream *); +public: // actually package-private + static ::java::lang::String * getenv0(::java::lang::String *); +public: + static ::java::nio::channels::Channel * inheritedChannel(); + static ::java::io::InputStream * in; + static ::java::io::PrintStream * out; + static ::java::io::PrintStream * err; +private: + static ::java::util::Map * environmentMap; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_System__ diff --git a/libjava/java/lang/System.java b/libjava/java/lang/System.java new file mode 100644 index 000000000..ecfad2557 --- /dev/null +++ b/libjava/java/lang/System.java @@ -0,0 +1,1089 @@ +/* System.java -- useful methods to interface with the system + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 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 gnu.classpath.SystemProperties; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.channels.Channel; +import java.nio.channels.spi.SelectorProvider; +import java.util.AbstractCollection; +import java.util.ArrayList; +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; + +/** + * System represents system-wide resources; things that represent the + * general environment. As such, all methods are static. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 functionality + */ +public final class System +{ + // WARNING: System is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * The standard InputStream. This is assigned at startup and starts its + * life perfectly valid. Although it is marked final, you can change it + * using {@link #setIn(InputStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stdin and C++ cin variables, which + * typically input from the keyboard, but may be used to pipe input from + * other processes or files. That should all be transparent to you, + * however. + */ + public static final InputStream in + = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setOut(PrintStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stdout and C++ cout variables, which + * typically output normal messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream out + = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), true); + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setErr(PrintStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stderr and C++ cerr variables, which + * typically output error messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream err + = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err)), true); + + /** + * A cached copy of the environment variable map. + */ + private static Map<String,String> environmentMap; + + /** + * This class is uninstantiable. + */ + private System() + { + } + + /** + * Set {@link #in} to a new InputStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param in the new InputStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setIn(InputStream in) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + setIn0(in); + } + + /** + * Set {@link #out} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param out the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setOut(PrintStream out) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + + setOut0(out); + } + + /** + * Set {@link #err} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param err the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setErr(PrintStream err) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + setErr0(err); + } + + /** + * Set the current SecurityManager. If a security manager already exists, + * then <code>RuntimePermission("setSecurityManager")</code> is checked + * first. Since this permission is denied by the default security manager, + * setting the security manager is often an irreversible action. + * + * @param sm the new SecurityManager + * @throws SecurityException if permission is denied + */ + public static synchronized void setSecurityManager(SecurityManager sm) + { + // Implementation note: the field lives in SecurityManager because of + // bootstrap initialization issues. This method is synchronized so that + // no other thread changes it to null before this thread makes the change. + if (SecurityManager.current != null) + SecurityManager.current.checkPermission + (new RuntimePermission("setSecurityManager")); + SecurityManager.current = sm; + } + + /** + * Get the current SecurityManager. If the SecurityManager has not been + * set yet, then this method returns null. + * + * @return the current SecurityManager, or null + */ + public static SecurityManager getSecurityManager() + { + return SecurityManager.current; + } + + /** + * Get the current time, measured in the number of milliseconds from the + * beginning of Jan. 1, 1970. This is gathered from the system clock, with + * any attendant incorrectness (it may be timezone dependent). + * + * @return the current time + * @see java.util.Date + */ + public static native long currentTimeMillis(); + + /** + * Get the current time, measured in nanoseconds. The result is as + * precise as possible, and is measured against a fixed epoch. + * However, unlike currentTimeMillis(), the epoch chosen is + * arbitrary and may vary by platform, etc. + * @since 1.5 + */ + public static native long 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: + * neither array may be null, they must be of compatible types, and the + * start and length must fit within both arrays. Then the copying starts, + * and proceeds through increasing slots. If src and dest are the same + * array, this will appear to copy the data to a temporary location first. + * An ArrayStoreException in the middle of copying will leave earlier + * elements copied, but later elements unchanged. + * + * @param src the array to copy elements from + * @param srcStart the starting position in src + * @param dest the array to copy elements to + * @param destStart the starting position in dest + * @param len the number of elements to copy + * @throws NullPointerException if src or dest is null + * @throws ArrayStoreException if src or dest is not an array, if they are + * not compatible array types, or if an incompatible runtime type + * is stored in dest + * @throws IndexOutOfBoundsException if len is negative, or if the start or + * end copy position in either array is out of bounds + */ + public static native void arraycopy(Object src, int srcStart, + Object dest, int destStart, int len); + + /** + * Get a hash code computed by the VM for the Object. This hash code will + * be the same as Object's hashCode() method. It is usually some + * convolution of the pointer to the Object internal to the VM. It + * follows standard hash code rules, in that it will remain the same for a + * given Object for the lifetime of that Object. + * + * @param o the Object to get the hash code for + * @return the VM-dependent hash code for this Object + * @since 1.1 + */ + public static native int identityHashCode(Object o); + + /** + * Get all the system properties at once. A security check may be performed, + * <code>checkPropertiesAccess</code>. Note that a security manager may + * allow getting a single property, but not the entire group. + * + * <p>The required properties include: + * <dl> + * <dt>java.version</dt> <dd>Java version number</dd> + * <dt>java.vendor</dt> <dd>Java vendor specific string</dd> + * <dt>java.vendor.url</dt> <dd>Java vendor URL</dd> + * <dt>java.home</dt> <dd>Java installation directory</dd> + * <dt>java.vm.specification.version</dt> <dd>VM Spec version</dd> + * <dt>java.vm.specification.vendor</dt> <dd>VM Spec vendor</dd> + * <dt>java.vm.specification.name</dt> <dd>VM Spec name</dd> + * <dt>java.vm.version</dt> <dd>VM implementation version</dd> + * <dt>java.vm.vendor</dt> <dd>VM implementation vendor</dd> + * <dt>java.vm.name</dt> <dd>VM implementation name</dd> + * <dt>java.specification.version</dt> <dd>Java Runtime Environment version</dd> + * <dt>java.specification.vendor</dt> <dd>Java Runtime Environment vendor</dd> + * <dt>java.specification.name</dt> <dd>Java Runtime Environment name</dd> + * <dt>java.class.version</dt> <dd>Java class version number</dd> + * <dt>java.class.path</dt> <dd>Java classpath</dd> + * <dt>java.library.path</dt> <dd>Path for finding Java libraries</dd> + * <dt>java.io.tmpdir</dt> <dd>Default temp file path</dd> + * <dt>java.compiler</dt> <dd>Name of JIT to use</dd> + * <dt>java.ext.dirs</dt> <dd>Java extension path</dd> + * <dt>os.name</dt> <dd>Operating System Name</dd> + * <dt>os.arch</dt> <dd>Operating System Architecture</dd> + * <dt>os.version</dt> <dd>Operating System Version</dd> + * <dt>file.separator</dt> <dd>File separator ("/" on Unix)</dd> + * <dt>path.separator</dt> <dd>Path separator (":" on Unix)</dd> + * <dt>line.separator</dt> <dd>Line separator ("\n" on Unix)</dd> + * <dt>user.name</dt> <dd>User account name</dd> + * <dt>user.home</dt> <dd>User home directory</dd> + * <dt>user.dir</dt> <dd>User's current working directory</dd> + * </dl> + * + * In addition, gnu defines several other properties, where ? stands for + * each character in '0' through '9': + * <dl> + * <dt>gnu.classpath.home</dt> <dd>Path to the classpath libraries.</dd> + * <dt>gnu.classpath.version</dt> <dd>Version of the classpath libraries.</dd> + * <dt>gnu.classpath.vm.shortname</dt> <dd>Succinct version of the VM name; + * used for finding property files in file system</dd> + * <dt>gnu.classpath.home.url</dt> <dd> Base URL; used for finding + * property files in file system</dd> + * <dt>gnu.cpu.endian</dt> <dd>big or little</dd> + * <dt>gnu.java.io.encoding_scheme_alias.ISO-8859-?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.iso-8859-?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.iso8859_?</dt> <dd>8859_?</dd> + * <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.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd> + * <dt>gnu.java.util.zoneinfo.dir</dt> <dd>Root of zoneinfo tree</dd> + * </dl> + * + * @return the system properties, will never be null + * @throws SecurityException if permission is denied + */ + public static Properties getProperties() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + return SystemProperties.getProperties(); + } + + /** + * Set all the system properties at once. A security check may be performed, + * <code>checkPropertiesAccess</code>. Note that a security manager may + * allow setting a single property, but not the entire group. An argument + * of null resets the properties to the startup default. + * + * @param properties the new set of system properties + * @throws SecurityException if permission is denied + */ + public static void setProperties(Properties properties) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + SystemProperties.setProperties(properties); + } + + /** + * Get a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key)</code>. + * + * @param key the name of the system property to get + * @return the property, or null if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + else if (key.length() == 0) + throw new IllegalArgumentException("key can't be empty"); + return SystemProperties.getProperty(key); + } + + /** + * Get a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key)</code>. + * + * @param key the name of the system property to get + * @param def the default + * @return the property, or def if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key, String def) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + return SystemProperties.getProperty(key, def); + } + + /** + * Set a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key, "write")</code>. + * + * @param key the name of the system property to set + * @param value the new value + * @return the previous value, or null + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * @since 1.2 + */ + public static String setProperty(String key, String value) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + return SystemProperties.setProperty(key, value); + } + + /** + * Remove a single system property by name. A security check may be + * performed, <code>checkPropertyAccess(key, "write")</code>. + * + * @param key the name of the system property to remove + * @return the previous value, or null + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * @since 1.5 + */ + public static String clearProperty(String key) + { + 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.remove(key); + } + + /** + * Gets the value of an environment variable. + * + * @param name the name of the environment variable + * @return the string value of the variable or null when the + * environment variable is not defined. + * @throws NullPointerException + * @throws SecurityException if permission is denied + * @since 1.5 + * @specnote This method was deprecated in some JDK releases, but + * was restored in 1.5. + */ + public static String getenv(String name) + { + if (name == null) + throw new NullPointerException(); + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getenv." + name)); + return getenv0(name); + } + + /** + * <p> + * Returns an unmodifiable view of the system environment variables. + * If the underlying system does not support environment variables, + * an empty map is returned. + * </p> + * <p> + * The returned map is read-only and does not accept queries using + * null keys or values, or those of a type other than <code>String</code>. + * Attempts to modify the map will throw an + * <code>UnsupportedOperationException</code>, while attempts + * to pass in a null value will throw a + * <code>NullPointerException</code>. Types other than <code>String</code> + * throw a <code>ClassCastException</code>. + * </p> + * <p> + * As the returned map is generated using data from the underlying + * platform, it may not comply with the <code>equals()</code> + * and <code>hashCode()</code> contracts. It is also likely that + * the keys of this map will be case-sensitive. + * </p> + * <p> + * Use of this method may require a security check for the + * RuntimePermission "getenv.*". + * </p> + * + * @return a map of the system environment variables. + * @throws SecurityException if the checkPermission method of + * an installed security manager prevents access to + * the system environment variables. + * @since 1.5 + */ + public static Map<String, String> getenv() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getenv.*")); + if (environmentMap == null) + { + // List<String> environ = (List<String>)VMSystem.environ(); + // FIXME + List<String> environ = new ArrayList<String>(); + Map<String,String> variables = new EnvironmentMap(); + for (String pair : environ) + { + String[] parts = pair.split("="); + variables.put(parts[0], parts[1]); + } + environmentMap = Collections.unmodifiableMap(variables); + } + return environmentMap; + } + + /** + * Terminate the Virtual Machine. This just calls + * <code>Runtime.getRuntime().exit(status)</code>, and never returns. + * Obviously, a security check is in order, <code>checkExit</code>. + * + * @param status the exit status; by convention non-zero is abnormal + * @throws SecurityException if permission is denied + * @see Runtime#exit(int) + */ + public static void exit(int status) + { + Runtime.getRuntime().exit(status); + } + + /** + * Calls the garbage collector. This is only a hint, and it is up to the + * implementation what this hint suggests, but it usually causes a + * best-effort attempt to reclaim unused memory from discarded objects. + * This calls <code>Runtime.getRuntime().gc()</code>. + * + * @see Runtime#gc() + */ + public static void gc() + { + Runtime.getRuntime().gc(); + } + + /** + * Runs object finalization on pending objects. This is only a hint, and + * it is up to the implementation what this hint suggests, but it usually + * causes a best-effort attempt to run finalizers on all objects ready + * to be reclaimed. This calls + * <code>Runtime.getRuntime().runFinalization()</code>. + * + * @see Runtime#runFinalization() + */ + public static void runFinalization() + { + Runtime.getRuntime().runFinalization(); + } + + /** + * Tell the Runtime whether to run finalization before exiting the + * JVM. This is inherently unsafe in multi-threaded applications, + * since it can force initialization on objects which are still in use + * by live threads, leading to deadlock; therefore this is disabled by + * default. There may be a security check, <code>checkExit(0)</code>. This + * calls <code>Runtime.getRuntime().runFinalizersOnExit()</code>. + * + * @param finalizeOnExit whether to run finalizers on exit + * @throws SecurityException if permission is denied + * @see Runtime#runFinalizersOnExit() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + Runtime.getRuntime().runFinalizersOnExit(finalizeOnExit); + } + + /** + * Load a code file using its explicit system-dependent filename. A security + * check may be performed, <code>checkLink</code>. This just calls + * <code>Runtime.getRuntime().load(filename)</code>. + * + * <p> + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param filename the code file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void load(String filename) + { + Runtime.getRuntime().load(filename); + } + + /** + * Load a library using its explicit system-dependent filename. A security + * check may be performed, <code>checkLink</code>. This just calls + * <code>Runtime.getRuntime().load(filename)</code>. + * + * <p> + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param libname the library file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void loadLibrary(String libname) + { + Runtime.getRuntime().loadLibrary(libname); + } + + /** + * Convert a library name to its platform-specific variant. + * + * @param libname the library name, as used in <code>loadLibrary</code> + * @return the platform-specific mangling of the name + * @since 1.2 + */ + public static String mapLibraryName(String libname) + { + // XXX Fix this!!!! + return Runtime.nativeGetLibname("", libname); + } + + /** + * Set {@link #in} to a new InputStream. + * + * @param in the new InputStream + * @see #setIn(InputStream) + */ + private static native void setIn0(InputStream in); + + /** + * Set {@link #out} to a new PrintStream. + * + * @param out the new PrintStream + * @see #setOut(PrintStream) + */ + private static native void setOut0(PrintStream out); + + /** + * Set {@link #err} to a new PrintStream. + * + * @param err the new PrintStream + * @see #setErr(PrintStream) + */ + private static native void setErr0(PrintStream err); + + /** + * Gets the value of an environment variable. + * + * @see #getenv(String) + */ + static native String getenv0(String name); + + /** + * Returns the inherited channel of the VM. + * + * This wraps the inheritedChannel() call of the system's default + * {@link SelectorProvider}. + * + * @return the inherited channel of the VM + * + * @throws IOException If an I/O error occurs + * @throws SecurityException If an installed security manager denies access + * to RuntimePermission("inheritedChannel") + * + * @since 1.5 + */ + public static Channel inheritedChannel() + throws IOException + { + return SelectorProvider.provider().inheritedChannel(); + } + + /** + * This is a specialised <code>Collection</code>, providing + * the necessary provisions for the collections used by the + * environment variable map. Namely, it prevents + * querying anything but <code>String</code>s. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static class EnvironmentCollection + extends AbstractCollection<String> + { + + /** + * The wrapped collection. + */ + protected Collection<String> c; + + /** + * Constructs a new environment collection, which + * wraps the elements of the supplied collection. + * + * @param coll the collection to use as a base for + * this collection. + */ + public EnvironmentCollection(Collection<String> coll) + { + c = coll; + } + + /** + * Blocks queries containing a null object or an object which + * isn't of type <code>String</code>. All other queries + * are forwarded to the underlying collection. + * + * @param obj the object to look for. + * @return true if the object exists in the collection. + * @throws NullPointerException if the specified object is null. + * @throws ClassCastException if the specified object is not a String. + */ + public boolean contains(Object obj) + { + if (obj == null) + throw new + NullPointerException("This collection does not support " + + "null values."); + if (!(obj instanceof String)) + throw new + ClassCastException("This collection only supports Strings."); + return c.contains(obj); + } + + /** + * Blocks queries where the collection contains a null object or + * an object which isn't of type <code>String</code>. All other + * queries are forwarded to the underlying collection. + * + * @param coll the collection of objects to look for. + * @return true if the collection contains all elements in the collection. + * @throws NullPointerException if the collection is null. + * @throws NullPointerException if any collection entry is null. + * @throws ClassCastException if any collection entry is not a String. + */ + public boolean containsAll(Collection<?> coll) + { + for (Object o: coll) + { + if (o == null) + throw new + NullPointerException("This collection does not support " + + "null values."); + if (!(o instanceof String)) + throw new + ClassCastException("This collection only supports Strings."); + } + return c.containsAll(coll); + } + + /** + * This returns an iterator over the map elements, with the + * same provisions as for the collection and underlying map. + * + * @return an iterator over the map elements. + */ + public Iterator<String> iterator() + { + return c.iterator(); + } + + /** + * Blocks the removal of elements from the collection. + * + * @return true if the removal was sucessful. + * @throws NullPointerException if the collection is null. + * @throws NullPointerException if any collection entry is null. + * @throws ClassCastException if any collection entry is not a String. + */ + public boolean remove(Object key) + { + if (key == null) + throw new + NullPointerException("This collection does not support " + + "null values."); + if (!(key instanceof String)) + throw new + ClassCastException("This collection only supports Strings."); + return c.contains(key); + } + + /** + * Blocks the removal of all elements in the specified + * collection from the collection. + * + * @param coll the collection of elements to remove. + * @return true if the elements were removed. + * @throws NullPointerException if the collection is null. + * @throws NullPointerException if any collection entry is null. + * @throws ClassCastException if any collection entry is not a String. + */ + public boolean removeAll(Collection<?> coll) + { + for (Object o: coll) + { + if (o == null) + throw new + NullPointerException("This collection does not support " + + "null values."); + if (!(o instanceof String)) + throw new + ClassCastException("This collection only supports Strings."); + } + return c.removeAll(coll); + } + + /** + * Blocks the retention of all elements in the specified + * collection from the collection. + * + * @param c the collection of elements to retain. + * @return true if the other elements were removed. + * @throws NullPointerException if the collection is null. + * @throws NullPointerException if any collection entry is null. + * @throws ClassCastException if any collection entry is not a String. + */ + public boolean retainAll(Collection<?> coll) + { + for (Object o: coll) + { + if (o == null) + throw new + NullPointerException("This collection does not support " + + "null values."); + if (!(o instanceof String)) + throw new + ClassCastException("This collection only supports Strings."); + } + return c.containsAll(coll); + } + + /** + * This simply calls the same method on the wrapped + * collection. + * + * @return the size of the underlying collection. + */ + public int size() + { + return c.size(); + } + + } // class EnvironmentCollection<String> + + /** + * This is a specialised <code>HashMap</code>, which + * prevents the addition or querying of anything other than + * <code>String</code> objects. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + static class EnvironmentMap + extends HashMap<String,String> + { + + /** + * Cache the entry set. + */ + private transient Set<Map.Entry<String,String>> entries; + + /** + * Cache the key set. + */ + private transient Set<String> keys; + + /** + * Cache the value collection. + */ + private transient Collection<String> values; + + /** + * Constructs a new empty <code>EnvironmentMap</code>. + */ + EnvironmentMap() + { + super(); + } + + /** + * Constructs a new <code>EnvironmentMap</code> containing + * the contents of the specified map. + * + * @param m the map to be added to this. + * @throws NullPointerException if a key or value is null. + * @throws ClassCastException if a key or value is not a String. + */ + EnvironmentMap(Map<String,String> m) + { + super(m); + } + + /** + * Blocks queries containing a null key or one which is not + * of type <code>String</code>. All other queries + * are forwarded to the superclass. + * + * @param key the key to look for in the map. + * @return true if the key exists in the map. + * @throws NullPointerException if the specified key is null. + */ + public boolean containsKey(Object key) + { + if (key == null) + throw new + NullPointerException("This map does not support null keys."); + if (!(key instanceof String)) + throw new + ClassCastException("This map only allows queries using Strings."); + return super.containsKey(key); + } + + /** + * Blocks queries using a null or non-<code>String</code> value. + * All other queries are forwarded to the superclass. + * + * @param value the value to look for in the map. + * @return true if the value exists in the map. + * @throws NullPointerException if the specified value is null. + */ + public boolean containsValue(Object value) + { + if (value == null) + throw new + NullPointerException("This map does not support null values."); + if (!(value instanceof String)) + throw new + ClassCastException("This map only allows queries using Strings."); + return super.containsValue(value); + } + + /** + * Returns a set view of the map entries, with the same + * provisions as for the underlying map. + * + * @return a set containing the map entries. + */ + public Set<Map.Entry<String,String>> entrySet() + { + if (entries == null) + entries = super.entrySet(); + return entries; + } + + /** + * Blocks queries containing a null or non-<code>String</code> key. + * All other queries are passed on to the superclass. + * + * @param key the key to retrieve the value for. + * @return the value associated with the given key. + * @throws NullPointerException if the specified key is null. + * @throws ClassCastException if the specified key is not a String. + */ + public String get(Object key) + { + if (key == null) + throw new + NullPointerException("This map does not support null keys."); + if (!(key instanceof String)) + throw new + ClassCastException("This map only allows queries using Strings."); + return super.get(key); + } + + /** + * Returns a set view of the keys, with the same + * provisions as for the underlying map. + * + * @return a set containing the keys. + */ + public Set<String> keySet() + { + if (keys == null) + keys = new EnvironmentSet(super.keySet()); + return keys; + } + + /** + * Associates the given key to the given value. If the + * map already contains the key, its value is replaced. + * The map does not accept null keys or values, or keys + * and values not of type {@link String}. + * + * @param key the key to map. + * @param value the value to be mapped. + * @return the previous value of the key, or null if there was no mapping + * @throws NullPointerException if a key or value is null. + * @throws ClassCastException if a key or value is not a String. + */ + public String put(String key, String value) + { + if (key == null) + throw new NullPointerException("A new key is null."); + if (value == null) + throw new NullPointerException("A new value is null."); + if (!(key instanceof String)) + throw new ClassCastException("A new key is not a String."); + if (!(value instanceof String)) + throw new ClassCastException("A new value is not a String."); + return super.put(key, value); + } + + /** + * Removes a key-value pair from the map. The queried key may not + * be null or of a type other than a <code>String</code>. + * + * @param key the key of the entry to remove. + * @return the removed value. + * @throws NullPointerException if the specified key is null. + * @throws ClassCastException if the specified key is not a String. + */ + public String remove(Object key) + { + if (key == null) + throw new + NullPointerException("This map does not support null keys."); + if (!(key instanceof String)) + throw new + ClassCastException("This map only allows queries using Strings."); + return super.remove(key); + } + + /** + * Returns a collection view of the values, with the same + * provisions as for the underlying map. + * + * @return a collection containing the values. + */ + public Collection<String> values() + { + if (values == null) + values = new EnvironmentCollection(super.values()); + return values; + } + + } + + /** + * This is a specialised <code>Set</code>, providing + * the necessary provisions for the collections used by the + * environment variable map. Namely, it prevents + * modifications and the use of queries with null + * or non-<code>String</code> values. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static class EnvironmentSet + extends EnvironmentCollection + implements Set<String> + { + + /** + * Constructs a new environment set, which + * wraps the elements of the supplied set. + * + * @param set the set to use as a base for + * this set. + */ + public EnvironmentSet(Set<String> set) + { + super(set); + } + + /** + * This simply calls the same method on the wrapped + * collection. + * + * @param obj the object to compare with. + * @return true if the two objects are equal. + */ + public boolean equals(Object obj) + { + return c.equals(obj); + } + + /** + * This simply calls the same method on the wrapped + * collection. + * + * @return the hashcode of the collection. + */ + public int hashCode() + { + return c.hashCode(); + } + + } // class EnvironmentSet<String> + +} // class System diff --git a/libjava/java/lang/Thread$State.h b/libjava/java/lang/Thread$State.h new file mode 100644 index 000000000..4620c7224 --- /dev/null +++ b/libjava/java/lang/Thread$State.h @@ -0,0 +1,32 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Thread$State__ +#define __java_lang_Thread$State__ + +#pragma interface + +#include <java/lang/Enum.h> +#include <gcj/array.h> + + +class java::lang::Thread$State : public ::java::lang::Enum +{ + + Thread$State(::java::lang::String *, jint); +public: + static JArray< ::java::lang::Thread$State * > * values(); + static ::java::lang::Thread$State * valueOf(::java::lang::String *); + static ::java::lang::Thread$State * BLOCKED; + static ::java::lang::Thread$State * NEW; + static ::java::lang::Thread$State * RUNNABLE; + static ::java::lang::Thread$State * TERMINATED; + static ::java::lang::Thread$State * TIMED_WAITING; + static ::java::lang::Thread$State * WAITING; +private: + static JArray< ::java::lang::Thread$State * > * ENUM$VALUES; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Thread$State__ diff --git a/libjava/java/lang/Thread$UncaughtExceptionHandler.h b/libjava/java/lang/Thread$UncaughtExceptionHandler.h new file mode 100644 index 000000000..88d2b5b90 --- /dev/null +++ b/libjava/java/lang/Thread$UncaughtExceptionHandler.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Thread$UncaughtExceptionHandler__ +#define __java_lang_Thread$UncaughtExceptionHandler__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Thread$UncaughtExceptionHandler : public ::java::lang::Object +{ + +public: + virtual void uncaughtException(::java::lang::Thread *, ::java::lang::Throwable *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_Thread$UncaughtExceptionHandler__ diff --git a/libjava/java/lang/Thread.h b/libjava/java/lang/Thread.h new file mode 100644 index 000000000..54764c83c --- /dev/null +++ b/libjava/java/lang/Thread.h @@ -0,0 +1,157 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Thread__ +#define __java_lang_Thread__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawData; + class RawDataManaged; + } + } +} + +class _Jv_JNIEnv; +#define _JV_NOT_OWNER 1 +#define _JV_INTERRUPTED 2 +_Jv_JNIEnv * _Jv_GetCurrentJNIEnv (); +void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env); +void _Jv_ThreadRun (java::lang::Thread* thread); +jint _Jv_AttachCurrentThread(java::lang::Thread* thread); +java::lang::Thread* _Jv_AttachCurrentThread (jstring name, java::lang::ThreadGroup* group); +java::lang::Thread* _Jv_AttachCurrentThreadAsDaemon (jstring name, java::lang::ThreadGroup* group); +jint _Jv_DetachCurrentThread (); +struct _Jv_Thread_t; +_Jv_Thread_t* _Jv_ThreadGetData (java::lang::Thread* thread); + +class java::lang::Thread : public ::java::lang::Object +{ + +public: + Thread(); + Thread(::java::lang::Runnable *); + Thread(::java::lang::String *); + Thread(::java::lang::ThreadGroup *, ::java::lang::Runnable *); + Thread(::java::lang::ThreadGroup *, ::java::lang::String *); + Thread(::java::lang::Runnable *, ::java::lang::String *); + Thread(::java::lang::ThreadGroup *, ::java::lang::Runnable *, ::java::lang::String *); + Thread(::java::lang::ThreadGroup *, ::java::lang::Runnable *, ::java::lang::String *, jlong); +public: // actually package-private + Thread(::java::lang::String *, jboolean); +private: + Thread(::java::lang::Thread *, ::java::lang::ThreadGroup *, ::java::lang::Runnable *, ::java::lang::String *, jboolean); +public: + static jint activeCount(); + virtual void checkAccess(); + virtual jint countStackFrames(); + static ::java::lang::Thread * currentThread(); + virtual void destroy(); + static void dumpStack(); + static jint enumerate(JArray< ::java::lang::Thread * > *); + virtual ::java::lang::String * getName(); + virtual jint getPriority(); + virtual ::java::lang::ThreadGroup * getThreadGroup(); + static jboolean holdsLock(::java::lang::Object *); + virtual void interrupt(); + static jboolean interrupted(); + virtual jboolean isInterrupted(); + virtual jboolean isAlive(); + virtual jboolean isDaemon(); + virtual void join(); + virtual void join(jlong); + virtual void join(jlong, jint); + virtual void resume(); +private: + void finish_(); + jboolean isInterrupted(jboolean); +public: + virtual void run(); + virtual void setDaemon(jboolean); + virtual ::java::lang::ClassLoader * getContextClassLoader(); + virtual void setContextClassLoader(::java::lang::ClassLoader *); + virtual void setName(::java::lang::String *); + static void yield(); + static void sleep(jlong); + static void sleep(jlong, jint); + virtual void start(); + virtual void stop(); + virtual void stop(::java::lang::Throwable *); + virtual void suspend(); + virtual void setPriority(jint); + virtual ::java::lang::String * toString(); +private: + void initialize_native(); + static ::java::lang::String * gen_name(); +public: // actually package-private + static ::java::lang::ThreadLocalMap * getThreadLocals(); +public: + virtual void setUncaughtExceptionHandler(::java::lang::Thread$UncaughtExceptionHandler *); + virtual ::java::lang::Thread$UncaughtExceptionHandler * getUncaughtExceptionHandler(); + static void setDefaultUncaughtExceptionHandler(::java::lang::Thread$UncaughtExceptionHandler *); + static ::java::lang::Thread$UncaughtExceptionHandler * getDefaultUncaughtExceptionHandler(); + virtual jlong getId(); + virtual ::java::lang::Thread$State * getState(); + static ::java::util::Map * getAllStackTraces(); + virtual JArray< ::java::lang::StackTraceElement * > * getStackTrace(); + static const jint MIN_PRIORITY = 1; + static const jint NORM_PRIORITY = 5; + static const jint MAX_PRIORITY = 10; +public: // actually package-private + ::java::lang::ThreadGroup * __attribute__((aligned(__alignof__( ::java::lang::Object)))) group; +private: + ::java::lang::Runnable * runnable; +public: // actually package-private + ::java::lang::String * name; +private: + jboolean daemon; + jint priority; +public: // actually package-private + jboolean interrupt_flag; +private: + static const jbyte THREAD_DEAD = 0; + static const jbyte THREAD_ALIVE = 1; + static const jbyte THREAD_SIGNALED = 2; + jboolean startable_flag; + ::java::lang::ClassLoader * contextClassLoader; + jlong threadId; + static jlong nextThreadId; + static jlong totalThreadsCreated; + static ::java::lang::Thread$UncaughtExceptionHandler * defaultHandler; +public: // actually package-private + ::java::lang::ThreadLocalMap * locals; + ::java::lang::Thread$UncaughtExceptionHandler * exceptionHandler; +private: + ::java::lang::Object * parkBlocker; +public: // actually package-private + static const jbyte THREAD_PARK_RUNNING = 0; + static const jbyte THREAD_PARK_PERMIT = 1; + static const jbyte THREAD_PARK_PARKED = 2; + static const jbyte THREAD_PARK_DEAD = 3; + ::java::lang::Object * accessControlState; + ::gnu::gcj::RawData * interp_frame; + ::gnu::gcj::RawData * frame; + jint volatile state; + ::gnu::gcj::RawDataManaged * data; +public: + static ::java::lang::Class class$; + + friend _Jv_JNIEnv * ::_Jv_GetCurrentJNIEnv (); + friend void ::_Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env); + friend void ::_Jv_ThreadRun (java::lang::Thread* thread); + friend jint (::_Jv_AttachCurrentThread) (java::lang::Thread* thread); + friend java::lang::Thread* ::_Jv_AttachCurrentThread (jstring name, java::lang::ThreadGroup* group); + friend java::lang::Thread* ::_Jv_AttachCurrentThreadAsDaemon (jstring name, java::lang::ThreadGroup* group); + friend jint (::_Jv_DetachCurrentThread) (); +}; + +#endif // __java_lang_Thread__ diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java new file mode 100644 index 000000000..8b6d4ba75 --- /dev/null +++ b/libjava/java/lang/Thread.java @@ -0,0 +1,1358 @@ +/* Thread -- an independent thread of executable code + Copyright (C) 1998, 1999, 2000, 2001, 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.classpath.VMStackWalker; +import gnu.gcj.RawData; +import gnu.gcj.RawDataManaged; +import gnu.java.util.WeakIdentityHashMap; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import java.util.HashMap; +import java.util.Map; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/* 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. + */ + +/** + * 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 (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @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 +{ + /** The minimum priority for a Thread. */ + public static final int MIN_PRIORITY = 1; + + /** 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 group this thread belongs to. This is set to null by + * ThreadGroup.removeThread when the thread dies. + */ + ThreadGroup group; + + /** The object to run(), null if this is the target. */ + private Runnable runnable; + + /** The thread name, non-null. */ + String name; + + /** Whether the thread is a daemon. */ + private boolean daemon; + + /** The thread priority, 1 to 10. */ + private int priority; + + boolean interrupt_flag; + + /** A thread is either alive, dead, or being sent a signal; if it is + being sent a signal, it is also alive. Thus, if you want to + know if a thread is alive, it is sufficient to test + alive_status != THREAD_DEAD. */ + private static final byte THREAD_DEAD = 0; + private static final byte THREAD_ALIVE = 1; + private static final byte THREAD_SIGNALED = 2; + + private boolean startable_flag; + + /** The context classloader for this Thread. */ + private ClassLoader contextClassLoader; + + /** This thread's ID. */ + private final long threadId; + + /** The next thread ID to use. */ + private static long nextThreadId; + + /** Used to generate the next thread ID to use. */ + private static long totalThreadsCreated; + + /** The default exception handler. */ + private static UncaughtExceptionHandler defaultHandler; + + /** Thread local storage. Package accessible for use by + * InheritableThreadLocal. + */ + ThreadLocalMap locals; + + /** The uncaught exception handler. */ + UncaughtExceptionHandler exceptionHandler; + + /** This object is recorded while the thread is blocked to permit + * monitoring and diagnostic tools to identify the reasons that + * threads are blocked. + */ + private Object parkBlocker; + + /** Used by Unsafe.park and Unsafe.unpark. Se Unsafe for a full + description. */ + static final byte THREAD_PARK_RUNNING = 0; + static final byte THREAD_PARK_PERMIT = 1; + static final byte THREAD_PARK_PARKED = 2; + static final byte THREAD_PARK_DEAD = 3; + + /** The access control state for this thread. Package accessible + * for use by java.security.VMAccessControlState's native method. + */ + Object accessControlState = null; + + // This describes the top-most interpreter frame for this thread. + RawData interp_frame; + + // This describes the top most frame in the composite (interp + JNI) stack + RawData frame; + + // Current state. + volatile int state; + + // Our native data - points to an instance of struct natThread. + RawDataManaged data; + + /** + * 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, gen_name()); + } + + /** + * 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 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 Thread(Runnable target) + { + this(null, target, gen_name()); + } + + /** + * 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 Thread(String name) + { + this(null, null, name); + } + + /** + * 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 Thread(ThreadGroup group, Runnable target) + { + this(group, target, gen_name()); + } + + /** + * 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(ThreadGroup group, String name) + { + this(group, null, name); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, target, name)</code>. + * + * @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, String name) + { + this(null, target, 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. + * + * <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(ThreadGroup group, Runnable target, String name) + { + this(currentThread(), group, target, name, false); + } + + /** + * 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) + { + // Just ignore stackSize for now. + this(currentThread(), group, target, name, false); + } + + /** + * Allocate a new Thread object for threads used internally to the + * run time. Runtime threads should not be members of an + * application ThreadGroup, nor should they execute arbitrary user + * code as part of the InheritableThreadLocal protocol. + * + * @param name the name for the Thread + * @param noInheritableThreadLocal if true, do not initialize + * InheritableThreadLocal variables for this thread. + * @throws IllegalThreadStateException if group is destroyed + */ + Thread(String name, boolean noInheritableThreadLocal) + { + this(null, null, null, name, noInheritableThreadLocal); + } + + private Thread (Thread current, ThreadGroup g, Runnable r, String n, boolean noInheritableThreadLocal) + { + // Make sure the current thread may create a new thread. + checkAccess(); + + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (n == null) + throw new NullPointerException (); + + if (g == null) + { + // If CURRENT is null, then we are bootstrapping the first thread. + // Use ThreadGroup.root, the main threadgroup. + if (current == null) + group = ThreadGroup.root; + else + group = current.getThreadGroup(); + } + else + group = g; + + data = null; + interrupt_flag = false; + startable_flag = true; + + synchronized (Thread.class) + { + this.threadId = nextThreadId++; + } + + // Always create the ThreadLocalMap when creating a thread; the + // previous code did this lazily when getThreadLocals was called, + // but this is a divergence from Classpath's implementation of + // ThreadLocal. + this.locals = new ThreadLocalMap(); + + if (current != null) + { + group.checkAccess(); + + daemon = current.isDaemon(); + int gmax = group.getMaxPriority(); + int pri = current.getPriority(); + priority = (gmax < pri ? gmax : pri); + contextClassLoader = current.contextClassLoader; + // InheritableThreadLocal allows arbitrary user code to be + // executed, only do this if our caller desires it. + if (!noInheritableThreadLocal) + InheritableThreadLocal.newChildThread(this); + } + else + { + daemon = false; + priority = NORM_PRIORITY; + } + + name = n; + group.addThread(this); + runnable = r; + + initialize_native (); + } + + /** + * Get the number of active threads in the current Thread's ThreadGroup. + * This implementation calls + * <code>currentThread().getThreadGroup().activeCount()</code>. + * + * @return the number of active threads in the current ThreadGroup + * @see ThreadGroup#activeCount() + */ + public static int activeCount() + { + return currentThread().group.activeCount(); + } + + /** + * Check whether the current Thread is allowed to modify this Thread. This + * passes the check on to <code>SecurityManager.checkAccess(this)</code>. + * + * @throws SecurityException if the current Thread cannot modify this Thread + * @see SecurityManager#checkAccess(Thread) + */ + public final void checkAccess() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkAccess(this); + } + + /** + * Count the number of stack frames in this Thread. The Thread in question + * must be suspended when this occurs. + * + * @return the number of stack frames in this Thread + * @throws IllegalThreadStateException if this Thread is not suspended + * @deprecated pointless, since suspend is deprecated + */ + public native int countStackFrames(); + + /** + * Get the currently executing Thread. In the situation that the + * currently running thread was created by native code and doesn't + * have an associated Thread object yet, a new Thread object is + * constructed and associated with the native thread. + * + * @return the currently executing Thread + */ + public static native Thread currentThread(); + + /** + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. + * + * @deprecated This method was originally intended to simply destroy + * the thread without performing any form of cleanup operation. + * However, it was never implemented. It is now deprecated + * for the same reason as <code>suspend()</code>, + * <code>stop()</code> and <code>resume()</code>; namely, + * it is prone to deadlocks. If a thread is destroyed while + * it still maintains a lock on a resource, then this resource + * will remain locked and any attempts by other threads to + * access the resource will result in a deadlock. Thus, even + * an implemented version of this method would be still be + * deprecated, due to its unsafe nature. + * @throws NoSuchMethodError as this method was never implemented. + */ + public void destroy() + { + throw new NoSuchMethodError(); + } + + /** + * Print a stack trace of the current thread to stderr using the same + * format as Throwable's printStackTrace() method. + * + * @see Throwable#printStackTrace() + */ + public static void dumpStack() + { + (new Exception("Stack trace")).printStackTrace(); + } + + /** + * Copy every active thread in the current Thread's ThreadGroup into the + * array. Extra threads are silently ignored. This implementation calls + * <code>getThreadGroup().enumerate(array)</code>, which may have a + * security check, <code>checkAccess(group)</code>. + * + * @param array the array to place the Threads into + * @return the number of Threads placed into the array + * @throws NullPointerException if array is null + * @throws SecurityException if you cannot access the ThreadGroup + * @see ThreadGroup#enumerate(Thread[]) + * @see #activeCount() + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public static int enumerate(Thread[] array) + { + return currentThread().group.enumerate(array); + } + + /** + * Get this Thread's name. + * + * @return this Thread's name + */ + public final String getName() + { + return name; + } + + /** + * Get this Thread's priority. + * + * @return the Thread's priority + */ + public final int getPriority() + { + return priority; + } + + /** + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. + * + * @return this Thread's ThreadGroup + */ + public final ThreadGroup getThreadGroup() + { + return group; + } + + /** + * Checks whether the current thread holds the monitor on a given object. + * This allows you to do <code>assert Thread.holdsLock(obj)</code>. + * + * @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 + */ + public static native boolean holdsLock(Object obj); + + /** + * Interrupt this Thread. First, there is a security check, + * <code>checkAccess</code>. Then, depending on the current state of the + * thread, various actions take place: + * + * <p>If the thread is waiting because of {@link #wait()}, + * {@link #sleep(long)}, or {@link #join()}, its <i>interrupt status</i> + * will be cleared, and an InterruptedException will be thrown. Notice that + * this case is only possible if an external thread called interrupt(). + * + * <p>If the thread is blocked in an interruptible I/O operation, in + * {@link java.nio.channels.InterruptibleChannel}, the <i>interrupt + * status</i> will be set, and ClosedByInterruptException will be thrown. + * + * <p>If the thread is blocked on a {@link java.nio.channels.Selector}, the + * <i>interrupt status</i> will be set, and the selection will return, with + * a possible non-zero value, as though by the wakeup() method. + * + * <p>Otherwise, the interrupt status will be set. + * + * @throws SecurityException if you cannot modify this Thread + */ + public native void interrupt(); + + /** + * Determine whether the current Thread has been interrupted, and clear + * the <i>interrupted status</i> in the process. + * + * @return whether the current Thread has been interrupted + * @see #isInterrupted() + */ + public static boolean interrupted() + { + return currentThread().isInterrupted(true); + } + + /** + * Determine whether the given Thread has been interrupted, but leave + * the <i>interrupted status</i> alone in the process. + * + * @return whether the Thread has been interrupted + * @see #interrupted() + */ + public boolean isInterrupted() + { + return interrupt_flag; + } + + /** + * Determine whether this Thread is alive. A thread which is alive has + * started and not yet died. + * + * @return whether this Thread is alive + */ + public final native boolean isAlive(); + + /** + * Tell whether this is a daemon Thread or not. + * + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) + */ + public final boolean isDaemon() + { + return daemon; + } + + /** + * Wait forever for the Thread in question to die. + * + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + */ + public final void join() throws InterruptedException + { + join(0, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + */ + public final void join(long ms) throws InterruptedException + { + join(ms, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + * @throws IllegalArgumentException if ns is invalid + * @XXX A ThreadListener would be nice, to make this efficient. + */ + public final native void join(long ms, int ns) + throws InterruptedException; + + /** + * Resume this Thread. If the thread is not suspended, this method does + * nothing. To mirror suspend(), there may be a security check: + * <code>checkAccess</code>. + * + * @throws SecurityException if you cannot resume the Thread + * @see #checkAccess() + * @see #suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final native void resume(); + + private final native void finish_(); + + /** + * Determine whether the given Thread has been interrupted, but leave + * the <i>interrupted status</i> alone in the process. + * + * @return whether the current Thread has been interrupted + * @see #interrupted() + */ + private boolean isInterrupted(boolean clear_flag) + { + boolean r = interrupt_flag; + if (clear_flag && r) + { + // Only clear the flag if we saw it as set. Otherwise this could + // potentially cause us to miss an interrupt in a race condition, + // because this method is not synchronized. + interrupt_flag = false; + } + return r; + } + + /** + * The method of Thread that will be run if there is no Runnable object + * associated with the Thread. Thread's implementation does nothing at all. + * + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) + */ + public void run() + { + if (runnable != null) + runnable.run(); + } + + /** + * Set the daemon status of this Thread. If this is a daemon Thread, then + * the VM may exit even if it is still running. This may only be called + * before the Thread starts running. There may be a security check, + * <code>checkAccess</code>. + * + * @param daemon whether this should be a daemon thread or not + * @throws SecurityException if you cannot modify this Thread + * @throws IllegalThreadStateException if the Thread is active + * @see #isDaemon() + * @see #checkAccess() + */ + public final void setDaemon(boolean daemon) + { + if (!startable_flag) + throw new IllegalThreadStateException(); + checkAccess(); + this.daemon = daemon; + } + + /** + * Returns the context classloader of this Thread. The context + * classloader can be used by code that want to load classes depending + * on the current thread. Normally classes are loaded depending on + * the classloader of the current class. There may be a security check + * for <code>RuntimePermission("getClassLoader")</code> if the caller's + * class loader is not null or an ancestor of this thread's context class + * loader. + * + * @return the context class loader + * @throws SecurityException when permission is denied + * @see #setContextClassLoader(ClassLoader) + * @since 1.2 + */ + public synchronized ClassLoader getContextClassLoader() + { + if (contextClassLoader == null) + contextClassLoader = ClassLoader.getSystemClassLoader(); + + // Check if we may get the classloader + SecurityManager sm = System.getSecurityManager(); + if (contextClassLoader != null && sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(contextClassLoader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return contextClassLoader; + } + + /** + * Sets the context classloader for this Thread. When not explicitly set, + * the context classloader for a thread is the same as the context + * classloader of the thread that created this thread. The first thread has + * as context classloader the system classloader. There may be a security + * check for <code>RuntimePermission("setContextClassLoader")</code>. + * + * @param classloader the new context class loader + * @throws SecurityException when permission is denied + * @see #getContextClassLoader() + * @since 1.2 + */ + public synchronized void setContextClassLoader(ClassLoader classloader) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + this.contextClassLoader = classloader; + } + + /** + * Set this Thread's name. There may be a security check, + * <code>checkAccess</code>. + * + * @param name the new name for this Thread + * @throws NullPointerException if name is null + * @throws SecurityException if you cannot modify this Thread + */ + public final void setName(String name) + { + checkAccess(); + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (name == null) + throw new NullPointerException(); + this.name = name; + } + + /** + * Yield to another thread. The Thread will not lose any locks it holds + * during this time. There are no guarantees which thread will be + * next to run, and it could even be this one, but most VMs will choose + * the highest priority thread that has been waiting longest. + */ + public static native void yield(); + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's <i>interrupted status</i> will be cleared + * @throws IllegalArgumentException if ms is negative + * @see #interrupt() + * @see #notify() + * @see #wait(long) + */ + public static void sleep(long ms) throws InterruptedException + { + sleep(ms, 0); + } + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * <p> + * Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs + * do not offer that fine a grain of timing resolution. When ms is + * zero and ns is non-zero the Thread will sleep for at least one + * milli second. There is no guarantee that this thread can start up + * immediately when time expires, because some other thread may be + * active. So don't expect real-time performance. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's <i>interrupted status</i> will be cleared + * @throws IllegalArgumentException if ms or ns is negative + * or ns is larger than 999999. + * @see #interrupt() + * @see #notify() + * @see #wait(long, int) + */ + public static native void sleep(long timeout, int nanos) + throws InterruptedException; + + /** + * Start this Thread, calling the run() method of the Runnable this Thread + * was created with, or else the run() method of the Thread itself. This + * is the only way to start a new thread; calling run by yourself will just + * stay in the same thread. The virtual machine will remove the thread from + * its thread group when the run() method completes. + * + * @throws IllegalThreadStateException if the thread has already started + * @see #run() + */ + public native void start(); + + /** + * Cause this Thread to stop abnormally because of the throw of a ThreadDeath + * error. If you stop a Thread that has not yet started, it will stop + * immediately when it is actually started. + * + * <p>This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * <code>checkAccess(this)</code>, plus another one if the current thread + * is not this: <code>RuntimePermission("stopThread")</code>. If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @throws SecurityException if you cannot stop the Thread + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final void stop() + { + // Argument doesn't matter, because this is no longer + // supported. + stop(null); + } + + /** + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, the stop is ignored + * (contrary to what the JDK documentation says). + * <b>WARNING</b>This bypasses Java security, and can throw a checked + * exception which the call stack is unprepared to handle. Do not abuse + * this power. + * + * <p>This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * <code>checkAccess(this)</code>, plus another one if the current thread + * is not this: <code>RuntimePermission("stopThread")</code>. If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @param t the Throwable to throw when the Thread dies + * @throws SecurityException if you cannot stop the Thread + * @throws NullPointerException in the calling thread, if t is null + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final native void stop(Throwable t); + + /** + * Suspend this Thread. It will not come back, ever, unless it is resumed. + * + * <p>This is inherently unsafe, as the suspended thread still holds locks, + * and can potentially deadlock your program. Hence, there is a security + * check: <code>checkAccess</code>. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use + */ + public final native void suspend(); + + /** + * Set this Thread's priority. There may be a security check, + * <code>checkAccess</code>, then the priority is set to the smaller of + * priority and the ThreadGroup maximum priority. + * + * @param priority the new priority for this Thread + * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or + * MAX_PRIORITY + * @throws SecurityException if you cannot modify this Thread + * @see #getPriority() + * @see #checkAccess() + * @see ThreadGroup#getMaxPriority() + * @see #MIN_PRIORITY + * @see #MAX_PRIORITY + */ + public final native void setPriority(int newPriority); + + /** + * Returns a string representation of this thread, including the + * thread's name, priority, and thread group. + * + * @return a human-readable String representing this Thread + */ + public String toString() + { + return ("Thread[" + name + "," + priority + "," + + (group == null ? "" : group.getName()) + "]"); + } + + private final native void initialize_native(); + + private final native static String gen_name(); + + /** + * Returns the map used by ThreadLocal to store the thread local values. + */ + static ThreadLocalMap getThreadLocals() + { + Thread thread = currentThread(); + ThreadLocalMap locals = thread.locals; + + return locals; + } + + /** + * Assigns the given <code>UncaughtExceptionHandler</code> to this + * thread. This will then be called if the thread terminates due + * to an uncaught exception, pre-empting that of the + * <code>ThreadGroup</code>. + * + * @param h the handler to use for this thread. + * @throws SecurityException if the current thread can't modify this thread. + * @since 1.5 + */ + public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkAccess(this); + exceptionHandler = h; + } + + /** + * <p> + * Returns the handler used when this thread terminates due to an + * uncaught exception. The handler used is determined by the following: + * </p> + * <ul> + * <li>If this thread has its own handler, this is returned.</li> + * <li>If not, then the handler of the thread's <code>ThreadGroup</code> + * object is returned.</li> + * <li>If both are unavailable, then <code>null</code> is returned + * (which can only happen when the thread was terminated since + * then it won't have an associated thread group anymore).</li> + * </ul> + * + * @return the appropriate <code>UncaughtExceptionHandler</code> or + * <code>null</code> if one can't be obtained. + * @since 1.5 + */ + public UncaughtExceptionHandler getUncaughtExceptionHandler() + { + // FIXME: if thread is dead, should return null... + return exceptionHandler != null ? exceptionHandler : group; + } + + /** + * <p> + * Sets the default uncaught exception handler used when one isn't + * provided by the thread or its associated <code>ThreadGroup</code>. + * This exception handler is used when the thread itself does not + * have an exception handler, and the thread's <code>ThreadGroup</code> + * does not override this default mechanism with its own. As the group + * calls this handler by default, this exception handler should not defer + * to that of the group, as it may lead to infinite recursion. + * </p> + * <p> + * Uncaught exception handlers are used when a thread terminates due to + * an uncaught exception. Replacing this handler allows default code to + * be put in place for all threads in order to handle this eventuality. + * </p> + * + * @param h the new default uncaught exception handler to use. + * @throws SecurityException if a security manager is present and + * disallows the runtime permission + * "setDefaultUncaughtExceptionHandler". + * @since 1.5 + */ + public static void + setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler")); + defaultHandler = h; + } + + /** + * Returns the handler used by default when a thread terminates + * unexpectedly due to an exception, or <code>null</code> if one doesn't + * exist. + * + * @return the default uncaught exception handler. + * @since 1.5 + */ + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() + { + return defaultHandler; + } + + /** + * Returns the unique identifier for this thread. This ID is generated + * on thread creation, and may be re-used on its death. + * + * @return a positive long number representing the thread's ID. + * @since 1.5 + */ + public long getId() + { + return threadId; + } + + /** + * <p> + * This interface is used to handle uncaught exceptions + * which cause a <code>Thread</code> to terminate. When + * a thread, t, is about to terminate due to an uncaught + * exception, the virtual machine looks for a class which + * implements this interface, in order to supply it with + * the dying thread and its uncaught exception. + * </p> + * <p> + * The virtual machine makes two attempts to find an + * appropriate handler for the uncaught exception, in + * the following order: + * </p> + * <ol> + * <li> + * <code>t.getUncaughtExceptionHandler()</code> -- + * the dying thread is queried first for a handler + * specific to that thread. + * </li> + * <li> + * <code>t.getThreadGroup()</code> -- + * the thread group of the dying thread is used to + * handle the exception. If the thread group has + * no special requirements for handling the exception, + * it may simply forward it on to + * <code>Thread.getDefaultUncaughtExceptionHandler()</code>, + * the default handler, which is used as a last resort. + * </li> + * </ol> + * <p> + * The first handler found is the one used to handle + * the uncaught exception. + * </p> + * + * @author Tom Tromey <tromey@redhat.com> + * @author Andrew John Hughes <gnu_andrew@member.fsf.org> + * @since 1.5 + * @see Thread#getUncaughtExceptionHandler() + * @see Thread#setUncaughtExceptionHandler(UncaughtExceptionHandler) + * @see Thread#getDefaultUncaughtExceptionHandler() + * @see + * Thread#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) + */ + public interface UncaughtExceptionHandler + { + /** + * Invoked by the virtual machine with the dying thread + * and the uncaught exception. Any exceptions thrown + * by this method are simply ignored by the virtual + * machine. + * + * @param thr the dying thread. + * @param exc the uncaught exception. + */ + void uncaughtException(Thread thr, Throwable exc); + } + + /** + * <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; + } + + + /** + * Returns the current state of the thread. This + * is designed for monitoring thread behaviour, rather + * than for synchronization control. + * + * @return the current thread state. + */ + public native State getState(); + + /** + * <p> + * Returns a map of threads to stack traces for each + * live thread. The keys of the map are {@link Thread} + * objects, which map to arrays of {@link StackTraceElement}s. + * The results obtained from Calling this method are + * equivalent to calling {@link getStackTrace()} on each + * thread in succession. Threads may be executing while + * this takes place, and the results represent a snapshot + * of the thread at the time its {@link getStackTrace()} + * method is called. + * </p> + * <p> + * The stack trace information contains the methods called + * by the thread, with the most recent method forming the + * first element in the array. The array will be empty + * if the virtual machine can not obtain information on the + * thread. + * </p> + * <p> + * To execute this method, the current security manager + * (if one exists) must allow both the + * <code>"getStackTrace"</code> and + * <code>"modifyThreadGroup"</code> {@link RuntimePermission}s. + * </p> + * + * @return a map of threads to arrays of {@link StackTraceElement}s. + * @throws SecurityException if a security manager exists, and + * prevents either or both the runtime + * permissions specified above. + * @since 1.5 + * @see #getStackTrace() + */ + public static Map<Thread, StackTraceElement[]> getAllStackTraces() + { + ThreadGroup group = currentThread().group; + while (group.getParent() != null) + group = group.getParent(); + int arraySize = group.activeCount(); + Thread[] threadList = new Thread[arraySize]; + int filled = group.enumerate(threadList); + while (filled == arraySize) + { + arraySize *= 2; + threadList = new Thread[arraySize]; + filled = group.enumerate(threadList); + } + Map traces = new HashMap(); + for (int a = 0; a < filled; ++a) + traces.put(threadList[a], + threadList[a].getStackTrace()); + return traces; + } + + /** + * <p> + * Returns an array of {@link StackTraceElement}s + * representing the current stack trace of this thread. + * The first element of the array is the most recent + * method called, and represents the top of the stack. + * The elements continue in this order, with the last + * element representing the bottom of the stack. + * </p> + * <p> + * A zero element array is returned for threads which + * have not yet started (and thus have not yet executed + * any methods) or for those which have terminated. + * Where the virtual machine can not obtain a trace for + * the thread, an empty array is also returned. The + * virtual machine may also omit some methods from the + * trace in non-zero arrays. + * </p> + * <p> + * To execute this method, the current security manager + * (if one exists) must allow both the + * <code>"getStackTrace"</code> and + * <code>"modifyThreadGroup"</code> {@link RuntimePermission}s. + * </p> + * + * @return a stack trace for this thread. + * @throws SecurityException if a security manager exists, and + * prevents the use of the + * <code>"getStackTrace"</code> + * permission. + * @since 1.5 + * @see #getAllStackTraces() + */ + public StackTraceElement[] getStackTrace() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getStackTrace")); + + // Calling java.lang.management via reflection means that + // javax.management be overridden in the endorsed directory. + + // This is the equivalent code: + // + // ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + // ThreadInfo info = bean.getThreadInfo(getId(), Integer.MAX_VALUE); + // return info.getStackTrace(); + + try + { + try + { + Object bean + = (Class.forName("java.lang.management.ManagementFactory") + .getDeclaredMethod("getThreadMXBean") + .invoke(null)); + Object info = bean.getClass() + .getDeclaredMethod("getThreadInfo", long.class, int.class) + .invoke(bean, new Long(getId()), new Integer(Integer.MAX_VALUE)); + Object trace = info.getClass() + .getDeclaredMethod("getStackTrace").invoke(info); + return (StackTraceElement[])trace; + } + catch (InvocationTargetException e) + { + throw (Exception)e.getTargetException(); + } + } + catch (UnsupportedOperationException e) + { + throw e; + } + catch (Exception e) + { + throw new UnsupportedOperationException(e); + } + } +} diff --git a/libjava/java/lang/ThreadDeath.h b/libjava/java/lang/ThreadDeath.h new file mode 100644 index 000000000..d06ce3458 --- /dev/null +++ b/libjava/java/lang/ThreadDeath.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ThreadDeath__ +#define __java_lang_ThreadDeath__ + +#pragma interface + +#include <java/lang/Error.h> + +class java::lang::ThreadDeath : public ::java::lang::Error +{ + +public: + ThreadDeath(); +private: + static const jlong serialVersionUID = -4417128565033088268LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ThreadDeath__ diff --git a/libjava/java/lang/ThreadGroup.h b/libjava/java/lang/ThreadGroup.h new file mode 100644 index 000000000..a197ca16e --- /dev/null +++ b/libjava/java/lang/ThreadGroup.h @@ -0,0 +1,69 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ThreadGroup__ +#define __java_lang_ThreadGroup__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::ThreadGroup : public ::java::lang::Object +{ + + ThreadGroup(); +public: + ThreadGroup(::java::lang::String *); + ThreadGroup(::java::lang::ThreadGroup *, ::java::lang::String *); + virtual ::java::lang::String * getName(); + virtual ::java::lang::ThreadGroup * getParent(); + virtual jint getMaxPriority(); + virtual jboolean isDaemon(); + virtual jboolean isDestroyed(); + virtual void setDaemon(jboolean); + virtual void setMaxPriority(jint); + virtual jboolean parentOf(::java::lang::ThreadGroup *); + virtual void checkAccess(); + virtual jint activeCount(); + virtual jint enumerate(JArray< ::java::lang::Thread * > *); + virtual jint enumerate(JArray< ::java::lang::Thread * > *, jboolean); + virtual jint activeGroupCount(); + virtual jint enumerate(JArray< ::java::lang::ThreadGroup * > *); + virtual jint enumerate(JArray< ::java::lang::ThreadGroup * > *, jboolean); + virtual void stop(); + virtual void interrupt(); + virtual void suspend(); + virtual void resume(); + virtual void destroy(); + virtual void list(); + virtual void uncaughtException(::java::lang::Thread *, ::java::lang::Throwable *); + virtual jboolean allowThreadSuspension(jboolean); + virtual ::java::lang::String * toString(); +private: + jint enumerate(JArray< ::java::lang::Thread * > *, jint, jboolean); + jint enumerate(JArray< ::java::lang::ThreadGroup * > *, jint, jboolean); + void list(::java::lang::String *); +public: // actually package-private + virtual void addThread(::java::lang::Thread *); + virtual void removeThread(::java::lang::Thread *); + virtual void removeGroup(::java::lang::ThreadGroup *); + static ::java::lang::Thread * getThreadFromId(jlong); +private: + ::java::lang::Thread * getThreadFromIdImpl(jlong); +public: // actually package-private + static ::java::lang::ThreadGroup * root; + static jboolean had_uncaught_exception; + ::java::lang::ThreadGroup * __attribute__((aligned(__alignof__( ::java::lang::Object)))) parent; + ::java::lang::String * name; +private: + ::java::util::Vector * threads; + ::java::util::Vector * groups; + jboolean daemon_flag; + jint maxpri; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ThreadGroup__ diff --git a/libjava/java/lang/ThreadLocal.h b/libjava/java/lang/ThreadLocal.h new file mode 100644 index 000000000..13e1f84c6 --- /dev/null +++ b/libjava/java/lang/ThreadLocal.h @@ -0,0 +1,57 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ThreadLocal__ +#define __java_lang_ThreadLocal__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawData; + } + } +} + +class java::lang::ThreadLocal : public ::java::lang::Object +{ + + jint computeNextHash(); +public: + ThreadLocal(); +public: // actually protected + virtual ::java::lang::Object * initialValue(); +public: + virtual ::java::lang::Object * get(); +private: + ::java::lang::Object * internalGet(); +public: + virtual void set(::java::lang::Object *); +private: + void internalSet(::java::lang::Object *); +public: + virtual void remove(); +private: + void internalRemove(); +public: // actually protected + virtual void finalize(); +private: + void constructNative(); +public: // actually package-private + static ::java::lang::Object * sentinel; +private: + static jint nextHashBase; +public: // actually package-private + jint __attribute__((aligned(__alignof__( ::java::lang::Object)))) fastHash; +private: + ::gnu::gcj::RawData * TLSPointer; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ThreadLocal__ diff --git a/libjava/java/lang/ThreadLocal.java b/libjava/java/lang/ThreadLocal.java new file mode 100644 index 000000000..9223dbaae --- /dev/null +++ b/libjava/java/lang/ThreadLocal.java @@ -0,0 +1,198 @@ +/* ThreadLocal -- a variable with a unique value per thread + Copyright (C) 2000, 2002, 2003, 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 java.lang; + +import java.util.Map; + + +/** + * ThreadLocal objects have a different state associated with every + * Thread that accesses them. Every access to the ThreadLocal object + * (through the <code>get()</code> and <code>set()</code> methods) + * only affects the state of the object as seen by the currently + * executing Thread. + * + * <p>The first time a ThreadLocal object is accessed on a particular + * Thread, the state for that Thread's copy of the local variable is set by + * executing the method <code>initialValue()</code>. + * </p> + * + * <p>An example how you can use this: + * </p> + * + * <pre> + * class Connection + * { + * private static ThreadLocal owner = new ThreadLocal() + * { + * public Object initialValue() + * { + * return("nobody"); + * } + * }; + * ... + * } + * </pre> + * + * <p>Now all instances of connection can see who the owner of the currently + * executing Thread is by calling <code>owner.get()</code>. By default any + * Thread would be associated with 'nobody'. But the Connection object could + * offer a method that changes the owner associated with the Thread on + * which the method was called by calling <code>owner.put("somebody")</code>. + * (Such an owner changing method should then be guarded by security checks.) + * </p> + * + * <p>When a Thread is garbage collected all references to values of + * the ThreadLocal objects associated with that Thread are removed. + * </p> + * + * @author Mark Wielaard (mark@klomp.org) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.5 + */ +public class ThreadLocal<T> +{ + /** + * Placeholder to distinguish between uninitialized and null set by the + * user. Do not expose this to the public. Package visible for use by + * InheritableThreadLocal + */ + static final Object sentinel = new Object(); + + /** + * The base for the computation of the next hash for a thread local. + */ + private static int nextHashBase = 1; + + /** + * Allocate a new hash. + */ + private synchronized int computeNextHash() + { + return nextHashBase++ * 6709; + } + + /** + * Hash code computed for ThreadLocalMap + */ + final int fastHash; + + /** + * Creates a ThreadLocal object without associating any value to it yet. + */ + public ThreadLocal() + { + constructNative(); + fastHash = computeNextHash(); + } + + /** + * Called once per thread on the first invocation of get(), if set() was + * not already called. The default implementation returns <code>null</code>. + * Often, this method is overridden to create the appropriate initial object + * for the current thread's view of the ThreadLocal. + * + * @return the initial value of the variable in this thread + */ + protected T initialValue() + { + return null; + } + + /** + * Gets the value associated with the ThreadLocal object for the currently + * executing Thread. If this is the first time the current thread has called + * get(), and it has not already called set(), the value is obtained by + * <code>initialValue()</code>. + * + * @return the value of the variable in this thread + */ + public native T get(); + + private final Object internalGet() + { + ThreadLocalMap map = Thread.getThreadLocals(); + // Note that we don't have to synchronize, as only this thread will + // ever modify the map. + T value = (T) map.get(this); + if (value == sentinel) + { + value = initialValue(); + map.set(this, value); + } + return value; + } + + /** + * Sets the value associated with the ThreadLocal object for the currently + * executing Thread. This overrides any existing value associated with the + * current Thread and prevents <code>initialValue()</code> from being + * called if this is the first access to this ThreadLocal in this Thread. + * + * @param value the value to set this thread's view of the variable to + */ + public native void set(T value); + + private final void internalSet(Object value) + { + ThreadLocalMap map = Thread.getThreadLocals(); + // Note that we don't have to synchronize, as only this thread will + // ever modify the map. + map.set(this, value); + } + + /** + * Removes the value associated with the ThreadLocal object for the + * currently executing Thread. + * @since 1.5 + */ + public native void remove(); + + private final void internalRemove() + { + ThreadLocalMap map = Thread.getThreadLocals(); + map.remove(this); + } + + protected native void finalize () throws Throwable; + + private native void constructNative(); + + private gnu.gcj.RawData TLSPointer; +} diff --git a/libjava/java/lang/ThreadLocalMap$Entry.h b/libjava/java/lang/ThreadLocalMap$Entry.h new file mode 100644 index 000000000..51b4db9c2 --- /dev/null +++ b/libjava/java/lang/ThreadLocalMap$Entry.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ThreadLocalMap$Entry__ +#define __java_lang_ThreadLocalMap$Entry__ + +#pragma interface + +#include <java/lang/ref/WeakReference.h> + +class java::lang::ThreadLocalMap$Entry : public ::java::lang::ref::WeakReference +{ + +public: // actually package-private + ThreadLocalMap$Entry(::java::lang::ThreadLocal *); + ::java::lang::Object * __attribute__((aligned(__alignof__( ::java::lang::ref::WeakReference)))) value; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ThreadLocalMap$Entry__ diff --git a/libjava/java/lang/ThreadLocalMap.h b/libjava/java/lang/ThreadLocalMap.h new file mode 100644 index 000000000..3a1f107cf --- /dev/null +++ b/libjava/java/lang/ThreadLocalMap.h @@ -0,0 +1,41 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ThreadLocalMap__ +#define __java_lang_ThreadLocalMap__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::ThreadLocalMap : public ::java::lang::Object +{ + +public: // actually package-private + ThreadLocalMap(); +private: + void newEntryArray(jint); + void overflow(); +public: + ::java::lang::Object * get(::java::lang::ThreadLocal *); + void set(::java::lang::ThreadLocal *, ::java::lang::Object *); + void remove(::java::lang::ThreadLocal *); +public: // actually package-private + void clear(); +public: + void inherit(::java::lang::ThreadLocalMap *); +private: + static const jint LOG_INITIAL_SIZE = 3; + static jfloat MAX_OCCUPANCY; + static jfloat TARGET_OCCUPANCY; + static ::java::lang::ThreadLocalMap$Entry * deletedEntry; + JArray< ::java::lang::ThreadLocalMap$Entry * > * __attribute__((aligned(__alignof__( ::java::lang::Object)))) entries; + jint hashMask; + jint count; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ThreadLocalMap__ diff --git a/libjava/java/lang/Throwable$StaticData.h b/libjava/java/lang/Throwable$StaticData.h new file mode 100644 index 000000000..6bb0912de --- /dev/null +++ b/libjava/java/lang/Throwable$StaticData.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Throwable$StaticData__ +#define __java_lang_Throwable$StaticData__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Throwable$StaticData : public ::java::lang::Object +{ + + Throwable$StaticData(); +public: // actually package-private + static ::java::lang::String * nl; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Throwable$StaticData__ diff --git a/libjava/java/lang/Throwable.h b/libjava/java/lang/Throwable.h new file mode 100644 index 000000000..2e7532c3a --- /dev/null +++ b/libjava/java/lang/Throwable.h @@ -0,0 +1,59 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Throwable__ +#define __java_lang_Throwable__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace java + { + namespace lang + { + class CPStringBuilder; + } + } + } +} + +class java::lang::Throwable : public ::java::lang::Object +{ + +public: + Throwable(); + Throwable(::java::lang::String *); + Throwable(::java::lang::String *, ::java::lang::Throwable *); + Throwable(::java::lang::Throwable *); + virtual ::java::lang::String * getMessage(); + virtual ::java::lang::String * getLocalizedMessage(); + virtual ::java::lang::Throwable * getCause(); + virtual ::java::lang::Throwable * initCause(::java::lang::Throwable *); + virtual ::java::lang::String * toString(); + virtual void printStackTrace(); + virtual void printStackTrace(::java::io::PrintStream *); + virtual void printStackTrace(::java::io::PrintWriter *); +private: + ::java::lang::String * stackTraceString(); + static void stackTraceStringBuffer(::gnu::java::lang::CPStringBuilder *, ::java::lang::String *, JArray< ::java::lang::StackTraceElement * > *, jint); +public: + virtual ::java::lang::Throwable * fillInStackTrace(); + virtual JArray< ::java::lang::StackTraceElement * > * getStackTrace(); + virtual void setStackTrace(JArray< ::java::lang::StackTraceElement * > *); +private: + static const jlong serialVersionUID = -3042686055658047285LL; + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) detailMessage; + ::java::lang::Throwable * cause; + JArray< ::java::lang::StackTraceElement * > * stackTrace; + ::java::lang::VMThrowable * vmState; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Throwable__ diff --git a/libjava/java/lang/TypeNotPresentException.h b/libjava/java/lang/TypeNotPresentException.h new file mode 100644 index 000000000..076f0a6d4 --- /dev/null +++ b/libjava/java/lang/TypeNotPresentException.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_TypeNotPresentException__ +#define __java_lang_TypeNotPresentException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::TypeNotPresentException : public ::java::lang::RuntimeException +{ + +public: + TypeNotPresentException(::java::lang::String *, ::java::lang::Throwable *); + virtual ::java::lang::String * typeName(); +private: + static const jlong serialVersionUID = -5101214195716534496LL; + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::RuntimeException)))) typeName__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_TypeNotPresentException__ diff --git a/libjava/java/lang/UnknownError.h b/libjava/java/lang/UnknownError.h new file mode 100644 index 000000000..2ed851aae --- /dev/null +++ b/libjava/java/lang/UnknownError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_UnknownError__ +#define __java_lang_UnknownError__ + +#pragma interface + +#include <java/lang/VirtualMachineError.h> + +class java::lang::UnknownError : public ::java::lang::VirtualMachineError +{ + +public: + UnknownError(); + UnknownError(::java::lang::String *); +private: + static const jlong serialVersionUID = 2524784860676771849LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_UnknownError__ diff --git a/libjava/java/lang/UnsatisfiedLinkError.h b/libjava/java/lang/UnsatisfiedLinkError.h new file mode 100644 index 000000000..a560313fe --- /dev/null +++ b/libjava/java/lang/UnsatisfiedLinkError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_UnsatisfiedLinkError__ +#define __java_lang_UnsatisfiedLinkError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::UnsatisfiedLinkError : public ::java::lang::LinkageError +{ + +public: + UnsatisfiedLinkError(); + UnsatisfiedLinkError(::java::lang::String *); +private: + static const jlong serialVersionUID = -4019343241616879428LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_UnsatisfiedLinkError__ diff --git a/libjava/java/lang/UnsupportedClassVersionError.h b/libjava/java/lang/UnsupportedClassVersionError.h new file mode 100644 index 000000000..afa5b1875 --- /dev/null +++ b/libjava/java/lang/UnsupportedClassVersionError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_UnsupportedClassVersionError__ +#define __java_lang_UnsupportedClassVersionError__ + +#pragma interface + +#include <java/lang/ClassFormatError.h> + +class java::lang::UnsupportedClassVersionError : public ::java::lang::ClassFormatError +{ + +public: + UnsupportedClassVersionError(); + UnsupportedClassVersionError(::java::lang::String *); +private: + static const jlong serialVersionUID = -7123279212883497373LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_UnsupportedClassVersionError__ diff --git a/libjava/java/lang/UnsupportedOperationException.h b/libjava/java/lang/UnsupportedOperationException.h new file mode 100644 index 000000000..ce808bded --- /dev/null +++ b/libjava/java/lang/UnsupportedOperationException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_UnsupportedOperationException__ +#define __java_lang_UnsupportedOperationException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::UnsupportedOperationException : public ::java::lang::RuntimeException +{ + +public: + UnsupportedOperationException(); + UnsupportedOperationException(::java::lang::String *); + UnsupportedOperationException(::java::lang::String *, ::java::lang::Throwable *); + UnsupportedOperationException(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -1242599979055084673LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_UnsupportedOperationException__ diff --git a/libjava/java/lang/VMClassLoader.h b/libjava/java/lang/VMClassLoader.h new file mode 100644 index 000000000..dce7092bf --- /dev/null +++ b/libjava/java/lang/VMClassLoader.h @@ -0,0 +1,74 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMClassLoader__ +#define __java_lang_VMClassLoader__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace runtime + { + class BootClassLoader; + } + } + } + namespace java + { + namespace net + { + class URL; + } + namespace security + { + class Permission; + class ProtectionDomain; + } + } +} + +class java::lang::VMClassLoader : public ::java::lang::Object +{ + +public: // actually package-private + VMClassLoader(); + static ::java::lang::Class * defineClass(::java::lang::ClassLoader *, ::java::lang::String *, JArray< jbyte > *, jint, jint, ::java::security::ProtectionDomain *); + static void resolveClass(::java::lang::Class *); + static ::java::lang::Class * loadClass(::java::lang::String *, jboolean); + static ::java::net::URL * getResource(::java::lang::String *); + static ::java::util::Enumeration * getResources(::java::lang::String *); + static ::java::lang::Package * getPackage(::java::lang::String *); + static JArray< ::java::lang::Package * > * getPackages(); + static void definePackageForNative(::java::lang::String *); + static ::java::lang::Class * getPrimitiveClass(jchar); + static jboolean defaultAssertionStatus(); + static ::java::util::Map * packageAssertionStatus(); + static ::java::util::Map * classAssertionStatus(); + static ::java::lang::ClassLoader * getSystemClassLoaderInternal(); + static void initBootLoader(::java::lang::String *); + static void initialize(::java::lang::String *); + static ::java::lang::Class * nativeFindClass(::java::lang::String *); + static ::java::lang::ClassLoader * getSystemClassLoader(); + static ::java::security::Permission * protectionDomainPermission; + static ::java::security::ProtectionDomain * unknownProtectionDomain; + static ::java::util::HashMap * definedPackages; + static ::gnu::gcj::runtime::BootClassLoader * bootLoader; +private: + static ::java::util::HashSet * tried_libraries; + static jint lib_control; + static const jint LIB_FULL = 0; + static const jint LIB_CACHE = 1; + static const jint LIB_NEVER = 2; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMClassLoader__ diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java new file mode 100644 index 000000000..21019b757 --- /dev/null +++ b/libjava/java/lang/VMClassLoader.java @@ -0,0 +1,348 @@ +/* VMClassLoader.java -- Reference implementation of native interface + required by ClassLoader + Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005 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.util.EmptyEnumeration; +import java.lang.reflect.Constructor; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AllPermission; +import java.security.Permission; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.StringTokenizer; +import gnu.gcj.runtime.BootClassLoader; + +/** + * java.lang.VMClassLoader is a package-private helper for VMs to implement + * on behalf of java.lang.ClassLoader. + * + * @author John Keiser + * @author Mark Wielaard <mark@klomp.org> + * @author Eric Blake <ebb9@email.byu.edu> + */ +final class VMClassLoader +{ + // Protection Domain definitions + // FIXME: should there be a special protection domain used for native code? + + // The permission required to check what a classes protection domain is. + static final Permission protectionDomainPermission + = new RuntimePermission("getProtectionDomain"); + // The protection domain returned if we cannot determine it. + static ProtectionDomain unknownProtectionDomain; + + static + { + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + unknownProtectionDomain = new ProtectionDomain(null, permissions); + } + + static final HashMap definedPackages = new HashMap(); + + // This is a helper for handling java.endorsed.dirs. It is null + // until we've initialized the system, at which point it is created. + static BootClassLoader bootLoader; + + // This keeps track of shared libraries we've already tried to load. + private static HashSet tried_libraries; + + // Holds one of the LIB_* constants; used to determine how shared + // library loads are done. + private static int lib_control; + + private static final int LIB_FULL = 0; + private static final int LIB_CACHE = 1; + private static final int LIB_NEVER = 2; + + /** + * Helper to define a class using a string of bytes. This assumes that + * the security checks have already been performed, if necessary. + * + * <strong>For backward compatibility, this just ignores the protection + * domain; that is the wrong behavior, and you should directly implement + * this method natively if you can.</strong> + * + * @param name the name to give the class, or null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @param pd the protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + */ + static final native Class defineClass(ClassLoader cl, String name, + byte[] data, int offset, int len, + ProtectionDomain pd) + throws ClassFormatError; + + /** + * Helper to resolve all references to other classes from this class. + * + * @param c the class to resolve + */ + static final void resolveClass(Class clazz) + { + // There doesn't seem to be a need for this to do anything. + // Testing reveals that the JDK doesn't seem to do anything here, + // either. + } + + /** + * Helper to load a class from the bootstrap class loader. + * + * @param name the class name to load + * @param resolve whether to resolve it + * @return the class, loaded by the bootstrap classloader or null + * if the class wasn't found. Returning null is equivalent to throwing + * a ClassNotFoundException (but a possible performance optimization). + */ + static final native Class loadClass(String name, boolean resolve) + throws ClassNotFoundException; + + /** + * Helper to load a resource from the bootstrap class loader. + * + * In libgcj, this does nothing, as the default system loader knows + * how to find resources that have been linked in. + * + * @param name the resource to find + * @return the URL to the resource + */ + static URL getResource(String name) + { + if (bootLoader != null) + return bootLoader.bootGetResource(name); + return null; + } + + /** + * Helper to get a list of resources from the bootstrap class loader. + * + * In libgcj, this does nothing, as the default system loader knows + * how to find resources that have been linked in. + * + * @param name the resource to find + * @return an enumeration of resources + * @throws IOException if one occurs + */ + static Enumeration getResources(String name) throws IOException + { + if (bootLoader != null) + return bootLoader.bootGetResources(name); + return EmptyEnumeration.getInstance(); + } + + /** + * Helper to get a package from the bootstrap class loader. The default + * implementation of returning null may be adequate, or you may decide + * that this needs some native help. + * + * @param name the name to find + * @return the named package, if it exists + */ + static synchronized Package getPackage(String name) + { + return (Package) definedPackages.get(name); + } + + /** + * Helper to get all packages from the bootstrap class loader. The default + * implementation of returning an empty array may be adequate, or you may + * decide that this needs some native help. + * + * @return all named packages, if any exist + */ + static synchronized Package[] getPackages() + { + Package[] packages = new Package[definedPackages.size()]; + return (Package[]) definedPackages.values().toArray(packages); + } + + // Define a package for something loaded natively. + static synchronized void definePackageForNative(String className) + { + int lastDot = className.lastIndexOf('.'); + if (lastDot != -1) + { + String packageName = className.substring(0, lastDot); + if (getPackage(packageName) == null) + { + // FIXME: this assumes we're defining the core, which + // isn't necessarily so. We could detect this and set up + // appropriately. We could also look at a manifest file + // compiled into the .so. + Package p = new Package(packageName, + "Java Platform API Specification", + "GNU", "1.4", "gcj", "GNU", + null, // FIXME: gcj version. + null); + definedPackages.put(packageName, p); + } + } + } + + /** + * Helper for java.lang.Integer, Byte, etc to get the TYPE class + * at initialization time. The type code is one of the chars that + * represents the primitive type as in JNI. + * + * <ul> + * <li>'Z' - boolean</li> + * <li>'B' - byte</li> + * <li>'C' - char</li> + * <li>'D' - double</li> + * <li>'F' - float</li> + * <li>'I' - int</li> + * <li>'J' - long</li> + * <li>'S' - short</li> + * <li>'V' - void</li> + * </ul> + * + * @param type the primitive type + * @return a "bogus" class representing the primitive type + */ + static final native Class getPrimitiveClass(char type); + + /** + * The system default for assertion status. This is used for all system + * classes (those with a null ClassLoader), as well as the initial value for + * every ClassLoader's default assertion status. + * + * XXX - Not implemented yet; this requires native help. + * + * @return the system-wide default assertion status + */ + static final boolean defaultAssertionStatus() + { + return true; + } + + /** + * The system default for package assertion status. This is used for all + * ClassLoader's packageAssertionStatus defaults. It must be a map of + * package names to Boolean.TRUE or Boolean.FALSE, with the unnamed package + * represented as a null key. + * + * XXX - Not implemented yet; this requires native help. + * + * @return a (read-only) map for the default packageAssertionStatus + */ + static final Map packageAssertionStatus() + { + return new HashMap(); + } + + /** + * The system default for class assertion status. This is used for all + * ClassLoader's classAssertionStatus defaults. It must be a map of + * class names to Boolean.TRUE or Boolean.FALSE + * + * XXX - Not implemented yet; this requires native help. + * + * @return a (read-only) map for the default classAssertionStatus + */ + static final Map classAssertionStatus() + { + return new HashMap(); + } + + static native ClassLoader getSystemClassLoaderInternal(); + + static native void initBootLoader(String libdir); + + static void initialize(String libdir) + { + initBootLoader(libdir); + + String p + = System.getProperty ("gnu.gcj.runtime.VMClassLoader.library_control", + ""); + if ("never".equals(p)) + lib_control = LIB_NEVER; + else if ("cache".equals(p)) + lib_control = LIB_CACHE; + else if ("full".equals(p)) + lib_control = LIB_FULL; + else + lib_control = LIB_NEVER; + + tried_libraries = new HashSet(); + } + + /** + * Possibly load a .so and search it for classes. + */ + static native Class nativeFindClass(String name); + + static ClassLoader getSystemClassLoader() + { + // This method is called as the initialization of systemClassLoader, + // so if there is a null value, this is the first call and we must check + // for java.system.class.loader. + String loader = System.getProperty("java.system.class.loader"); + ClassLoader default_sys = getSystemClassLoaderInternal(); + if (loader != null) + { + try + { + Class load_class = Class.forName(loader, true, default_sys); + Constructor c + = load_class.getConstructor(new Class[] { ClassLoader.class }); + default_sys + = (ClassLoader) c.newInstance(new Object[] { default_sys }); + } + catch (Exception ex) + { + throw new Error("Failed to load requested system classloader " + + loader, ex); + } + } + + return default_sys; + } +} diff --git a/libjava/java/lang/VMCompiler.h b/libjava/java/lang/VMCompiler.h new file mode 100644 index 000000000..e81f694e1 --- /dev/null +++ b/libjava/java/lang/VMCompiler.h @@ -0,0 +1,64 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMCompiler__ +#define __java_lang_VMCompiler__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace java + { + namespace security + { + namespace hash + { + class MD5; + } + } + } + } + namespace java + { + namespace security + { + class ProtectionDomain; + } + } +} + +class java::lang::VMCompiler : public ::java::lang::Object +{ + +public: + static jboolean precompiles(); +private: + VMCompiler(); + static ::java::lang::Class * loadSharedLibrary(::java::lang::ClassLoader *, ::java::lang::String *, ::java::security::ProtectionDomain *, ::java::lang::String *); +public: + static ::java::lang::Class * compileClass(::java::lang::ClassLoader *, ::java::lang::String *, JArray< jbyte > *, jint, jint, ::java::security::ProtectionDomain *); + static jboolean compileClass(::java::lang::Class *); + static jboolean compileClasses(::java::lang::String *); + static ::java::lang::Object * command(::java::lang::Object *); + static void enable(); + static void disable(); + static jboolean useCompiler; + static jboolean canUseCompiler; + static ::java::lang::String * gcjJitCompiler; + static ::java::lang::String * gcjJitCompilerOptions; + static ::java::lang::String * gcjJitTmpdir; +private: + static ::java::util::WeakHashMap * sharedHelperMap; + static ::java::util::Vector * precompiledMapFiles; + static ::gnu::java::security::hash::MD5 * md5Digest; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMCompiler__ diff --git a/libjava/java/lang/VMCompiler.java b/libjava/java/lang/VMCompiler.java new file mode 100644 index 000000000..1f600f12e --- /dev/null +++ b/libjava/java/lang/VMCompiler.java @@ -0,0 +1,369 @@ +/* VMClassLoader.java -- Reference implementation of compiler interface + Copyright (C) 2004, 2005, 2006, 2007 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.File; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.security.ProtectionDomain; +import java.security.NoSuchAlgorithmException; +import java.util.WeakHashMap; +import java.util.HashSet; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; +import gnu.gcj.runtime.SharedLibHelper; +import gnu.gcj.runtime.PersistentByteMap; +import gnu.java.security.hash.MD5; + +/** + * This class is just a per-VM reflection of java.lang.Compiler. + * All methods are defined identically. + */ +final class VMCompiler +{ + // True if we want to use gcj-jit. + public static boolean useCompiler = true; + + // True if we're able to use gcj-jit. + public static final boolean canUseCompiler; + + // Compiler to use. + public static String gcjJitCompiler; + + // Compiler options. + public static String gcjJitCompilerOptions; + + // Temporary directory to use. + public static String gcjJitTmpdir; + + public static boolean precompiles() + { + return (canUseCompiler & useCompiler); + } + + // This maps a ClassLoader to a set of SharedLibHelper objects that + // it has used. We do things this way to ensure that a + // SharedLibHelper is collected if and only if the ClassLoader is. + private static WeakHashMap sharedHelperMap = new WeakHashMap(); + + private static Vector precompiledMapFiles; + + // We create a single MD5 engine and then clone it whenever we want + // a new one. + + // We don't use + // + // md5Digest = MessageDigest.getInstance("MD5"); + // + // here because that loads a great deal of security provider code as + // interpreted bytecode -- before we're able to use this class to + // load precompiled classes. + + private static final MD5 md5Digest + = new gnu.java.security.hash.MD5(); + + static + { + gcjJitCompiler = System.getProperty("gnu.gcj.jit.compiler"); + if (gcjJitCompiler == null) + canUseCompiler = false; + else + { + gcjJitCompilerOptions = System.getProperty("gnu.gcj.jit.options", + "-g"); + gcjJitTmpdir = System.getProperty("gnu.gcj.jit.cachedir"); + // Note that we *don't* choose java.io.tmpdir as a default -- + // that would allow easy attacks against the VM. + if (gcjJitTmpdir == null) + canUseCompiler = false; + else + canUseCompiler = true; + } + + String prop = System.getProperty ("gnu.gcj.precompiled.db.path"); + if (prop != null) + { + precompiledMapFiles = new Vector(); + // Add the + StringTokenizer st + = new StringTokenizer (prop, + System.getProperty ("path.separator", ":")); + { + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + PersistentByteMap map + = new PersistentByteMap + (e, PersistentByteMap.AccessMode.READ_ONLY); + precompiledMapFiles.add(map); + } + catch (IllegalArgumentException _) + { + // Not a map file + } + catch (java.io.IOException _) + { + } + catch (java.nio.BufferUnderflowException _) + { + // Invalid map file. + } + } + } + } + } + + /** + * Don't allow new `Compiler's to be made. + */ + private VMCompiler() + { + } + + private static Class loadSharedLibrary(ClassLoader loader, + String fileName, + ProtectionDomain domain, + String className) + { + Class c = null; + SharedLibHelper helper + = SharedLibHelper.findHelper (loader, fileName, domain.getCodeSource(), + domain, false); + c = helper.findClass (className); + if (c != null) + { + HashSet hs = (HashSet) sharedHelperMap.get(loader); + if (hs == null) + { + hs = new HashSet(); + sharedHelperMap.put(loader, hs); + } + hs.add(helper); + } + return c; + } + + /** + * Compile a class given the bytes for it. Returns the Class, or + * null if compilation failed or otherwise could not be done. + */ + public static Class compileClass(ClassLoader loader, + String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + { + if (precompiledMapFiles == null && !precompiles()) + return null; + + byte digest[]; + + try + { + MD5 md = (MD5) md5Digest.clone(); + md.update(data); + digest = md.digest(); + } + catch (NullPointerException _) + { + // If md5Digest==null -- but really this should never happen + // either, since the MD5 digest is in libgcj. + return null; + } + + // We use lookaside cache files to determine whether these bytes + // correspond to a class file that is part of a precompiled DSO. + if (precompiledMapFiles != null) + { + try + { + Enumeration elements = precompiledMapFiles.elements(); + while (elements.hasMoreElements()) + { + PersistentByteMap map = (PersistentByteMap)elements.nextElement(); + byte[] soName = map.get(digest); + if (soName != null) + return loadSharedLibrary(loader, + new String(soName), + domain, name); + } + } + catch (Exception _) + { + } + catch (UnknownError _) + { + // SharedLibHelper will throw UnknownError if the dlopen + // fails for some reason. We ignore it and continue on. + } + } + + if (!precompiles()) + return null; + + try + { + // FIXME: Make sure that the class represented by the + // bytes in DATA really is the class named in NAME. Make + // sure it's not "java.*". + StringBuffer hexBytes = new StringBuffer(gcjJitTmpdir); + hexBytes.append(File.separatorChar); + int digestLength = digest.length; + for (int i = 0; i < digestLength; ++i) + { + int v = digest[i] & 0xff; + if (v < 16) + hexBytes.append('0'); + hexBytes.append(Integer.toHexString(v)); + } + + // FIXME: use System.mapLibraryName? + // I'm thinking we should use that, plus a class specified + // via a property that determines lookup policy. + File soFile = new File(hexBytes + ".so"); + if (soFile.isFile()) + return loadSharedLibrary (loader, soFile.toString(), domain, + name); + + File classFile = new File(hexBytes + ".class"); + classFile.delete(); + if (classFile.createNewFile() != true) + return null; + + FileOutputStream f = new FileOutputStream (classFile); + // FIXME: race condition if bytes change... ? + f.write(data, offset, len); + + // Invoke the compiler. + StringBuffer command = new StringBuffer(gcjJitCompiler); + command.append(" "); + command.append(classFile); + command.append(" "); + command.append(gcjJitCompilerOptions); + // These options are required. + command.append(" -findirect-dispatch -fjni -shared -fPIC -o "); + command.append(soFile); + Process p = Runtime.getRuntime().exec(command.toString()); + + // Read the process' stderr into a string. + StringBuffer err = new StringBuffer(); + InputStreamReader stderr = new InputStreamReader (p.getErrorStream()); + char[] inBuf = new char[500]; + int bytesRead; + while ((bytesRead = stderr.read (inBuf)) != -1) + err.append(inBuf, 0, bytesRead); + + if (p.waitFor() != 0) + { + // FIXME: we could log err.toString() somewhere... + return null; + } + + return loadSharedLibrary(loader, soFile.toString(), domain, name); + } + catch (Exception _) + { + return null; + } + } + + /** + * Compile the class named by <code>oneClass</code>. + * + * @param oneClass the class to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if oneClass is null + */ + public static boolean compileClass(Class oneClass) + { + // Never succeed. + return false; + } + + /** + * Compile the classes whose name matches <code>classNames</code>. + * + * @param classNames the name of classes to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if classNames is null + */ + public static boolean compileClasses(String classNames) + { + // Note the incredibly lame interface. Always fail. + return false; + } + + /** + * This method examines the argument and performs an operation + * according to the compilers documentation. No specific operation + * is required. + * + * @param arg a compiler-specific argument + * @return a compiler-specific value, including null + * @throws NullPointerException if the compiler doesn't like a null arg + */ + public static Object command(Object arg) + { + // Our implementation defines this to a no-op. + return null; + } + + /** + * Calling <code>Compiler.enable()</code> will cause the compiler + * to resume operation if it was previously disabled; provided that a + * compiler even exists. + */ + public static void enable() + { + useCompiler = true; + } + + /** + * Calling <code>Compiler.disable()</code> will cause the compiler + * to be suspended; provided that a compiler even exists. + */ + public static void disable() + { + useCompiler = false; + } +} diff --git a/libjava/java/lang/VMDouble.h b/libjava/java/lang/VMDouble.h new file mode 100644 index 000000000..76b6d5020 --- /dev/null +++ b/libjava/java/lang/VMDouble.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMDouble__ +#define __java_lang_VMDouble__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::VMDouble : public ::java::lang::Object +{ + +public: // actually package-private + VMDouble(); +public: + static jlong doubleToLongBits(jdouble); + static jlong doubleToRawLongBits(jdouble); + static jdouble longBitsToDouble(jlong); + static ::java::lang::String * toString(jdouble, jboolean); + static jdouble parseDouble(::java::lang::String *); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMDouble__ diff --git a/libjava/java/lang/VMDouble.java b/libjava/java/lang/VMDouble.java new file mode 100644 index 000000000..9205eb3b3 --- /dev/null +++ b/libjava/java/lang/VMDouble.java @@ -0,0 +1,111 @@ +/* VMDouble.java -- VM Specific Double methods + Copyright (C) 2003, 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.classpath.Configuration; + +/* + * This class is a reference version, mainly for compiling a class library + * jar. It is likely that VM implementers replace this with their own + * version that can communicate effectively with the VM. + */ + +/** + * Code relocated from java.lang.Double by + * @author Dave Grove (groved@us.ibm.com) + */ +final class VMDouble +{ + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * collapses all versions of NaN to 0x7ff8000000000000L. The result of this + * function can be used as the argument to + * <code>Double.longBitsToDouble(long)</code> to obtain the original + * <code>double</code> value. + * + * @param value the <code>double</code> to convert + * @return the bits of the <code>double</code> + * @see #longBitsToDouble(long) + */ + public static native long doubleToLongBits(double value); + + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * leaves NaN alone, rather than collapsing to a canonical value. The + * result of this function can be used as the argument to + * <code>Double.longBitsToDouble(long)</code> to obtain the original + * <code>double</code> value. + * + * @param value the <code>double</code> to convert + * @return the bits of the <code>double</code> + * @see #longBitsToDouble(long) + */ + public static native long doubleToRawLongBits(double value); + + /** + * Convert the argument in IEEE 754 floating-point "double format" bit + * layout to the corresponding float. Bit 63 (the most significant) is the + * sign bit, bits 62-52 (masked by 0x7ff0000000000000L) represent the + * exponent, and bits 51-0 (masked by 0x000fffffffffffffL) are the mantissa. + * This function leaves NaN alone, so that you can recover the bit pattern + * with <code>Double.doubleToRawLongBits(double)</code>. + * + * @param bits the bits to convert + * @return the <code>double</code> represented by the bits + * @see #doubleToLongBits(double) + * @see #doubleToRawLongBits(double) + */ + public static native double longBitsToDouble(long bits); + + /** + * Helper method to convert to string. + * + * @param d the double to convert + * @param isFloat true if the conversion is requested by Float (results in + * fewer digits) + */ + public static native String toString(double d, boolean isFloat); + + public static native double parseDouble(String str); +} diff --git a/libjava/java/lang/VMFloat.h b/libjava/java/lang/VMFloat.h new file mode 100644 index 000000000..fec037b2c --- /dev/null +++ b/libjava/java/lang/VMFloat.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMFloat__ +#define __java_lang_VMFloat__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::VMFloat : public ::java::lang::Object +{ + +public: // actually package-private + VMFloat(); + static jint floatToIntBits(jfloat); + static jint floatToRawIntBits(jfloat); + static jfloat intBitsToFloat(jint); + static ::java::lang::String * toString(jfloat); + static jfloat parseFloat(::java::lang::String *); +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMFloat__ diff --git a/libjava/java/lang/VMFloat.java b/libjava/java/lang/VMFloat.java new file mode 100644 index 000000000..72a8c3c6b --- /dev/null +++ b/libjava/java/lang/VMFloat.java @@ -0,0 +1,121 @@ +/* VMFloat.java -- VM Specific Float methods + Copyright (C) 2003, 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.classpath.Configuration; + +/* + * This class is a reference version, mainly for compiling a class library + * jar. It is likely that VM implementers replace this with their own + * version that can communicate effectively with the VM. + */ + +/** + * Code relocated from java.lang.Float by + * @author Dave Grove <groved@us.ibm.com> + */ +final class VMFloat +{ + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function collapses all + * versions of NaN to 0x7fc00000. The result of this function can be used + * as the argument to <code>Float.intBitsToFloat(int)</code> to obtain the + * original <code>float</code> value. + * + * @param value the <code>float</code> to convert + * @return the bits of the <code>float</code> + * @see #intBitsToFloat(int) + */ + static native int floatToIntBits(float value); + + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function leaves NaN alone, + * rather than collapsing to a canonical value. The result of this function + * can be used as the argument to <code>Float.intBitsToFloat(int)</code> to + * obtain the original <code>float</code> value. + * + * @param value the <code>float</code> to convert + * @return the bits of the <code>float</code> + * @see #intBitsToFloat(int) + */ + static native int floatToRawIntBits(float value); + + /** + * Convert the argument in IEEE 754 floating-point "single format" bit + * layout to the corresponding float. Bit 31 (the most significant) is the + * sign bit, bits 30-23 (masked by 0x7f800000) represent the exponent, and + * bits 22-0 (masked by 0x007fffff) are the mantissa. This function leaves + * NaN alone, so that you can recover the bit pattern with + * <code>Float.floatToRawIntBits(float)</code>. + * + * @param bits the bits to convert + * @return the <code>float</code> represented by the bits + * @see #floatToIntBits(float) + * @see #floatToRawIntBits(float) + */ + static native float intBitsToFloat(int bits); + + /** + * @param f the <code>float</code> to convert + * @return the <code>String</code> representing the <code>float</code> + */ + static String toString(float f) + { + return VMDouble.toString(f, true); + } + + /** + * @param str the <code>String</code> to convert + * @return the <code>float</code> value of <code>s</code> + * @throws NumberFormatException if <code>str</code> cannot be parsed as a + * <code>float</code> + * @throws NullPointerException if <code>str</code> is null + */ + static float parseFloat(String str) + { + // XXX Rounding parseDouble() causes some errors greater than 1 ulp from + // the infinitely precise decimal. + return (float) Double.parseDouble(str); + } +} // class VMFloat diff --git a/libjava/java/lang/VMProcess.h b/libjava/java/lang/VMProcess.h new file mode 100644 index 000000000..c0912e5c2 --- /dev/null +++ b/libjava/java/lang/VMProcess.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMProcess__ +#define __java_lang_VMProcess__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::VMProcess : public ::java::lang::Object +{ + +public: // actually package-private + VMProcess(); + static ::java::lang::Process * nativeExec(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); + static ::java::lang::Process * exec(::java::util::List *, ::java::util::Map *, ::java::io::File *, jboolean); +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMProcess__ diff --git a/libjava/java/lang/VMProcess.java b/libjava/java/lang/VMProcess.java new file mode 100644 index 000000000..c0c7bebc1 --- /dev/null +++ b/libjava/java/lang/VMProcess.java @@ -0,0 +1,68 @@ +/* java.lang.VMProcess -- VM implementation of java.lang.ProcessBuilder + Copyright (C) 2007 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.util.Iterator; +import java.util.List; +import java.util.Map; + +final class VMProcess +{ + static native Process nativeExec(String[] cmd, String[] env, + File dir, boolean redirect) + throws IOException; + + static Process exec(List<String> cmd, Map<String, String> 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 nativeExec(acmd, aenv, dir, redirect); + } +} diff --git a/libjava/java/lang/VMThrowable.h b/libjava/java/lang/VMThrowable.h new file mode 100644 index 000000000..1991b6cd8 --- /dev/null +++ b/libjava/java/lang/VMThrowable.h @@ -0,0 +1,36 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VMThrowable__ +#define __java_lang_VMThrowable__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawDataManaged; + } + } +} + +class java::lang::VMThrowable : public ::java::lang::Object +{ + + VMThrowable(); +public: // actually package-private + static ::java::lang::VMThrowable * fillInStackTrace(::java::lang::Throwable *); + JArray< ::java::lang::StackTraceElement * > * getStackTrace(::java::lang::Throwable *); +private: + ::gnu::gcj::RawDataManaged * __attribute__((aligned(__alignof__( ::java::lang::Object)))) data; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VMThrowable__ diff --git a/libjava/java/lang/VMThrowable.java b/libjava/java/lang/VMThrowable.java new file mode 100644 index 000000000..9dde28d29 --- /dev/null +++ b/libjava/java/lang/VMThrowable.java @@ -0,0 +1,82 @@ +/* java.lang.VMThrowable -- VM support methods for Throwable. + Copyright (C) 1998, 1999, 2002, 2004, 2005, 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 java.lang; + +import gnu.gcj.RawDataManaged; + +/** + * VM dependent state and support methods Throwable. + * It is deliberately package local and final and should only be accessed + * by the Throwable class. + * <p> + * This is the version used by libgcj (http://gcc.gnu.org/java/). + * + * @author Mark Wielaard (mark@klomp.org) + */ +final class VMThrowable +{ + /** + * Private contructor, create VMThrowables with StackTrace(); + */ + private VMThrowable() { } + + /** + * Fill in the stack trace with the current execution stack. + * Called by <code>Throwable.fillInStackTrace()</code> to get the state of + * the VM. Can return null when the VM does not support caputing the VM + * execution state. + * + * @return a new VMThrowable containing the current execution stack trace. + * @see Throwable#fillInStackTrace() + */ + static native VMThrowable fillInStackTrace(Throwable t); + + /** + * Returns an <code>StackTraceElement</code> array based on the execution + * state of the VM as captured by <code>fillInStackTrace</code>. + * Called by <code>Throwable.getStackTrace()</code>. + * + * @return a non-null but possible zero length array of StackTraceElement. + * @see Throwable#getStackTrace() + */ + native StackTraceElement[] getStackTrace(Throwable t); + + // Native stack data. + private RawDataManaged data; +} diff --git a/libjava/java/lang/VerifyError.h b/libjava/java/lang/VerifyError.h new file mode 100644 index 000000000..54aafd27e --- /dev/null +++ b/libjava/java/lang/VerifyError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VerifyError__ +#define __java_lang_VerifyError__ + +#pragma interface + +#include <java/lang/LinkageError.h> + +class java::lang::VerifyError : public ::java::lang::LinkageError +{ + +public: + VerifyError(); + VerifyError(::java::lang::String *); +private: + static const jlong serialVersionUID = 7001962396098498785LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VerifyError__ diff --git a/libjava/java/lang/VirtualMachineError.h b/libjava/java/lang/VirtualMachineError.h new file mode 100644 index 000000000..9eb04ceaa --- /dev/null +++ b/libjava/java/lang/VirtualMachineError.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_VirtualMachineError__ +#define __java_lang_VirtualMachineError__ + +#pragma interface + +#include <java/lang/Error.h> + +class java::lang::VirtualMachineError : public ::java::lang::Error +{ + +public: + VirtualMachineError(); + VirtualMachineError(::java::lang::String *); +private: + static const jlong serialVersionUID = 4161983926571568670LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_VirtualMachineError__ diff --git a/libjava/java/lang/Void.h b/libjava/java/lang/Void.h new file mode 100644 index 000000000..be277b02a --- /dev/null +++ b/libjava/java/lang/Void.h @@ -0,0 +1,20 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Void__ +#define __java_lang_Void__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::Void : public ::java::lang::Object +{ + + Void(); +public: + static ::java::lang::Class * TYPE; + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Void__ diff --git a/libjava/java/lang/Win32Process$EOFInputStream.h b/libjava/java/lang/Win32Process$EOFInputStream.h new file mode 100644 index 000000000..b0224f332 --- /dev/null +++ b/libjava/java/lang/Win32Process$EOFInputStream.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Win32Process$EOFInputStream__ +#define __java_lang_Win32Process$EOFInputStream__ + +#pragma interface + +#include <java/io/InputStream.h> + +class java::lang::Win32Process$EOFInputStream : public ::java::io::InputStream +{ + + Win32Process$EOFInputStream(); +public: + virtual jint read(); +public: // actually package-private + static ::java::lang::Win32Process$EOFInputStream * instance; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Win32Process$EOFInputStream__ diff --git a/libjava/java/lang/Win32Process.h b/libjava/java/lang/Win32Process.h new file mode 100644 index 000000000..5e22934a9 --- /dev/null +++ b/libjava/java/lang/Win32Process.h @@ -0,0 +1,37 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_Win32Process__ +#define __java_lang_Win32Process__ + +#pragma interface + +#include <java/lang/Process.h> +#include <gcj/array.h> + + +class java::lang::Win32Process : public ::java::lang::Process +{ + +public: + void destroy(); + jint exitValue(); + ::java::io::InputStream * getErrorStream(); + ::java::io::InputStream * getInputStream(); + ::java::io::OutputStream * getOutputStream(); + jint waitFor(); + Win32Process(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); +private: + jboolean hasExited(); + void startProcess(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); + void cleanup(); + ::java::io::OutputStream * __attribute__((aligned(__alignof__( ::java::lang::Process)))) outputStream; + ::java::io::InputStream * inputStream; + ::java::io::InputStream * errorStream; + jint procHandle; + jint exitCode; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_Win32Process__ diff --git a/libjava/java/lang/Win32Process.java b/libjava/java/lang/Win32Process.java new file mode 100644 index 000000000..f22b54882 --- /dev/null +++ b/libjava/java/lang/Win32Process.java @@ -0,0 +1,97 @@ +// Win32Process.java - Subclass of Process for Win32 systems. + +/* Copyright (C) 2002, 2003, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Adam Megacz + * @date Feb 24, 2002 + */ + +// This is entirely internal to our implementation. + +final class Win32Process extends Process +{ + public native void destroy (); + + public int exitValue () + { + if (! hasExited ()) + throw new IllegalThreadStateException ("Process has not exited"); + + return exitCode; + } + + public InputStream getErrorStream () + { + return errorStream; + } + + public InputStream getInputStream () + { + return inputStream; + } + + public OutputStream getOutputStream () + { + return outputStream; + } + + public native int waitFor () throws InterruptedException; + + public Win32Process (String[] progarray, String[] envp, File dir, + boolean redirect) + throws IOException + { + for (int i = 0; i < progarray.length; i++) + { + String s = progarray[i]; + + if ( (s.indexOf (' ') >= 0) || (s.indexOf ('\t') >= 0)) + progarray[i] = "\"" + s + "\""; + } + + startProcess (progarray, envp, dir, redirect); + } + + // The standard streams (stdin, stdout and stderr, respectively) + // of the child as seen by the parent process. + private OutputStream outputStream; + private InputStream inputStream; + private InputStream errorStream; + + // Handle to the child process - cast to HANDLE before use. + private int procHandle; + + // Exit code of the child if it has exited. + private int exitCode; + + private native boolean hasExited (); + private native void startProcess (String[] progarray, + String[] envp, + File dir, + boolean redirect) + throws IOException; + private native void cleanup (); + + private static class EOFInputStream extends InputStream + { + static EOFInputStream instance = new EOFInputStream(); + public int read() + { + return -1; + } + } +} diff --git a/libjava/java/lang/annotation/Annotation.h b/libjava/java/lang/annotation/Annotation.h new file mode 100644 index 000000000..9c9c3d7ab --- /dev/null +++ b/libjava/java/lang/annotation/Annotation.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_Annotation__ +#define __java_lang_annotation_Annotation__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::annotation::Annotation : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * annotationType() = 0; + virtual jboolean equals(::java::lang::Object *) = 0; + virtual jint hashCode() = 0; + virtual ::java::lang::String * toString() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_annotation_Annotation__ diff --git a/libjava/java/lang/annotation/AnnotationFormatError.h b/libjava/java/lang/annotation/AnnotationFormatError.h new file mode 100644 index 000000000..f5c43b241 --- /dev/null +++ b/libjava/java/lang/annotation/AnnotationFormatError.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_AnnotationFormatError__ +#define __java_lang_annotation_AnnotationFormatError__ + +#pragma interface + +#include <java/lang/Error.h> + +class java::lang::annotation::AnnotationFormatError : public ::java::lang::Error +{ + +public: + AnnotationFormatError(::java::lang::String *); + AnnotationFormatError(::java::lang::String *, ::java::lang::Throwable *); + AnnotationFormatError(::java::lang::Throwable *); +private: + static const jlong serialVersionUID = -4256701562333669892LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_annotation_AnnotationFormatError__ diff --git a/libjava/java/lang/annotation/AnnotationTypeMismatchException.h b/libjava/java/lang/annotation/AnnotationTypeMismatchException.h new file mode 100644 index 000000000..082d9f6a3 --- /dev/null +++ b/libjava/java/lang/annotation/AnnotationTypeMismatchException.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_AnnotationTypeMismatchException__ +#define __java_lang_annotation_AnnotationTypeMismatchException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::annotation::AnnotationTypeMismatchException : public ::java::lang::RuntimeException +{ + +public: + AnnotationTypeMismatchException(::java::lang::reflect::Method *, ::java::lang::String *); + virtual ::java::lang::reflect::Method * element(); + virtual ::java::lang::String * foundType(); +private: + static const jlong serialVersionUID = 8125925355765570191LL; + ::java::lang::reflect::Method * __attribute__((aligned(__alignof__( ::java::lang::RuntimeException)))) element__; + ::java::lang::String * foundType__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_annotation_AnnotationTypeMismatchException__ diff --git a/libjava/java/lang/annotation/Documented.h b/libjava/java/lang/annotation/Documented.h new file mode 100644 index 000000000..d2a920dc7 --- /dev/null +++ b/libjava/java/lang/annotation/Documented.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_Documented__ +#define __java_lang_annotation_Documented__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::annotation::Documented : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_annotation_Documented__ diff --git a/libjava/java/lang/annotation/ElementType.h b/libjava/java/lang/annotation/ElementType.h new file mode 100644 index 000000000..c475967ab --- /dev/null +++ b/libjava/java/lang/annotation/ElementType.h @@ -0,0 +1,35 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_ElementType__ +#define __java_lang_annotation_ElementType__ + +#pragma interface + +#include <java/lang/Enum.h> +#include <gcj/array.h> + + +class java::lang::annotation::ElementType : public ::java::lang::Enum +{ + + ElementType(::java::lang::String *, jint); +public: + static JArray< ::java::lang::annotation::ElementType * > * values(); + static ::java::lang::annotation::ElementType * valueOf(::java::lang::String *); + static ::java::lang::annotation::ElementType * ANNOTATION_TYPE; + static ::java::lang::annotation::ElementType * CONSTRUCTOR; + static ::java::lang::annotation::ElementType * FIELD; + static ::java::lang::annotation::ElementType * LOCAL_VARIABLE; + static ::java::lang::annotation::ElementType * METHOD; + static ::java::lang::annotation::ElementType * PACKAGE; + static ::java::lang::annotation::ElementType * PARAMETER; + static ::java::lang::annotation::ElementType * TYPE; +private: + static const jlong serialVersionUID = 2798216111136361587LL; + static JArray< ::java::lang::annotation::ElementType * > * ENUM$VALUES; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_annotation_ElementType__ diff --git a/libjava/java/lang/annotation/IncompleteAnnotationException.h b/libjava/java/lang/annotation/IncompleteAnnotationException.h new file mode 100644 index 000000000..aff0f7e0b --- /dev/null +++ b/libjava/java/lang/annotation/IncompleteAnnotationException.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_IncompleteAnnotationException__ +#define __java_lang_annotation_IncompleteAnnotationException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::annotation::IncompleteAnnotationException : public ::java::lang::RuntimeException +{ + +public: + IncompleteAnnotationException(::java::lang::Class *, ::java::lang::String *); + virtual ::java::lang::Class * annotationType(); + virtual ::java::lang::String * elementName(); +private: + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::RuntimeException)))) annotationType__; + ::java::lang::String * elementName__; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_annotation_IncompleteAnnotationException__ diff --git a/libjava/java/lang/annotation/Inherited.h b/libjava/java/lang/annotation/Inherited.h new file mode 100644 index 000000000..b1ebc883e --- /dev/null +++ b/libjava/java/lang/annotation/Inherited.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_Inherited__ +#define __java_lang_annotation_Inherited__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::annotation::Inherited : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_annotation_Inherited__ diff --git a/libjava/java/lang/annotation/Retention.h b/libjava/java/lang/annotation/Retention.h new file mode 100644 index 000000000..42fb4a542 --- /dev/null +++ b/libjava/java/lang/annotation/Retention.h @@ -0,0 +1,20 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_Retention__ +#define __java_lang_annotation_Retention__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::annotation::Retention : public ::java::lang::Object +{ + +public: + virtual ::java::lang::annotation::RetentionPolicy * value() = 0; + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_annotation_Retention__ diff --git a/libjava/java/lang/annotation/RetentionPolicy.h b/libjava/java/lang/annotation/RetentionPolicy.h new file mode 100644 index 000000000..5d642601d --- /dev/null +++ b/libjava/java/lang/annotation/RetentionPolicy.h @@ -0,0 +1,30 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_RetentionPolicy__ +#define __java_lang_annotation_RetentionPolicy__ + +#pragma interface + +#include <java/lang/Enum.h> +#include <gcj/array.h> + + +class java::lang::annotation::RetentionPolicy : public ::java::lang::Enum +{ + + RetentionPolicy(::java::lang::String *, jint); +public: + static JArray< ::java::lang::annotation::RetentionPolicy * > * values(); + static ::java::lang::annotation::RetentionPolicy * valueOf(::java::lang::String *); + static ::java::lang::annotation::RetentionPolicy * CLASS; + static ::java::lang::annotation::RetentionPolicy * RUNTIME; + static ::java::lang::annotation::RetentionPolicy * SOURCE; +private: + static const jlong serialVersionUID = -1700821648800605045LL; + static JArray< ::java::lang::annotation::RetentionPolicy * > * ENUM$VALUES; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_annotation_RetentionPolicy__ diff --git a/libjava/java/lang/annotation/Target.h b/libjava/java/lang/annotation/Target.h new file mode 100644 index 000000000..96ac51788 --- /dev/null +++ b/libjava/java/lang/annotation/Target.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_annotation_Target__ +#define __java_lang_annotation_Target__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::annotation::Target : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::annotation::ElementType * > * value() = 0; + virtual ::java::lang::Class * annotationType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_annotation_Target__ diff --git a/libjava/java/lang/instrument/ClassDefinition.h b/libjava/java/lang/instrument/ClassDefinition.h new file mode 100644 index 000000000..b9106ed8e --- /dev/null +++ b/libjava/java/lang/instrument/ClassDefinition.h @@ -0,0 +1,27 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_instrument_ClassDefinition__ +#define __java_lang_instrument_ClassDefinition__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::instrument::ClassDefinition : public ::java::lang::Object +{ + +public: + ClassDefinition(::java::lang::Class *, JArray< jbyte > *); + ::java::lang::Class * getDefinitionClass(); + JArray< jbyte > * getDefinitionClassFile(); +private: + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::Object)))) theClass; + JArray< jbyte > * theClassFile; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_instrument_ClassDefinition__ diff --git a/libjava/java/lang/instrument/ClassFileTransformer.h b/libjava/java/lang/instrument/ClassFileTransformer.h new file mode 100644 index 000000000..cda1510b0 --- /dev/null +++ b/libjava/java/lang/instrument/ClassFileTransformer.h @@ -0,0 +1,31 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_instrument_ClassFileTransformer__ +#define __java_lang_instrument_ClassFileTransformer__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace java + { + namespace security + { + class ProtectionDomain; + } + } +} + +class java::lang::instrument::ClassFileTransformer : public ::java::lang::Object +{ + +public: + virtual JArray< jbyte > * transform(::java::lang::ClassLoader *, ::java::lang::String *, ::java::lang::Class *, ::java::security::ProtectionDomain *, JArray< jbyte > *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_instrument_ClassFileTransformer__ diff --git a/libjava/java/lang/instrument/IllegalClassFormatException.h b/libjava/java/lang/instrument/IllegalClassFormatException.h new file mode 100644 index 000000000..c1b8783e7 --- /dev/null +++ b/libjava/java/lang/instrument/IllegalClassFormatException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_instrument_IllegalClassFormatException__ +#define __java_lang_instrument_IllegalClassFormatException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::instrument::IllegalClassFormatException : public ::java::lang::Exception +{ + +public: + IllegalClassFormatException(); + IllegalClassFormatException(::java::lang::String *); +private: + static const jlong serialVersionUID = -3841736710924794009LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_instrument_IllegalClassFormatException__ diff --git a/libjava/java/lang/instrument/Instrumentation.h b/libjava/java/lang/instrument/Instrumentation.h new file mode 100644 index 000000000..d131d0c69 --- /dev/null +++ b/libjava/java/lang/instrument/Instrumentation.h @@ -0,0 +1,27 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_instrument_Instrumentation__ +#define __java_lang_instrument_Instrumentation__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::instrument::Instrumentation : public ::java::lang::Object +{ + +public: + virtual void addTransformer(::java::lang::instrument::ClassFileTransformer *) = 0; + virtual jboolean removeTransformer(::java::lang::instrument::ClassFileTransformer *) = 0; + virtual jboolean isRedefineClassesSupported() = 0; + virtual void redefineClasses(JArray< ::java::lang::instrument::ClassDefinition * > *) = 0; + virtual JArray< ::java::lang::Class * > * getAllLoadedClasses() = 0; + virtual JArray< ::java::lang::Class * > * getInitiatedClasses(::java::lang::ClassLoader *) = 0; + virtual jlong getObjectSize(::java::lang::Object *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_instrument_Instrumentation__ diff --git a/libjava/java/lang/instrument/UnmodifiableClassException.h b/libjava/java/lang/instrument/UnmodifiableClassException.h new file mode 100644 index 000000000..e5fac3cdd --- /dev/null +++ b/libjava/java/lang/instrument/UnmodifiableClassException.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_instrument_UnmodifiableClassException__ +#define __java_lang_instrument_UnmodifiableClassException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::instrument::UnmodifiableClassException : public ::java::lang::Exception +{ + +public: + UnmodifiableClassException(); + UnmodifiableClassException(::java::lang::String *); +private: + static const jlong serialVersionUID = 1716652643585309178LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_instrument_UnmodifiableClassException__ diff --git a/libjava/java/lang/management/ClassLoadingMXBean.h b/libjava/java/lang/management/ClassLoadingMXBean.h new file mode 100644 index 000000000..371b63d3d --- /dev/null +++ b/libjava/java/lang/management/ClassLoadingMXBean.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ClassLoadingMXBean__ +#define __java_lang_management_ClassLoadingMXBean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::ClassLoadingMXBean : public ::java::lang::Object +{ + +public: + virtual jint getLoadedClassCount() = 0; + virtual jlong getTotalLoadedClassCount() = 0; + virtual jlong getUnloadedClassCount() = 0; + virtual jboolean isVerbose() = 0; + virtual void setVerbose(jboolean) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_ClassLoadingMXBean__ diff --git a/libjava/java/lang/management/CompilationMXBean.h b/libjava/java/lang/management/CompilationMXBean.h new file mode 100644 index 000000000..bbd1e0a21 --- /dev/null +++ b/libjava/java/lang/management/CompilationMXBean.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_CompilationMXBean__ +#define __java_lang_management_CompilationMXBean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::CompilationMXBean : public ::java::lang::Object +{ + +public: + virtual ::java::lang::String * getName() = 0; + virtual jboolean isCompilationTimeMonitoringSupported() = 0; + virtual jlong getTotalCompilationTime() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_CompilationMXBean__ diff --git a/libjava/java/lang/management/GarbageCollectorMXBean.h b/libjava/java/lang/management/GarbageCollectorMXBean.h new file mode 100644 index 000000000..35222cab0 --- /dev/null +++ b/libjava/java/lang/management/GarbageCollectorMXBean.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_GarbageCollectorMXBean__ +#define __java_lang_management_GarbageCollectorMXBean__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::management::GarbageCollectorMXBean : public ::java::lang::Object +{ + +public: + virtual jlong getCollectionCount() = 0; + virtual jlong getCollectionTime() = 0; + virtual JArray< ::java::lang::String * > * getMemoryPoolNames() = 0; + virtual ::java::lang::String * getName() = 0; + virtual jboolean isValid() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_GarbageCollectorMXBean__ diff --git a/libjava/java/lang/management/LockInfo.h b/libjava/java/lang/management/LockInfo.h new file mode 100644 index 000000000..ec4291753 --- /dev/null +++ b/libjava/java/lang/management/LockInfo.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_LockInfo__ +#define __java_lang_management_LockInfo__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::LockInfo : public ::java::lang::Object +{ + +public: + LockInfo(::java::lang::String *, jint); + virtual ::java::lang::String * getClassName(); + virtual jint getIdentityHashCode(); + virtual ::java::lang::String * toString(); +private: + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) className; + jint identityHashCode; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_LockInfo__ diff --git a/libjava/java/lang/management/ManagementFactory$ManagementInvocationHandler.h b/libjava/java/lang/management/ManagementFactory$ManagementInvocationHandler.h new file mode 100644 index 000000000..33603be20 --- /dev/null +++ b/libjava/java/lang/management/ManagementFactory$ManagementInvocationHandler.h @@ -0,0 +1,38 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ManagementFactory$ManagementInvocationHandler__ +#define __java_lang_management_ManagementFactory$ManagementInvocationHandler__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace javax + { + namespace management + { + class MBeanServerConnection; + class ObjectName; + } + } +} + +class java::lang::management::ManagementFactory$ManagementInvocationHandler : public ::java::lang::Object +{ + +public: + ManagementFactory$ManagementInvocationHandler(::javax::management::MBeanServerConnection *, ::javax::management::ObjectName *); + virtual ::java::lang::Object * invoke(::java::lang::Object *, ::java::lang::reflect::Method *, JArray< ::java::lang::Object * > *); +private: + ::java::lang::Object * translate(::java::lang::Object *, ::java::lang::reflect::Method *); + ::javax::management::MBeanServerConnection * __attribute__((aligned(__alignof__( ::java::lang::Object)))) conn; + ::javax::management::ObjectName * bean; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_ManagementFactory$ManagementInvocationHandler__ diff --git a/libjava/java/lang/management/ManagementFactory.h b/libjava/java/lang/management/ManagementFactory.h new file mode 100644 index 000000000..c51809371 --- /dev/null +++ b/libjava/java/lang/management/ManagementFactory.h @@ -0,0 +1,59 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ManagementFactory__ +#define __java_lang_management_ManagementFactory__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace javax + { + namespace management + { + class MBeanServer; + class MBeanServerConnection; + } + } +} + +class java::lang::management::ManagementFactory : public ::java::lang::Object +{ + + ManagementFactory(); +public: + static ::java::lang::management::OperatingSystemMXBean * getOperatingSystemMXBean(); + static ::java::lang::management::RuntimeMXBean * getRuntimeMXBean(); + static ::java::lang::management::ClassLoadingMXBean * getClassLoadingMXBean(); + static ::java::lang::management::ThreadMXBean * getThreadMXBean(); + static ::java::lang::management::MemoryMXBean * getMemoryMXBean(); + static ::java::lang::management::CompilationMXBean * getCompilationMXBean(); + static ::java::util::List * getMemoryPoolMXBeans(); + static ::java::util::List * getMemoryManagerMXBeans(); + static ::java::util::List * getGarbageCollectorMXBeans(); + static ::javax::management::MBeanServer * getPlatformMBeanServer(); + static ::java::lang::Object * newPlatformMXBeanProxy(::javax::management::MBeanServerConnection *, ::java::lang::String *, ::java::lang::Class *); + static ::java::lang::String * CLASS_LOADING_MXBEAN_NAME; + static ::java::lang::String * COMPILATION_MXBEAN_NAME; + static ::java::lang::String * GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE; + static ::java::lang::String * MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE; + static ::java::lang::String * MEMORY_MXBEAN_NAME; + static ::java::lang::String * MEMORY_POOL_MXBEAN_DOMAIN_TYPE; + static ::java::lang::String * OPERATING_SYSTEM_MXBEAN_NAME; + static ::java::lang::String * RUNTIME_MXBEAN_NAME; + static ::java::lang::String * THREAD_MXBEAN_NAME; +private: + static ::java::lang::management::OperatingSystemMXBean * osBean; + static ::java::lang::management::RuntimeMXBean * runtimeBean; + static ::java::lang::management::ClassLoadingMXBean * classLoadingBean; + static ::java::lang::management::ThreadMXBean * threadBean; + static ::java::lang::management::MemoryMXBean * memoryBean; + static ::java::lang::management::CompilationMXBean * compilationBean; + static ::javax::management::MBeanServer * platformServer; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_ManagementFactory__ diff --git a/libjava/java/lang/management/ManagementPermission.h b/libjava/java/lang/management/ManagementPermission.h new file mode 100644 index 000000000..4ac4a4fef --- /dev/null +++ b/libjava/java/lang/management/ManagementPermission.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ManagementPermission__ +#define __java_lang_management_ManagementPermission__ + +#pragma interface + +#include <java/security/BasicPermission.h> + +class java::lang::management::ManagementPermission : public ::java::security::BasicPermission +{ + +public: + ManagementPermission(::java::lang::String *); + ManagementPermission(::java::lang::String *, ::java::lang::String *); +private: + static const jlong serialVersionUID = 1897496590799378737LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_ManagementPermission__ diff --git a/libjava/java/lang/management/MemoryMXBean.h b/libjava/java/lang/management/MemoryMXBean.h new file mode 100644 index 000000000..2fb70add2 --- /dev/null +++ b/libjava/java/lang/management/MemoryMXBean.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryMXBean__ +#define __java_lang_management_MemoryMXBean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::MemoryMXBean : public ::java::lang::Object +{ + +public: + virtual void gc() = 0; + virtual ::java::lang::management::MemoryUsage * getHeapMemoryUsage() = 0; + virtual ::java::lang::management::MemoryUsage * getNonHeapMemoryUsage() = 0; + virtual jint getObjectPendingFinalizationCount() = 0; + virtual jboolean isVerbose() = 0; + virtual void setVerbose(jboolean) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_MemoryMXBean__ diff --git a/libjava/java/lang/management/MemoryManagerMXBean.h b/libjava/java/lang/management/MemoryManagerMXBean.h new file mode 100644 index 000000000..6509205a9 --- /dev/null +++ b/libjava/java/lang/management/MemoryManagerMXBean.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryManagerMXBean__ +#define __java_lang_management_MemoryManagerMXBean__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::management::MemoryManagerMXBean : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::String * > * getMemoryPoolNames() = 0; + virtual ::java::lang::String * getName() = 0; + virtual jboolean isValid() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_MemoryManagerMXBean__ diff --git a/libjava/java/lang/management/MemoryNotificationInfo.h b/libjava/java/lang/management/MemoryNotificationInfo.h new file mode 100644 index 000000000..07cfefff3 --- /dev/null +++ b/libjava/java/lang/management/MemoryNotificationInfo.h @@ -0,0 +1,43 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryNotificationInfo__ +#define __java_lang_management_MemoryNotificationInfo__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace javax + { + namespace management + { + namespace openmbean + { + class CompositeData; + } + } + } +} + +class java::lang::management::MemoryNotificationInfo : public ::java::lang::Object +{ + +public: + MemoryNotificationInfo(::java::lang::String *, ::java::lang::management::MemoryUsage *, jlong); + static ::java::lang::management::MemoryNotificationInfo * from(::javax::management::openmbean::CompositeData *); + virtual jlong getCount(); + virtual ::java::lang::String * getPoolName(); + virtual ::java::lang::management::MemoryUsage * getUsage(); + static ::java::lang::String * MEMORY_THRESHOLD_EXCEEDED; + static ::java::lang::String * MEMORY_COLLECTION_THRESHOLD_EXCEEDED; +private: + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) poolName; + ::java::lang::management::MemoryUsage * usage; + jlong count; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_MemoryNotificationInfo__ diff --git a/libjava/java/lang/management/MemoryPoolMXBean.h b/libjava/java/lang/management/MemoryPoolMXBean.h new file mode 100644 index 000000000..4209d573a --- /dev/null +++ b/libjava/java/lang/management/MemoryPoolMXBean.h @@ -0,0 +1,38 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryPoolMXBean__ +#define __java_lang_management_MemoryPoolMXBean__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::management::MemoryPoolMXBean : public ::java::lang::Object +{ + +public: + virtual ::java::lang::management::MemoryUsage * getCollectionUsage() = 0; + virtual jlong getCollectionUsageThreshold() = 0; + virtual jlong getCollectionUsageThresholdCount() = 0; + virtual JArray< ::java::lang::String * > * getMemoryManagerNames() = 0; + virtual ::java::lang::String * getName() = 0; + virtual ::java::lang::management::MemoryUsage * getPeakUsage() = 0; + virtual ::java::lang::management::MemoryType * getType() = 0; + virtual ::java::lang::management::MemoryUsage * getUsage() = 0; + virtual jlong getUsageThreshold() = 0; + virtual jlong getUsageThresholdCount() = 0; + virtual jboolean isCollectionUsageThresholdExceeded() = 0; + virtual jboolean isCollectionUsageThresholdSupported() = 0; + virtual jboolean isUsageThresholdExceeded() = 0; + virtual jboolean isUsageThresholdSupported() = 0; + virtual jboolean isValid() = 0; + virtual void resetPeakUsage() = 0; + virtual void setCollectionUsageThreshold(jlong) = 0; + virtual void setUsageThreshold(jlong) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_MemoryPoolMXBean__ diff --git a/libjava/java/lang/management/MemoryType.h b/libjava/java/lang/management/MemoryType.h new file mode 100644 index 000000000..b93587d30 --- /dev/null +++ b/libjava/java/lang/management/MemoryType.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryType__ +#define __java_lang_management_MemoryType__ + +#pragma interface + +#include <java/lang/Enum.h> +#include <gcj/array.h> + + +class java::lang::management::MemoryType : public ::java::lang::Enum +{ + + MemoryType(::java::lang::String *, jint); +public: + static JArray< ::java::lang::management::MemoryType * > * values(); + static ::java::lang::management::MemoryType * valueOf(::java::lang::String *); + static ::java::lang::management::MemoryType * HEAP; + static ::java::lang::management::MemoryType * NON_HEAP; +private: + static JArray< ::java::lang::management::MemoryType * > * ENUM$VALUES; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_MemoryType__ diff --git a/libjava/java/lang/management/MemoryUsage.h b/libjava/java/lang/management/MemoryUsage.h new file mode 100644 index 000000000..3b126f818 --- /dev/null +++ b/libjava/java/lang/management/MemoryUsage.h @@ -0,0 +1,44 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MemoryUsage__ +#define __java_lang_management_MemoryUsage__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace javax + { + namespace management + { + namespace openmbean + { + class CompositeData; + } + } + } +} + +class java::lang::management::MemoryUsage : public ::java::lang::Object +{ + +public: + MemoryUsage(jlong, jlong, jlong, jlong); + static ::java::lang::management::MemoryUsage * from(::javax::management::openmbean::CompositeData *); + virtual jlong getCommitted(); + virtual jlong getInit(); + virtual jlong getMax(); + virtual jlong getUsed(); + virtual ::java::lang::String * toString(); +private: + jlong __attribute__((aligned(__alignof__( ::java::lang::Object)))) init; + jlong used; + jlong committed; + jlong maximum; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_MemoryUsage__ diff --git a/libjava/java/lang/management/MonitorInfo.h b/libjava/java/lang/management/MonitorInfo.h new file mode 100644 index 000000000..6d2a0f01f --- /dev/null +++ b/libjava/java/lang/management/MonitorInfo.h @@ -0,0 +1,39 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_MonitorInfo__ +#define __java_lang_management_MonitorInfo__ + +#pragma interface + +#include <java/lang/management/LockInfo.h> +extern "Java" +{ + namespace javax + { + namespace management + { + namespace openmbean + { + class CompositeData; + } + } + } +} + +class java::lang::management::MonitorInfo : public ::java::lang::management::LockInfo +{ + +public: + MonitorInfo(::java::lang::String *, jint, jint, ::java::lang::StackTraceElement *); + static ::java::lang::management::MonitorInfo * from(::javax::management::openmbean::CompositeData *); + virtual jint getLockedStackDepth(); + virtual ::java::lang::StackTraceElement * getLockedStackFrame(); +private: + jint __attribute__((aligned(__alignof__( ::java::lang::management::LockInfo)))) stackDepth; + ::java::lang::StackTraceElement * stackFrame; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_MonitorInfo__ diff --git a/libjava/java/lang/management/OperatingSystemMXBean.h b/libjava/java/lang/management/OperatingSystemMXBean.h new file mode 100644 index 000000000..bbf37070b --- /dev/null +++ b/libjava/java/lang/management/OperatingSystemMXBean.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_OperatingSystemMXBean__ +#define __java_lang_management_OperatingSystemMXBean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::OperatingSystemMXBean : public ::java::lang::Object +{ + +public: + virtual ::java::lang::String * getArch() = 0; + virtual jint getAvailableProcessors() = 0; + virtual ::java::lang::String * getName() = 0; + virtual jdouble getSystemLoadAverage() = 0; + virtual ::java::lang::String * getVersion() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_OperatingSystemMXBean__ diff --git a/libjava/java/lang/management/RuntimeMXBean.h b/libjava/java/lang/management/RuntimeMXBean.h new file mode 100644 index 000000000..c26667440 --- /dev/null +++ b/libjava/java/lang/management/RuntimeMXBean.h @@ -0,0 +1,34 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_RuntimeMXBean__ +#define __java_lang_management_RuntimeMXBean__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::management::RuntimeMXBean : public ::java::lang::Object +{ + +public: + virtual ::java::lang::String * getBootClassPath() = 0; + virtual ::java::lang::String * getClassPath() = 0; + virtual ::java::util::List * getInputArguments() = 0; + virtual ::java::lang::String * getLibraryPath() = 0; + virtual ::java::lang::String * getManagementSpecVersion() = 0; + virtual ::java::lang::String * getName() = 0; + virtual ::java::lang::String * getSpecName() = 0; + virtual ::java::lang::String * getSpecVendor() = 0; + virtual ::java::lang::String * getSpecVersion() = 0; + virtual jlong getStartTime() = 0; + virtual ::java::util::Map * getSystemProperties() = 0; + virtual jlong getUptime() = 0; + virtual ::java::lang::String * getVmName() = 0; + virtual ::java::lang::String * getVmVendor() = 0; + virtual ::java::lang::String * getVmVersion() = 0; + virtual jboolean isBootClassPathSupported() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_RuntimeMXBean__ diff --git a/libjava/java/lang/management/ThreadInfo.h b/libjava/java/lang/management/ThreadInfo.h new file mode 100644 index 000000000..4d87277be --- /dev/null +++ b/libjava/java/lang/management/ThreadInfo.h @@ -0,0 +1,77 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ThreadInfo__ +#define __java_lang_management_ThreadInfo__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace javax + { + namespace management + { + namespace openmbean + { + class CompositeData; + class CompositeType; + class OpenType; + } + } + } +} + +class java::lang::management::ThreadInfo : public ::java::lang::Object +{ + + ThreadInfo(jlong, ::java::lang::String *, ::java::lang::Thread$State *, jlong, jlong, ::java::lang::String *, jlong, ::java::lang::String *, jlong, jlong, jboolean, jboolean, JArray< ::java::lang::StackTraceElement * > *, JArray< ::java::lang::management::MonitorInfo * > *, JArray< ::java::lang::management::LockInfo * > *); +public: // actually package-private + static void checkAttribute(::javax::management::openmbean::CompositeType *, ::java::lang::String *, ::javax::management::openmbean::OpenType *); + static ::javax::management::openmbean::CompositeType * getStackTraceType(); +public: + static ::java::lang::management::ThreadInfo * from(::javax::management::openmbean::CompositeData *); + virtual jlong getBlockedCount(); + virtual jlong getBlockedTime(); + virtual JArray< ::java::lang::management::MonitorInfo * > * getLockedMonitors(); + virtual JArray< ::java::lang::management::LockInfo * > * getLockedSynchronizers(); + virtual ::java::lang::management::LockInfo * getLockInfo(); + virtual ::java::lang::String * getLockName(); + virtual jlong getLockOwnerId(); + virtual ::java::lang::String * getLockOwnerName(); + virtual JArray< ::java::lang::StackTraceElement * > * getStackTrace(); + virtual jlong getThreadId(); + virtual ::java::lang::String * getThreadName(); + virtual ::java::lang::Thread$State * getThreadState(); + virtual jlong getWaitedCount(); + virtual jlong getWaitedTime(); + virtual jboolean isInNative(); + virtual jboolean isSuspended(); + virtual ::java::lang::String * toString(); +private: + jboolean isThreadBlocked(); + jlong __attribute__((aligned(__alignof__( ::java::lang::Object)))) threadId; + ::java::lang::String * threadName; + ::java::lang::Thread$State * threadState; + jlong blockedCount; + jlong blockedTime; + ::java::lang::String * lockName; + jlong lockOwnerId; + ::java::lang::String * lockOwnerName; + jlong waitedCount; + jlong waitedTime; + jboolean isInNative__; + jboolean isSuspended__; + JArray< ::java::lang::StackTraceElement * > * trace; + JArray< ::java::lang::management::MonitorInfo * > * lockedMonitors; + JArray< ::java::lang::management::LockInfo * > * lockedSynchronizers; + static ::java::lang::management::ThreadMXBean * bean; + static ::javax::management::openmbean::CompositeType * seType; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_ThreadInfo__ diff --git a/libjava/java/lang/management/ThreadMXBean.h b/libjava/java/lang/management/ThreadMXBean.h new file mode 100644 index 000000000..a1d4636c9 --- /dev/null +++ b/libjava/java/lang/management/ThreadMXBean.h @@ -0,0 +1,47 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_ThreadMXBean__ +#define __java_lang_management_ThreadMXBean__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::management::ThreadMXBean : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::management::ThreadInfo * > * dumpAllThreads(jboolean, jboolean) = 0; + virtual JArray< jlong > * findDeadlockedThreads() = 0; + virtual JArray< jlong > * findMonitorDeadlockedThreads() = 0; + virtual JArray< jlong > * getAllThreadIds() = 0; + virtual jlong getCurrentThreadCpuTime() = 0; + virtual jlong getCurrentThreadUserTime() = 0; + virtual jint getDaemonThreadCount() = 0; + virtual jint getPeakThreadCount() = 0; + virtual jint getThreadCount() = 0; + virtual jlong getThreadCpuTime(jlong) = 0; + virtual ::java::lang::management::ThreadInfo * getThreadInfo(jlong) = 0; + virtual JArray< ::java::lang::management::ThreadInfo * > * getThreadInfo(JArray< jlong > *) = 0; + virtual JArray< ::java::lang::management::ThreadInfo * > * getThreadInfo(JArray< jlong > *, jboolean, jboolean) = 0; + virtual ::java::lang::management::ThreadInfo * getThreadInfo(jlong, jint) = 0; + virtual JArray< ::java::lang::management::ThreadInfo * > * getThreadInfo(JArray< jlong > *, jint) = 0; + virtual jlong getThreadUserTime(jlong) = 0; + virtual jlong getTotalStartedThreadCount() = 0; + virtual jboolean isCurrentThreadCpuTimeSupported() = 0; + virtual jboolean isObjectMonitorUsageSupported() = 0; + virtual jboolean isSynchronizerUsageSupported() = 0; + virtual jboolean isThreadContentionMonitoringEnabled() = 0; + virtual jboolean isThreadContentionMonitoringSupported() = 0; + virtual jboolean isThreadCpuTimeEnabled() = 0; + virtual jboolean isThreadCpuTimeSupported() = 0; + virtual void resetPeakThreadCount() = 0; + virtual void setThreadContentionMonitoringEnabled(jboolean) = 0; + virtual void setThreadCpuTimeEnabled(jboolean) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_management_ThreadMXBean__ diff --git a/libjava/java/lang/management/VMManagementFactory.h b/libjava/java/lang/management/VMManagementFactory.h new file mode 100644 index 000000000..e712cbfc8 --- /dev/null +++ b/libjava/java/lang/management/VMManagementFactory.h @@ -0,0 +1,25 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_management_VMManagementFactory__ +#define __java_lang_management_VMManagementFactory__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::management::VMManagementFactory : public ::java::lang::Object +{ + +public: // actually package-private + VMManagementFactory(); + static JArray< ::java::lang::String * > * getMemoryPoolNames(); + static JArray< ::java::lang::String * > * getMemoryManagerNames(); + static JArray< ::java::lang::String * > * getGarbageCollectorNames(); +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_management_VMManagementFactory__ diff --git a/libjava/java/lang/management/VMManagementFactory.java b/libjava/java/lang/management/VMManagementFactory.java new file mode 100644 index 000000000..35b15e360 --- /dev/null +++ b/libjava/java/lang/management/VMManagementFactory.java @@ -0,0 +1,87 @@ +/* VMManagementFactory.java - VM interface for obtaining system beans. + Copyright (C) 2006, 2007 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.management; + +/** + * Provides lists of resources required by the + * {@link java.lang.management.ManagementFactory} for + * creating beans. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +final class VMManagementFactory +{ + + /** + * Return a list of the names of the currently available + * memory pools within the virtual machine. + * + * @return a list of memory pool names. + */ + static String[] getMemoryPoolNames() + { + String[] result = {"Heap"}; + return result; + } + + /** + * Return a list of the names of the currently available + * memory managers within the virtual machine. This should + * not include the garbage collectors listed below. + * + * @return a list of memory manager names. + */ + static String[] getMemoryManagerNames() + { + String[] result = {}; + return result; + } + + /** + * Return a list of the names of the currently available + * garbage collectors within the virtual machine. + * + * @return a list of garbage collector names. + */ + static String[] getGarbageCollectorNames() + { + String[] result = {"BoehmGC"}; + return result; + } +} diff --git a/libjava/java/lang/natAbstractStringBuffer.cc b/libjava/java/lang/natAbstractStringBuffer.cc new file mode 100644 index 000000000..b2df69cc3 --- /dev/null +++ b/libjava/java/lang/natAbstractStringBuffer.cc @@ -0,0 +1,41 @@ +// natStringBuffer.cc - Implementation of java.lang.StringBuffer native methods. + +/* Copyright (C) 2001, 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <gcj/cni.h> +#include <java/lang/AbstractStringBuffer.h> + +java::lang::AbstractStringBuffer* +java::lang::AbstractStringBuffer::append (jint num) +{ + // Use an array large enough for "-2147483648"; i.e. 11 chars. + jchar buffer[11]; + int i = _Jv_FormatInt (buffer+11, num); + jint needed = count + i; + ensureCapacity_unsynchronized (needed); + jchar* dst = elements (value) + count; + jchar* src = buffer+11-i; + while (--i >= 0) + *dst++ = *src++; + count = needed; + return this; +} + +jboolean +java::lang::AbstractStringBuffer::regionMatches(jint toffset, jstring other) +{ + jint len = other->count; + jchar *tptr = elements(value) + toffset; + jchar *optr = JvGetStringChars(other); + while (--len >= 0) + if (*tptr++ != *optr++) + return false; + return true; +} diff --git a/libjava/java/lang/natCharacter.cc b/libjava/java/lang/natCharacter.cc new file mode 100644 index 000000000..dea2086eb --- /dev/null +++ b/libjava/java/lang/natCharacter.cc @@ -0,0 +1,235 @@ +/* java.lang.Character -- Wrapper class for char, and Unicode subsets + Copyright (C) 1998, 1999, 2001, 2002, 2007 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. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Character.h> + +#include <java-chartables.h> + + + +// These constants define the return values for characters that are unassigned +// or reserved for private use. +#define UNASSIGNED_TYPE 0 +#define UNASSIGNED_DIGIT -1 +#define UNASSIGNED_DIRECTION -1 +#define UNASSIGNED_NUMERIC_VALUE -1 + +#define PRIVATE_TYPE 18 +#define PRIVATE_DIRECTION 0 + +// The methods that take a char as an argument all have counterparts that +// take ints. The ones that take chars only work for the BMP or plane 0 of the +// Unicode standard but the ones that take ints work for all Unicode code +// points. However, the ones that take chars don't simply redirect the calls +// because the BMP is by far the most used plane so saving a little time on +// each call makes sense. + +jchar +java::lang::Character::readChar(jchar ch) +{ + // Perform 16-bit addition to find the correct entry in data. + return data[0][(jchar) (blocks[0][ch >> shift[0]] + ch)]; +} + +jchar +java::lang::Character::readCodePoint(jint codePoint) +{ + jint plane = codePoint >> 16; + jchar offset = (jchar)(codePoint & 0xffff); + // Be careful not to call this method with an unassigned character. The only + // characters assigned as of Unicode 4.0.0 belong to planes 0, 1, 2, and 14. + return data[plane][(jchar) (blocks[plane][offset >> shift[plane]] + offset)]; +} + +jint +java::lang::Character::getType(jchar ch) +{ + // Perform 16-bit addition to find the correct entry in data. + return (jint) (data[0][(jchar) (blocks[0][ch >> shift[0]] + ch)] & TYPE_MASK); +} + +jint +java::lang::Character::getType(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + { + if (plane > 14 && ((codePoint & 0xffff) < 0xfffe)) + return (jint) PRIVATE_TYPE; + return (jint) UNASSIGNED_TYPE; + } + jint offset = codePoint & 0xffff; + return (jint) + (data[plane] + [(jchar) (blocks[plane][offset >> shift[plane]] + offset)] & TYPE_MASK); +} + +jchar +java::lang::Character::toLowerCase(jchar ch) +{ + return (jchar) (ch + lower[0][readChar(ch) >> 7]); +} + +jint +java::lang::Character::toLowerCase(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + return codePoint; + return (lower[plane][readCodePoint(codePoint) >> 7]) + codePoint; +} + +jchar +java::lang::Character::toUpperCase(jchar ch) +{ + return (jchar) (ch + upper[0][readChar(ch) >> 7]); +} + +jint +java::lang::Character::toUpperCase(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + return codePoint; + return (upper[plane][readCodePoint(codePoint) >> 7]) + codePoint; +} + +jchar +java::lang::Character::toTitleCase(jchar ch) +{ + // As title is short, it doesn't hurt to exhaustively iterate over it. + for (int i = title_length - 2; i >= 0; i -= 2) + if (title[i] == ch) + return title[i + 1]; + return toUpperCase(ch); +} + +jint +java::lang::Character::toTitleCase(jint codePoint) +{ + // As of Unicode 4.0.0 no characters outside of plane 0 have titlecase + // mappings that are different from their uppercase mapping. + if (codePoint >= 0 && codePoint < 0x10000) + return toTitleCase((jchar)codePoint); + return toUpperCase(codePoint); +} + +jint +java::lang::Character::digit(jchar ch, jint radix) +{ + if (radix < MIN_RADIX || radix > MAX_RADIX) + return (jint) -1; + jchar attr = readChar(ch); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER)))) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + jint digit = (jint) numValue[0][attr >> 7]; + return (digit >= 0 && digit < radix) ? digit : (jint) -1; + } + return (jint) -1; +} + +jint +java::lang::Character::digit(jint codePoint, jint radix) +{ + if (radix < MIN_RADIX || radix > MAX_RADIX) + return (jint) -1; + + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + return UNASSIGNED_DIGIT; + + jchar attr = readCodePoint(codePoint); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER)))) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + jint digit = (jint) numValue[plane][attr >> 7]; + if (digit <= -3) + digit = largenums[-digit -3]; + return (digit >= 0 && digit < radix) ? digit : (jint) -1; + } + return (jint) -1; + +} + +jint +java::lang::Character::getNumericValue(jchar ch) +{ + // numValue is stored as an array of jshort, since 10000 is the maximum. + return (jint) numValue[0][readChar(ch) >> 7]; +} + +jint +java::lang::Character::getNumericValue(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + return UNASSIGNED_NUMERIC_VALUE; + jshort num = numValue[plane][readCodePoint(codePoint) >> 7]; + if (num <= -3) + return largenums[-num - 3]; + return num; +} + +jbyte +java::lang::Character::getDirectionality(jchar ch) +{ + return direction[0][readChar(ch) >> 7]; +} + +jbyte +java::lang::Character::getDirectionality(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane < 0 || (plane > 2 && plane != 14)) + { + if (plane > 14 && ((codePoint & 0xffff) < 0xfffe)) + return (jint) PRIVATE_DIRECTION; + return (jint) UNASSIGNED_DIRECTION; + } + return direction[plane][readCodePoint(codePoint) >> 7]; +} diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc new file mode 100644 index 000000000..d6969d49b --- /dev/null +++ b/libjava/java/lang/natClass.cc @@ -0,0 +1,2089 @@ +// natClass.cc - Implementation of java.lang.Class native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2010 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <limits.h> +#include <string.h> +#include <stddef.h> +#include <stdio.h> + +#pragma implementation "Class.h" + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <java/lang/Class.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/String.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/reflect/Member.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Field.h> +#include <java/lang/reflect/Proxy.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/AbstractMethodError.h> +#include <java/lang/ArrayStoreException.h> +#include <java/lang/ClassCastException.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ExceptionInInitializerError.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/NoSuchFieldError.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/InstantiationException.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/NoSuchFieldException.h> +#include <java/lang/NoSuchMethodError.h> +#include <java/lang/NoSuchMethodException.h> +#include <java/lang/Thread.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/RuntimePermission.h> +#include <java/lang/System.h> +#include <java/lang/SecurityException.h> +#include <java/lang/SecurityManager.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/VMClassLoader.h> +#include <gcj/method.h> +#include <gnu/gcj/RawData.h> +#include <java/lang/VerifyError.h> +#include <java/lang/InternalError.h> +#include <java/lang/TypeNotPresentException.h> +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Long.h> +#include <java/lang/Character.h> +#include <java/lang/Boolean.h> +#include <java/lang/annotation/Annotation.h> +#include <java/util/HashMap.h> +#include <java/util/Map.h> +#include <sun/reflect/annotation/AnnotationInvocationHandler.h> +#include <java/lang/Enum.h> + +#include <java-cpool.h> +#include <java-interp.h> +#include <java-assert.h> +#include <java-stack.h> +#include <execution.h> + + + +using namespace gcj; + +jclass +java::lang::Class::forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader) +{ + if (! className) + throw new java::lang::NullPointerException; + + jsize length = _Jv_GetStringUTFLength (className); + char buffer[length]; + _Jv_GetStringUTFRegion (className, 0, className->length(), buffer); + + _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length); + + if (! _Jv_VerifyClassName (name)) + throw new java::lang::ClassNotFoundException (className); + + jclass klass = (buffer[0] == '[' + ? _Jv_FindClassFromSignature (name->chars(), loader) + : _Jv_FindClass (name, loader)); + + if (klass == NULL) + throw new java::lang::ClassNotFoundException (className); + + if (initialize) + _Jv_InitClass (klass); + + return klass; +} + +jclass +java::lang::Class::forName (jstring className) +{ + java::lang::ClassLoader *loader = NULL; + + jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); + if (caller) + loader = caller->getClassLoaderInternal(); + + return forName (className, true, loader); +} + +java::lang::ClassLoader * +java::lang::Class::getClassLoader (void) +{ + java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); + if (s != NULL) + { + jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); + return getClassLoader (caller); + } + + return loader; +} + +java::lang::ClassLoader * +java::lang::Class::getClassLoader (jclass caller) +{ + java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); + if (s != NULL) + { + ClassLoader *caller_loader = caller->getClassLoaderInternal(); + + // If the caller has a non-null class loader, and that loader + // is not this class' loader or an ancestor thereof, then do a + // security check. + if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader)) + s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); + } + + return loader; +} + +java::lang::reflect::Constructor * +java::lang::Class::getConstructor (JArray<jclass> *param_types) +{ + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + + jstring partial_sig = getSignature (param_types, true); + jint hash = partial_sig->hashCode (); + + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. For getConstructor, the constructor must be + // public. + using namespace java::lang::reflect; + if (! Modifier::isPublic(methods[i].accflags)) + break; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); +} + +JArray<java::lang::reflect::Constructor *> * +java::lang::Class::getDeclaredConstructors (jboolean publicOnly) +{ + int numConstructors = 0; + int max = isPrimitive () ? 0 : method_count; + int i; + for (i = max; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (publicOnly + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + numConstructors++; + } + JArray<java::lang::reflect::Constructor *> *result + = (JArray<java::lang::reflect::Constructor *> *) + JvNewObjectArray (numConstructors, + &java::lang::reflect::Constructor::class$, + NULL); + java::lang::reflect::Constructor** cptr = elements (result); + for (i = 0; i < max; i++) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (publicOnly + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + java::lang::reflect::Constructor *cons + = new java::lang::reflect::Constructor (); + cons->offset = (char *) method - (char *) methods; + cons->declaringClass = this; + *cptr++ = cons; + } + return result; +} + +java::lang::reflect::Constructor * +java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + + jstring partial_sig = getSignature (param_types, true); + jint hash = partial_sig->hashCode (); + + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. + using namespace java::lang::reflect; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); +} + +java::lang::reflect::Field * +java::lang::Class::getField (jstring name, jint hash) +{ + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getField(name, hash); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getField (name, hash); + return rfield; +} + +java::lang::reflect::Field * +java::lang::Class::getDeclaredField (jstring name) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + int hash = name->hashCode(); + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + throw new java::lang::NoSuchFieldException (name); +} + +JArray<java::lang::reflect::Field *> * +java::lang::Class::getDeclaredFields (jboolean public_only) +{ + int size; + if (public_only) + { + size = 0; + for (int i = 0; i < field_count; ++i) + { + _Jv_Field *field = &fields[i]; + if ((field->flags & java::lang::reflect::Modifier::PUBLIC)) + ++size; + } + } + else + size = field_count; + + JArray<java::lang::reflect::Field *> *result + = (JArray<java::lang::reflect::Field *> *) + JvNewObjectArray (size, &java::lang::reflect::Field::class$, NULL); + java::lang::reflect::Field** fptr = elements (result); + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (public_only + && ! (field->flags & java::lang::reflect::Modifier::PUBLIC)) + continue; + java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + *fptr++ = rfield; + } + return result; +} + +void +java::lang::Class::getSignature (java::lang::StringBuffer *buffer) +{ + if (isPrimitive()) + buffer->append((jchar) method_count); + else + { + jstring name = getName(); + if (name->charAt(0) != '[') + buffer->append((jchar) 'L'); + buffer->append(name); + if (name->charAt(0) != '[') + buffer->append((jchar) ';'); + } +} + +// This doesn't have to be native. It is an implementation detail +// only called from the C++ code, though, so maybe this is clearer. +jstring +java::lang::Class::getSignature (JArray<jclass> *param_types, + jboolean is_constructor) +{ + java::lang::StringBuffer *buf = new java::lang::StringBuffer (); + buf->append((jchar) '('); + // A NULL param_types means "no parameters". + if (param_types != NULL) + { + jclass *v = elements (param_types); + for (int i = 0; i < param_types->length; ++i) + v[i]->getSignature(buf); + } + buf->append((jchar) ')'); + if (is_constructor) + buf->append((jchar) 'V'); + return buf->toString(); +} + +java::lang::reflect::Method * +java::lang::Class::_getDeclaredMethod (jstring name, + JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, utf_name) + && _Jv_equaln (methods[i].signature, partial_sig, p_len) + && (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) == 0) + { + // Found it. + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char*) (&methods[i]) - (char*) methods; + rmethod->declaringClass = this; + return rmethod; + } + } + return NULL; +} + +JArray<java::lang::reflect::Method *> * +java::lang::Class::getDeclaredMethods (void) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + + int numMethods = 0; + int max = isPrimitive () ? 0 : method_count; + int i; + for (i = max; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + numMethods++; + } + JArray<java::lang::reflect::Method *> *result + = (JArray<java::lang::reflect::Method *> *) + JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL); + java::lang::reflect::Method** mptr = elements (result); + for (i = 0; i < max; i++) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + java::lang::reflect::Method* rmethod + = new java::lang::reflect::Method (); + rmethod->offset = (char*) method - (char*) methods; + rmethod->declaringClass = this; + *mptr++ = rmethod; + } + return result; +} + +jstring +java::lang::Class::getName (void) +{ + return name->toString(); +} + +JArray<jclass> * +java::lang::Class::getInterfaces (void) +{ + jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL); + jobject *data = elements (r); + for (int i = 0; i < interface_count; ++i) + { + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + data[i] = interfaces[i]; + if ((uaddr)data[i] < (uaddr)constants.size) + fprintf (stderr, "ERROR !!!\n"); + } + return reinterpret_cast<JArray<jclass> *> (r); +} + +java::lang::reflect::Method * +java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len) + && (klass->methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) == 0) + { + // Found it. + using namespace java::lang::reflect; + + // Method must be public. + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (isInterface()) + { + for (int i = 0; i < interface_count; ++i) + { + using namespace java::lang::reflect; + Method *rmethod = interfaces[i]->_getMethod (name, param_types); + if (rmethod != NULL) + return rmethod; + } + } + + return NULL; +} + +// This is a very slow implementation, since it re-scans all the +// methods we've already listed to make sure we haven't duplicated a +// method. It also over-estimates the required size, so we have to +// shrink the result array later. +jint +java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result, + jint offset) +{ + jint count = 0; + + // First examine all local methods + for (int i = isPrimitive () ? 0 : method_count; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (method->accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + // Only want public methods. + if (! java::lang::reflect::Modifier::isPublic (method->accflags)) + continue; + + // This is where we over-count the slots required if we aren't + // filling the result for real. + if (result != NULL) + { + jboolean add = true; + java::lang::reflect::Method **mp = elements (result); + // If we already have a method with this name and signature, + // then ignore this one. This can happen with virtual + // methods. + for (int j = 0; j < offset; ++j) + { + _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]); + if (_Jv_equalUtf8Consts (method->name, meth_2->name) + && _Jv_equalUtf8Consts (method->signature, + meth_2->signature)) + { + add = false; + break; + } + } + if (! add) + continue; + } + + if (result != NULL) + { + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char *) method - (char *) methods; + rmethod->declaringClass = this; + Method **mp = elements (result); + mp[offset + count] = rmethod; + } + ++count; + } + offset += count; + + // Now examine superclasses. + if (getSuperclass () != NULL) + { + jint s_count = getSuperclass()->_getMethods (result, offset); + offset += s_count; + count += s_count; + } + + // Finally, examine interfaces. + for (int i = 0; i < interface_count; ++i) + { + int f_count = interfaces[i]->_getMethods (result, offset); + count += f_count; + offset += f_count; + } + + return count; +} + +JArray<java::lang::reflect::Method *> * +java::lang::Class::getMethods (void) +{ + using namespace java::lang::reflect; + + memberAccessCheck(Member::PUBLIC); + + // This will overestimate the size we need. + jint count = _getMethods (NULL, 0); + + JArray<Method *> *result + = ((JArray<Method *> *) JvNewObjectArray (count, + &Method::class$, + NULL)); + + // When filling the array for real, we get the actual count. Then + // we resize the array. + jint real_count = _getMethods (result, 0); + + if (real_count != count) + { + JArray<Method *> *r2 + = ((JArray<Method *> *) JvNewObjectArray (real_count, + &Method::class$, + NULL)); + + Method **destp = elements (r2); + Method **srcp = elements (result); + + for (int i = 0; i < real_count; ++i) + *destp++ = *srcp++; + + result = r2; + } + + return result; +} + +jboolean +java::lang::Class::isAssignableFrom (jclass klass) +{ + // Arguments may not have been initialized, given ".class" syntax. + // This ensures we can at least look at their superclasses. + _Jv_Linker::wait_for_state (this, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + return _Jv_IsAssignableFrom (klass, this); +} + +jboolean +java::lang::Class::isInstance (jobject obj) +{ + if (! obj) + return false; + return _Jv_IsAssignableFrom (JV_CLASS (obj), this); +} + +jobject +java::lang::Class::newInstance (void) +{ + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + + if (isPrimitive () + || isInterface () + || isArray () + || java::lang::reflect::Modifier::isAbstract(accflags)) + throw new java::lang::InstantiationException (getName ()); + + _Jv_InitClass (this); + + _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature); + if (! meth) + throw new java::lang::InstantiationException (getName()); + + jobject r = _Jv_AllocObject (this); + ((void (*) (jobject)) meth->ncode) (r); + return r; +} + +void +java::lang::Class::finalize (void) +{ + // Array classes don't have an engine, and don't need to be finalized. + if (engine) + engine->unregister(this); +} + +#ifdef INTERPRETER +void +_Jv_ClosureList::releaseClosures (_Jv_ClosureList **closures) +{ + if (!closures) + return; + + while (_Jv_ClosureList *current = *closures) + { + *closures = current->next; + ffi_closure_free (current->ptr); + } +} + +void +_Jv_ClosureList::registerClosure (jclass klass, void *ptr) +{ + _Jv_ClosureList **closures = klass->engine->get_closure_list (klass); + if (closures) + { + this->ptr = ptr; + this->next = *closures; + *closures = this; + } +} +#endif + +// This implements the initialization process for a class. From Spec +// section 12.4.2. +void +java::lang::Class::initializeClass (void) +{ + // Short-circuit to avoid needless locking (expression includes + // JV_STATE_PHANTOM and JV_STATE_DONE). + if (state >= JV_STATE_PHANTOM) + return; + + // Step 1. We introduce a new scope so we can synchronize more + // easily. + { + JvSynchronize sync (this); + + if (state < JV_STATE_LINKED) + { + try + { + _Jv_Linker::wait_for_state(this, JV_STATE_LINKED); + } + catch (java::lang::SecurityException *x) + { + throw x; + } + catch (java::lang::Throwable *x) + { + // Turn into a NoClassDefFoundError. + java::lang::NoClassDefFoundError *result + = new java::lang::NoClassDefFoundError(getName()); + result->initCause(x); + throw result; + } + } + + // Step 2. + java::lang::Thread *self = java::lang::Thread::currentThread(); + self = (java::lang::Thread *) ((long) self | 1); + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) + wait (); + + // Steps 3 & 4. + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS) + return; + + // Step 5. + if (state == JV_STATE_ERROR) + throw new java::lang::NoClassDefFoundError (getName()); + + // Step 6. + thread = self; + _Jv_Linker::wait_for_state (this, JV_STATE_LINKED); + state = JV_STATE_IN_PROGRESS; + } + + // Step 7. + if (! isInterface () && superclass) + { + try + { + _Jv_InitClass (superclass); + } + catch (java::lang::SecurityException *x) + { + throw x; + } + catch (java::lang::Throwable *except) + { + // Caught an exception. + JvSynchronize sync (this); + state = JV_STATE_ERROR; + notifyAll (); + throw except; + } + } + + // Steps 8, 9, 10, 11. + try + { + _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, + void_signature); + if (meth) + ((void (*) (void)) meth->ncode) (); + } + catch (java::lang::SecurityException *x) + { + throw x; + } + catch (java::lang::Throwable *except) + { + if (! java::lang::Error::class$.isInstance(except)) + { + try + { + except = new ExceptionInInitializerError (except); + } + catch (java::lang::Throwable *t) + { + except = t; + } + } + + JvSynchronize sync (this); + state = JV_STATE_ERROR; + notifyAll (); + throw except; + } + + JvSynchronize sync (this); + state = JV_STATE_DONE; + notifyAll (); +} + +// Only used by serialization +java::lang::reflect::Field * +java::lang::Class::getPrivateField (jstring name) +{ + int hash = name->hashCode (); + + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getPrivateField(name); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getPrivateField (name); + return rfield; +} + +// Only used by serialization +java::lang::reflect::Method * +java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + throw new java::lang::NoSuchMethodException (name); +} + +// Private accessor method for Java code to retrieve the protection domain. +java::security::ProtectionDomain * +java::lang::Class::getProtectionDomain0 () +{ + return protectionDomain; +} + +JArray<jobject> * +java::lang::Class::getSigners() +{ + return hack_signers; +} + +void +java::lang::Class::setSigners(JArray<jobject> *s) +{ + hack_signers = s; +} + + + +static unsigned char +read_u1 (unsigned char *&p) +{ + return *p++; +} + +static unsigned char +read_u1 (unsigned char *&p, unsigned char *next) +{ + if (next - p < 1) + throw new java::lang::InternalError(); + return *p++; +} + +static unsigned int +read_u2 (unsigned char *&p) +{ + unsigned int b1 = *p++; + unsigned int b2 = *p++; + return (b1 << 8) | b2; +} + +static unsigned int +read_u2 (unsigned char *&p, unsigned char *next) +{ + if (next - p < 2) + throw new java::lang::InternalError(); + return read_u2 (p); +} + +static int +read_4 (unsigned char *&p) +{ + int b1 = *p++; + int b2 = *p++; + int b3 = *p++; + int b4 = *p++; + return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; +} + +jstring +java::lang::Class::getReflectionSignature (jint /*jv_attr_type*/ type, + jint obj_index) +{ + // We just re-parse the bytecode for this data each time. If + // necessary we can cache results, but I suspect this is not + // performance sensitive. + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return NULL; + while (true) + { + int kind = read_u1 (bytes); + if (kind == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (kind != type) + { + bytes = next; + continue; + } + if (type != JV_CLASS_ATTR) + { + unsigned short index = read_u2 (bytes, next); + if (index != obj_index) + { + bytes = next; + continue; + } + } + int nt = read_u1 (bytes, next); + if (nt != JV_SIGNATURE_KIND) + { + bytes = next; + continue; + } + unsigned int cpool_idx = read_u2 (bytes, next); + if (cpool_idx >= (unsigned int) constants.size + || constants.tags[cpool_idx] != JV_CONSTANT_Utf8) + { + // We just ignore errors for now. It isn't clear what is + // best to do here, as an encoding error here means a bug + // either in the compiler or in defineclass.cc. + return NULL; + } + return _Jv_NewStringUtf8Const (constants.data[cpool_idx].utf8); + } +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Constructor *c) +{ + _Jv_Method *meth = _Jv_FromReflectedConstructor (c); + unsigned short meth_index = meth - methods; + return getReflectionSignature (JV_METHOD_ATTR, meth_index); +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Method *m) +{ + _Jv_Method *meth = _Jv_FromReflectedMethod (m); + unsigned short meth_index = meth - methods; + return getReflectionSignature (JV_METHOD_ATTR, meth_index); +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Field *f) +{ + _Jv_Field *fld = _Jv_FromReflectedField (f); + unsigned short fld_index = fld - fields; + return getReflectionSignature (JV_FIELD_ATTR, fld_index); +} + +jstring +java::lang::Class::getClassSignature() +{ + return getReflectionSignature (JV_CLASS_ATTR, 0); +} + +jint +java::lang::Class::getEnclosingMethodData() +{ + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + while (true) + { + int kind = read_u1 (bytes); + if (kind == JV_DONE_ATTR) + return 0; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (kind != JV_CLASS_ATTR) + { + bytes = next; + continue; + } + int type = read_u1 (bytes, next); + if (type != JV_ENCLOSING_METHOD_KIND) + { + bytes = next; + continue; + } + int class_index = read_u2 (bytes, next); + int method_index = read_u2 (bytes, next); + _Jv_word result; + _Jv_storeIndexes (&result, class_index, method_index); + return result.i; + } +} + +jclass +java::lang::Class::getEnclosingClass() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + // No enclosing method, but perhaps a member or anonymous class + return getDeclaringClass(); + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + return _Jv_Linker::resolve_pool_entry (this, class_index).clazz; +} + +::java::lang::reflect::Method * +java::lang::Class::getEnclosingMethod() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + return NULL; + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + jclass found_class; + _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, + class_index, + method_index, + false, false); + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char *) method - (char *) found_class->methods; + rmethod->declaringClass = found_class; + return rmethod; +} + +::java::lang::reflect::Constructor * +java::lang::Class::getEnclosingConstructor() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + return NULL; + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + jclass found_class; + _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, + class_index, + method_index, + false, false); + using namespace java::lang::reflect; + Constructor *cons = new Constructor (); + cons->offset = (char *) method - (char *) found_class->methods; + cons->declaringClass = this; + return cons; +} + +static void +check_constant (_Jv_Constants *pool, jint cpool_index, jint type) +{ + if (cpool_index <= 0 || cpool_index >= pool->size) + throw new InternalError(JvNewStringLatin1("invalid constant pool index")); + if ((pool->tags[cpool_index] & + ~(JV_CONSTANT_ResolvedFlag|JV_CONSTANT_LazyFlag)) != type) + { + ::java::lang::StringBuffer *sb = new ::java::lang::StringBuffer(); + sb->append(JvNewStringLatin1("expected pool constant ")); + sb->append(type); + sb->append(JvNewStringLatin1(" but got ")); + sb->append(jint (pool->tags[cpool_index])); + throw new InternalError(sb->toString()); + } +} + +// Forward declaration +static ::java::lang::annotation::Annotation * +parseAnnotation(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last); + +static jobject +parseAnnotationElement(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int tag = read_u1 (bytes, last); + jobject result; + switch (tag) + { + case 'B': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Byte::valueOf (pool->data[cindex].i); + } + break; + case 'C': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Character::valueOf (pool->data[cindex].i); + } + break; + case 'S': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Short::valueOf (pool->data[cindex].i); + } + break; + case 'Z': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Boolean::valueOf (jboolean (pool->data[cindex].i)); + } + break; + case 'I': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Integer::valueOf (pool->data[cindex].i); + } + break; + case 'D': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Double); + _Jv_word2 word; + memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); + result = Double::valueOf (word.d); + } + break; + case 'F': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Float); + result = Float::valueOf (pool->data[cindex].f); + } + break; + case 'J': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Long); + _Jv_word2 word; + memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); + result = Long::valueOf (word.l); + } + break; + case 's': + { + int cindex = read_u2 (bytes, last); + // Despite what the JVM spec says, compilers generate a Utf8 + // constant here, not a String. + check_constant (pool, cindex, JV_CONSTANT_Utf8); + result = pool->data[cindex].utf8->toString(); + } + break; + case 'e': + { + int type_name_index = read_u2 (bytes, last); + check_constant (pool, type_name_index, JV_CONSTANT_Utf8); + int const_name_index = read_u2 (bytes, last); + check_constant (pool, const_name_index, JV_CONSTANT_Utf8); + + _Jv_Utf8Const *u_name = pool->data[type_name_index].utf8; + _Jv_Utf8Const *e_name = pool->data[const_name_index].utf8; + + // FIXME: throw correct exceptions at the correct times. + jclass e_class = _Jv_FindClassFromSignature(u_name->chars(), + klass->getClassLoaderInternal()); + result = ::java::lang::Enum::valueOf(e_class, e_name->toString()); + } + break; + case 'c': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Utf8); + _Jv_Utf8Const *u_name = pool->data[cindex].utf8; + jclass anno_class + = _Jv_FindClassFromSignatureNoException(u_name->chars(), + klass->getClassLoaderInternal()); + // FIXME: not correct: we should lazily do this when trying to + // read the element. This means that + // AnnotationInvocationHandler needs to have a special case. + if (! anno_class) + // FIXME: original exception... + throw new TypeNotPresentException(u_name->toString(), NULL); + result = anno_class; + } + break; + case '@': + result = parseAnnotation (klass, pool, bytes, last); + break; + case '[': + { + int n_array_elts = read_u2 (bytes, last); + jobjectArray aresult = _Jv_NewObjectArray (n_array_elts, + &Object::class$, NULL); + jobject *elts = elements (aresult); + for (int i = 0; i < n_array_elts; ++i) + elts[i] = parseAnnotationElement(klass, pool, bytes, last); + result = aresult; + } + break; + default: + throw new java::lang::InternalError(); + } + return result; +} + +static ::java::lang::annotation::Annotation * +parseAnnotation(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int type_index = read_u2 (bytes, last); + check_constant (pool, type_index, JV_CONSTANT_Utf8); + + _Jv_Utf8Const *u_name = pool->data[type_index].utf8; + jclass anno_class = _Jv_FindClassFromSignatureNoException(u_name->chars(), + klass->getClassLoaderInternal()); + // FIXME: what to do if anno_class==NULL? + + ::java::util::HashMap *hmap = new ::java::util::HashMap(); + int npairs = read_u2 (bytes, last); + for (int i = 0; i < npairs; ++i) + { + int name_index = read_u2 (bytes, last); + check_constant (pool, name_index, JV_CONSTANT_Utf8); + jstring name = _Jv_NewStringUtf8Const (pool->data[name_index].utf8); + jobject value = parseAnnotationElement (klass, pool, bytes, last); + // FIXME: any checks needed for name? + hmap->put(name, value); + } + using namespace ::sun::reflect::annotation; + return AnnotationInvocationHandler::create (anno_class, + (::java::util::Map *) hmap); +} + +static jobjectArray +parseAnnotations(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int num = read_u2 (bytes, last); + jobjectArray result = _Jv_NewObjectArray (num, + &::java::lang::annotation::Annotation::class$, + NULL); + jobject *elts = elements (result); + for (int i = 0; i < num; ++i) + elts[i] = parseAnnotation(klass, pool, bytes, last); + return result; +} + +static jobjectArray +parseParameterAnnotations(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + jclass anno = &::java::lang::annotation::Annotation::class$; + jclass annoary = _Jv_GetArrayClass (anno, anno->getClassLoaderInternal()); + + // FIXME: something should check the number of params versus the + // method + int n_params = read_u1 (bytes, last); + jobjectArray result = _Jv_NewObjectArray (n_params, annoary, NULL); + jobject *elts = elements (result); + for (int i = 0; i < n_params; ++i) + elts[i] = parseAnnotations(klass, pool, bytes, last); + return result; +} + +jobject +java::lang::Class::getMethodDefaultValue(::java::lang::reflect::Method *meth) +{ + // FIXME: could cache the value here... + + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + + unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; + + while (true) + { + int type = read_u1 (bytes); + if (type == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (type != JV_METHOD_ATTR) + { + bytes = next; + continue; + } + int kind = read_u1 (bytes, next); + if (kind != JV_ANNOTATION_DEFAULT_KIND) + { + bytes = next; + continue; + } + int index = read_u2 (bytes, next); + if (meth_index != index) + { + bytes = next; + continue; + } + + // FIXME: could cache here. If we do then we have to clone any + // array result. + return parseAnnotationElement(this, &this->constants, bytes, next); + } +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(jint /* jv_attr_type */ member_type, + jint member_index, + jint /* jv_attr_kind */ kind_req) +{ + using namespace java::lang::annotation; + jobjectArray result; + + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + + if (loader == NULL) + loader = (ClassLoader *)VMClassLoader::bootLoader; + + result = (loader->getDeclaredAnnotations + (this, member_type, member_index, kind_req)); + if (result) + return result; + + for (;;) + { + int type = read_u1 (bytes); + if (type == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (type != member_type) + { + bytes = next; + continue; + } + int kind = read_u1 (bytes, next); + if (kind != kind_req) + { + bytes = next; + continue; + } + if (member_type != JV_CLASS_ATTR) + { + int index = read_u2 (bytes, next); + if (member_index != index) + { + bytes = next; + continue; + } + } + + if (kind_req == JV_PARAMETER_ANNOTATIONS_KIND) + result = ((parseParameterAnnotations + (this, &this->constants, bytes, next))); + else + result = ((parseAnnotations (this, &this->constants, bytes, next))); + break; + } + + return (loader->putDeclaredAnnotations + (this, member_type, member_index, kind_req, result)); +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Method *meth, + jboolean is_param) +{ + unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; + return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, + (is_param + ? JV_PARAMETER_ANNOTATIONS_KIND + : JV_ANNOTATIONS_KIND)); +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Constructor *cons, + jboolean is_param) +{ + unsigned short meth_index = _Jv_FromReflectedConstructor (cons) - methods; + return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, + (is_param + ? JV_PARAMETER_ANNOTATIONS_KIND + : JV_ANNOTATIONS_KIND)); +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Field *fld) +{ + unsigned short field_index = _Jv_FromReflectedField (fld) - fields; + return getDeclaredAnnotations(JV_FIELD_ATTR, field_index, + JV_ANNOTATIONS_KIND); +} + +JArray< ::java::lang::annotation::Annotation *> * +java::lang::Class::getDeclaredAnnotationsInternal() +{ + return (JArray< ::java::lang::annotation::Annotation *> *) getDeclaredAnnotations(JV_CLASS_ATTR, 0, JV_ANNOTATIONS_KIND); +} + +static jclass +resolve_class_constant (jclass klass, _Jv_Constants *pool, int cpool_index) +{ + check_constant (pool, cpool_index, JV_CONSTANT_Class); + // FIXME: what is the correct thing to do with an exception here? + return _Jv_Linker::resolve_pool_entry (klass, cpool_index, false).clazz; +} + +jint +java::lang::Class::findInnerClassAttribute() +{ + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return -1; + while (true) + { + int type = read_u1 (bytes); + if (type == JV_DONE_ATTR) + break; + // After the type but before the length. + unsigned char *save = bytes; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (type != JV_CLASS_ATTR) + { + bytes = next; + continue; + } + int kind = read_u1 (bytes, next); + if (kind != JV_INNER_CLASSES_KIND) + { + bytes = next; + continue; + } + return save - reflection_data; + } + return -1; +} + +jint +java::lang::Class::findDeclaredClasses(JArray<jclass> *result, + jboolean publicOnly, + jint offset) +{ + unsigned char *bytes = reflection_data + offset; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + // Skip a byte. + read_u1 (bytes, next); + int n_classes = read_u2 (bytes, next); + int count = 0; + for (int i = 0; i < n_classes; ++i) + { + int inner_class_index = read_u2 (bytes, next); + int outer_class_index = read_u2 (bytes, next); + /*int inner_name_index = */ read_u2 (bytes, next); + int inner_flags = read_u2 (bytes, next); + + if (inner_class_index == 0 || outer_class_index == 0) + continue; + if (resolve_class_constant (this, &constants, outer_class_index) == this) + { + jclass inner = resolve_class_constant (this, &constants, + inner_class_index); + if (! publicOnly + || ((inner_flags + & java::lang::reflect::Modifier::PUBLIC) != 0)) + { + if (result) + { + jclass *elts = elements (result); + elts[count] = inner; + } + ++count; + } + } + } + + return count; +} + +JArray<jclass> * +java::lang::Class::getDeclaredClasses (jboolean publicOnly) +{ + int offset = findInnerClassAttribute(); + int count; + if (offset == -1) + { + // No InnerClasses attribute, so no declared classes. + count = 0; + } + else + count = findDeclaredClasses(NULL, publicOnly, offset); + JArray<jclass> *result + = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$, + NULL); + if (count > 0) + findDeclaredClasses(result, publicOnly, offset); + return result; +} + +jclass +java::lang::Class::getDeclaringClass (void) +{ + int offset = findInnerClassAttribute(); + if (offset == -1) + return NULL; + + unsigned char *bytes = reflection_data + offset; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + // Skip a byte. + read_u1 (bytes, next); + int n_classes = read_u2 (bytes, next); + for (int i = 0; i < n_classes; ++i) + { + int inner_class_index = read_u2 (bytes, next); + int outer_class_index = read_u2 (bytes, next); + /*int inner_name_index = */read_u2 (bytes, next); + /*int inner_flags = */read_u2 (bytes, next); + + if (inner_class_index == 0 || outer_class_index == 0) + continue; + if (resolve_class_constant (this, &constants, inner_class_index) == this) + return resolve_class_constant (this, &constants, outer_class_index); + } + + return NULL; +} + +jboolean +java::lang::Class::isAnonymousClass() +{ + int offset = findInnerClassAttribute(); + if (offset == -1) + return false; + + unsigned char *bytes = reflection_data + offset; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + // Skip a byte. + read_u1 (bytes, next); + int n_classes = read_u2 (bytes, next); + for (int i = 0; i < n_classes; ++i) + { + int inner_class_index = read_u2 (bytes, next); + /*int outer_class_index = */read_u2 (bytes, next); + int inner_name_index = read_u2 (bytes, next); + /*int inner_flags = */read_u2 (bytes, next); + + if (inner_class_index == 0) + continue; + if (resolve_class_constant (this, &constants, inner_class_index) == this) + return inner_name_index == 0; + } + + return false; +} + +jboolean +java::lang::Class::isLocalClass() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + return indexes.i != 0; +} + +jboolean +java::lang::Class::isMemberClass() +{ + // FIXME: is this correct? + return !isLocalClass() && getDeclaringClass() != NULL; +} + + + +// +// Some class-related convenience functions. +// + +// Find a method declared in the class. If it is not declared locally +// (or if it is inherited), return NULL. +_Jv_Method * +_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (int i = 0; i < klass->method_count; ++i) + { + if (_Jv_equalUtf8Consts (name, klass->methods[i].name) + && _Jv_equalUtf8Consts (signature, klass->methods[i].signature)) + return &klass->methods[i]; + } + return NULL; +} + +_Jv_Method * +_Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature, + jclass *declarer_result) +{ + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + + if (meth) + { + if (declarer_result) + *declarer_result = klass; + return meth; + } + } + + return NULL; +} + +java::lang::reflect::Method * +_Jv_GetReflectedMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + if (meth) + { + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char*) meth - (char*) klass->methods; + rmethod->declaringClass = klass; + return rmethod; + } + } + + return NULL; +} + +#ifdef HAVE_TLS + +// NOTE: MCACHE_SIZE should be a power of 2 minus one. +#define MCACHE_SIZE 31 + +struct _Jv_mcache +{ + jclass klass; + _Jv_Method *method; +}; + +static __thread _Jv_mcache *method_cache; +#endif // HAVE_TLS + +static void * +_Jv_FindMethodInCache (jclass klass MAYBE_UNUSED, + _Jv_Utf8Const *name MAYBE_UNUSED, + _Jv_Utf8Const *signature MAYBE_UNUSED) +{ +#ifdef HAVE_TLS + _Jv_mcache *cache = method_cache; + if (cache) + { + int index = name->hash16 () & MCACHE_SIZE; + _Jv_mcache *mc = &cache[index]; + _Jv_Method *m = mc->method; + + if (mc->klass == klass + && _Jv_equalUtf8Consts (m->name, name) + && _Jv_equalUtf8Consts (m->signature, signature)) + return mc->method->ncode; + } +#endif // HAVE_TLS + return NULL; +} + +static void +_Jv_AddMethodToCache (jclass klass MAYBE_UNUSED, + _Jv_Method *method MAYBE_UNUSED) +{ +#ifdef HAVE_TLS + if (method_cache == NULL) + method_cache = (_Jv_mcache *) _Jv_MallocUnchecked((MCACHE_SIZE + 1) + * sizeof (_Jv_mcache)); + // If the allocation failed, just keep going. + if (method_cache != NULL) + { + int index = method->name->hash16 () & MCACHE_SIZE; + method_cache[index].method = method; + method_cache[index].klass = klass; + } +#endif // HAVE_TLS +} + +// Free this thread's method cache. We explicitly manage this memory +// as the GC does not yet know how to scan TLS on all platforms. +void +_Jv_FreeMethodCache () +{ +#ifdef HAVE_TLS + if (method_cache != NULL) + { + _Jv_Free(method_cache); + method_cache = NULL; + } +#endif // HAVE_TLS +} + +void * +_Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + using namespace java::lang::reflect; + + void *ncode = _Jv_FindMethodInCache (klass, name, signature); + if (ncode != 0) + return ncode; + + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + if (! meth) + continue; + + if (Modifier::isStatic(meth->accflags)) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (klass, meth)); + if (Modifier::isAbstract(meth->accflags)) + throw new java::lang::AbstractMethodError + (_Jv_GetMethodString (klass, meth)); + if (! Modifier::isPublic(meth->accflags)) + throw new java::lang::IllegalAccessError + (_Jv_GetMethodString (klass, meth)); + + _Jv_AddMethodToCache (klass, meth); + + return meth->ncode; + } + throw new java::lang::IncompatibleClassChangeError; +} + +// Fast interface method lookup by index. +void * +_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx) +{ + _Jv_IDispatchTable *cldt = klass->idt; + int idx = iface->ioffsets[cldt->iindex] + method_idx; + return cldt->itable[idx]; +} + +jboolean +_Jv_IsAssignableFrom (jclass source, jclass target) +{ + if (source == target) + return true; + + // If target is array, so must source be. + while (target->isArray ()) + { + if (! source->isArray()) + return false; + target = target->getComponentType(); + source = source->getComponentType(); + } + + if (target->isInterface()) + { + // Abstract classes have no IDT, and IDTs provide no way to check + // two interfaces for assignability. + if (__builtin_expect + (source->idt == NULL || source->isInterface(), false)) + return _Jv_InterfaceAssignableFrom (source, target); + + _Jv_IDispatchTable *cl_idt = source->idt; + + if (__builtin_expect ((target->ioffsets == NULL), false)) + return false; // No class implementing TARGET has been loaded. + jshort cl_iindex = cl_idt->iindex; + if (cl_iindex < target->ioffsets[0]) + { + jshort offset = target->ioffsets[cl_iindex]; + if (offset != -1 && offset < cl_idt->itable_length + && cl_idt->itable[offset] == target) + return true; + } + return false; + } + + // Primitive TYPE classes are only assignable to themselves. + if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false)) + return false; + + if (target == &java::lang::Object::class$) + return true; + else if (source->ancestors == NULL || target->ancestors == NULL) + { + // We need this case when either SOURCE or TARGET has not has + // its constant-time tables prepared. + + // At this point we know that TARGET can't be Object, so it is + // safe to use that as the termination point. + while (source && source != &java::lang::Object::class$) + { + if (source == target) + return true; + source = source->getSuperclass(); + } + } + else if (source->depth >= target->depth + && source->ancestors[source->depth - target->depth] == target) + return true; + + return false; +} + +// Interface type checking, the slow way. Returns TRUE if IFACE is a +// superinterface of SOURCE. This is used when SOURCE is also an interface, +// or a class with no interface dispatch table. +jboolean +_Jv_InterfaceAssignableFrom (jclass source, jclass iface) +{ + for (int i = 0; i < source->interface_count; i++) + { + jclass interface = source->interfaces[i]; + if (iface == interface + || _Jv_InterfaceAssignableFrom (interface, iface)) + return true; + } + + if (!source->isInterface() + && source->superclass + && _Jv_InterfaceAssignableFrom (source->superclass, iface)) + return true; + + return false; +} + +jboolean +_Jv_IsInstanceOf(jobject obj, jclass cl) +{ + if (__builtin_expect (!obj, false)) + return false; + return _Jv_IsAssignableFrom (JV_CLASS (obj), cl); +} + +void * +_Jv_CheckCast (jclass c, jobject obj) +{ + if (__builtin_expect + (obj != NULL && ! _Jv_IsAssignableFrom(JV_CLASS (obj), c), false)) + throw new java::lang::ClassCastException + ((new java::lang::StringBuffer + (obj->getClass()->getName()))->append + (JvNewStringUTF(" cannot be cast to "))->append + (c->getName())->toString()); + + return obj; +} + +void +_Jv_CheckArrayStore (jobject arr, jobject obj) +{ + if (obj) + { + JvAssert (arr != NULL); + jclass elt_class = (JV_CLASS (arr))->getComponentType(); + if (elt_class == &java::lang::Object::class$) + return; + jclass obj_class = JV_CLASS (obj); + if (__builtin_expect + (! _Jv_IsAssignableFrom (obj_class, elt_class), false)) + throw new java::lang::ArrayStoreException + ((new java::lang::StringBuffer + (JvNewStringUTF("Cannot store ")))->append + (obj_class->getName())->append + (JvNewStringUTF(" in array of type "))->append + (elt_class->getName())->toString()); + } +} + +jboolean +_Jv_IsAssignableFromSlow (jclass source, jclass target) +{ + // First, strip arrays. + while (target->isArray ()) + { + // If target is array, source must be as well. + if (! source->isArray ()) + return false; + target = target->getComponentType (); + source = source->getComponentType (); + } + + // Quick success. + if (target == &java::lang::Object::class$) + return true; + + // Ensure that the classes have their supers installed. + _Jv_Linker::wait_for_state (source, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (target, JV_STATE_LOADING); + + do + { + if (source == target) + return true; + + if (target->isPrimitive () || source->isPrimitive ()) + return false; + + if (target->isInterface ()) + { + for (int i = 0; i < source->interface_count; ++i) + { + // We use a recursive call because we also need to + // check superinterfaces. + if (_Jv_IsAssignableFromSlow (source->getInterface (i), target)) + return true; + } + } + source = source->getSuperclass (); + } + while (source != NULL); + + return false; +} + +// Lookup an interface method by name. This is very similar to +// purpose to _getMethod, but the interfaces are quite different. It +// might be a good idea for _getMethod to call this function. +// +// Return true of the method is found, with the class in FOUND_CLASS +// and the index in INDEX. +bool +_Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index, + const _Jv_Utf8Const *utf_name, + const _Jv_Utf8Const *utf_sig) +{ + for (jclass klass = search_class; klass; klass = klass->getSuperclass()) + { + // FIXME: Throw an exception? + if (!klass->isInterface ()) + return false; + + int max = klass->method_count; + int offset = 0; + for (int i = 0; i < max; ++i) + { + // Skip <clinit> here, as it will not be in the IDT. + if (klass->methods[i].name->first() == '<') + continue; + + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig)) + { + // Found it. + using namespace java::lang::reflect; + + // FIXME: Method must be public. Throw an exception? + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; + + found_class = klass; + // Interface method indexes count from 1. + index = offset + 1; + return true; + } + + ++offset; + } + } + + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (search_class->isInterface()) + { + for (int i = 0; i < search_class->interface_count; ++i) + { + using namespace java::lang::reflect; + bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], + found_class, index, + utf_name, utf_sig); + if (found) + return true; + } + } + + return false; +} + +#ifdef INTERPRETER +_Jv_MethodBase * +_Jv_FindInterpreterMethod (jclass klass, jmethodID desired_method) +{ + using namespace java::lang::reflect; + + _Jv_InterpClass *iclass + = reinterpret_cast<_Jv_InterpClass *> (klass->aux_info); + _Jv_MethodBase **imethods = _Jv_GetFirstMethod (iclass); + + for (int i = 0; i < JvNumMethods (klass); ++i) + { + _Jv_MethodBase *imeth = imethods[i]; + if (imeth->get_method () == desired_method) + return imeth; + } + + return NULL; +} +#endif + +// Return Utf8 name of a class. This function is here for code that +// can't access klass->name directly. +_Jv_Utf8Const* +_Jv_GetClassNameUtf8 (jclass klass) +{ + return klass->name; +} + +jclass +_Jv_GetMethodDeclaringClass (jmethodID method) +{ + _Jv_StackTrace::UpdateNCodeMap (); + jobject obj = reinterpret_cast<jobject> (method->ncode); + return reinterpret_cast<jclass> (_Jv_StackTrace::ncodeMap->get (obj)); +} + +jbyte +_Jv_GetClassState (jclass klass) +{ + return klass->state; +} + +#ifdef INTERPRETER +jstring +_Jv_GetInterpClassSourceFile (jclass klass) +{ + if (_Jv_IsInterpretedClass (klass)) + { + _Jv_InterpClass *iclass = + reinterpret_cast<_Jv_InterpClass *> (klass->aux_info); + return iclass->source_file_name; + } + + return NULL; +} +#endif diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc new file mode 100644 index 000000000..237e038d1 --- /dev/null +++ b/libjava/java/lang/natClassLoader.cc @@ -0,0 +1,734 @@ +// natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <execution.h> + +#include <java-threads.h> +#include <java-interp.h> + +#include <java/lang/Character.h> +#include <java/lang/Thread.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/InternalError.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/LinkageError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ClassCircularityError.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/Runtime.h> +#include <java/lang/StringBuffer.h> +#include <java/io/Serializable.h> +#include <java/lang/Cloneable.h> +#include <java/lang/ref/WeakReference.h> +#include <java/util/HashMap.h> +#include <gnu/gcj/runtime/BootClassLoader.h> +#include <gnu/gcj/runtime/SystemClassLoader.h> + +// Size of local hash table. +#define HASH_LEN 1013 + +// Hash function for Utf8Consts. +#define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN) + +// This records classes which will be registered with the system class +// loader when it is initialized. +static jclass system_class_list; + +// This is used as the value of system_class_list after we have +// initialized the system class loader; it lets us know that we should +// no longer pay attention to the system abi flag. +#define SYSTEM_LOADER_INITIALIZED ((jclass) -1) + +static jclass loaded_classes[HASH_LEN]; + +// This is the root of a linked list of classes +static jclass stack_head; + +// While bootstrapping we keep a list of classes we found, so that we +// can register their packages. There aren't many of these so we +// just keep a small buffer here and abort if we overflow. +#define BOOTSTRAP_CLASS_LIST_SIZE 20 +static jclass bootstrap_class_list[BOOTSTRAP_CLASS_LIST_SIZE]; +static int bootstrap_index; + + + + +jclass +java::lang::ClassLoader::loadClassFromSig(jstring name) +{ + int len = _Jv_GetStringUTFLength (name); + char sig[len + 1]; + _Jv_GetStringUTFRegion (name, 0, name->length(), sig); + jclass result = _Jv_FindClassFromSignature(sig, this); + if (result == NULL) + throw new ClassNotFoundException(name); + return result; +} + + + +// This tries to find a class in our built-in cache. This cache is +// used only for classes which are linked in to the executable or +// loaded via dlopen(). +jclass +_Jv_FindClassInCache (_Jv_Utf8Const *name) +{ + JvSynchronize sync (&java::lang::Class::class$); + jint hash = HASH_UTF (name); + + jclass klass; + for (klass = loaded_classes[hash]; klass; klass = klass->next_or_version) + { + if (_Jv_equalUtf8Consts (name, klass->name)) + break; + } + + return klass; +} + +void +_Jv_UnregisterClass (jclass the_class) +{ + // This can happen if the class could not be defined properly. + if (! the_class->name) + return; + + JvSynchronize sync (&java::lang::Class::class$); + jint hash = HASH_UTF(the_class->name); + + jclass *klass = &(loaded_classes[hash]); + for ( ; *klass; klass = &((*klass)->next_or_version)) + { + if (*klass == the_class) + { + *klass = (*klass)->next_or_version; + break; + } + } +} + +// Register an initiating class loader for a given class. +void +_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + if (! loader) + { + // Very early in the bootstrap process, the Bootstrap classloader may + // not exist yet. + // FIXME: We could maintain a list of these and come back and register + // them later. + return; + } + + JvSynchronize sync (loader->loadingConstraints); + + using namespace java::lang::ref; + + jstring name = klass->getName(); + WeakReference *ref = (WeakReference *) loader->loadingConstraints->get (name); + if (ref) + { + jclass constraint = (jclass) ref->get(); + if (constraint && constraint != klass) + throw new java::lang::LinkageError(JvNewStringLatin1("loading constraint violated")); + } + loader->loadingConstraints->put(name, new WeakReference(klass)); + loader->loadedClasses->put(name, klass); +} + +// If we found an error while defining an interpreted class, we must +// go back and unregister it. +void +_Jv_UnregisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + loader->loadedClasses->remove(klass->name->toString()); +} + +// Check a loading constraint. In particular check that, if there is +// a constraint for the name of KLASS in LOADER, that it maps to +// KLASS. If there is no such constraint, make a new one. If the +// constraint is violated, throw an exception. Do nothing for +// primitive types. +void +_Jv_CheckOrCreateLoadingConstraint (jclass klass, + java::lang::ClassLoader *loader) +{ + // Strip arrays. + while (klass->isArray()) + klass = klass->getComponentType(); + // Ignore primitive types. + if (klass->isPrimitive()) + return; + + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + jstring name = klass->getName(); + + JvSynchronize sync (loader->loadingConstraints); + + using namespace java::lang::ref; + + WeakReference *ref = (WeakReference *) loader->loadingConstraints->get (name); + if (ref) + { + jclass constraint = (jclass) ref->get(); + if (constraint) + { + if (klass != constraint) + throw new java::lang::LinkageError(JvNewStringLatin1("loading constraint violated")); + // Otherwise, all is ok. + return; + } + } + // No constraint (or old constraint GC'd). Make a new one. + loader->loadingConstraints->put(name, new WeakReference(klass)); +} + + +// Class registration. +// +// There are two kinds of functions that register classes. +// +// Type 1: +// +// These take the address of a class that is in an object file. +// Because these classes are not allocated on the heap, It is also +// necessary to register the address of the object for garbage +// collection. This is used with the "old" C++ ABI and with +// -findirect-dispatch -fno-indirect-classes. +// +// Type 2: +// +// These take an initializer struct, create the class, and return the +// address of the newly created class to their caller. These are used +// with -findirect-dispatch. +// +// _Jv_RegisterClasses() and _Jv_RegisterClasses_Counted() are +// functions of Type 1, and _Jv_NewClassFromInitializer() and +// _Jv_RegisterNewClasses() are of Type 2. + + +// Check that the file we're trying to load has been compiled with a +// compatible version of gcj. In previous versions of libgcj we +// silently failed to register classes of an incompatible ABI version, +// but this was totally bogus. +void +_Jv_CheckABIVersion (unsigned long value) +{ + // We are compatible with GCJ 4.0.0 BC-ABI classes. This release used a + // different format for the version ID string. + if (value == OLD_GCJ_40_BC_ABI_VERSION) + return; + + // The 20 low-end bits are used for the version number. + unsigned long version = value & 0xfffff; + + if (value & FLAG_BINARYCOMPAT_ABI) + { + int abi_rev = version % 100; + int abi_ver = version - abi_rev; + // We are compatible with abi_rev 0 and 1. + if (abi_ver == GCJ_40_BC_ABI_VERSION && abi_rev <= 1) + return; + } + else + { + // C++ ABI + if (version == GCJ_CXX_ABI_VERSION) + return; + + // If we've loaded a library that uses the C++ ABI, and this + // library is an incompatible version, then we're dead. There's + // no point throwing an exception: that will crash. + JvFail ("gcj linkage error.\n" + "Incorrect library ABI version detected. Aborting.\n"); + } + + throw new ::java::lang::ClassFormatError + (JvNewStringLatin1 ("Library compiled with later ABI version than" + " this version of libgcj supports")); +} + +// This function is called many times during startup, before main() is +// run. At that point in time we know for certain we are running +// single-threaded, so we don't need to lock when adding classes to the +// class chain. At all other times, the caller should synchronize on +// Class::class$. +void +_Jv_RegisterClasses (const jclass *classes) +{ + _Jv_RegisterLibForGc (classes); + + for (; *classes; ++classes) + { + jclass klass = *classes; + + _Jv_CheckABIVersion ((unsigned long) klass->next_or_version); + (*_Jv_RegisterClassHook) (klass); + } +} + +// This is a version of _Jv_RegisterClasses that takes a count. +void +_Jv_RegisterClasses_Counted (const jclass * classes, size_t count) +{ + size_t i; + + _Jv_RegisterLibForGc (classes); + + for (i = 0; i < count; i++) + { + jclass klass = classes[i]; + + _Jv_CheckABIVersion ((unsigned long) klass->next_or_version); + (*_Jv_RegisterClassHook) (klass); + } +} + +// Create a class on the heap from an initializer struct. +inline jclass +_Jv_NewClassFromInitializer (const char *class_initializer) +{ + const unsigned long version + = ((unsigned long) + ((::java::lang::Class *)class_initializer)->next_or_version); + _Jv_CheckABIVersion (version); + + /* We create an instance of java::lang::Class and copy all of its + fields except the first word (the vtable pointer) from + CLASS_INITIALIZER. This first word is pre-initialized by + _Jv_AllocObj, and we don't want to overwrite it. */ + + jclass new_class + = (jclass)_Jv_AllocObj (sizeof (::java::lang::Class), + &::java::lang::Class::class$); + const char *src = class_initializer + sizeof (void*); + char *dst = (char*)new_class + sizeof (void*); + size_t len = (::java::lang::Class::initializerSize (version) + - sizeof (void*)); + memcpy (dst, src, len); + + new_class->engine = &_Jv_soleIndirectCompiledEngine; + + /* FIXME: Way back before the dawn of time, we overloaded the + SYNTHETIC class access modifier to mean INTERPRETED. This was a + Bad Thing, but it didn't matter then because classes were never + marked synthetic. However, it is possible to redeem the + situation: _Jv_NewClassFromInitializer is only called from + compiled classes, so we clear the INTERPRETED flag. This is a + kludge! */ + new_class->accflags &= ~java::lang::reflect::Modifier::INTERPRETED; + + (*_Jv_RegisterClassHook) (new_class); + + return new_class; +} + +// Called by compiler-generated code at DSO initialization. CLASSES +// is an array of pairs: the first item of each pair is a pointer to +// the initialized data that is a class initializer in a DSO, and the +// second is a pointer to a class reference. +// _Jv_NewClassFromInitializer() creates the new class (on the Java +// heap) and we write the address of the new class into the address +// pointed to by the second word. +void +_Jv_RegisterNewClasses (char **classes) +{ + _Jv_InitGC (); + + const char *initializer; + + while ((initializer = *classes++)) + { + jclass *class_ptr = (jclass *)*classes++; + *class_ptr = _Jv_NewClassFromInitializer (initializer); + } +} + +void +_Jv_RegisterClassHookDefault (jclass klass) +{ + // This is bogus, but there doesn't seem to be a better place to do + // it. + if (! klass->engine) + klass->engine = &_Jv_soleCompiledEngine; + + /* FIXME: Way back before the dawn of time, we overloaded the + SYNTHETIC class access modifier to mean INTERPRETED. This was a + Bad Thing, but it didn't matter then because classes were never + marked synthetic. However, it is possible to redeem the + situation: _Jv_RegisterClassHookDefault is only called from + compiled classes, so we clear the INTERPRETED flag. This is a + kludge! */ + klass->accflags &= ~java::lang::reflect::Modifier::INTERPRETED; + + if (system_class_list != SYSTEM_LOADER_INITIALIZED) + { + unsigned long abi = (unsigned long) klass->next_or_version; + if (! _Jv_ClassForBootstrapLoader (abi)) + { + klass->next_or_version = system_class_list; + system_class_list = klass; + return; + } + } + + jint hash = HASH_UTF (klass->name); + + // If the class is already registered, don't re-register it. + for (jclass check_class = loaded_classes[hash]; + check_class != NULL; + check_class = check_class->next_or_version) + { + if (check_class == klass) + { + // If you get this, it means you have the same class in two + // different libraries. +#define TEXT "Duplicate class registration: " + // We size-limit MESSAGE so that you can't trash the stack. + char message[200]; + strcpy (message, TEXT); + strncpy (message + sizeof (TEXT) - 1, klass->name->chars(), + sizeof (message) - sizeof (TEXT)); + message[sizeof (message) - 1] = '\0'; + if (! gcj::runtimeInitialized) + JvFail (message); + else + { + java::lang::String *str = JvNewStringLatin1 (message); + throw new java::lang::VirtualMachineError (str); + } + } + } + + klass->next_or_version = loaded_classes[hash]; + loaded_classes[hash] = klass; +} + +// A pointer to a function that actually registers a class. +// Normally _Jv_RegisterClassHookDefault, but could be some other function +// that registers the class in e.g. a ClassLoader-local table. +// Should synchronize on Class:class$ while setting/restore this variable. + +void (*_Jv_RegisterClassHook) (jclass cl) = _Jv_RegisterClassHookDefault; + +void +_Jv_RegisterClass (jclass klass) +{ + jclass classes[2]; + classes[0] = klass; + classes[1] = NULL; + _Jv_RegisterClasses (classes); +} + +// This is used during initialization to register all compiled-in +// classes that are not part of the core with the system class loader. +void +_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader) +{ + for (jclass klass = system_class_list; + klass; + klass = klass->next_or_version) + { + klass->loader = loader; + loader->addClass(klass); + } + system_class_list = SYSTEM_LOADER_INITIALIZED; +} + +// An internal variant of _Jv_FindClass which simply swallows a +// NoClassDefFoundError or a ClassNotFoundException. This gives the +// caller a chance to evaluate the situation and behave accordingly. +jclass +_Jv_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + jclass klass; + + try + { + klass = _Jv_FindClass(name, loader); + } + catch ( java::lang::NoClassDefFoundError *ncdfe ) + { + return NULL; + } + catch ( java::lang::ClassNotFoundException *cnfe ) + { + return NULL; + } + + return klass; +} + +jclass +_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + // See if the class was already loaded by this loader. This handles + // initiating loader checks, as we register classes with their + // initiating loaders. + + java::lang::ClassLoader *boot = java::lang::VMClassLoader::bootLoader; + java::lang::ClassLoader *real = loader; + if (! real) + real = boot; + jstring sname = name->toString(); + // We might still be bootstrapping the VM, in which case there + // won't be a bootstrap class loader yet. + jclass klass = real ? real->findLoadedClass (sname) : NULL; + + if (! klass) + { + if (loader) + { + // Load using a user-defined loader, jvmspec 5.3.2. + // Note that we explicitly must call the single-argument form. + klass = loader->loadClass(sname); + + // If "loader" delegated the loadClass operation to another + // loader, explicitly register that it is also an initiating + // loader of the given class. + java::lang::ClassLoader *delegate = (loader == boot + ? NULL + : loader); + if (klass && klass->getClassLoaderInternal () != delegate) + _Jv_RegisterInitiatingLoader (klass, loader); + } + else if (boot) + { + // Load using the bootstrap loader jvmspec 5.3.1. + klass = java::lang::VMClassLoader::loadClass (sname, false); + + // Register that we're an initiating loader. + if (klass) + _Jv_RegisterInitiatingLoader (klass, 0); + } + else + { + // Not even a bootstrap loader, try the built-in cache. + klass = _Jv_FindClassInCache (name); + + if (klass) + { + bool found = false; + for (int i = 0; i < bootstrap_index; ++i) + { + if (bootstrap_class_list[i] == klass) + { + found = true; + break; + } + } + if (! found) + { + if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE) + abort (); + bootstrap_class_list[bootstrap_index++] = klass; + } + } + } + } + + return klass; +} + +void +_Jv_RegisterBootstrapPackages () +{ + for (int i = 0; i < bootstrap_index; ++i) + java::lang::VMClassLoader::definePackageForNative(bootstrap_class_list[i]->getName()); +} + +jclass +_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader) +{ + jclass ret = (jclass) _Jv_AllocObject (&java::lang::Class::class$); + ret->name = name; + ret->superclass = superclass; + ret->loader = loader; + + _Jv_RegisterInitiatingLoader (ret, loader); + + return ret; +} + +static _Jv_IDispatchTable *array_idt = NULL; +static jshort array_depth = 0; +static jclass *array_ancestors = NULL; + +static jclass interfaces[] = +{ + &java::lang::Cloneable::class$, + &java::io::Serializable::class$ +}; + +// Create a class representing an array of ELEMENT and store a pointer to it +// in element->arrayclass. LOADER is the ClassLoader which _initiated_ the +// instantiation of this array. ARRAY_VTABLE is the vtable to use for the new +// array class. This parameter is optional. +void +_Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable) +{ + JvSynchronize sync (element); + + _Jv_Utf8Const *array_name; + int len; + + if (element->arrayclass) + return; + + if (element->isPrimitive()) + { + if (element == JvPrimClass (void)) + throw new java::lang::ClassNotFoundException (); + len = 3; + } + else + len = element->name->len() + 5; + + { + char signature[len]; + int index = 0; + signature[index++] = '['; + // Compute name of array class. + if (element->isPrimitive()) + { + signature[index++] = (char) element->method_count; + } + else + { + size_t length = element->name->len(); + const char *const name = element->name->chars(); + if (name[0] != '[') + signature[index++] = 'L'; + memcpy (&signature[index], name, length); + index += length; + if (name[0] != '[') + signature[index++] = ';'; + } + array_name = _Jv_makeUtf8Const (signature, index); + } + + // Create new array class. + jclass array_class = _Jv_NewClass (array_name, &java::lang::Object::class$, + element->loader); + + // Note that `vtable_method_count' doesn't include the initial + // gc_descr slot. + int dm_count = java::lang::Object::class$.vtable_method_count; + + // Create a new vtable by copying Object's vtable. + _Jv_VTable *vtable; + if (array_vtable) + vtable = array_vtable; + else + vtable = _Jv_VTable::new_vtable (dm_count); + vtable->clas = array_class; + vtable->gc_descr = java::lang::Object::class$.vtable->gc_descr; + for (int i = 0; i < dm_count; ++i) + vtable->set_method (i, java::lang::Object::class$.vtable->get_method (i)); + + array_class->vtable = vtable; + array_class->vtable_method_count + = java::lang::Object::class$.vtable_method_count; + + // Stash the pointer to the element type. + array_class->element_type = element; + + // Register our interfaces. + array_class->interfaces = interfaces; + array_class->interface_count = sizeof interfaces / sizeof interfaces[0]; + + // Since all array classes have the same interface dispatch table, we can + // cache one and reuse it. It is not necessary to synchronize this. + if (!array_idt) + { + _Jv_Linker::wait_for_state(array_class, JV_STATE_PREPARED); + array_idt = array_class->idt; + array_depth = array_class->depth; + array_ancestors = array_class->ancestors; + } + else + { + array_class->idt = array_idt; + array_class->depth = array_depth; + array_class->ancestors = array_ancestors; + } + + using namespace java::lang::reflect; + { + // Array classes are "abstract final" and inherit accessibility + // from element type, per vmspec 5.3.3.2 + _Jv_ushort accflags = (Modifier::FINAL | Modifier::ABSTRACT + | (element->accflags + & (Modifier::PUBLIC | Modifier::PROTECTED + | Modifier::PRIVATE))); + array_class->accflags = accflags; + } + + // An array class has no visible instance fields. "length" is invisible to + // reflection. + + // Say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; + + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); + + element->arrayclass = array_class; +} + +// These two functions form a stack of classes. When a class is loaded +// it is pushed onto the stack by the class loader; this is so that +// StackTrace can quickly determine which classes have been loaded. + +jclass +_Jv_PopClass (void) +{ + JvSynchronize sync (&java::lang::Class::class$); + if (stack_head) + { + jclass tmp = stack_head; + stack_head = tmp->chain; + return tmp; + } + return NULL; +} + +void +_Jv_PushClass (jclass k) +{ + JvSynchronize sync (&java::lang::Class::class$); + jclass tmp = stack_head; + stack_head = k; + k->chain = tmp; +} diff --git a/libjava/java/lang/natEcosProcess.cc b/libjava/java/lang/natEcosProcess.cc new file mode 100644 index 000000000..7d8edfb0e --- /dev/null +++ b/libjava/java/lang/natEcosProcess.cc @@ -0,0 +1,25 @@ +// natEcosProcess.cc - Native side of eCos processes. + +/* Copyright (C) 1998, 1999, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// The configury system needs this file to exist, since we can't +// really conditionally link files (an autoconf bug). To avoid having +// an empty translation unit, we make a single method native. FIXME. + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/lang/EcosProcess.h> + +void +java::lang::EcosProcess::destroy (void) +{ +} diff --git a/libjava/java/lang/natMath.cc b/libjava/java/lang/natMath.cc new file mode 100644 index 000000000..d86d6307d --- /dev/null +++ b/libjava/java/lang/natMath.cc @@ -0,0 +1,184 @@ +/* Copyright (C) 1998, 1999, 2000, 2002, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/** + * @author Andrew Haley <aph@cygnus.com> + * @date Tue Sep 22 1998 */ +/* 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 and correct. + */ + +#include <config.h> + +#include <java/lang/String.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Math.h> +#include <gcj/array.h> + +#include "fdlibm.h" + +jdouble java::lang::Math::cos(jdouble x) +{ + return (jdouble)::cos((double)x); +} + +jdouble java::lang::Math::sin(jdouble x) +{ + return (jdouble)::sin((double)x); +} + +jdouble java::lang::Math::tan(jdouble x) +{ + return (jdouble)::tan((double)x); +} + +jdouble java::lang::Math::asin(jdouble x) +{ + return (jdouble)::asin((double)x); +} + +jdouble java::lang::Math::acos(jdouble x) +{ + return (jdouble)::acos((double)x); +} + +jdouble java::lang::Math::atan(jdouble x) +{ + return (jdouble)::atan((double)x); +} + +jdouble java::lang::Math::atan2(jdouble y, jdouble x) +{ + return (jdouble)::atan2((double)y, (double)x); +} + +jdouble java::lang::Math::log(jdouble x) +{ + return (jdouble)::log((double)x); +} + +jdouble java::lang::Math::exp(jdouble x) +{ + return (jdouble)::exp((double)x); +} + +jdouble java::lang::Math::sqrt(jdouble x) +{ + return (jdouble)::sqrt((double)x); +} + +jdouble java::lang::Math::pow(jdouble y, jdouble x) +{ + return (jdouble)::pow((double)y, (double)x); +} + +jdouble java::lang::Math::IEEEremainder(jdouble y, jdouble x) +{ + return (jdouble)::__ieee754_remainder((double)y, (double)x); +} + +jdouble java::lang::Math::rint(jdouble x) +{ + return (jdouble)::rint((double)x); +} + +jdouble java::lang::Math::floor(jdouble x) +{ + return (jdouble)::floor((double)x); +} + +jdouble java::lang::Math::ceil(jdouble x) +{ + return (jdouble)::ceil((double)x); +} + +jdouble java::lang::Math::log10(jdouble x) +{ + return (jdouble)::log10((double)x); +} + +jdouble java::lang::Math::cbrt(jdouble x) +{ + return (jdouble)::cbrt((double)x); +} + +jdouble java::lang::Math::cosh(jdouble x) +{ + return (jdouble)::cosh((double)x); +} + +jdouble java::lang::Math::expm1(jdouble x) +{ + return (jdouble)::expm1((double)x); +} + +jdouble java::lang::Math::hypot(jdouble x, jdouble y) +{ + return (jdouble)::hypot((double)x, (double)y); +} + +jdouble java::lang::Math::log1p(jdouble x) +{ + return (jdouble)::log1p((double)x); +} + +jdouble java::lang::Math::sinh(jdouble x) +{ + return (jdouble)::sinh((double)x); +} + +jdouble java::lang::Math::tanh(jdouble x) +{ + return (jdouble)::tanh((double)x); +} + +static inline int +floatToIntBits (jfloat value) +{ + union { + jint l; + jfloat d; + } u; + u.d = value; + return u.l; +} + +static inline bool +isNaN (jint bits) +{ + jint e = bits & 0x7f800000; + jint f = bits & 0x007fffff; + + return e == 0x7f800000 && f != 0; +} + +static inline jlong +doubleToLongBits (jdouble value) +{ + union { + jlong l; + jdouble d; + } u; + u.d = value; + return u.l; +} + +static inline bool +isNaN (jlong bits) +{ + jlong e = bits & 0x7ff0000000000000LL; + jlong f = bits & 0x000fffffffffffffLL; + + return e == 0x7ff0000000000000LL && f != 0LL; +} + diff --git a/libjava/java/lang/natObject.cc b/libjava/java/lang/natObject.cc new file mode 100644 index 000000000..87f2044dd --- /dev/null +++ b/libjava/java/lang/natObject.cc @@ -0,0 +1,1457 @@ +// natObject.cc - Implementation of the Object class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <string.h> + +#pragma implementation "Object.h" + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Object.h> +#include <java-threads.h> +#include <java-signal.h> +#include <java/lang/CloneNotSupportedException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalMonitorStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Class.h> +#include <java/lang/Cloneable.h> +#include <java/lang/Thread.h> + +#ifdef LOCK_DEBUG +# include <stdio.h> +#endif + + + +using namespace java::lang; + +// This is used to represent synchronization information. +struct _Jv_SyncInfo +{ +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // We only need to keep track of initialization state if we can + // possibly finalize this object. + bool init; +#endif + _Jv_ConditionVariable_t condition; + _Jv_Mutex_t mutex; +}; + + + +jclass +java::lang::Object::getClass (void) +{ + _Jv_VTable **dt = (_Jv_VTable **) this; + return (*dt)->clas; +} + +jint +java::lang::Object::hashCode (void) +{ + return _Jv_HashCode (this); +} + +jobject +java::lang::Object::clone (void) +{ + jclass klass = getClass (); + jobject r; + jint size; + + // We also clone arrays here. If we put the array code into + // __JArray, then we'd have to figure out a way to find the array + // vtbl when creating a new array class. This is easier, if uglier. + if (klass->isArray()) + { + __JArray *array = (__JArray *) this; + jclass comp = getClass()->getComponentType(); + jint eltsize; + if (comp->isPrimitive()) + { + r = _Jv_NewPrimArray (comp, array->length); + eltsize = comp->size(); + } + else + { + r = _Jv_NewObjectArray (array->length, comp, NULL); + eltsize = sizeof (jobject); + } + // We can't use sizeof on __JArray because we must account for + // alignment of the element type. + size = (_Jv_GetArrayElementFromElementType (array, comp) - (char *) array + + array->length * eltsize); + } + else + { + if (! java::lang::Cloneable::class$.isAssignableFrom(klass)) + throw new CloneNotSupportedException; + + size = klass->size(); + r = _Jv_AllocObject (klass); + } + + memcpy ((void *) r, (void *) this, size); +#ifndef JV_HASH_SYNCHRONIZATION + // Guarantee that the locks associated to the two objects are + // distinct. + r->sync_info = NULL; +#endif + return r; +} + +void +_Jv_FinalizeObject (jobject obj) +{ + // Ignore exceptions. From section 12.6 of the Java Language Spec. + try + { + obj->finalize (); + } + catch (java::lang::Throwable *t) + { + // Ignore. + } +} + + +// +// Synchronization code. +// + +#ifndef JV_HASH_SYNCHRONIZATION +// This global is used to make sure that only one thread sets an +// object's `sync_info' field. +static _Jv_Mutex_t sync_mutex; + +// This macro is used to see if synchronization initialization is +// needed. +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +# define INIT_NEEDED(Obj) (! (Obj)->sync_info \ + || ! ((_Jv_SyncInfo *) ((Obj)->sync_info))->init) +#else +# define INIT_NEEDED(Obj) (! (Obj)->sync_info) +#endif + +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +// If we have to run a destructor for a sync_info member, then this +// function is registered as a finalizer for the sync_info. +static void +finalize_sync_info (jobject obj) +{ + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj; +#if defined (_Jv_HaveCondDestroy) + _Jv_CondDestroy (&si->condition); +#endif +#if defined (_Jv_HaveMutexDestroy) + _Jv_MutexDestroy (&si->mutex); +#endif + si->init = false; +} +#endif + +// This is called to initialize the sync_info element of an object. +void +java::lang::Object::sync_init (void) +{ + _Jv_MutexLock (&sync_mutex); + // Check again to see if initialization is needed now that we have + // the lock. + if (INIT_NEEDED (this)) + { + // We assume there are no pointers in the sync_info + // representation. + _Jv_SyncInfo *si; + // We always create a new sync_info, even if there is already + // one available. Any given object can only be finalized once. + // If we get here and sync_info is not null, then it has already + // been finalized. So if we just reinitialize the old one, + // we'll never be able to (re-)destroy the mutex and/or + // condition variable. + si = (_Jv_SyncInfo *) _Jv_AllocBytes (sizeof (_Jv_SyncInfo)); + _Jv_MutexInit (&si->mutex); + _Jv_CondInit (&si->condition); +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Register a finalizer. + si->init = true; + _Jv_RegisterFinalizer (si, finalize_sync_info); +#endif + sync_info = (jobject) si; + } + _Jv_MutexUnlock (&sync_mutex); +} + +void +java::lang::Object::notify (void) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + if (__builtin_expect (_Jv_CondNotify (&si->condition, &si->mutex), false)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::notifyAll (void) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + if (__builtin_expect (_Jv_CondNotifyAll (&si->condition, &si->mutex), false)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::wait (jlong timeout, jint nanos) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) + throw new IllegalArgumentException; + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + switch (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos)) + { + case _JV_NOT_OWNER: + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + case _JV_INTERRUPTED: + if (Thread::interrupted ()) + throw new InterruptedException; + } +} + +// +// Some runtime code. +// + +// This function is called at system startup to initialize the +// `sync_mutex'. +void +_Jv_InitializeSyncMutex (void) +{ + _Jv_MutexInit (&sync_mutex); +} + +void +_Jv_MonitorEnter (jobject obj) +{ +#ifndef HANDLE_SEGV + if (__builtin_expect (! obj, false)) + throw new java::lang::NullPointerException; +#endif + if (__builtin_expect (INIT_NEEDED (obj), false)) + obj->sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + _Jv_MutexLock (&si->mutex); + // FIXME: In the Windows case, this can return a nonzero error code. + // We should turn that into some exception ... +} + +void +_Jv_MonitorExit (jobject obj) +{ + JvAssert (obj); + JvAssert (! INIT_NEEDED (obj)); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + if (__builtin_expect (_Jv_MutexUnlock (&si->mutex), false)) + throw new java::lang::IllegalMonitorStateException; +} + +bool +_Jv_ObjectCheckMonitor (jobject obj) +{ + if (__builtin_expect (INIT_NEEDED (obj), false)) + obj->sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + return _Jv_MutexCheckMonitor (&si->mutex); +} + +#else /* JV_HASH_SYNCHRONIZATION */ + +// FIXME: We shouldn't be calling GC_register_finalizer directly. +#ifndef HAVE_BOEHM_GC +# error Hash synchronization currently requires boehm-gc +// That's actually a bit of a lie: It should also work with the null GC, +// probably even better than the alternative. +// To really support alternate GCs here, we would need to widen the +// interface to finalization, since we sometimes have to register a +// second finalizer for an object that already has one. +// We might also want to move the GC interface to a .h file, since +// the number of procedure call levels involved in some of these +// operations is already ridiculous, and would become worse if we +// went through the proper intermediaries. +#else +# ifdef LIBGCJ_GC_DEBUG +# define GC_DEBUG +# endif +# include "gc.h" +#endif + +// What follows currenly assumes a Linux-like platform. +// Some of it specifically assumes X86 or IA64 Linux, though that +// should be easily fixable. + +// A Java monitor implemention based on a table of locks. +// Each entry in the table describes +// locks held for objects that hash to that location. +// This started out as a reimplementation of the technique used in SGIs JVM, +// for which we obtained permission from SGI. +// But in fact, this ended up quite different, though some ideas are +// still shared with the original. +// It was also influenced by some of the published IBM work, +// though it also differs in many ways from that. +// We could speed this up if we had a way to atomically update +// an entire cache entry, i.e. 2 contiguous words of memory. +// That would usually be the case with a 32 bit ABI on a 64 bit processor. +// But we don't currently go out of our way to target those. +// I don't know how to do much better with a N bit ABI on a processor +// that can atomically update only N bits at a time. +// Author: Hans-J. Boehm (Hans_Boehm@hp.com, boehm@acm.org) + +#include <limits.h> +#include <unistd.h> // for usleep, sysconf. +#include <gcj/javaprims.h> +#include <sysdep/locks.h> +#include <java/lang/Thread.h> + +// Try to determine whether we are on a multiprocessor, i.e. whether +// spinning may be profitable. +// This should really use a suitable autoconf macro. +// False is the conservative answer, though the right one is much better. +static bool +is_mp() +{ +#ifdef _SC_NPROCESSORS_ONLN + long nprocs = sysconf(_SC_NPROCESSORS_ONLN); + return (nprocs > 1); +#else + return false; +#endif +} + +// A call to keep_live(p) forces p to be accessible to the GC +// at this point. +inline static void +keep_live(obj_addr_t p) +{ + __asm__ __volatile__("" : : "rm"(p) : "memory"); +} + +// Each hash table entry holds a single preallocated "lightweight" lock. +// In addition, it holds a chain of "heavyweight" locks. Lightweight +// locks do not support Object.wait(), and are converted to heavyweight +// status in response to contention. Unlike the SGI scheme, both +// ligtweight and heavyweight locks in one hash entry can be simultaneously +// in use. (The SGI scheme requires that we be able to acquire a heavyweight +// lock on behalf of another thread, and can thus convert a lock we don't +// hold to heavyweight status. Here we don't insist on that, and thus +// let the original holder of the lighweight lock keep it.) + +struct heavy_lock { + void * reserved_for_gc; + struct heavy_lock *next; // Hash chain link. + // Traced by GC. + void * old_client_data; // The only other field traced by GC. + GC_finalization_proc old_finalization_proc; + obj_addr_t address; // Object to which this lock corresponds. + // Should not be traced by GC. + // Cleared as heavy_lock is destroyed. + // Together with the rest of the heavy lock + // chain, this is protected by the lock + // bit in the hash table entry to which + // the chain is attached. + _Jv_SyncInfo si; + // The remaining fields save prior finalization info for + // the object, which we needed to replace in order to arrange + // for cleanup of the lock structure. +}; + +#ifdef LOCK_DEBUG +void +print_hl_list(heavy_lock *hl) +{ + heavy_lock *p = hl; + for (; 0 != p; p = p->next) + fprintf (stderr, "(hl = %p, addr = %p)", p, (void *)(p -> address)); +} +#endif /* LOCK_DEBUG */ + +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +// If we have to run a destructor for a sync_info member, then this +// function could be registered as a finalizer for the sync_info. +// In fact, we now only invoke it explicitly. +static inline void +heavy_lock_finalization_proc (heavy_lock *hl) +{ +#if defined (_Jv_HaveCondDestroy) + _Jv_CondDestroy (&hl->si.condition); +#endif +#if defined (_Jv_HaveMutexDestroy) + _Jv_MutexDestroy (&hl->si.mutex); +#endif + hl->si.init = false; +} +#endif /* defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) */ + +// We convert the lock back to lightweight status when +// we exit, so that a single contention episode doesn't doom the lock +// forever. But we also need to make sure that lock structures for dead +// objects are eventually reclaimed. We do that in a an additional +// finalizer on the underlying object. +// Note that if the corresponding object is dead, it is safe to drop +// the heavy_lock structure from its list. It is not necessarily +// safe to deallocate it, since the unlock code could still be running. + +struct hash_entry { + volatile obj_addr_t address; // Address of object for which lightweight + // k is held. + // We assume the 3 low order bits are zero. + // With the Boehm collector and bitmap + // allocation, objects of size 4 bytes are + // broken anyway. Thus this is primarily + // a constraint on statically allocated + // objects used for synchronization. + // This allows us to use the low order + // bits as follows: +# define LOCKED 1 // This hash entry is locked, and its + // state may be invalid. + // The lock protects both the hash_entry + // itself (except for the light_count + // and light_thr_id fields, which + // are protected by the lightweight + // lock itself), and any heavy_monitor + // structures attached to it. +# define HEAVY 2 // Heavyweight locks associated with this + // hash entry may be held. + // The lightweight entry is still valid, + // if the leading bits of the address + // field are nonzero. + // If the LOCKED bit is clear, then this is + // set exactly when heavy_count is > 0 . + // Stored redundantly so a single + // compare-and-swap works in the easy case. + // If HEAVY is not set, it is safe to use + // an available lightweight lock entry + // without checking if there is an existing + // heavyweight lock for the same object. + // (There may be one, but it won't be held + // or waited for.) +# define REQUEST_CONVERSION 4 // The lightweight lock is held. But + // one or more other threads have tried + // to acquire the lock, and hence request + // conversion to heavyweight status. + // The heavyweight lock is already allocated. + // Threads requesting conversion are + // waiting on the condition variable associated + // with the heavyweight lock. + // Not used for conversion due to + // Object.wait() calls. +# define FLAGS (LOCKED | HEAVY | REQUEST_CONVERSION) + volatile _Jv_ThreadId_t light_thr_id; + // Thr_id of holder of lightweight lock. + // Only updated by lightweight lock holder. + // Must be recognizably invalid if the + // lightweight lock is not held. +# define INVALID_THREAD_ID 0 // Works for Linux? + // If zero doesn't work, we have to + // initialize lock table. + volatile unsigned short light_count; + // Number of times the lightweight lock + // is held minus one. Zero if lightweight + // lock is not held. Only updated by + // lightweight lock holder or, in one + // case, while holding the LOCKED bit in + // a state in which there can be no + // lightweight lock holder. + unsigned short heavy_count; // Total number of times heavyweight locks + // associated with this hash entry are held + // or waiting to be acquired. + // Threads in wait() are included eventhough + // they have temporarily released the lock. + // Protected by LOCKED bit. + // Threads requesting conversion to heavyweight + // status are also included. + struct heavy_lock * heavy_locks; + // Chain of heavy locks. Protected + // by lockbit for he. Locks may + // remain allocated here even if HEAVY + // is not set and heavy_count is 0. + // If a lightweight and heavyweight lock + // correspond to the same address, the + // lightweight lock is the right one. +}; + +#ifndef JV_SYNC_TABLE_SZ +# define JV_SYNC_TABLE_SZ 2048 // Must be power of 2. +#endif + +hash_entry light_locks[JV_SYNC_TABLE_SZ]; + +#define JV_SYNC_HASH(p) (((long)p ^ ((long)p >> 10)) & (JV_SYNC_TABLE_SZ-1)) + +// Note that the light_locks table is scanned conservatively by the +// collector. It is essential the the heavy_locks field is scanned. +// Currently the address field may or may not cause the associated object +// to be retained, depending on whether flag bits are set. +// This means that we can conceivable get an unexpected deadlock if +// 1) Object at address A is locked. +// 2) The client drops A without unlocking it. +// 3) Flag bits in the address entry are set, so the collector reclaims +// the object at A. +// 4) A is reallocated, and an attempt is made to lock the result. +// This could be fixed by scanning light_locks in a more customized +// manner that ignores the flag bits. But it can only happen with hand +// generated semi-illegal .class files, and then it doesn't present a +// security hole. + +#ifdef LOCK_DEBUG + void print_he(hash_entry *he) + { + fprintf(stderr, "lock hash entry = %p, index = %d, address = 0x%lx\n" + "\tlight_thr_id = 0x%lx, light_count = %d, " + "heavy_count = %d\n\theavy_locks:", he, + he - light_locks, (unsigned long)(he -> address), + (unsigned long)(he -> light_thr_id), + he -> light_count, he -> heavy_count); + print_hl_list(he -> heavy_locks); + fprintf(stderr, "\n"); + } +#endif /* LOCK_DEBUG */ + +#ifdef LOCK_LOG + // Log locking operations. For debugging only. + // Logging is intended to be as unintrusive as possible. + // Log calls are made after an operation completes, and hence + // may not completely reflect actual synchronization ordering. + // The choice of events to log is currently a bit haphazard. + // The intent is that if we have to track down any other bugs + // inthis code, we extend the logging as appropriate. + typedef enum + { + ACQ_LIGHT, ACQ_LIGHT2, ACQ_HEAVY, ACQ_HEAVY2, PROMOTE, REL_LIGHT, + REL_HEAVY, REQ_CONV, PROMOTE2, WAIT_START, WAIT_END, NOTIFY, NOTIFY_ALL + } event_type; + + struct lock_history + { + event_type tp; + obj_addr_t addr; // Often includes flags. + _Jv_ThreadId_t thr; + }; + + const int LOG_SIZE = 128; // Power of 2. + + lock_history lock_log[LOG_SIZE]; + + volatile obj_addr_t log_next = 0; + // Next location in lock_log. + // Really an int, but we need compare_and_swap. + + static void add_log_entry(event_type t, obj_addr_t a, _Jv_ThreadId_t th) + { + obj_addr_t my_entry; + obj_addr_t next_entry; + do + { + my_entry = log_next; + next_entry = ((my_entry + 1) & (LOG_SIZE - 1)); + } + while (!compare_and_swap(&log_next, my_entry, next_entry)); + lock_log[my_entry].tp = t; + lock_log[my_entry].addr = a; + lock_log[my_entry].thr = th; + } + +# define LOG(t, a, th) add_log_entry(t, a, th) +#else /* !LOCK_LOG */ +# define LOG(t, a, th) +#endif + +static bool mp = false; // Known multiprocesssor. + +// Wait for roughly 2^n units, touching as little memory as possible. +static void +spin(unsigned n) +{ + const unsigned MP_SPINS = 10; + const unsigned YIELDS = 4; + const unsigned SPINS_PER_UNIT = 30; + const unsigned MIN_SLEEP_USECS = 2001; // Shorter times spin under Linux. + const unsigned MAX_SLEEP_USECS = 200000; + static unsigned spin_limit = 0; + static unsigned yield_limit = YIELDS; + static bool spin_initialized = false; + + if (!spin_initialized) + { + mp = is_mp(); + if (mp) + { + spin_limit = MP_SPINS; + yield_limit = MP_SPINS + YIELDS; + } + spin_initialized = true; + } + if (n < spin_limit) + { + unsigned i = SPINS_PER_UNIT << n; + for (; i > 0; --i) + __asm__ __volatile__(""); + } + else if (n < yield_limit) + { + _Jv_ThreadYield(); + } + else + { + unsigned duration = MIN_SLEEP_USECS << (n - yield_limit); + if (n >= 15 + yield_limit || duration > MAX_SLEEP_USECS) + duration = MAX_SLEEP_USECS; + _Jv_platform_usleep(duration); + } +} + +// Wait for a hash entry to become unlocked. +static void +wait_unlocked (hash_entry *he) +{ + unsigned i = 0; + while (he -> address & LOCKED) + spin (i++); +} + +// Return the heavy lock for addr if it was already allocated. +// The client passes in the appropriate hash_entry. +// We hold the lock for he. +static inline heavy_lock * +find_heavy (obj_addr_t addr, hash_entry *he) +{ + heavy_lock *hl = he -> heavy_locks; + while (hl != 0 && hl -> address != addr) hl = hl -> next; + return hl; +} + +// Unlink the heavy lock for the given address from its hash table chain. +// Dies miserably and conspicuously if it's not there, since that should +// be impossible. +static inline void +unlink_heavy (obj_addr_t addr, hash_entry *he) +{ + heavy_lock **currentp = &(he -> heavy_locks); + while ((*currentp) -> address != addr) + currentp = &((*currentp) -> next); + *currentp = (*currentp) -> next; +} + +// Finalization procedure for objects that have associated heavy-weight +// locks. This may replace the real finalization procedure. +static void +heavy_lock_obj_finalization_proc (void *obj, void *cd) +{ + heavy_lock *hl = (heavy_lock *)cd; + +// This only addresses misalignment of statics, not heap objects. It +// works only because registering statics for finalization is a noop, +// no matter what the least significant bits are. +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)0x7); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + hash_entry *he = light_locks + JV_SYNC_HASH(addr); + obj_addr_t he_address = (he -> address & ~LOCKED); + + // Acquire lock bit immediately. It's possible that the hl was already + // destroyed while we were waiting for the finalizer to run. If it + // was, the address field was set to zero. The address filed access is + // protected by the lock bit to ensure that we do this exactly once. + // The lock bit also protects updates to the objects finalizer. + while (!compare_and_swap(&(he -> address), he_address, he_address|LOCKED )) + { + // Hash table entry is currently locked. We can't safely + // touch the list of heavy locks. + wait_unlocked(he); + he_address = (he -> address & ~LOCKED); + } + if (0 == hl -> address) + { + // remove_all_heavy destroyed hl, and took care of the real finalizer. + release_set(&(he -> address), he_address); + return; + } + JvAssert(hl -> address == addr); + GC_finalization_proc old_finalization_proc = hl -> old_finalization_proc; + if (old_finalization_proc != 0) + { + // We still need to run a real finalizer. In an idealized + // world, in which people write thread-safe finalizers, that is + // likely to require synchronization. Thus we reregister + // ourselves as the only finalizer, and simply run the real one. + // Thus we don't clean up the lock yet, but we're likely to do so + // on the next GC cycle. + // It's OK if remove_all_heavy actually destroys the heavy lock, + // since we've updated old_finalization_proc, and thus the user's + // finalizer won't be rerun. + void * old_client_data = hl -> old_client_data; + hl -> old_finalization_proc = 0; + hl -> old_client_data = 0; +# ifdef HAVE_BOEHM_GC + GC_REGISTER_FINALIZER_NO_ORDER(obj, heavy_lock_obj_finalization_proc, cd, 0, 0); +# endif + release_set(&(he -> address), he_address); + old_finalization_proc(obj, old_client_data); + } + else + { + // The object is really dead, although it's conceivable that + // some thread may still be in the process of releasing the + // heavy lock. Unlink it and, if necessary, register a finalizer + // to destroy sync_info. + unlink_heavy(addr, he); + hl -> address = 0; // Don't destroy it again. + release_set(&(he -> address), he_address); +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Make sure lock is not held and then destroy condvar and mutex. + _Jv_MutexLock(&(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + heavy_lock_finalization_proc (hl); +# endif + } +} + +// We hold the lock on he, and heavy_count is 0. +// Release the lock by replacing the address with new_address_val. +// Remove all heavy locks on the list. Note that the only possible way +// in which a lock may still be in use is if it's in the process of +// being unlocked. +// FIXME: Why does this unlock the hash entry? I think that +// could now be done more cleanly in MonitorExit. +static void +remove_all_heavy (hash_entry *he, obj_addr_t new_address_val) +{ + JvAssert(he -> heavy_count == 0); + JvAssert(he -> address & LOCKED); + heavy_lock *hl = he -> heavy_locks; + he -> heavy_locks = 0; + // We would really like to release the lock bit here. Unfortunately, that + // Creates a race between or finalizer removal, and the potential + // reinstallation of a new finalizer as a new heavy lock is created. + // This may need to be revisited. + for(; 0 != hl; hl = hl->next) + { + obj_addr_t obj = hl -> address; + JvAssert(0 != obj); // If this was previously finalized, it should no + // longer appear on our list. + hl -> address = 0; // Finalization proc might still see it after we + // finish. + GC_finalization_proc old_finalization_proc = hl -> old_finalization_proc; + void * old_client_data = hl -> old_client_data; +# ifdef HAVE_BOEHM_GC + // Remove our finalization procedure. + // Reregister the clients if applicable. + GC_REGISTER_FINALIZER_NO_ORDER((GC_PTR)obj, old_finalization_proc, + old_client_data, 0, 0); + // Note that our old finalization procedure may have been + // previously determined to be runnable, and may still run. + // FIXME - direct dependency on boehm GC. +# endif +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Wait for a possible lock holder to finish unlocking it. + // This is only an issue if we have to explicitly destroy the mutex + // or possibly if we have to destroy a condition variable that is + // still being notified. + _Jv_MutexLock(&(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + heavy_lock_finalization_proc (hl); +# endif + } + release_set(&(he -> address), new_address_val); +} + +// We hold the lock on he and heavy_count is 0. +// We release it by replacing the address field with new_address_val. +// Remove all heavy locks on the list if the list is sufficiently long. +// This is called periodically to avoid very long lists of heavy locks. +// This seems to otherwise become an issue with SPECjbb, for example. +static inline void +maybe_remove_all_heavy (hash_entry *he, obj_addr_t new_address_val) +{ + static const int max_len = 5; + heavy_lock *hl = he -> heavy_locks; + + for (int i = 0; i < max_len; ++i) + { + if (0 == hl) + { + release_set(&(he -> address), new_address_val); + return; + } + hl = hl -> next; + } + remove_all_heavy(he, new_address_val); +} + +// Allocate a new heavy lock for addr, returning its address. +// Assumes we already have the hash_entry locked, and there +// is currently no lightweight or allocated lock for addr. +// We register a finalizer for addr, which is responsible for +// removing the heavy lock when addr goes away, in addition +// to the responsibilities of any prior finalizer. +// This unfortunately holds the lock bit for the hash entry while it +// allocates two objects (on for the finalizer). +// It would be nice to avoid that somehow ... +static heavy_lock * +alloc_heavy(obj_addr_t addr, hash_entry *he) +{ + heavy_lock * hl = (heavy_lock *) _Jv_AllocTraceTwo(sizeof (heavy_lock)); + + hl -> address = addr; + _Jv_MutexInit (&(hl -> si.mutex)); + _Jv_CondInit (&(hl -> si.condition)); +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + hl->si.init = true; // needed ? +# endif + hl -> next = he -> heavy_locks; + he -> heavy_locks = hl; + // FIXME: The only call that cheats and goes directly to the GC interface. +# ifdef HAVE_BOEHM_GC + GC_REGISTER_FINALIZER_NO_ORDER( + (void *)addr, heavy_lock_obj_finalization_proc, + hl, &hl->old_finalization_proc, + &hl->old_client_data); +# endif /* HAVE_BOEHM_GC */ + return hl; +} + +// Return the heavy lock for addr, allocating if necessary. +// Assumes we have the cache entry locked, and there is no lightweight +// lock for addr. +static heavy_lock * +get_heavy(obj_addr_t addr, hash_entry *he) +{ + heavy_lock *hl = find_heavy(addr, he); + if (0 == hl) + hl = alloc_heavy(addr, he); + return hl; +} + +void +_Jv_MonitorEnter (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + obj_addr_t address; + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned count; + const unsigned N_SPINS = 18; + + // We need to somehow check that addr is not NULL on the fast path. + // A very predictable + // branch on a register value is probably cheaper than dereferencing addr. + // We could also permanently lock the NULL entry in the hash table. + // But it's not clear that's cheaper either. + if (__builtin_expect(!addr, false)) + throw new java::lang::NullPointerException; + + JvAssert(!(addr & FLAGS)); +retry: + if (__builtin_expect(compare_and_swap(&(he -> address), + 0, addr),true)) + { + JvAssert(he -> light_thr_id == INVALID_THREAD_ID); + JvAssert(he -> light_count == 0); + he -> light_thr_id = self; + // Count fields are set correctly. Heavy_count was also zero, + // but can change asynchronously. + // This path is hopefully both fast and the most common. + LOG(ACQ_LIGHT, addr, self); + return; + } + address = he -> address; + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + { + if (he -> light_thr_id == self) + { + // We hold the lightweight lock, and it's for the right + // address. + count = he -> light_count; + if (count == USHRT_MAX) + { + // I think most JVMs don't check for this. + // But I'm not convinced I couldn't turn this into a security + // hole, even with a 32 bit counter. + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("maximum monitor nesting level exceeded")); + } + he -> light_count = count + 1; + return; + } + else + { + JvAssert(!(address & LOCKED)); + // Lightweight lock is held, but by somone else. + // Spin a few times. This avoids turning this into a heavyweight + // lock if the current holder is about to release it. + // FIXME: Does this make sense on a uniprocessor, where + // it actually yields? It's probably cheaper to convert. + for (unsigned int i = 0; i < N_SPINS; ++i) + { + if ((he -> address & ~LOCKED) != address) goto retry; + spin(i); + } + if (!compare_and_swap(&(he -> address), address, address | LOCKED )) + { + wait_unlocked(he); + goto retry; + } + heavy_lock *hl = get_heavy(addr, he); + ++ (he -> heavy_count); + // The hl lock acquisition can't block for long, since it can + // only be held by other threads waiting for conversion, and + // they, like us, drop it quickly without blocking. + _Jv_MutexLock(&(hl->si.mutex)); + JvAssert(he -> address == address | LOCKED ); + release_set(&(he -> address), (address | REQUEST_CONVERSION | HEAVY)); + // release lock on he + LOG(REQ_CONV, (address | REQUEST_CONVERSION | HEAVY), self); + // If _Jv_CondWait is interrupted, we ignore the interrupt, but + // restore the thread's interrupt status flag when done. + jboolean interrupt_flag = false; + while ((he -> address & ~FLAGS) == (address & ~FLAGS)) + { + // Once converted, the lock has to retain heavyweight + // status, since heavy_count > 0. + int r = _Jv_CondWait (&(hl->si.condition), &(hl->si.mutex), 0, 0); + if (r == _JV_INTERRUPTED) + { + interrupt_flag = true; + Thread::currentThread()->interrupt_flag = false; + } + } + if (interrupt_flag) + Thread::currentThread()->interrupt_flag = interrupt_flag; + keep_live(addr); + // Guarantee that hl doesn't get unlinked by finalizer. + // This is only an issue if the client fails to release + // the lock, which is unlikely. + JvAssert(he -> address & HEAVY); + // Lock has been converted, we hold the heavyweight lock, + // heavy_count has been incremented. + return; + } + } + obj_addr_t was_heavy = (address & HEAVY); + if ((address & LOCKED) || + !compare_and_swap(&(he -> address), address, (address | LOCKED ))) + { + wait_unlocked(he); + goto retry; + } + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == 0) + { + // Either was_heavy is true, or something changed out from under us, + // since the initial test for 0 failed. + JvAssert(!(address & REQUEST_CONVERSION)); + // Can't convert a nonexistent lightweight lock. + heavy_lock *hl; + hl = (was_heavy? find_heavy(addr, he) : 0); + // The CAS succeeded, so was_heavy is still accurate. + if (0 == hl) + { + // It is OK to use the lighweight lock, since either the + // heavyweight lock does not exist, or none of the + // heavyweight locks are currently in use. Future threads + // trying to acquire the lock will see the lightweight + // one first and use that. + he -> light_thr_id = self; // OK, since nobody else can hold + // light lock or do this at the same time. + JvAssert(he -> light_count == 0); + JvAssert(was_heavy == (he -> address & HEAVY)); + release_set(&(he -> address), (addr | was_heavy)); + LOG(ACQ_LIGHT2, addr | was_heavy, self); + } + else + { + // Must use heavy lock. + ++ (he -> heavy_count); + JvAssert(0 == (address & ~HEAVY)); + release_set(&(he -> address), HEAVY); + LOG(ACQ_HEAVY, addr | was_heavy, self); + _Jv_MutexLock(&(hl->si.mutex)); + keep_live(addr); + } + return; + } + // Lightweight lock is held, but does not correspond to this object. + // We hold the lock on the hash entry, and he -> address can't + // change from under us. Neither can the chain of heavy locks. + { + JvAssert(0 == he -> heavy_count || (address & HEAVY)); + heavy_lock *hl = get_heavy(addr, he); + ++ (he -> heavy_count); + release_set(&(he -> address), address | HEAVY); + LOG(ACQ_HEAVY2, address | HEAVY, self); + _Jv_MutexLock(&(hl->si.mutex)); + keep_live(addr); + } +} + + +void +_Jv_MonitorExit (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + _Jv_ThreadId_t light_thr_id; + unsigned count; + obj_addr_t address; + +retry: + light_thr_id = he -> light_thr_id; + // Unfortunately, it turns out we always need to read the address + // first. Even if we are going to update it with compare_and_swap, + // we need to reset light_thr_id, and that's not safe unless we know + // that we hold the lock. + address = he -> address; + // First the (relatively) fast cases: + if (__builtin_expect(light_thr_id == self, true)) + // Above must fail if addr == 0 . + { + count = he -> light_count; + if (__builtin_expect((address & ~HEAVY) == addr, true)) + { + if (count != 0) + { + // We held the lightweight lock all along. Thus the values + // we saw for light_thr_id and light_count must have been valid. + he -> light_count = count - 1; + return; + } + else + { + // We hold the lightweight lock once. + he -> light_thr_id = INVALID_THREAD_ID; + if (compare_and_swap_release(&(he -> address), address, + address & HEAVY)) + { + LOG(REL_LIGHT, address & HEAVY, self); + return; + } + else + { + he -> light_thr_id = light_thr_id; // Undo prior damage. + goto retry; + } + } + } + // else lock is not for this address, conversion is requested, + // or the lock bit in the address field is set. + } + else + { + if (__builtin_expect(!addr, false)) + throw new java::lang::NullPointerException; + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Lightweight lock held by other thread\n\t" + "light_thr_id = 0x%lx, self = 0x%lx, " + "address = 0x%lx, heavy_count = %d, pid = %d\n", + light_thr_id, self, (unsigned long)address, + he -> heavy_count, getpid()); + print_he(he); + for(;;) {} +# endif + // Someone holds the lightweight lock for this object, and + // it can't be us. + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("current thread not owner")); + } + else + count = he -> light_count; + } + if (address & LOCKED) + { + wait_unlocked(he); + goto retry; + } + // Now the unlikely cases. + // We do know that: + // - Address is set, and doesn't contain the LOCKED bit. + // - If address refers to the same object as addr, then he -> light_thr_id + // refers to this thread, and count is valid. + // - The case in which we held the lightweight lock has been + // completely handled, except for the REQUEST_CONVERSION case. + // + if ((address & ~FLAGS) == addr) + { + // The lightweight lock is assigned to this object. + // Thus we must be in the REQUEST_CONVERSION case. + if (0 != count) + { + // Defer conversion until we exit completely. + he -> light_count = count - 1; + return; + } + JvAssert(he -> light_thr_id == self); + JvAssert(address & REQUEST_CONVERSION); + // Conversion requested + // Convert now. + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + goto retry; + heavy_lock *hl = find_heavy(addr, he); + JvAssert (0 != hl); + // Requestor created it. + he -> light_count = 0; + JvAssert(he -> heavy_count > 0); + // was incremented by requestor. + _Jv_MutexLock(&(hl->si.mutex)); + // Release the he lock after acquiring the mutex. + // Otherwise we can accidentally + // notify a thread that has already seen a heavyweight + // lock. + he -> light_thr_id = INVALID_THREAD_ID; + release_set(&(he -> address), HEAVY); + LOG(PROMOTE, address, self); + // lightweight lock now unused. + _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + // heavy_count was already incremented by original requestor. + keep_live(addr); + return; + } + // lightweight lock not for this object. + JvAssert(!(address & LOCKED)); + JvAssert((address & ~FLAGS) != addr); + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + goto retry; + heavy_lock *hl = find_heavy(addr, he); + if (NULL == hl) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Failed to find heavyweight lock for addr 0x%lx" + " pid = %d\n", addr, getpid()); + print_he(he); + for(;;) {} +# endif + release_set(&(he -> address), address); + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("current thread not owner")); + } + JvAssert(address & HEAVY); + count = he -> heavy_count; + JvAssert(count > 0); + --count; + he -> heavy_count = count; + if (0 == count) + { + const unsigned test_freq = 16; // Power of 2 + static volatile unsigned counter = 0; + unsigned my_counter = counter; + + counter = my_counter + 1; + if (my_counter%test_freq == 0) + { + // Randomize the interval length a bit. + counter = my_counter + (my_counter >> 4) % (test_freq/2); + // Unlock mutex first, to avoid self-deadlock, or worse. + _Jv_MutexUnlock(&(hl->si.mutex)); + maybe_remove_all_heavy(he, address &~HEAVY); + // release lock bit, preserving + // REQUEST_CONVERSION + // and object address. + } + else + { + release_set(&(he -> address), address &~HEAVY); + _Jv_MutexUnlock(&(hl->si.mutex)); + // Unlock after releasing the lock bit, so that + // we don't switch to another thread prematurely. + } + } + else + { + release_set(&(he -> address), address); + _Jv_MutexUnlock(&(hl->si.mutex)); + } + LOG(REL_HEAVY, addr, self); + keep_live(addr); +} + +// Return false if obj's monitor is held by the current thread +bool +_Jv_ObjectCheckMonitor (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + obj_addr_t address; + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + + JvAssert(!(addr & FLAGS)); + address = he -> address; + // Try it the easy way first: + if (address == 0) return true; + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + // Fails if entry is LOCKED. + // I can't asynchronously become or stop being the holder. + return he -> light_thr_id != self; +retry: + // Acquire the hash table entry lock + address &= ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + + bool not_mine; + + if ((address & ~FLAGS) == addr) + not_mine = (he -> light_thr_id != self); + else + { + heavy_lock* hl = find_heavy(addr, he); + not_mine = hl ? _Jv_MutexCheckMonitor(&hl->si.mutex) : true; + } + + release_set(&(he -> address), address); // unlock hash entry + return not_mine; +} + +// The rest of these are moderately thin veneers on _Jv_Cond ops. +// The current version of Notify might be able to make the pthread +// call AFTER releasing the lock, thus saving some context switches?? + +void +java::lang::Object::wait (jlong timeout, jint nanos) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + unsigned count; + obj_addr_t address; + heavy_lock *hl; + + if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) + throw new IllegalArgumentException; +retry: + address = he -> address; + address &= ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + // address did not have the lock bit set. We now hold the lock on he. + if ((address & ~FLAGS) == addr) + { + // Convert to heavyweight. + if (he -> light_thr_id != self) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Found wrong lightweight lock owner in wait " + "address = 0x%lx pid = %d\n", address, getpid()); + print_he(he); + for(;;) {} +# endif + release_set(&(he -> address), address); + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + } + count = he -> light_count; + hl = get_heavy(addr, he); + he -> light_count = 0; + he -> heavy_count += count + 1; + for (unsigned i = 0; i <= count; ++i) + _Jv_MutexLock(&(hl->si.mutex)); + // Again release the he lock after acquiring the mutex. + he -> light_thr_id = INVALID_THREAD_ID; + release_set(&(he -> address), HEAVY); // lightweight lock now unused. + LOG(PROMOTE2, addr, self); + if (address & REQUEST_CONVERSION) + _Jv_CondNotifyAll (&(hl->si.condition), &(hl->si.mutex)); + // Since we do this before we do a CondWait, we guarantee that + // threads waiting on requested conversion are awoken before + // a real wait on the same condition variable. + // No other notification can occur in the interim, since + // we hold the heavy lock, and notifications are made + // without acquiring it. + } + else /* We should hold the heavyweight lock. */ + { + hl = find_heavy(addr, he); + release_set(&(he -> address), address); + if (0 == hl) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Couldn't find heavy lock in wait " + "addr = 0x%lx pid = %d\n", addr, getpid()); + print_he(he); + for(;;) {} +# endif + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + } + JvAssert(address & HEAVY); + } + LOG(WAIT_START, addr, self); + switch (_Jv_CondWait (&(hl->si.condition), &(hl->si.mutex), timeout, nanos)) + { + case _JV_NOT_OWNER: + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + case _JV_INTERRUPTED: + if (Thread::interrupted ()) + throw new InterruptedException; + } + LOG(WAIT_END, addr, self); +} + +void +java::lang::Object::notify (void) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + heavy_lock *hl; + obj_addr_t address; + int result; + +retry: + address = ((he -> address) & ~LOCKED); + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + if ((address & ~FLAGS) == addr && he -> light_thr_id == self) + { + // We hold lightweight lock. Since it has not + // been inflated, there are no waiters. + release_set(&(he -> address), address); // unlock + return; + } + hl = find_heavy(addr, he); + // Hl can't disappear since we point to the underlying object. + // It's important that we release the lock bit before the notify, since + // otherwise we will try to wake up the target while we still hold the + // bit. This results in lock bit contention, which we don't handle + // terribly well. + release_set(&(he -> address), address); // unlock + if (0 == hl) + { + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); + return; + } + // We know that we hold the heavyweight lock at this point, + // and the lightweight lock is not in use. + result = _Jv_CondNotify(&(hl->si.condition), &(hl->si.mutex)); + LOG(NOTIFY, addr, self); + keep_live(addr); + if (__builtin_expect (result, 0)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::notifyAll (void) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + heavy_lock *hl; + obj_addr_t address; + int result; + +retry: + address = (he -> address) & ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + hl = find_heavy(addr, he); + if ((address & ~FLAGS) == addr && he -> light_thr_id == self) + { + // We hold lightweight lock. Since it has not + // been inflated, there are no waiters. + release_set(&(he -> address), address); // unlock + return; + } + release_set(&(he -> address), address); // unlock + if (0 == hl) + { + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); + } + result = _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); + LOG(NOTIFY_ALL, addr, self); + if (__builtin_expect (result, 0)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +// This is declared in Java code and in Object.h. +// It should never be called with JV_HASH_SYNCHRONIZATION +void +java::lang::Object::sync_init (void) +{ + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("internal error: sync_init")); +} + +// This is called on startup and declared in Object.h. +// For now we just make it a no-op. +void +_Jv_InitializeSyncMutex (void) +{ +} + +#endif /* JV_HASH_SYNCHRONIZATION */ + diff --git a/libjava/java/lang/natPosixProcess.cc b/libjava/java/lang/natPosixProcess.cc new file mode 100644 index 000000000..fbd3f6a0a --- /dev/null +++ b/libjava/java/lang/natPosixProcess.cc @@ -0,0 +1,515 @@ +// natPosixProcess.cc - Native side of POSIX process code. + +/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> + +#include <posix.h> +#include <posix-threads.h> +#include <jvm.h> + +#include <java/lang/PosixProcess$ProcessManager.h> +#include <java/lang/PosixProcess.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InternalError.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Thread.h> +#include <java/io/File.h> +#include <java/io/FileDescriptor.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> +#include <java/io/FileInputStream.h> +#include <java/io/FileOutputStream.h> +#include <java/io/IOException.h> +#include <java/lang/OutOfMemoryError.h> +#include <java/lang/PosixProcess$EOFInputStream.h> + +using gnu::java::nio::channels::FileChannelImpl; +using namespace java::lang; + +extern char **environ; + +static char * +new_string (jstring string) +{ + jsize s = _Jv_GetStringUTFLength (string); + char *buf = (char *) _Jv_Malloc (s + 1); + _Jv_GetStringUTFRegion (string, 0, string->length(), buf); + buf[s] = '\0'; + return buf; +} + +static void +cleanup (char **args, char **env, char *path) +{ + if (args != NULL) + { + for (int i = 0; args[i] != NULL; ++i) + _Jv_Free (args[i]); + _Jv_Free (args); + } + if (env != NULL) + { + for (int i = 0; env[i] != NULL; ++i) + _Jv_Free (env[i]); + _Jv_Free (env); + } + if (path != NULL) + _Jv_Free (path); +} + +// This makes our error handling a bit simpler and it lets us avoid +// thread bugs where we close a possibly-reopened file descriptor for +// a second time. +static void +myclose (int &fd) +{ + if (fd != -1) + close (fd); + fd = -1; +} + +namespace +{ + struct ProcessManagerInternal + { + int pipe_ends[2]; + struct sigaction old_sigaction; + }; +} + + +// There has to be a signal handler in order to be able to +// sigwait() on SIGCHLD. The information passed is ignored as it +// will be recovered by the waitpid() call. +static void +#ifdef SA_SIGINFO +sigchld_handler (int sig, siginfo_t *si, void *third) +#else +sigchld_handler (int sig) +#endif +{ + if (PosixProcess$ProcessManager::nativeData != NULL) + { + ProcessManagerInternal *pmi = + (ProcessManagerInternal *)PosixProcess$ProcessManager::nativeData; + char c = 0; + ::write(pmi->pipe_ends[1], &c, 1); + if (pmi->old_sigaction.sa_handler != SIG_DFL + && pmi->old_sigaction.sa_handler != SIG_IGN) + { +#ifdef SA_SIGINFO + if ((pmi->old_sigaction.sa_flags & SA_SIGINFO) != 0) + pmi->old_sigaction.sa_sigaction(sig, si, third); + else +#endif + (*pmi->old_sigaction.sa_handler)(sig); + } + } +} + + +// Get ready to enter the main reaper thread loop. +void +java::lang::PosixProcess$ProcessManager::init () +{ + // The nativeData is static to avoid races installing the signal + // handler in the case that it is chained. + if (nativeData == NULL ) + { + ProcessManagerInternal *pmi = + (ProcessManagerInternal *)JvAllocBytes(sizeof(ProcessManagerInternal)); + + if (0 != ::pipe(pmi->pipe_ends)) + goto error; + + // Make writing non-blocking so that the signal handler will + // never block. + int fl = ::fcntl(pmi->pipe_ends[1], F_GETFL); + ::fcntl(pmi->pipe_ends[1], F_SETFL, fl | O_NONBLOCK); + + nativeData = (::gnu::gcj::RawDataManaged *)pmi; + + // SIGCHLD is blocked in all threads in posix-threads.cc. + // Setup the SIGCHLD handler. + struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + +#ifdef SA_SIGINFO + sa.sa_sigaction = sigchld_handler; + // We only want signals when the things exit. + sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; +#else + sa.sa_handler = sigchld_handler; + // We only want signals when the things exit. + sa.sa_flags = SA_NOCLDSTOP; +#endif + + if (-1 == sigaction (SIGCHLD, &sa, &pmi->old_sigaction)) + goto error; + } + // All OK. + return; + +error: + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::PosixProcess$ProcessManager::waitForSignal () +{ + // Wait for SIGCHLD + _Jv_UnBlockSigchld(); + ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData; + + // Try to read multiple (64) notifications in one go. + char c[64]; + ::read(pmi->pipe_ends[0], c, sizeof (c)); + + _Jv_BlockSigchld(); + + return; +} + +jboolean java::lang::PosixProcess$ProcessManager::reap (PosixProcess *p) +{ + pid_t rv; + + // Try to get the return code from the child process. + int status; + rv = ::waitpid ((pid_t)p->pid, &status, WNOHANG); + if (rv == -1) + throw new InternalError (JvNewStringUTF (strerror (errno))); + + if (rv == 0) + return false; // No children to wait for. + + JvSynchronize sync (p); + p->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1; + p->state = PosixProcess::STATE_TERMINATED; + p->processTerminationCleanup(); + p->notifyAll (); + return true; +} + +void +java::lang::PosixProcess$ProcessManager::signalReaper () +{ + ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData; + char c = 0; + ::write(pmi->pipe_ends[1], &c, 1); + // Ignore errors. If EPIPE the reaper has already exited. +} + +void +java::lang::PosixProcess::nativeDestroy () +{ + int c = ::kill ((pid_t) pid, SIGKILL); + if (c == 0) + return; + // kill() failed. + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::PosixProcess::nativeSpawn () +{ + using namespace java::io; + + // Initialize all locals here to make cleanup simpler. + char **args = NULL; + char **env = NULL; + char *path = NULL; + int inp[2], outp[2], errp[2], msgp[2]; + inp[0] = -1; + inp[1] = -1; + outp[0] = -1; + outp[1] = -1; + errp[0] = -1; + errp[1] = -1; + msgp[0] = -1; + msgp[1] = -1; + errorStream = NULL; + inputStream = NULL; + outputStream = NULL; + + try + { + // Transform arrays to native form. + args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *)); + + // Initialize so we can gracefully recover. + jstring *elts = elements (progarray); + for (int i = 0; i <= progarray->length; ++i) + args[i] = NULL; + + for (int i = 0; i < progarray->length; ++i) + args[i] = new_string (elts[i]); + args[progarray->length] = NULL; + + if (envp) + { + bool need_path = true; + bool need_ld_library_path = true; + int i; + + // Preserve PATH and LD_LIBRARY_PATH unless specified + // explicitly. We need three extra slots. Potentially PATH + // and LD_LIBRARY_PATH will be added plus the NULL + // termination. + env = (char **) _Jv_Malloc ((envp->length + 3) * sizeof (char *)); + elts = elements (envp); + + // Initialize so we can gracefully recover. + for (i = 0; i < envp->length + 3; ++i) + env[i] = NULL; + + for (i = 0; i < envp->length; ++i) + { + env[i] = new_string (elts[i]); + if (!strncmp (env[i], "PATH=", sizeof("PATH="))) + need_path = false; + if (!strncmp (env[i], "LD_LIBRARY_PATH=", + sizeof("LD_LIBRARY_PATH="))) + need_ld_library_path = false; + } + + if (need_path) + { + char *path_val = getenv ("PATH"); + if (path_val) + { + env[i] = (char *) _Jv_Malloc (strlen (path_val) + + sizeof("PATH=") + 1); + strcpy (env[i], "PATH="); + strcat (env[i], path_val); + i++; + } + } + if (need_ld_library_path) + { + char *path_val = getenv ("LD_LIBRARY_PATH"); + if (path_val) + { + env[i] = + (char *) _Jv_Malloc (strlen (path_val) + + sizeof("LD_LIBRARY_PATH=") + 1); + strcpy (env[i], "LD_LIBRARY_PATH="); + strcat (env[i], path_val); + i++; + } + } + env[i] = NULL; + } + + // We allocate this here because we can't call malloc() after + // the fork. + if (dir != NULL) + path = new_string (dir->getPath ()); + + // Create pipes for I/O. MSGP is for communicating exec() + // status. If redirecting stderr to stdout, we don't need to + // create the ERRP pipe. + if (pipe (inp) || pipe (outp) || pipe (msgp) + || fcntl (msgp[1], F_SETFD, FD_CLOEXEC)) + throw new IOException (JvNewStringUTF (strerror (errno))); + if (! redirect && pipe (errp)) + throw new IOException (JvNewStringUTF (strerror (errno))); + + // We create the streams before forking. Otherwise if we had an + // error while creating the streams we would have run the child + // with no way to communicate with it. + if (redirect) + errorStream = PosixProcess$EOFInputStream::instance; + else + errorStream = + new FileInputStream (new + FileChannelImpl (errp[0], + FileChannelImpl::READ)); + inputStream = + new FileInputStream (new + FileChannelImpl (inp[0], FileChannelImpl::READ)); + outputStream = + new FileOutputStream (new FileChannelImpl (outp[1], + FileChannelImpl::WRITE)); + + // We don't use vfork() because that would cause the local + // environment to be set by the child. + + // Use temporary for fork result to avoid dirtying an extra page. + pid_t pid_tmp; + if ((pid_tmp = fork ()) == -1) + throw new IOException (JvNewStringUTF (strerror (errno))); + + if (pid_tmp == 0) + { + // Child process, so remap descriptors, chdir and exec. + if (envp) + environ = env; + + // We ignore errors from dup2 because they should never occur. + dup2 (outp[0], 0); + dup2 (inp[1], 1); + dup2 (redirect ? inp[1] : errp[1], 2); + + // Use close and not myclose -- we're in the child, and we + // aren't worried about the possible race condition. + close (inp[0]); + close (inp[1]); + if (! redirect) + { + close (errp[0]); + close (errp[1]); + } + close (outp[0]); + close (outp[1]); + close (msgp[0]); + + // Change directory. + if (path != NULL) + { + if (chdir (path) != 0) + { + char c = errno; + write (msgp[1], &c, 1); + _exit (127); + } + } + // Make sure all file descriptors are closed. In + // multi-threaded programs, there is a race between when a + // descriptor is obtained, when we can set FD_CLOEXEC, and + // fork(). If the fork occurs before FD_CLOEXEC is set, the + // descriptor would leak to the execed process if we did not + // manually close it. So that is what we do. Since we + // close all the descriptors, it is redundant to set + // FD_CLOEXEC on them elsewhere. + int max_fd; +#ifdef HAVE_GETRLIMIT + rlimit rl; + int rv = getrlimit(RLIMIT_NOFILE, &rl); + if (rv == 0) + max_fd = rl.rlim_max - 1; + else + max_fd = 1024 - 1; +#else + max_fd = 1024 - 1; +#endif + while(max_fd > 2) + { + if (max_fd != msgp[1]) + close (max_fd); + max_fd--; + } + // Make sure that SIGCHLD is unblocked for the new process. + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + sigprocmask (SIG_UNBLOCK, &mask, NULL); + + execvp (args[0], args); + + // Send the parent notification that the exec failed. + char c = errno; + write (msgp[1], &c, 1); + _exit (127); + } + + // Parent. Close extra file descriptors and mark ours as + // close-on-exec. + pid = (jlong) pid_tmp; + + myclose (outp[0]); + myclose (inp[1]); + if (! redirect) + myclose (errp[1]); + myclose (msgp[1]); + + char c; + int r = read (msgp[0], &c, 1); + if (r == -1) + throw new IOException (JvNewStringUTF (strerror (errno))); + else if (r != 0) + throw new IOException (JvNewStringUTF (strerror (c))); + } + catch (java::lang::Throwable *thrown) + { + // Do some cleanup we only do on failure. If a stream object + // has been created, we must close the stream itself (to avoid + // duplicate closes when the stream object is collected). + // Otherwise we simply close the underlying file descriptor. + // We ignore errors here as they are uninteresting. + + try + { + if (inputStream != NULL) + inputStream->close (); + else + myclose (inp[0]); + } + catch (java::lang::Throwable *ignore) + { + } + + try + { + if (outputStream != NULL) + outputStream->close (); + else + myclose (outp[1]); + } + catch (java::lang::Throwable *ignore) + { + } + + try + { + if (errorStream != NULL) + errorStream->close (); + else if (! redirect) + myclose (errp[0]); + } + catch (java::lang::Throwable *ignore) + { + } + + // These are potentially duplicate, but it doesn't matter due to + // the use of myclose. + myclose (outp[0]); + myclose (inp[1]); + if (! redirect) + myclose (errp[1]); + myclose (msgp[1]); + + exception = thrown; + } + + myclose (msgp[0]); + cleanup (args, env, path); +} diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc new file mode 100644 index 000000000..02842b1df --- /dev/null +++ b/libjava/java/lang/natRuntime.cc @@ -0,0 +1,323 @@ +// natRuntime.cc - Implementation of native side of Runtime class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-props.h> +#include <java-stack.h> +#include <java/lang/Long.h> +#include <java/lang/Runtime.h> +#include <java/lang/UnknownError.h> +#include <java/lang/UnsatisfiedLinkError.h> +#include <gnu/gcj/runtime/FinalizerThread.h> +#include <java/io/File.h> +#include <java/util/TimeZone.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/Process.h> +#include <java/lang/ClassLoader.h> + +// It is convenient and safe to simply include all of these. +#include <java/lang/Win32Process.h> +#include <java/lang/EcosProcess.h> +#include <java/lang/PosixProcess.h> + +#include <jni.h> + +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <errno.h> + +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif + + + +#ifdef USE_LTDL +#include <ltdl.h> + +/* FIXME: we don't always need this. The next libtool will let us use + AC_LTDL_PREOPEN to see if we do. */ +extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } }; + +struct lookup_data +{ + const char *symname; + void *result; +}; + +static int +find_symbol (lt_dlhandle handle, lt_ptr data) +{ + lookup_data *ld = (lookup_data *) data; + ld->result = lt_dlsym (handle, ld->symname); + return ld->result != NULL; +} + +void * +_Jv_FindSymbolInExecutable (const char *symname) +{ + lookup_data data; + data.symname = symname; + data.result = NULL; + lt_dlforeach (find_symbol, (lt_ptr) &data); + return data.result; +} + +#else + +void * +_Jv_FindSymbolInExecutable (const char *) +{ + return NULL; +} + +#endif /* USE_LTDL */ + + + +void +java::lang::Runtime::runFinalizationForExit () +{ + if (finalizeOnExit) + _Jv_RunAllFinalizers (); +} + +void +java::lang::Runtime::exitInternal (jint status) +{ + // Make status right for Unix. This is perhaps strange. + if (status < 0 || status > 255) + status = 255; + + ::exit (status); +} + +jlong +java::lang::Runtime::freeMemory (void) +{ + return _Jv_GCFreeMemory (); +} + +void +java::lang::Runtime::gc (void) +{ + _Jv_RunGC (); +} + +#ifdef USE_LTDL +// List of names for JNI_OnLoad. +static const char *onload_names[] = _Jv_platform_onload_names; +#endif + +void +java::lang::Runtime::_load (jstring path, jboolean do_search) +{ + JvSynchronize sync (this); + using namespace java::lang; +#ifdef USE_LTDL + jint len = _Jv_GetStringUTFLength (path); + char buf[len + 1 + strlen (_Jv_platform_solib_prefix) + + strlen (_Jv_platform_solib_suffix)]; + int offset = 0; + if (do_search) + { + strcpy (buf, _Jv_platform_solib_prefix); + offset = strlen (_Jv_platform_solib_prefix); + } + jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]); + buf[offset + total] = '\0'; + + char *lib_name = buf; + + if (do_search) + { + ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader (); + + if (look != NULL) + { + // Don't include solib prefix in string passed to + // findLibrary. + jstring name = look->findLibrary(JvNewStringUTF(&buf[offset])); + if (name != NULL) + { + len = _Jv_GetStringUTFLength (name); + lib_name = (char *) _Jv_AllocBytes(len + 1); + total = JvGetStringUTFRegion (name, 0, + name->length(), lib_name); + lib_name[total] = '\0'; + // Don't append suffixes any more; we have the full file + // name. + do_search = false; + } + } + } + + lt_dlhandle h; + // FIXME: make sure path is absolute. + { + // Synchronize on java.lang.Class. This is to protect the class chain from + // concurrent modification by class registration calls which may be run + // during the dlopen(). + JvSynchronize sync (&java::lang::Class::class$); + h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name); + } + if (h == NULL) + { + const char *msg = lt_dlerror (); + jstring str = JvNewStringLatin1 (lib_name); + str = str->concat (JvNewStringLatin1 (": ")); + str = str->concat (JvNewStringLatin1 (msg)); + throw new UnsatisfiedLinkError (str); + } + + // Search for JNI_OnLoad function. + void *onload = NULL; + const char **name = onload_names; + while (*name != NULL) + { + onload = lt_dlsym (h, *name); + if (onload != NULL) + break; + ++name; + } + + if (onload != NULL) + { + JavaVM *vm = _Jv_GetJavaVM (); + if (vm == NULL) + { + // FIXME: what? + return; + } + + // Push a new frame so that JNI_OnLoad will get the right class + // loader if it calls FindClass. + ::java::lang::ClassLoader *loader + = _Jv_StackTrace::GetFirstNonSystemClassLoader(); + JNIEnv *env = _Jv_GetJNIEnvNewFrameWithLoader (loader); + jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL); + _Jv_JNI_PopSystemFrame (env); + if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2 + && vers != JNI_VERSION_1_4) + { + // FIXME: unload the library. + throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad")); + } + } +#else + throw new UnknownError + (JvNewStringLatin1 (do_search + ? "Runtime.loadLibrary not implemented" + : "Runtime.load not implemented")); +#endif /* USE_LTDL */ +} + +jboolean +java::lang::Runtime::loadLibraryInternal (jstring lib) +{ + JvSynchronize sync (this); + using namespace java::lang; +#ifdef USE_LTDL + jint len = _Jv_GetStringUTFLength (lib); + char buf[len + 1]; + jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf); + buf[total] = '\0'; + // FIXME: make sure path is absolute. + lt_dlhandle h = lt_dlopenext (buf); + return h != NULL; +#else + return false; +#endif /* USE_LTDL */ +} + +void +java::lang::Runtime::init (void) +{ +#ifdef USE_LTDL + lt_dlinit (); + // Set module load path. + lt_dlsetsearchpath (_Jv_Module_Load_Path); + // Make sure self is opened. + lt_dlopen (NULL); +#endif +} + +void +java::lang::Runtime::runFinalization (void) +{ + gnu::gcj::runtime::FinalizerThread::finalizerReady (); +} + +jlong +java::lang::Runtime::totalMemory (void) +{ + return _Jv_GCTotalMemory (); +} + +jlong +java::lang::Runtime::maxMemory (void) +{ + // We don't have a maximum. FIXME: we might if we ask the GC for + // one. + return Long::MAX_VALUE; +} + +void +java::lang::Runtime::traceInstructions (jboolean) +{ + // Do nothing. +} + +void +java::lang::Runtime::traceMethodCalls (jboolean) +{ + // Do nothing. +} + +java::lang::Process * +java::lang::Runtime::execInternal (jstringArray cmd, + jstringArray env, + java::io::File *dir) +{ + return new _Jv_platform_process (cmd, env, dir, false); +} + +jint +java::lang::Runtime::availableProcessors (void) +{ + // FIXME: find the real value. + return 1; +} + +jstring +java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname) +{ + java::lang::StringBuffer *sb = new java::lang::StringBuffer (); + sb->append(pathname); + if (pathname->length() > 0) + sb->append (_Jv_platform_file_separator); + + sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix)); + sb->append(libname); + sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix)); + + return sb->toString(); +} diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc new file mode 100644 index 000000000..75006a7c9 --- /dev/null +++ b/libjava/java/lang/natString.cc @@ -0,0 +1,1068 @@ +// natString.cc - Implementation of java.lang.String native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007, 2008 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <string.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <java/lang/Character.h> +#include <java/lang/CharSequence.h> +#include <java/lang/String.h> +#include <java/lang/IndexOutOfBoundsException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/StringIndexOutOfBoundsException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/StringBuffer.h> +#include <java/io/ByteArrayOutputStream.h> +#include <java/io/CharConversionException.h> +#include <java/io/OutputStreamWriter.h> +#include <java/io/ByteArrayInputStream.h> +#include <java/io/InputStreamReader.h> +#include <java/util/Locale.h> +#include <gnu/gcj/convert/UnicodeToBytes.h> +#include <gnu/gcj/convert/BytesToUnicode.h> +#include <gnu/gcj/runtime/StringBuffer.h> +#include <jvm.h> + +static jstring* strhash = NULL; +static int strhash_count = 0; /* Number of slots used in strhash. */ +static int strhash_size = 0; /* Number of slots available in strhash. + * Assumed be power of 2! */ + +// Some defines used by toUpperCase / toLowerCase. +#define ESSET 0x00df +#define CAPITAL_S 0x0053 +#define SMALL_I 0x0069 +#define CAPITAL_I_WITH_DOT 0x0130 +#define SMALL_DOTLESS_I 0x0131 +#define CAPITAL_I 0x0049 + +#define DELETED_STRING ((jstring)(~0)) +#define SET_STRING_IS_INTERNED(STR) /* nothing */ + +#define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01) +#define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01) +#define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01) + +/* Find a slot where the string with elements DATA, length LEN, + and hash HASH should go in the strhash table of interned strings. */ +jstring* +_Jv_StringFindSlot (jchar* data, jint len, jint hash) +{ + JvSynchronize sync (&java::lang::String::class$); + + int start_index = hash & (strhash_size - 1); + int deleted_index = -1; + + int index = start_index; + /* step must be non-zero, and relatively prime with strhash_size. */ + jint step = (hash ^ (hash >> 16)) | 1; + do + { + jstring* ptr = &strhash[index]; + jstring value = (jstring) UNMASK_PTR (*ptr); + if (value == NULL) + { + if (deleted_index >= 0) + return (&strhash[deleted_index]); + else + return ptr; + } + else if (*ptr == DELETED_STRING) + deleted_index = index; + else if (value->length() == len + && memcmp(JvGetStringChars(value), data, 2*len) == 0) + return (ptr); + index = (index + step) & (strhash_size - 1); + } + while (index != start_index); + // Note that we can have INDEX == START_INDEX if the table has no + // NULL entries but does have DELETED_STRING entries. + JvAssert (deleted_index >= 0); + return &strhash[deleted_index]; +} + +/* Calculate a hash code for the string starting at PTR at given LENGTH. + This uses the same formula as specified for java.lang.String.hash. */ + +static jint +hashChars (jchar* ptr, jint length) +{ + jchar* limit = ptr + length; + jint hash = 0; + // Updated specification from + // http://www.javasoft.com/docs/books/jls/clarify.html. + while (ptr < limit) + hash = (31 * hash) + *ptr++; + return hash; +} + +jint +java::lang::String::hashCode() +{ + if (cachedHashCode == 0) + cachedHashCode = hashChars(JvGetStringChars(this), length()); + return cachedHashCode; +} + +jstring* +_Jv_StringGetSlot (jstring str) +{ + jchar* data = JvGetStringChars(str); + int length = str->length(); + return _Jv_StringFindSlot(data, length, hashChars (data, length)); +} + +static void +rehash () +{ + JvSynchronize sync (&java::lang::String::class$); + + if (strhash == NULL) + { + strhash_size = 1024; + strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring)); + } + else + { + int i = strhash_size; + jstring* ptr = strhash + i; + int nsize = strhash_size * 2; + jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring)); + + while (--i >= 0) + { + --ptr; + if (*ptr == NULL || *ptr == DELETED_STRING) + continue; + + /* This is faster equivalent of + * *__JvGetInternSlot(*ptr) = *ptr; */ + jstring val = (jstring) UNMASK_PTR (*ptr); + jint hash = val->hashCode(); + jint index = hash & (nsize - 1); + jint step = (hash ^ (hash >> 16)) | 1; + for (;;) + { + if (next[index] == NULL) + { + next[index] = *ptr; + break; + } + index = (index + step) & (nsize - 1); + } + } + + strhash_size = nsize; + strhash = next; + } +} + +jstring +java::lang::String::intern() +{ + JvSynchronize sync (&java::lang::String::class$); + if (3 * strhash_count >= 2 * strhash_size) + rehash(); + jstring* ptr = _Jv_StringGetSlot(this); + if (*ptr != NULL && *ptr != DELETED_STRING) + { + // See description in _Jv_FinalizeString() to understand this. + *ptr = (jstring) MASK_PTR (*ptr); + return (jstring) UNMASK_PTR (*ptr); + } + jstring str = (this->data == this + ? this + : _Jv_NewString(JvGetStringChars(this), this->length())); + SET_STRING_IS_INTERNED(str); + strhash_count++; + *ptr = str; + // When string is GC'd, clear the slot in the hash table. + _Jv_RegisterStringFinalizer (str); + return str; +} + +// The fake String finalizer. This is only used when the String has +// been intern()d. However, we must check this case, as it might be +// called by the Reference code for any String. +void +_Jv_FinalizeString (jobject obj) +{ + JvSynchronize sync (&java::lang::String::class$); + + // We might not actually have intern()d any strings at all, if + // we're being called from Reference. + if (! strhash) + return; + + jstring str = reinterpret_cast<jstring> (obj); + jstring *ptr = _Jv_StringGetSlot(str); + if (*ptr == NULL || *ptr == DELETED_STRING + || (jobject) UNMASK_PTR (*ptr) != obj) + return; + + // We assume the lowest bit of the pointer is free for our nefarious + // manipulations. What we do is set it to `0' (implicitly) when + // interning the String. If we subsequently re-intern the same + // String, then we set the bit. When finalizing, if the bit is set + // then we clear it and re-register the finalizer. We know this is + // a safe approach because both intern() and _Jv_FinalizeString() + // acquire the class lock; this bit can't be manipulated when the + // lock is not held. So if we are finalizing and the bit is clear + // then we know all references are gone and we can clear the entry + // in the hash table. The naive approach of simply clearing the + // pointer here fails in the case where a request to intern a new + // string with the same contents is made between the time the + // intern()d string is found to be unreachable and when the + // finalizer is actually run. In this case we could clear a pointer + // to a valid string, and future intern() calls for that particular + // value would spuriously fail. + if (PTR_MASKED (*ptr)) + { + *ptr = (jstring) UNMASK_PTR (*ptr); + _Jv_RegisterStringFinalizer (obj); + } + else + { + *ptr = DELETED_STRING; + strhash_count--; + } +} + +jstring +_Jv_NewStringUTF (const char *bytes) +{ + int size = strlen (bytes); + unsigned char *p = (unsigned char *) bytes; + + int length = _Jv_strLengthUtf8 ((char *) p, size); + if (length < 0) + return NULL; + + jstring jstr = JvAllocString (length); + jchar *chrs = JvGetStringChars (jstr); + + p = (unsigned char *) bytes; + unsigned char *limit = p + size; + while (p < limit) + *chrs++ = UTF8_GET (p, limit); + + return jstr; +} + +jstring +_Jv_NewStringUtf8Const (Utf8Const* str) +{ + jchar *chrs; + jchar buffer[100]; + jstring jstr; + unsigned char* data = (unsigned char*) str->data; + unsigned char* limit = data + str->length; + int length = _Jv_strLengthUtf8(str->data, str->length); + + if (length <= (int) (sizeof(buffer) / sizeof(jchar))) + { + jstr = NULL; + chrs = buffer; + } + else + { + jstr = JvAllocString(length); + chrs = JvGetStringChars(jstr); + } + + jint hash = 0; + while (data < limit) + { + jchar ch = UTF8_GET(data, limit); + hash = (31 * hash) + ch; + *chrs++ = ch; + } + chrs -= length; + + JvSynchronize sync (&java::lang::String::class$); + if (3 * strhash_count >= 2 * strhash_size) + rehash(); + jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); + if (*ptr != NULL && *ptr != DELETED_STRING) + return (jstring) UNMASK_PTR (*ptr); + strhash_count++; + if (jstr == NULL) + { + jstr = JvAllocString(length); + chrs = JvGetStringChars(jstr); + memcpy (chrs, buffer, sizeof(jchar)*length); + } + jstr->cachedHashCode = hash; + *ptr = jstr; + SET_STRING_IS_INTERNED(jstr); + // When string is GC'd, clear the slot in the hash table. Note that + // we don't have to call _Jv_RegisterStringFinalizer here, as we + // know the new object cannot be referred to by a Reference. + _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString); + return jstr; +} + +jsize +_Jv_GetStringUTFLength (jstring string) +{ + jsize len = 0; + jchar *ptr = JvGetStringChars (string); + jsize i = string->length(); + while (--i >= 0) + { + jchar ch = *ptr++; + if (ch > 0 && ch <= 0x7F) + len += 1; + else if (ch <= 0x7FF) + len += 2; + else + len += 3; + } + return len; +} + +// Not sure this quite matches GetStringUTFRegion. +// null-termination of result? len? throw exception? +jsize +_Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf) +{ + jchar *sptr = JvGetStringChars (str) + start; + jsize i = len; + char *dptr = buf; + while (--i >= 0) + { + jchar ch = *sptr++; + if (ch > 0 && ch <= 0x7F) + *dptr++ = (char) ch; + else if (ch <= 0x7FF) + { + *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F)); + *dptr++ = (char) (0x80 + (ch & 0x3F)); + } + else + { + *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF)); + *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F)); + *dptr++ = (char) (0x80 + (ch & 0x3F)); + } + } + return dptr - buf; +} + +/* Put printed (decimal) representation of NUM in a buffer. + BUFEND marks the end of the buffer, which must be at least 11 jchars long. + Returns the COUNT of jchars written. The result is in + (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */ + +jint +_Jv_FormatInt (jchar* bufend, jint num) +{ + register jchar* ptr = bufend; + jboolean isNeg; + if (num < 0) + { + isNeg = true; + if (num != (jint) -2147483648U) + num = -(num); + else + { + // Handle special case of MIN_VALUE. + *--ptr = '8'; + num = 214748364; + } + } + else + isNeg = false; + + do + { + *--ptr = (jchar) ((int) '0' + (num % 10)); + num /= 10; + } + while (num > 0); + + if (isNeg) + *--ptr = '-'; + return bufend - ptr; +} + +jstring +java::lang::String::valueOf (jint num) +{ + // Use an array large enough for "-2147483648"; i.e. 11 chars. + jchar buffer[11]; + int i = _Jv_FormatInt (buffer+11, num); + return _Jv_NewString (buffer+11-i, i); +} + +jstring +_Jv_NewString(const jchar *chars, jsize len) +{ + jstring str = _Jv_AllocString(len); + jchar* data = JvGetStringChars (str); + memcpy (data, chars, len * sizeof (jchar)); + return str; +} + +jstring +_Jv_NewStringLatin1(const char *bytes, jsize len) +{ + jstring str = JvAllocString(len); + jchar* data = JvGetStringChars (str); + while (--len >= 0) + *data++ = *(unsigned char*)bytes++; + return str; +} + +void +java::lang::String::init(jcharArray chars, jint offset, jint count, + jboolean dont_copy) +{ + if (! chars) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (chars); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array; + jchar *pdst; + if (! dont_copy) + { + array = JvNewCharArray(count); + pdst = elements (array); + memcpy (pdst, elements (chars) + offset, count * sizeof (jchar)); + } + else + { + array = chars; + pdst = &(elements(array)[offset]); + } + + data = array; + boffset = (char *) pdst - (char *) array; + this->count = count; +} + +void +java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset, + jint count) +{ + if (! ascii) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (ascii); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array = JvNewCharArray(count); + jbyte *psrc = elements (ascii) + offset; + jchar *pdst = elements (array); + data = array; + boffset = (char *) pdst - (char *) array; + this->count = count; + hibyte = (hibyte & 0xff) << 8; + while (-- count >= 0) + { + *pdst++ = hibyte | (*psrc++ & 0xff); + } +} + +void +java::lang::String::init (jbyteArray bytes, jint offset, jint count, + jstring encoding) +{ + if (! bytes) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (bytes); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array = JvNewCharArray (count); + gnu::gcj::convert::BytesToUnicode *converter + = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding); + jint outpos = 0; + int avail = count; + converter->setInput(bytes, offset, offset+count); + while (converter->inpos < converter->inlength) + { + int done; + try + { + done = converter->read(array, outpos, avail); + } + catch (::java::io::CharConversionException *e) + { + // Ignore it and silently throw away the offending data. + break; + } + if (done == 0) + { + // done is zero if either there is no space available in the + // output *or* the input is incomplete. We assume that if + // there are 20 characters available in the output, the + // input must be incomplete and there is no more work to do. + // This means we may skip several bytes of input, but that + // is OK as the behavior is explicitly unspecified in this + // case. + if (avail - outpos > 20) + break; + + jint new_size = 2 * (outpos + avail); + jcharArray new_array = JvNewCharArray (new_size); + memcpy (elements (new_array), elements (array), + outpos * sizeof(jchar)); + array = new_array; + avail = new_size - outpos; + } + else + { + outpos += done; + avail -= done; + } + } + converter->done (); + this->data = array; + this->boffset = (char *) elements (array) - (char *) array; + this->count = outpos; +} + +void +java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer) +{ + init (buffer->value, 0, buffer->count, true); +} + +jboolean +java::lang::String::equals(jobject anObject) +{ + if (anObject == NULL) + return false; + if (anObject == this) + return true; + if (anObject->getClass() != &java::lang::String::class$) + return false; + jstring other = (jstring) anObject; + if (count != other->count) + return false; + + // If both have cached hash codes, check that. If the cached hash + // codes are zero, don't bother trying to compute them. + int myHash = cachedHashCode; + int otherHash = other->cachedHashCode; + if (myHash && otherHash && myHash != otherHash) + return false; + + // We could see if both are interned, and return false. But that + // seems too expensive. + + jchar *xptr = JvGetStringChars (this); + jchar *yptr = JvGetStringChars (other); + return ! memcmp (xptr, yptr, count * sizeof (jchar)); +} + +jboolean +java::lang::String::contentEquals(java::lang::StringBuffer* buffer) +{ + if (buffer == NULL) + throw new NullPointerException; + JvSynchronize sync(buffer); + if (count != buffer->count) + return false; + if (data == buffer->value) + return true; // Possible if shared. + jchar *xptr = JvGetStringChars(this); + jchar *yptr = elements(buffer->value); + return ! memcmp (xptr, yptr, count * sizeof (jchar)); +} + +jboolean +java::lang::String::contentEquals(java::lang::CharSequence *seq) +{ + if (seq->length() != count) + return false; + jchar *value = JvGetStringChars(this); + for (int i = 0; i < count; ++i) + if (value[i] != seq->charAt(i)) + return false; + return true; +} + +jchar +java::lang::String::charAt(jint i) +{ + if (i < 0 || i >= count) + throw new java::lang::StringIndexOutOfBoundsException(i); + return JvGetStringChars(this)[i]; +} + +void +java::lang::String::getChars(jint srcBegin, jint srcEnd, + jcharArray dst, jint dstBegin) +{ + jint dst_length = JvGetArrayLength (dst); + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new java::lang::StringIndexOutOfBoundsException; + // The 2nd part of the test below is equivalent to + // dstBegin + (srcEnd-srcBegin) > dst_length + // except that it does not overflow. + if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin)) + throw new ArrayIndexOutOfBoundsException; + jchar *dPtr = elements (dst) + dstBegin; + jchar *sPtr = JvGetStringChars (this) + srcBegin; + jint i = srcEnd - srcBegin; + memcpy (dPtr, sPtr, i * sizeof (jchar)); +} + +jbyteArray +java::lang::String::getBytes (jstring enc) +{ + jint todo = length(); + jint buflen = todo; + jbyteArray buffer = JvNewByteArray(todo); + jint bufpos = 0; + jint offset = 0; + gnu::gcj::convert::UnicodeToBytes *converter + = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc); + while (todo > 0 || converter->havePendingBytes()) + { + converter->setOutput(buffer, bufpos); + int converted = converter->write(this, offset, todo, NULL); + bufpos = converter->count; + if (converted == 0) + { + buflen *= 2; + jbyteArray newbuffer = JvNewByteArray(buflen); + memcpy (elements (newbuffer), elements (buffer), bufpos); + buffer = newbuffer; + } + else + { + offset += converted; + todo -= converted; + } + } + if (length() > 0) + { + converter->setFinished(); + converter->write(this, 0, 0, NULL); + } + converter->done (); + if (bufpos == buflen) + return buffer; + jbyteArray result = JvNewByteArray(bufpos); + memcpy (elements (result), elements (buffer), bufpos); + return result; +} + +void +java::lang::String::getBytes(jint srcBegin, jint srcEnd, + jbyteArray dst, jint dstBegin) +{ + jint dst_length = JvGetArrayLength (dst); + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new java::lang::StringIndexOutOfBoundsException; + // The 2nd part of the test below is equivalent to + // dstBegin + (srcEnd-srcBegin) > dst_length + // except that it does not overflow. + if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin)) + throw new ArrayIndexOutOfBoundsException; + jbyte *dPtr = elements (dst) + dstBegin; + jchar *sPtr = JvGetStringChars (this) + srcBegin; + jint i = srcEnd-srcBegin; + while (--i >= 0) + *dPtr++ = (jbyte) *sPtr++; +} + +jcharArray +java::lang::String::toCharArray() +{ + jcharArray array = JvNewCharArray(count); + jchar *dPtr = elements (array); + jchar *sPtr = JvGetStringChars (this); + jint i = count; + memcpy (dPtr, sPtr, i * sizeof (jchar)); + return array; +} + +jboolean +java::lang::String::equalsIgnoreCase (jstring anotherString) +{ + if (anotherString == NULL || count != anotherString->count) + return false; + jchar *tptr = JvGetStringChars (this); + jchar *optr = JvGetStringChars (anotherString); + jint i = count; + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if (tch != och + && (java::lang::Character::toLowerCase (tch) + != java::lang::Character::toLowerCase (och)) + && (java::lang::Character::toUpperCase (tch) + != java::lang::Character::toUpperCase (och))) + return false; + } + return true; +} + +jboolean +java::lang::String::regionMatches (jint toffset, + jstring other, jint ooffset, jint len) +{ + if (toffset < 0 || ooffset < 0 || len < 0 + || toffset > count - len + || ooffset > other->count - len) + return false; + jchar *tptr = JvGetStringChars (this) + toffset; + jchar *optr = JvGetStringChars (other) + ooffset; + jint i = len; + return ! memcmp (tptr, optr, i * sizeof (jchar)); +} + +jint +java::lang::String::nativeCompareTo (jstring anotherString) +{ + jchar *tptr = JvGetStringChars (this); + jchar *optr = JvGetStringChars (anotherString); + jint tlen = this->count; + jint olen = anotherString->count; + jint i = tlen > olen ? olen : tlen; + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if (tch != och) + return (jint) tch - (jint) och; + } + return tlen - olen; +} + +jboolean +java::lang::String::regionMatches (jboolean ignoreCase, jint toffset, + jstring other, jint ooffset, jint len) +{ + if (toffset < 0 || ooffset < 0 || len < 0 + || toffset > count - len + || ooffset > other->count - len) + return false; + jchar *tptr = JvGetStringChars (this) + toffset; + jchar *optr = JvGetStringChars (other) + ooffset; + jint i = len; + if (ignoreCase) + { + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if ((java::lang::Character::toLowerCase (tch) + != java::lang::Character::toLowerCase (och)) + && (java::lang::Character::toUpperCase (tch) + != java::lang::Character::toUpperCase (och))) + return false; + } + return true; + } + return ! memcmp (tptr, optr, i * sizeof (jchar)); +} + +jboolean +java::lang::String::startsWith (jstring prefix, jint toffset) +{ + jint i = prefix->count; + if (toffset < 0 || toffset > count - i) + return false; + jchar *xptr = JvGetStringChars (this) + toffset; + jchar *yptr = JvGetStringChars (prefix); + return ! memcmp (xptr, yptr, i * sizeof (jchar)); +} + +jint +java::lang::String::indexOf (jint ch, jint fromIndex) +{ + if (fromIndex < 0) + fromIndex = 0; + jchar *ptr = JvGetStringChars(this); + for (;; ++fromIndex) + { + if (fromIndex >= count) + return -1; + if (ptr[fromIndex] == ch) + return fromIndex; + } +} + +jint +java::lang::String::indexOf (jstring s, jint fromIndex) +{ + const jchar *const xchars = JvGetStringChars(s); + const jchar *const ychars = JvGetStringChars(this) + fromIndex; + + const int xlength = s->length (); + const int ylength = length () - fromIndex; + + int i = 0; + int j = 0; + + while (i < ylength && j < xlength) + { + if (xchars[j] != ychars[i]) + { + i = i - j + 1; + j = 0; + } + else + i++, j++; + } + + if (j >= xlength) + return fromIndex + i - xlength; + else + return -1; +} + +jint +java::lang::String::lastIndexOf (jint ch, jint fromIndex) +{ + if (fromIndex >= count) + fromIndex = count - 1; + jchar *ptr = JvGetStringChars(this); + for (;; --fromIndex) + { + if (fromIndex < 0) + return -1; + if (ptr[fromIndex] == ch) + return fromIndex; + } +} + +jstring +java::lang::String::substring (jint beginIndex, jint endIndex) +{ + if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) + throw new StringIndexOutOfBoundsException; + if (beginIndex == 0 && endIndex == count) + return this; + jint newCount = endIndex - beginIndex; + // For very small strings, just allocate a new one. For other + // substrings, allocate a new one unless the substring is over half + // of the original string. + if (newCount <= 8 || newCount < (count >> 1)) + return JvNewString(JvGetStringChars(this) + beginIndex, newCount); + jstring s = new String(); + s->data = data; + s->count = newCount; + s->boffset = boffset + sizeof(jchar) * beginIndex; + return s; +} + +jstring +java::lang::String::concat(jstring str) +{ + jint str_count = str->count; + if (str_count == 0) + return this; + jstring result = JvAllocString(count + str_count); + jchar *dstPtr = JvGetStringChars(result); + jchar *srcPtr = JvGetStringChars(this); + jint i = count; + memcpy (dstPtr, srcPtr, i * sizeof (jchar)); + dstPtr += i; + srcPtr = JvGetStringChars(str); + i = str->count; + memcpy (dstPtr, srcPtr, i * sizeof (jchar)); + return result; +} + +jstring +java::lang::String::replace (jchar oldChar, jchar newChar) +{ + jint i; + jchar* chrs = JvGetStringChars (this); + for (i = 0; ; i++) + { + if (i == count) + return this; + if (chrs[i] == oldChar) + break; + } + jstring result = JvAllocString (count); + jchar *dPtr = JvGetStringChars (result); + for (int j = 0; j < i; j++) + *dPtr++ = chrs[j]; + for (; i < count; i++) + { + jchar ch = chrs[i]; + if (ch == oldChar) + ch = newChar; + *dPtr++ = ch; + } + return result; +} + +jstring +java::lang::String::toLowerCase (java::util::Locale *locale) +{ + jint i; + jchar* chrs = JvGetStringChars(this); + jchar ch = 0; + + bool handle_tr = false; + if (locale != NULL) + { + String *lang = locale->getLanguage (); + if (lang->length () == 2 + && lang->charAt (0) == 't' + && lang->charAt (1) == 'r') + handle_tr = true; + } + + for (i = 0; ; i++) + { + if (i == count) + return this; + jchar origChar = chrs[i]; + + if (handle_tr && (origChar == CAPITAL_I + || origChar == CAPITAL_I_WITH_DOT)) + break; + + ch = java::lang::Character::toLowerCase(origChar); + if (ch != origChar) + break; + } + jstring result = JvAllocString(count); + jchar *dPtr = JvGetStringChars (result); + for (int j = 0; j < i; j++) + *dPtr++ = chrs[j]; + *dPtr++ = ch; i++; + for (; i < count; i++) + { + if (handle_tr && chrs[i] == CAPITAL_I) + *dPtr++ = SMALL_DOTLESS_I; + else if (handle_tr && chrs[i] == CAPITAL_I_WITH_DOT) + *dPtr++ = SMALL_I; + else + *dPtr++ = java::lang::Character::toLowerCase(chrs[i]); + } + return result; +} + +jstring +java::lang::String::toUpperCase (java::util::Locale *locale) +{ + jint i; + jchar* chrs = JvGetStringChars(this); + jchar ch; + + // When handling a specific locale there might be special rules. + // Currently all existing rules are simply handled inline, as there + // are only two and they are documented in the online 1.2 docs. + bool handle_esset = locale != NULL; + bool handle_tr = false; + if (locale != NULL) + { + String *lang = locale->getLanguage (); + if (lang->length () == 2 + && lang->charAt (0) == 't' + && lang->charAt (1) == 'r') + handle_tr = true; + } + + int new_count = count; + bool new_string = false; + for (i = 0; ; i++) + { + if (i == count) + break; + jchar origChar = chrs[i]; + + if (handle_esset && origChar == ESSET) + { + ++new_count; + new_string = true; + } + else if (handle_tr && (origChar == SMALL_I + || origChar == SMALL_DOTLESS_I)) + new_string = true; + else + { + ch = java::lang::Character::toUpperCase(origChar); + if (ch != origChar) + new_string = true; + } + + if (new_string && ! handle_esset) + break; + } + if (! new_string) + return this; + jstring result = JvAllocString(new_count); + jchar *dPtr = JvGetStringChars (result); + for (i = 0; i < count; i++) + { + if (handle_esset && chrs[i] == ESSET) + { + *dPtr++ = CAPITAL_S; + *dPtr++ = CAPITAL_S; + } + else if (handle_tr && chrs[i] == SMALL_I) + *dPtr++ = CAPITAL_I_WITH_DOT; + else if (handle_tr && chrs[i] == SMALL_DOTLESS_I) + *dPtr++ = CAPITAL_I; + else + *dPtr++ = java::lang::Character::toUpperCase(chrs[i]); + } + return result; +} + +jstring +java::lang::String::trim () +{ + jchar* chrs = JvGetStringChars(this); + if (count == 0 || (chrs[0] > ' ' && chrs[count-1] > ' ')) + return this; + jint preTrim = 0; + for (;; preTrim++) + { + if (preTrim == count) + return new String(); + if (chrs[preTrim] > ' ') + break; + } + jint endTrim = count; + while (chrs[endTrim-1] <= ' ') + endTrim--; + return substring(preTrim, endTrim); +} + +jstring +java::lang::String::valueOf(jcharArray data, jint offset, jint count) +{ + jint data_length = JvGetArrayLength (data); + if (offset < 0 || count < 0 || offset > data_length - count) + throw new ArrayIndexOutOfBoundsException; + jstring result = JvAllocString(count); + jchar *sPtr = elements (data) + offset; + jchar *dPtr = JvGetStringChars(result); + memcpy (dPtr, sPtr, count * sizeof (jchar)); + return result; +} + +jstring +java::lang::String::valueOf(jchar c) +{ + jstring result = JvAllocString(1); + JvGetStringChars (result)[0] = c; + return result; +} diff --git a/libjava/java/lang/natSystem.cc b/libjava/java/lang/natSystem.cc new file mode 100644 index 000000000..42a13258d --- /dev/null +++ b/libjava/java/lang/natSystem.cc @@ -0,0 +1,150 @@ +// natSystem.cc - Native code implementing System class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/System.h> +#include <java/lang/Class.h> +#include <java/lang/ArrayStoreException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/NullPointerException.h> +#include <java/io/PrintStream.h> +#include <java/io/InputStream.h> + + + +void +java::lang::System::setErr0 (java::io::PrintStream *newErr) +{ + err = newErr; +} + +void +java::lang::System::setIn0 (java::io::InputStream *newIn) +{ + in = newIn; +} + +void +java::lang::System::setOut0 (java::io::PrintStream *newOut) +{ + out = newOut; +} + +void +java::lang::System::arraycopy (jobject src, jint src_offset, + jobject dst, jint dst_offset, + jint count) +{ + if (! src || ! dst) + throw new NullPointerException; + + jclass src_c = src->getClass(); + jclass dst_c = dst->getClass(); + jclass src_comp = src_c->getComponentType(); + jclass dst_comp = dst_c->getComponentType(); + + if (! src_c->isArray() || ! dst_c->isArray() + || src_comp->isPrimitive() != dst_comp->isPrimitive() + || (src_comp->isPrimitive() && src_comp != dst_comp)) + throw new ArrayStoreException; + + __JArray *src_a = (__JArray *) src; + __JArray *dst_a = (__JArray *) dst; + if (src_offset < 0 || dst_offset < 0 || count < 0 + || (unsigned jint) src_offset > (unsigned jint) src_a->length + || (unsigned jint) (src_offset + count) > (unsigned jint) src_a->length + || (unsigned jint) dst_offset > (unsigned jint) dst_a->length + || (unsigned jint) (dst_offset + count) > (unsigned jint) dst_a->length) + throw new ArrayIndexOutOfBoundsException; + + // Do-nothing cases. + if ((src == dst && src_offset == dst_offset) + || ! count) + return; + + // If both are primitive, we can optimize trivially. If DST + // components are always assignable from SRC components, then we + // will never need to raise an error, and thus can do the + // optimization. If source and destinations are the same, then we + // know that the assignability premise always holds. + const bool prim = src_comp->isPrimitive(); + if (prim || dst_comp->isAssignableFrom(src_comp) || src == dst) + { + const size_t size = (prim ? src_comp->size() + : sizeof elements((jobjectArray)src)[0]); + + char *src_elts = _Jv_GetArrayElementFromElementType (src, src_comp); + src_elts += size * src_offset; + + char *dst_elts = _Jv_GetArrayElementFromElementType (dst, dst_comp); + dst_elts += size * dst_offset; + +#if HAVE_MEMMOVE + // We don't bother trying memcpy. It can't be worth the cost of + // the check. + // Don't cast to (void*), as memmove may expect (char*) + memmove (dst_elts, src_elts, count * size); +#else + bcopy (src_elts, dst_elts, count * size); +#endif + } + else + { + jobject *src_elts = elements ((jobjectArray) src_a) + src_offset; + jobject *dst_elts = elements ((jobjectArray) dst_a) + dst_offset; + + for (int i = 0; i < count; ++i) + { + if (*src_elts + && ! dst_comp->isAssignableFrom((*src_elts)->getClass())) + throw new ArrayStoreException; + *dst_elts++ = *src_elts++; + } + } +} + +jlong +java::lang::System::currentTimeMillis (void) +{ + return _Jv_platform_gettimeofday (); +} + +jlong +java::lang::System::nanoTime () +{ + return _Jv_platform_nanotime (); +} + +jint +java::lang::System::identityHashCode (jobject obj) +{ + return _Jv_HashCode (obj); +} + +jstring +java::lang::System::getenv0 (jstring name) +{ + jint len = _Jv_GetStringUTFLength (name); + char buf[len + 1]; + jsize total = JvGetStringUTFRegion (name, 0, name->length(), buf); + buf[total] = '\0'; + const char *value = ::getenv (buf); + if (value == NULL) + return NULL; + return JvNewStringUTF (value); +} diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc new file mode 100644 index 000000000..d6abff13f --- /dev/null +++ b/libjava/java/lang/natThread.cc @@ -0,0 +1,534 @@ +// natThread.cc - Native part of Thread class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <gnu/gcj/RawDataManaged.h> +#include <java/lang/Thread.h> +#include <java/lang/Thread$State.h> +#include <java/lang/Thread$UncaughtExceptionHandler.h> +#include <java/lang/ThreadGroup.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> + +#include <jni.h> + +#ifdef INTERPRETER +#include <jvmti.h> +#include "jvmti-int.h" +#endif + +#ifdef ENABLE_JVMPI +#include <jvmpi.h> +#endif + + + +static void finalize_native (jobject ptr); + +// This is called from the constructor to initialize the native side +// of the Thread. +void +java::lang::Thread::initialize_native (void) +{ + natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread)); + + state = JV_NEW; + nt->alive_flag = THREAD_DEAD; + + data = (gnu::gcj::RawDataManaged *) nt; + + // Register a finalizer to clean up the native thread resources. + _Jv_RegisterFinalizer (data, finalize_native); + + _Jv_MutexInit (&nt->join_mutex); + _Jv_CondInit (&nt->join_cond); + + nt->park_helper.init(); + + nt->thread = _Jv_ThreadInitData (this); + // FIXME: if JNI_ENV is set we will want to free it. It is + // malloc()d. + nt->jni_env = NULL; +} + +static void +finalize_native (jobject ptr) +{ + natThread *nt = (natThread *) ptr; + _Jv_ThreadDestroyData (nt->thread); +#ifdef _Jv_HaveCondDestroy + _Jv_CondDestroy (&nt->join_cond); +#endif +#ifdef _Jv_HaveMutexDestroy + _Jv_MutexDestroy (&nt->join_mutex); +#endif + _Jv_FreeJNIEnv((JNIEnv*)nt->jni_env); + + nt->park_helper.destroy(); +} + +jint +java::lang::Thread::countStackFrames (void) +{ + // NOTE: This is deprecated in JDK 1.2. + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. + + return 0; +} + +java::lang::Thread * +java::lang::Thread::currentThread (void) +{ + return _Jv_ThreadCurrent (); +} + +jboolean +java::lang::Thread::holdsLock (jobject obj) +{ + if (!obj) + throw new NullPointerException; + return !_Jv_ObjectCheckMonitor (obj); +} + +jboolean +java::lang::Thread::isAlive (void) +{ + natThread *nt = (natThread *) data; + return nt->alive_flag != (obj_addr_t)THREAD_DEAD; +} + +void +java::lang::Thread::interrupt (void) +{ + checkAccess (); + + natThread *nt = (natThread *) data; + + // If a thread is in state ALIVE, we atomically set it to state + // SIGNALED and send it a signal. Once we've sent it the signal, we + // set its state back to ALIVE. + if (compare_and_swap + (&nt->alive_flag, Thread::THREAD_ALIVE, Thread::THREAD_SIGNALED)) + { + _Jv_ThreadInterrupt (nt->thread); + compare_and_swap + (&nt->alive_flag, THREAD_SIGNALED, Thread::THREAD_ALIVE); + + // Even though we've interrupted this thread, it might still be + // parked. + nt->park_helper.unpark (); + } +} + +void +java::lang::Thread::join (jlong millis, jint nanos) +{ + if (millis < 0 || nanos < 0 || nanos > 999999) + throw new IllegalArgumentException; + + Thread *current = currentThread (); + + // Here `NT' is the native structure for the thread we are trying to join. + natThread *nt = (natThread *) data; + + // Now wait for: (1) an interrupt, (2) the thread to exit, or (3) + // the timeout to occur. + _Jv_MutexLock (&nt->join_mutex); + if (! isAlive ()) + { + _Jv_MutexUnlock (&nt->join_mutex); + return; + } + _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos); + _Jv_MutexUnlock (&nt->join_mutex); + + if (current->isInterrupted (true)) + throw new InterruptedException; +} + +void +java::lang::Thread::resume (void) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +void +java::lang::Thread::setPriority (jint newPriority) +{ + checkAccess (); + if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY) + throw new IllegalArgumentException; + + jint gmax = group->getMaxPriority(); + if (newPriority > gmax) + newPriority = gmax; + + priority = newPriority; + natThread *nt = (natThread *) data; + _Jv_ThreadSetPriority (nt->thread, priority); +} + +void +java::lang::Thread::sleep (jlong millis, jint nanos) +{ + if (millis < 0 || nanos < 0 || nanos > 999999) + throw new IllegalArgumentException; + + if (millis == 0 && nanos == 0) + ++nanos; + + Thread *current = currentThread (); + + // We use a condition variable to implement sleeping so that an + // interrupt can wake us up. + natThread *nt = (natThread *) current->data; + _Jv_MutexLock (&nt->join_mutex); + _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos); + _Jv_MutexUnlock (&nt->join_mutex); + + if (current->isInterrupted (true)) + throw new InterruptedException; +} + +void +java::lang::Thread::finish_ () +{ + __sync_synchronize(); + natThread *nt = (natThread *) data; + + nt->park_helper.deactivate (); + group->removeThread (this); + +#ifdef INTERPRETER + if (JVMTI_REQUESTED_EVENT (ThreadEnd)) + _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, this, nt->jni_env); +#endif + +#ifdef ENABLE_JVMPI + if (_Jv_JVMPI_Notify_THREAD_END) + { + JVMPI_Event event; + + event.event_type = JVMPI_EVENT_THREAD_END; + event.env_id = _Jv_GetCurrentJNIEnv (); + + _Jv_DisableGC (); + (*_Jv_JVMPI_Notify_THREAD_END) (&event); + _Jv_EnableGC (); + } +#endif + + // If a method cache was created, free it. + _Jv_FreeMethodCache(); + + // Clear out thread locals. + locals = NULL; + + // Signal any threads that are waiting to join() us. + _Jv_MutexLock (&nt->join_mutex); + + { + JvSynchronize sync (this); + nt->alive_flag = THREAD_DEAD; + state = JV_TERMINATED; + } + + _Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex); + _Jv_MutexUnlock (&nt->join_mutex); +} + +// Run once at thread startup, either when thread is attached or when +// _Jv_ThreadRun is called. +static void +_Jv_NotifyThreadStart (java::lang::Thread* thread) +{ +#ifdef INTERPRETER + if (JVMTI_REQUESTED_EVENT (ThreadStart)) + { + natThread *nt = reinterpret_cast<natThread *> (thread->data); + _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_START, thread, nt->jni_env); + } +#endif + +#ifdef ENABLE_JVMPI + if (_Jv_JVMPI_Notify_THREAD_START) + { + JVMPI_Event event; + + jstring thread_name = thread->getName (); + jstring group_name = NULL, parent_name = NULL; + java::lang::ThreadGroup *group = thread->getThreadGroup (); + + if (group) + { + group_name = group->getName (); + group = group->getParent (); + + if (group) + parent_name = group->getName (); + } + + int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0; + int group_len = group_name ? JvGetStringUTFLength (group_name) : 0; + int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0; + + char thread_chars[thread_len + 1]; + char group_chars[group_len + 1]; + char parent_chars[parent_len + 1]; + + if (thread_name) + JvGetStringUTFRegion (thread_name, 0, + thread_name->length(), thread_chars); + if (group_name) + JvGetStringUTFRegion (group_name, 0, + group_name->length(), group_chars); + if (parent_name) + JvGetStringUTFRegion (parent_name, 0, + parent_name->length(), parent_chars); + + thread_chars[thread_len] = '\0'; + group_chars[group_len] = '\0'; + parent_chars[parent_len] = '\0'; + + event.event_type = JVMPI_EVENT_THREAD_START; + event.env_id = NULL; + event.u.thread_start.thread_name = thread_chars; + event.u.thread_start.group_name = group_chars; + event.u.thread_start.parent_name = parent_chars; + event.u.thread_start.thread_id = (jobjectID) thread; + event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv (); + + _Jv_DisableGC (); + (*_Jv_JVMPI_Notify_THREAD_START) (&event); + _Jv_EnableGC (); + } +#endif +} + +void +_Jv_ThreadRun (java::lang::Thread* thread) +{ + try + { + _Jv_NotifyThreadStart (thread); + thread->run (); + } + catch (java::lang::Throwable *t) + { + // Uncaught exceptions are forwarded to the ThreadGroup. If + // this results in an uncaught exception, that is ignored. + try + { + thread->getUncaughtExceptionHandler()->uncaughtException (thread, t); + } + catch (java::lang::Throwable *f) + { + // Nothing. + } + } + + thread->finish_ (); +} + +_Jv_Thread_t* +_Jv_ThreadGetData (java::lang::Thread* thread) +{ + natThread* nt = (natThread*) thread->data; + return nt->thread; +} + +void +java::lang::Thread::start (void) +{ + JvSynchronize sync (this); + + // Its illegal to re-start() a thread, even if its dead. + if (!startable_flag) + throw new IllegalThreadStateException; + + natThread *nt = (natThread *) data; + nt->alive_flag = THREAD_ALIVE; + startable_flag = false; + state = JV_RUNNABLE; + _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun); +} + +void +java::lang::Thread::stop (java::lang::Throwable *) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +void +java::lang::Thread::suspend (void) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +static int nextThreadNumber = 0; + +jstring +java::lang::Thread::gen_name (void) +{ + jint i; + jclass sync = &java::lang::Thread::class$; + { + JvSynchronize dummy(sync); + i = ++nextThreadNumber; + } + + // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-". + jchar buffer[7+11]; + jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer)); + i = _Jv_FormatInt (bufend, i); + jchar *ptr = bufend - i; + // Prepend "Thread-". + *--ptr = '-'; + *--ptr = 'd'; + *--ptr = 'a'; + *--ptr = 'e'; + *--ptr = 'r'; + *--ptr = 'h'; + *--ptr = 'T'; + return JvNewString (ptr, bufend - ptr); +} + +void +java::lang::Thread::yield (void) +{ + _Jv_ThreadYield (); +} + +::java::lang::Thread$State * +java::lang::Thread::getState() +{ + _Jv_InitClass(&::java::lang::Thread$State::class$); + + switch (state) + { + case JV_BLOCKED: + return ::java::lang::Thread$State::BLOCKED; + case JV_NEW: + return ::java::lang::Thread$State::NEW; + + case JV_RUNNABLE: + return ::java::lang::Thread$State::RUNNABLE; + case JV_TERMINATED: + return ::java::lang::Thread$State::TERMINATED; + case JV_TIMED_WAITING: + return ::java::lang::Thread$State::TIMED_WAITING; + case JV_WAITING: + return ::java::lang::Thread$State::WAITING; + } + + // We don't really need a default, but this makes the compiler + // happy. + return ::java::lang::Thread$State::RUNNABLE; +} + +JNIEnv * +_Jv_GetCurrentJNIEnv () +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + if (t == NULL) + return NULL; + return ((natThread *) t->data)->jni_env; +} + +void +_Jv_SetCurrentJNIEnv (JNIEnv *env) +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + JvAssert (t != NULL); + ((natThread *) t->data)->jni_env = env; +} + +// Attach the current native thread to an existing (but unstarted) Thread +// object. Does not register thread with the garbage collector. +// Returns -1 on failure, 0 upon success. +jint +_Jv_AttachCurrentThread(java::lang::Thread* thread) +{ + JvSynchronize sync (thread); + if (thread == NULL || thread->startable_flag == false) + return -1; + thread->startable_flag = false; + natThread *nt = (natThread *) thread->data; + nt->alive_flag = ::java::lang::Thread::THREAD_ALIVE; + thread->state = JV_RUNNABLE; + _Jv_ThreadRegister (nt->thread); + return 0; +} + +java::lang::Thread* +_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group) +{ + // Register thread with GC before attempting any allocations. + _Jv_GCAttachThread (); + java::lang::Thread *thread = _Jv_ThreadCurrent (); + if (thread != NULL) + return thread; + if (name == NULL) + name = java::lang::Thread::gen_name (); + thread = new java::lang::Thread (NULL, group, NULL, name, false); + _Jv_AttachCurrentThread (thread); + _Jv_NotifyThreadStart (thread); + return thread; +} + +java::lang::Thread* +_Jv_AttachCurrentThreadAsDaemon(jstring name, java::lang::ThreadGroup* group) +{ + java::lang::Thread *thread = _Jv_ThreadCurrent (); + if (thread != NULL) + return thread; + if (name == NULL) + name = java::lang::Thread::gen_name (); + thread = new java::lang::Thread (NULL, group, NULL, name, false); + thread->setDaemon (true); + _Jv_AttachCurrentThread (thread); + _Jv_NotifyThreadStart (thread); + return thread; +} + +jint +_Jv_DetachCurrentThread (void) +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + if (t == NULL) + return -1; + + _Jv_ThreadUnRegister (); + _Jv_GCDetachThread (); + // Release the monitors. + t->finish_ (); + + return 0; +} diff --git a/libjava/java/lang/natThreadLocal.cc b/libjava/java/lang/natThreadLocal.cc new file mode 100644 index 000000000..cd61f4a62 --- /dev/null +++ b/libjava/java/lang/natThreadLocal.cc @@ -0,0 +1,169 @@ +// natThreadLocal.cc - Native part of ThreadLocal class. + +// Fast thread local storage for systems that support the __thread +// variable attribute. + +/* Copyright (C) 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <gnu/gcj/RawDataManaged.h> +#include <java/lang/ThreadLocal.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/util/Map.h> + +#include <jni.h> + +/* We would like to have fast thread local variables that behave in + the same way as C and C++ thread local variables. This would mean + having an field attribute "thread" (like static, final, etc.). + However, this is not compatible with java semantics, which we wish + to support transparently. The problems we must overcome are: + + * In Java, ThreadLocal variables are not statically allocated: they + are objects, created at runtime. + + * Class ThreadLocal is not final and neither are its methods, so it + is possible to create a subclass of ThreadLocal that overrides + any method. + + * __thread variables in DSOs are not visible to the garbage + collector, so we must ensure that we keep a copy of every thread + local variable somewhere on the heap. + + * Once a ThreadLocal instance has been created and assigned to a + static field, that field may be reassigned to a different + ThreadLocal instance or null. + + So, we can't simply replace get() and set() with accesses of a + __thread variable. + + So, we create a pthread_key in each ThreadLocal object and use that + as a kind of "look-aside cache". When a ThreadLocal is set, we + also set the corresponding thread-specific value. When the + ThreadLocal is collected, we delete the key. + + This scheme is biased towards efficiency when get() is called much + more frequently than set(). It is slightly internaler than the + all-Java solution using the underlying map in the set() case. + However, get() is very much more frequently invoked than set(). + +*/ + + +#ifdef _POSIX_PTHREAD_SEMANTICS + +class tls_t +{ +public: + pthread_key_t key; +}; + +void +java::lang::ThreadLocal::constructNative (void) +{ + tls_t *tls = (tls_t *)_Jv_Malloc (sizeof (tls_t)); + if (pthread_key_create (&tls->key, NULL) == 0) + TLSPointer = (::gnu::gcj::RawData *)tls; + else + _Jv_Free (tls); +} + +void +java::lang::ThreadLocal::set (::java::lang::Object *value) +{ + if (TLSPointer != NULL) + { + tls_t* tls = (tls_t*)TLSPointer; + pthread_setspecific (tls->key, value); + } + + internalSet (value); +} + +::java::lang::Object * +java::lang::ThreadLocal::get (void) +{ + if (TLSPointer == NULL) + return internalGet (); + + tls_t* tls = (tls_t*)TLSPointer; + void *obj = pthread_getspecific(tls->key); + + if (obj) + return (::java::lang::Object *)obj; + + ::java::lang::Object *value = internalGet (); + pthread_setspecific (tls->key, value); + + return value; +} + +void +java::lang::ThreadLocal::remove (void) +{ + if (TLSPointer != NULL) + { + tls_t* tls = (tls_t*)TLSPointer; + pthread_setspecific (tls->key, NULL); + } + + internalRemove (); +} + +void +java::lang::ThreadLocal::finalize (void) +{ + if (TLSPointer != NULL) + { + tls_t* tls = (tls_t*)TLSPointer; + pthread_key_delete (tls->key); + _Jv_Free (tls); + } +} + +#else + +void +java::lang::ThreadLocal::constructNative (void) +{ +} + +void +java::lang::ThreadLocal::set (::java::lang::Object *value) +{ + internalSet (value); +} + +::java::lang::Object * +java::lang::ThreadLocal::get (void) +{ + return internalGet (); +} + +void +java::lang::ThreadLocal::remove (void) +{ + internalRemove (); +} + +void +java::lang::ThreadLocal::finalize (void) +{ +} + +#endif diff --git a/libjava/java/lang/natVMClassLoader.cc b/libjava/java/lang/natVMClassLoader.cc new file mode 100644 index 000000000..4edff7daf --- /dev/null +++ b/libjava/java/lang/natVMClassLoader.cc @@ -0,0 +1,245 @@ +// natVMClassLoader.cc - VMClassLoader native methods + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java-threads.h> +#include <java-interp.h> + +#include <java/lang/VMClassLoader.h> +#include <java/lang/VMCompiler.h> +#include <gnu/gcj/runtime/ExtensionClassLoader.h> +#include <gnu/gcj/runtime/SystemClassLoader.h> +#include <gnu/gcj/runtime/BootClassLoader.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/Class.h> +#include <java/lang/Throwable.h> +#include <java/security/ProtectionDomain.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/SecurityManager.h> +#include <java/lang/Runtime.h> +#include <java/util/HashSet.h> +#include <java/lang/SecurityException.h> +#include <java/lang/VirtualMachineError.h> + +java::lang::Class * +java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, + jstring name, + jbyteArray data, + jint offset, + jint length, + java::security::ProtectionDomain *pd) +{ + jclass klass = VMCompiler::compileClass(loader, name, data, + offset, length, pd); + + if (klass) + _Jv_RegisterInitiatingLoader (klass, klass->loader); + +#ifdef INTERPRETER + if (klass == NULL) + { + klass = new java::lang::Class (); + + // Synchronize on the class, so that it is not attempted initialized + // until we're done loading. + JvSynchronize sync (klass); + + // Record the defining loader. For the bootstrap class loader, + // we record NULL. + if (loader != bootLoader) + klass->loader = loader; + + if (name != 0) + { + _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); + + if (! _Jv_VerifyClassName (name2)) + throw new java::lang::ClassFormatError + (JvNewStringLatin1 ("erroneous class name")); + + klass->name = name2; + } + + _Jv_Utf8Const *found_name = NULL; + try + { + _Jv_DefineClass (klass, data, offset, length, pd, &found_name); + } + catch (java::lang::Throwable *ex) + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + if (found_name != NULL) + _Jv_UnregisterInitiatingLoader (klass, klass->loader); + + // If EX is not a ClassNotFoundException, that's ok, because we + // account for the possibility in defineClass(). + throw ex; + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_READ); + } +#endif // INTERPRETER + + if (! klass) + { + StringBuffer *sb = new StringBuffer(); + if (name) + { + sb->append(JvNewStringLatin1("found class file for class ")); + sb->append(name); + } + else + sb->append(JvNewStringLatin1("found unnamed class file")); + sb->append(JvNewStringLatin1(", but no interpreter configured in this libgcj")); + throw new VirtualMachineError(sb->toString()); + } + + return klass; +} + +java::lang::ClassLoader * +java::lang::VMClassLoader::getSystemClassLoaderInternal() +{ + _Jv_InitClass (&gnu::gcj::runtime::ExtensionClassLoader::class$); + _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::ExtensionClassLoader::system_instance); + return gnu::gcj::runtime::ExtensionClassLoader::system_instance; +} + +jclass +java::lang::VMClassLoader::getPrimitiveClass (jchar type) +{ + char sig[2]; + sig[0] = (char) type; + sig[1] = '\0'; + // Note: this cannot return NULL, since the input is always correct. + return _Jv_FindClassFromSignature (sig, NULL); +} + +void +java::lang::VMClassLoader::initBootLoader(jstring libdir) +{ + bootLoader = new gnu::gcj::runtime::BootClassLoader(libdir); +} + +jclass +java::lang::VMClassLoader::nativeFindClass (jstring name) +{ + jclass klass = NULL; + + if (lib_control != LIB_NEVER) + { + // Turn `gnu.pkg.quux' into `lib-gnu-pkg-quux'. Then search for + // a module named (eg, on Linux) `lib-gnu-pkg-quux.so', followed + // by `lib-gnu-pkg.so' and `lib-gnu.so'. If loading one of + // these causes the class to appear in the cache, then use it. + java::lang::StringBuffer *sb + = new java::lang::StringBuffer (JvNewStringLatin1("lib-")); + // Skip inner classes + jstring cn; + jint ci = name->indexOf('$'); + if (ci == -1) + cn = name; + else + cn = name->substring (0, ci); + jstring so_base_name + = (sb->append (cn)->toString ())->replace ('.', '-'); + + using namespace ::java::lang; + Runtime *rt = Runtime::getRuntime(); + + _Jv_Utf8Const *name_u = NULL; + + // Compare against `3' because that is the length of "lib". + while (! klass && so_base_name && so_base_name->length() > 3) + { + if (lib_control == LIB_CACHE) + { + // If we've already tried this name, we're done. + if (tried_libraries->contains(so_base_name)) + break; + tried_libraries->add(so_base_name); + } + + jboolean loaded = rt->loadLibraryInternal (so_base_name); + + jint nd = so_base_name->lastIndexOf ('-'); + if (nd == -1) + so_base_name = NULL; + else + so_base_name = so_base_name->substring (0, nd); + + if (loaded) + { + if (name_u == NULL) + name_u = _Jv_makeUtf8Const (name); + klass = _Jv_FindClassInCache (name_u); + } + } + } + + if (klass) + definePackageForNative(name); + + return klass; +} + +jclass +java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve) +{ + using namespace ::java::lang; + + SecurityManager *sm = (SecurityManager *)SecurityManager::current; + if (sm) + { + jint lastDot = name->lastIndexOf('.'); + if (lastDot != -1) + sm->checkPackageAccess(name->substring(0, lastDot)); + } + + // We try the boot loader first, so that the endorsed directory + // overrides compiled-in classes. + jclass klass = NULL; + if (bootLoader) + klass = bootLoader->bootLoadClass(name); + if (! klass) + { + _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name); + klass = _Jv_FindClassInCache (utf); + } + if (! klass) + klass = nativeFindClass(name); + if (klass) + { + // We never want to return a class without its supers linked. + // It isn't clear from the spec, but this is what other + // implementations do in practice. + if (resolve) + resolveClass (klass); + else + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + + definePackageForNative(name); + } + + return klass; +} diff --git a/libjava/java/lang/natVMDouble.cc b/libjava/java/lang/natVMDouble.cc new file mode 100644 index 000000000..f770bc422 --- /dev/null +++ b/libjava/java/lang/natVMDouble.cc @@ -0,0 +1,215 @@ +// natVMDouble.cc - Implementation of java.lang.VMDouble native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006, 2007 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <java/lang/String.h> +#include <java/lang/Double.h> +#include <java/lang/VMDouble.h> +#include <java/lang/Character.h> +#include <java/lang/NumberFormatException.h> +#include <jvm.h> + +#include <stdio.h> +#include <string.h> + +#include "fdlibm.h" + +union u +{ + jlong l; + jdouble d; +}; + +jlong +java::lang::VMDouble::doubleToLongBits(jdouble value) +{ + union u u; + u.d = value; + + jlong e = u.l & 0x7ff0000000000000LL; + jlong f = u.l & 0x000fffffffffffffLL; + + if (e == 0x7ff0000000000000LL && f != 0L) + u.l = 0x7ff8000000000000LL; + + return u.l; +} + +jlong +java::lang::VMDouble::doubleToRawLongBits(jdouble value) +{ + union u u; + u.d = value; + return u.l; +} + +jdouble +java::lang::VMDouble::longBitsToDouble(jlong bits) +{ + union u u; + u.l = bits; + return u.d; +} + +jstring +java::lang::VMDouble::toString(jdouble value, jboolean isFloat) +{ + if (Double::isNaN (value)) + return JvNewStringLatin1 ("NaN", sizeof ("NaN") - 1); + + if (value == Double::POSITIVE_INFINITY) + return JvNewStringLatin1 ("Infinity", sizeof ("Infinity") - 1); + + if (value == Double::NEGATIVE_INFINITY) + return JvNewStringLatin1 ("-Infinity", sizeof ("-Infinity") - 1); + + char buffer[50], result[50]; + int decpt, sign; + + _dtoa (value, 0, 20, &decpt, &sign, NULL, buffer, (int)isFloat); + + value = fabs (value); + + char *s = buffer; + char *d = result; + + if (sign) + *d++ = '-'; + + if ((value >= 1e-3 && value < 1e7) || value == 0) + { + if (decpt <= 0) + *d++ = '0'; + else + { + for (int i = 0; i < decpt; i++) + if (*s) + *d++ = *s++; + else + *d++ = '0'; + } + + *d++ = '.'; + + if (*s == 0) + { + *d++ = '0'; + decpt++; + } + + while (decpt++ < 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d = 0; + + return JvNewStringLatin1 (result, strlen (result)); + } + + *d++ = *s++; + decpt--; + *d++ = '.'; + + if (*s == 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d++ = 'E'; + + if (decpt < 0) + { + *d++ = '-'; + decpt = -decpt; + } + + { + char exp[4]; + char *e = exp + sizeof exp; + + *--e = 0; + do + { + *--e = '0' + decpt % 10; + decpt /= 10; + } + while (decpt > 0); + + while (*e) + *d++ = *e++; + } + + *d = 0; + + return JvNewStringLatin1 (result, strlen (result)); +} + +jdouble +java::lang::VMDouble::parseDouble(jstring str) +{ + int length = str->length(); + + while (length > 0 + && Character::isWhitespace(str->charAt(length - 1))) + length--; + + // The String could end with a f/F/d/D which is valid but we don't need. + bool saw_trailer = false; + if (length > 0) + { + jchar last = str->charAt(length-1); + if (last == 'f' || last == 'F' || last == 'd' || last == 'D') + { + length--; + saw_trailer = true; + } + } + + jsize start = 0; + while (length > 0 + && Character::isWhitespace(str->charAt(start))) + start++, length--; + + if (length > 0) + { + // Note that UTF can expand 3x. + char *data = (char *) __builtin_alloca (3 * length + 1); + jsize blength = _Jv_GetStringUTFRegion (str, start, length, data); + data[blength] = 0; + + if (! saw_trailer) + { + if (! strcmp (data, "NaN") || ! strcmp (data, "+NaN") + || ! strcmp (data, "-NaN")) + return Double::NaN; + else if (! strcmp (data, "Infinity") || ! strcmp (data, "+Infinity")) + return Double::POSITIVE_INFINITY; + else if (! strcmp (data, "-Infinity")) + return Double::NEGATIVE_INFINITY; + } + + struct _Jv_reent reent; + memset (&reent, 0, sizeof reent); + + char *endptr; + double val = _strtod_r (&reent, data, &endptr); + if (endptr == data + blength) + return val; + } + throw new NumberFormatException(str); +} diff --git a/libjava/java/lang/natVMFloat.cc b/libjava/java/lang/natVMFloat.cc new file mode 100644 index 000000000..54ae5191d --- /dev/null +++ b/libjava/java/lang/natVMFloat.cc @@ -0,0 +1,52 @@ +// natVMFloat.cc - Implementation of java.lang.VMFloat native methods. + +/* Copyright (C) 1998, 1999, 2001, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <java/lang/Float.h> +#include <java/lang/VMFloat.h> +#include <jvm.h> + +union u +{ + jint l; + jfloat d; +}; + +jint +java::lang::VMFloat::floatToIntBits(jfloat value) +{ + union u u; + u.d = value; + jint e = u.l & 0x7f800000; + jint f = u.l & 0x007fffff; + + if (e == 0x7f800000 && f != 0) + u.l = 0x7fc00000; + + return u.l; +} + +jint +java::lang::VMFloat::floatToRawIntBits(jfloat value) +{ + union u u; + u.d = value; + return u.l; +} + +jfloat +java::lang::VMFloat::intBitsToFloat(jint bits) +{ + union u u; + u.l = bits; + return u.d; +} + diff --git a/libjava/java/lang/natVMProcess.cc b/libjava/java/lang/natVMProcess.cc new file mode 100644 index 000000000..dfc6f6023 --- /dev/null +++ b/libjava/java/lang/natVMProcess.cc @@ -0,0 +1,33 @@ +// natVMProcess.cc - native code for ProcessBuilder + +/* Copyright (C) 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <platform.h> + +#include <jvm.h> + +#include <java/lang/VMProcess.h> +#include <java/lang/Process.h> +#include <java/io/File.h> + +// It is convenient and safe to simply include all of these. +#include <java/lang/Win32Process.h> +#include <java/lang/EcosProcess.h> +#include <java/lang/PosixProcess.h> + +::java::lang::Process * +java::lang::VMProcess::nativeExec (jstringArray cmd, + jstringArray env, + ::java::io::File *dir, + jboolean redirect) +{ + return new _Jv_platform_process (cmd, env, dir, redirect); +} diff --git a/libjava/java/lang/natVMThrowable.cc b/libjava/java/lang/natVMThrowable.cc new file mode 100644 index 000000000..b198f9073 --- /dev/null +++ b/libjava/java/lang/natVMThrowable.cc @@ -0,0 +1,45 @@ +// natVMThrowable.cc - Native part of VMThrowable class. + +/* Copyright (C) 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/Throwable.h> +#include <java/lang/VMThrowable.h> + +using namespace gnu::gcj; + +java::lang::VMThrowable * +java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable *) +{ + using namespace java::lang; + + // Don't trace stack during initialization of the runtime. + if (! gcj::runtimeInitialized) + return NULL; + + _Jv_StackTrace *trace = _Jv_StackTrace::GetStackTrace (); + VMThrowable *vmthrowable = new VMThrowable (); + vmthrowable->data = (RawDataManaged *) trace; + return vmthrowable; +} + + +JArray< ::java::lang::StackTraceElement *> * +java::lang::VMThrowable::getStackTrace (java::lang::Throwable *throwable) +{ + _Jv_StackTrace *trace = reinterpret_cast <_Jv_StackTrace *> (data); + return _Jv_StackTrace::GetStackTraceElements (trace, throwable); +} diff --git a/libjava/java/lang/natWin32Process.cc b/libjava/java/lang/natWin32Process.cc new file mode 100644 index 000000000..0e7f60d6c --- /dev/null +++ b/libjava/java/lang/natWin32Process.cc @@ -0,0 +1,360 @@ +// natWin32Process.cc - Native side of Win32 process code. + +/* Copyright (C) 2003, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +// Conflicts with the definition in "java/lang/reflect/Modifier.h" +#undef STRICT + +#include <java/lang/Win32Process.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Thread.h> +#include <java/io/File.h> +#include <java/io/FileDescriptor.h> +#include <java/io/FileInputStream.h> +#include <java/io/FileOutputStream.h> +#include <java/io/IOException.h> +#include <java/lang/OutOfMemoryError.h> +#include <java/lang/Win32Process$EOFInputStream.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> + +using gnu::java::nio::channels::FileChannelImpl; + +void +java::lang::Win32Process::cleanup (void) +{ + // FIXME: + // We used to close the input, output and + // error streams here, but we can't do that + // because the caller also has the right + // to close these and FileInputStream and FileOutputStream + // scream if you attempt to close() them twice. Presently, + // we use _Jv_platform_close_on_exec, which is similar + // to the POSIX approach. + // + // What I wanted to do is have private nested + // classes in Win32Process which extend FileInputStream + // and FileOutputStream, respectively, but override + // close() to permit multiple calls to close(). This + // led to class header and platform configury issues + // that I didn't feel like dealing with. However, + // this approach could conceivably be a good multiplatform + // one since delaying the pipe close until process + // termination could be wasteful if many child processes + // are spawned within the parent process' lifetime. + inputStream = NULL; + outputStream = NULL; + errorStream = NULL; + + if (procHandle) + { + CloseHandle((HANDLE) procHandle); + procHandle = (jint) INVALID_HANDLE_VALUE; + } +} + +void +java::lang::Win32Process::destroy (void) +{ + if (! hasExited ()) + { + // Kill it forcibly and assign an (arbitrary) exit code of 0. + TerminateProcess ((HANDLE) procHandle, 0); + exitCode = 0; + + cleanup (); + } +} + +jboolean +java::lang::Win32Process::hasExited (void) +{ + DWORD exitStatus; + + if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0) + { + // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the + // child actually exits with this return code, we have a + // problem here. See MSDN documentation on GetExitCodeProcess( ). + + if (exitStatus == STILL_ACTIVE) + return false; + else + { + cleanup (); + exitCode = exitStatus; + return true; + } + } + else + return true; +} + +jint +java::lang::Win32Process::waitFor (void) +{ + if (! hasExited ()) + { + DWORD exitStatus = 0UL; + + // Set up our waitable objects array + // - 0: the handle to the process we just launched + // - 1: our thread's interrupt event + HANDLE arh[2]; + arh[0] = (HANDLE) procHandle; + arh[1] = _Jv_Win32GetInterruptEvent (); + DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE); + + // Use the returned value from WaitForMultipleObjects + // instead of our thread's interrupt_flag to test for + // thread interruption. See the comment for + // _Jv_Win32GetInterruptEvent(). + bool bInterrupted = rval == (WAIT_OBJECT_0 + 1); + + if (bInterrupted) + { + // Querying this forces a reset our thread's interrupt flag. + Thread::interrupted(); + + cleanup (); + throw new InterruptedException (); + } + + GetExitCodeProcess ((HANDLE) procHandle, &exitStatus); + exitCode = exitStatus; + + cleanup (); + } + + return exitCode; +} + + +// Helper class for creating and managing the pipes +// used for I/O redirection for child processes. +class ChildProcessPipe +{ +public: + // Indicates from the child process' point of view + // whether the pipe is for reading or writing. + enum EType {INPUT, OUTPUT, DUMMY}; + + ChildProcessPipe(EType eType); + ~ChildProcessPipe(); + + // Returns a pipe handle suitable for use by the parent process + HANDLE getParentHandle(); + + // Returns a pipe handle suitable for use by the child process. + HANDLE getChildHandle(); + +private: + EType m_eType; + HANDLE m_hRead, m_hWrite; +}; + +ChildProcessPipe::ChildProcessPipe(EType eType): + m_eType(eType), m_hRead(0), m_hWrite(0) +{ + if (eType == DUMMY) + return; + + SECURITY_ATTRIBUTES sAttrs; + + // Explicitly allow the handles to the pipes to be inherited. + sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES); + sAttrs.bInheritHandle = 1; + sAttrs.lpSecurityDescriptor = NULL; + + if (CreatePipe (&m_hRead, &m_hWrite, &sAttrs, 0) == 0) + { + DWORD dwErrorCode = GetLastError (); + throw new java::io::IOException ( + _Jv_WinStrError (_T("Error creating pipe"), dwErrorCode)); + } + + // If this is the read end of the child, we need + // to make the parent write end non-inheritable. Similarly, + // if this is the write end of the child, we need to make + // the parent read end non-inheritable. If we didn't + // do this, the child would inherit these ends and we wouldn't + // be able to close them from our end. For full details, + // do a Google search on "Q190351". + HANDLE& rhStd = m_eType==INPUT ? m_hWrite : m_hRead; + _Jv_platform_close_on_exec (rhStd); +} + +ChildProcessPipe::~ChildProcessPipe() +{ + // Close the parent end of the pipe. This + // destructor is called after the child process + // has been spawned. + if (m_eType != DUMMY) + CloseHandle(getChildHandle()); +} + +HANDLE ChildProcessPipe::getParentHandle() +{ + return m_eType==INPUT ? m_hWrite : m_hRead; +} + +HANDLE ChildProcessPipe::getChildHandle() +{ + return m_eType==INPUT ? m_hRead : m_hWrite; +} + +void +java::lang::Win32Process::startProcess (jstringArray progarray, + jstringArray envp, + java::io::File *dir, + jboolean redirect) +{ + using namespace java::io; + + procHandle = (jint) INVALID_HANDLE_VALUE; + + // Reconstruct the command line. + jstring *elts = elements (progarray); + + int cmdLineLen = 0; + + for (int i = 0; i < progarray->length; ++i) + cmdLineLen += (elts[i]->length() + 1); + + LPTSTR cmdLine = (LPTSTR) _Jv_Malloc ((cmdLineLen + 1) * sizeof(TCHAR)); + LPTSTR cmdLineCurPos = cmdLine; + + for (int i = 0; i < progarray->length; ++i) + { + if (i > 0) + *cmdLineCurPos++ = _T(' '); + + jint len = elts[i]->length(); + JV_TEMP_STRING_WIN32(thiselt, elts[i]); + _tcscpy(cmdLineCurPos, thiselt); + cmdLineCurPos += len; + } + *cmdLineCurPos = _T('\0'); + + // Get the environment, if any. + LPTSTR env = NULL; + if (envp) + { + elts = elements (envp); + + int envLen = 0; + for (int i = 0; i < envp->length; ++i) + envLen += (elts[i]->length() + 1); + + env = (LPTSTR) _Jv_Malloc ((envLen + 1) * sizeof(TCHAR)); + + int j = 0; + for (int i = 0; i < envp->length; ++i) + { + jint len = elts[i]->length(); + + JV_TEMP_STRING_WIN32(thiselt, elts[i]); + _tcscpy(env + j, thiselt); + + j += len; + + // Skip past the null terminator that _tcscpy just inserted. + j++; + } + *(env + j) = _T('\0'); + } + + // Get the working directory path, if specified. + JV_TEMP_STRING_WIN32 (wdir, dir ? dir->getPath () : 0); + + errorStream = NULL; + inputStream = NULL; + outputStream = NULL; + + java::lang::Throwable *exc = NULL; + + try + { + // We create anonymous pipes to communicate with the child + // on each of standard streams. + ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT); + ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT); + ChildProcessPipe aChildStdErr(redirect ? ChildProcessPipe::DUMMY + : ChildProcessPipe::OUTPUT); + + outputStream = new FileOutputStream (new FileChannelImpl ( + (jint) aChildStdIn.getParentHandle (), + FileChannelImpl::WRITE)); + inputStream = new FileInputStream (new FileChannelImpl ( + (jint) aChildStdOut.getParentHandle (), + FileChannelImpl::READ)); + if (redirect) + errorStream = Win32Process$EOFInputStream::instance; + else + errorStream = new FileInputStream (new FileChannelImpl ( + (jint) aChildStdErr.getParentHandle (), + FileChannelImpl::READ)); + + // Now create the child process. + PROCESS_INFORMATION pi; + STARTUPINFO si; + + ZeroMemory (&pi, sizeof (PROCESS_INFORMATION)); + + ZeroMemory (&si, sizeof (STARTUPINFO)); + si.cb = sizeof (STARTUPINFO); + + // Explicitly specify the handles to the standard streams. + si.dwFlags |= STARTF_USESTDHANDLES; + + si.hStdInput = aChildStdIn.getChildHandle(); + si.hStdOutput = aChildStdOut.getChildHandle(); + si.hStdError = redirect ? aChildStdOut.getChildHandle() + : aChildStdErr.getChildHandle(); + + // Spawn the process. CREATE_NO_WINDOW only applies when + // starting a console application; it suppresses the + // creation of a console window. This flag is ignored on + // Win9X. + + if (CreateProcess (NULL, + cmdLine, + NULL, + NULL, + 1, + CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + env, + wdir, + &si, + &pi) == 0) + { + DWORD dwErrorCode = GetLastError (); + throw new IOException ( + _Jv_WinStrError (_T("Error creating child process"), dwErrorCode)); + } + + procHandle = (jint ) pi.hProcess; + + _Jv_Free (cmdLine); + if (env != NULL) + _Jv_Free (env); + } + catch (java::lang::Throwable *thrown) + { + cleanup (); + exc = thrown; + } + + if (exc != NULL) + throw exc; +} diff --git a/libjava/java/lang/ref/PhantomReference.h b/libjava/java/lang/ref/PhantomReference.h new file mode 100644 index 000000000..0c8a823d4 --- /dev/null +++ b/libjava/java/lang/ref/PhantomReference.h @@ -0,0 +1,20 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ref_PhantomReference__ +#define __java_lang_ref_PhantomReference__ + +#pragma interface + +#include <java/lang/ref/Reference.h> + +class java::lang::ref::PhantomReference : public ::java::lang::ref::Reference +{ + +public: + PhantomReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *); + virtual ::java::lang::Object * get(); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ref_PhantomReference__ diff --git a/libjava/java/lang/ref/Reference.h b/libjava/java/lang/ref/Reference.h new file mode 100644 index 000000000..3eeaf65c6 --- /dev/null +++ b/libjava/java/lang/ref/Reference.h @@ -0,0 +1,45 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ref_Reference__ +#define __java_lang_ref_Reference__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawData; + } + } +} + +class java::lang::ref::Reference : public ::java::lang::Object +{ + +public: // actually package-private + Reference(::java::lang::Object *); + Reference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *); +private: + void create(::java::lang::Object *); +public: + virtual ::java::lang::Object * get(); + virtual void clear(); + virtual jboolean isEnqueued(); + virtual jboolean enqueue(); +public: // actually package-private + ::gnu::gcj::RawData * __attribute__((aligned(__alignof__( ::java::lang::Object)))) referent; + ::gnu::gcj::RawData * copy; + jboolean cleared; + ::java::lang::ref::ReferenceQueue * queue; + ::java::lang::ref::Reference * nextOnQueue; + static ::java::lang::Object * lock; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ref_Reference__ diff --git a/libjava/java/lang/ref/Reference.java b/libjava/java/lang/ref/Reference.java new file mode 100644 index 000000000..a5184cee8 --- /dev/null +++ b/libjava/java/lang/ref/Reference.java @@ -0,0 +1,204 @@ +/* java.lang.ref.Reference + Copyright (C) 1999, 2002, 2003, 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 java.lang.ref; + +/** + * This is the base class of all references. A reference allows + * refering to an object without preventing the garbage collector to + * collect it. The only way to get the referred object is via the + * <code>get()</code>-method. This method will return + * <code>null</code> if the object was collected. <br> + * + * A reference may be registered with a queue. When a referred + * element gets collected the reference will be put on the queue, so + * that you will be notified. <br> + * + * There are currently three types of references: soft reference, + * weak reference and phantom reference. <br> + * + * Soft references will be cleared if the garbage collector is told + * to free some memory and there are no unreferenced or weakly referenced + * objects. It is useful for caches. <br> + * + * Weak references will be cleared as soon as the garbage collector + * determines that the refered object is only weakly reachable. They + * are useful as keys in hashtables (see <code>WeakHashtable</code>) as + * you get notified when nobody has the key anymore. + * + * Phantom references don't prevent finalization. If an object is only + * phantom reachable, it will be finalized, and the reference will be + * enqueued, but not cleared. Since you mustn't access an finalized + * object, the <code>get</code> method of a phantom reference will never + * work. It is useful to keep track, when an object is finalized. + * + * @author Jochen Hoenicke + * @see java.util.WeakHashtable + */ +public abstract class Reference<T> +{ + /** + * The underlying object. This field is handled in a special way by + * the garbage collector. + * GCJ LOCAL: + * This is a RawData because it must be disguised from the GC. + * END GCJ LOCAL + */ + gnu.gcj.RawData referent; + + /** + * This is like REFERENT but is not scanned by the GC. We keep a + * copy around so that we can clean up our internal data structure + * even after clear() is called. + * GCJ LOCAL: + * This field doesn't exist in Classpath. + * END GCJ LOCAL + */ + gnu.gcj.RawData copy; + + /** + * Set to true if {@link #clear()} is called. + * GCJ LOCAL: + * This field doesn't exist in Classpath. It is used internally in + * natReference.cc, which enqueues the reference unless it is true + * (has been cleared). + * END GCJ LOCAL + */ + boolean cleared = false; + + /** + * The queue this reference is registered on. This is null, if this + * wasn't registered to any queue or reference was already enqueued. + */ + ReferenceQueue<? super T> queue; + + /** + * Link to the next entry on the queue. If this is null, this + * reference is not enqueued. Otherwise it points to the next + * reference. The last reference on a queue will point to itself + * (not to null, that value is used to mark a not enqueued + * reference). + */ + Reference nextOnQueue; + + /** + * This lock should be taken by the garbage collector, before + * determining reachability. It will prevent the get()-method to + * return the reference so that reachability doesn't change. + */ + static Object lock = new Object(); + + /** + * Creates a new reference that is not registered to any queue. + * Since it is package private, it is not possible to overload this + * class in a different package. + * @param referent the object we refer to. + */ + Reference(T ref) + { + create (ref); + } + + /** + * Creates a reference that is registered to a queue. Since this is + * package private, it is not possible to overload this class in a + * different package. + * @param referent the object we refer to. + * @param q the reference queue to register on. + * @exception NullPointerException if q is null. + */ + Reference(T ref, ReferenceQueue<? super T> q) + { + if (q == null) + throw new NullPointerException(); + queue = q; + create (ref); + } + + /** + * Notifies the VM that a new Reference has been created. + */ + private native void create (T o); + + /** + * Returns the object, this reference refers to. + * @return the object, this reference refers to, or null if the + * reference was cleared. + */ + public native T get(); + + /** + * Clears the reference, so that it doesn't refer to its object + * anymore. For soft and weak references this is called by the + * garbage collector. For phantom references you should call + * this when enqueuing the reference. + */ + public void clear() + { + // Must synchronize so changes are visible in finalizer thread. + synchronized (lock) + { + referent = null; + cleared = true; + } + } + + /** + * Tells if the object is enqueued on a reference queue. + * @return true if it is enqueued, false otherwise. + */ + public boolean isEnqueued() + { + return nextOnQueue != null; + } + + /** + * Enqueue an object on a reference queue. This is normally executed + * by the garbage collector. + */ + public boolean enqueue() + { + if (queue != null && nextOnQueue == null) + { + queue.enqueue(this); + queue = null; + return true; + } + return false; + } +} diff --git a/libjava/java/lang/ref/ReferenceQueue.h b/libjava/java/lang/ref/ReferenceQueue.h new file mode 100644 index 000000000..bd4a9d8b7 --- /dev/null +++ b/libjava/java/lang/ref/ReferenceQueue.h @@ -0,0 +1,31 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ref_ReferenceQueue__ +#define __java_lang_ref_ReferenceQueue__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::ref::ReferenceQueue : public ::java::lang::Object +{ + +public: + ReferenceQueue(); + virtual ::java::lang::ref::Reference * poll(); +public: // actually package-private + virtual jboolean enqueue(::java::lang::ref::Reference *); +private: + ::java::lang::ref::Reference * dequeue(); +public: + virtual ::java::lang::ref::Reference * remove(jlong); + virtual ::java::lang::ref::Reference * remove(); +private: + ::java::lang::ref::Reference * __attribute__((aligned(__alignof__( ::java::lang::Object)))) first; + ::java::lang::Object * lock; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ref_ReferenceQueue__ diff --git a/libjava/java/lang/ref/SoftReference.h b/libjava/java/lang/ref/SoftReference.h new file mode 100644 index 000000000..faa98e7bd --- /dev/null +++ b/libjava/java/lang/ref/SoftReference.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ref_SoftReference__ +#define __java_lang_ref_SoftReference__ + +#pragma interface + +#include <java/lang/ref/Reference.h> + +class java::lang::ref::SoftReference : public ::java::lang::ref::Reference +{ + +public: + SoftReference(::java::lang::Object *); + SoftReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *); + virtual ::java::lang::Object * get(); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ref_SoftReference__ diff --git a/libjava/java/lang/ref/WeakReference.h b/libjava/java/lang/ref/WeakReference.h new file mode 100644 index 000000000..b540274d3 --- /dev/null +++ b/libjava/java/lang/ref/WeakReference.h @@ -0,0 +1,20 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_ref_WeakReference__ +#define __java_lang_ref_WeakReference__ + +#pragma interface + +#include <java/lang/ref/Reference.h> + +class java::lang::ref::WeakReference : public ::java::lang::ref::Reference +{ + +public: + WeakReference(::java::lang::Object *); + WeakReference(::java::lang::Object *, ::java::lang::ref::ReferenceQueue *); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_ref_WeakReference__ diff --git a/libjava/java/lang/ref/natReference.cc b/libjava/java/lang/ref/natReference.cc new file mode 100644 index 000000000..ac7272cf5 --- /dev/null +++ b/libjava/java/lang/ref/natReference.cc @@ -0,0 +1,377 @@ +// natReference.cc - Native code for References + +/* Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@redhat.com> + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Throwable.h> +#include <java/lang/ref/Reference.h> +#include <java/lang/ref/SoftReference.h> +#include <java/lang/ref/WeakReference.h> +#include <java/lang/ref/PhantomReference.h> +#include <java/lang/ref/ReferenceQueue.h> + +static void finalize_reference (jobject ref); +static void finalize_referred_to_object (jobject obj); + + + +enum weight +{ + SOFT = 0, + WEAK = 1, + FINALIZE = 2, + PHANTOM = 3, + + // This is used to mark the head of a list. + HEAD = 4, + + // This is used to mark a deleted item. + DELETED = 5 +}; + +// Objects of this type are used in the hash table to keep track of +// the mapping between a finalizable object and the various References +// which refer to it. +struct object_list +{ + // The reference object. This is NULL for FINALIZE weight. + jobject reference; + + // The weight of this object. + enum weight weight; + + // Next in list. + object_list *next; +}; + +// Hash table used to hold mapping from object to References. The +// object_list item in the hash holds the object itself in the +// reference field; chained to it are all the references sorted in +// order of weight (lowest first). +static object_list *hash = NULL; + +// Number of slots used in HASH. +static int hash_count = 0; + +// Number of slots total in HASH. Must be power of 2. +static int hash_size = 0; + +#define DELETED_REFERENCE ((jobject) -1) + +static object_list * +find_slot (jobject key) +{ + jint hcode = _Jv_HashCode (key); + /* step must be non-zero, and relatively prime with hash_size. */ + jint step = (hcode ^ (hcode >> 16)) | 1; + int start_index = hcode & (hash_size - 1); + int index = start_index; + int deleted_index = -1; + do + { + object_list *ptr = &hash[index]; + if (ptr->reference == key) + return ptr; + else if (ptr->reference == NULL) + { + if (deleted_index == -1) + return ptr; + else + return &hash[deleted_index]; + } + else if (ptr->weight == DELETED) + { + deleted_index = index; + JvAssert (ptr->reference == DELETED_REFERENCE); + } + index = (index + step) & (hash_size - 1); + } + while (index != start_index); + // Note that we can have INDEX == START_INDEX if the table has no + // NULL entries but does have DELETED entries. + JvAssert (deleted_index >= 0); + return &hash[deleted_index]; +} + +static void +rehash () +{ + if (hash == NULL) + { + hash_size = 1024; + hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list)); + memset (hash, 0, hash_size * sizeof (object_list)); + } + else + { + object_list *old = hash; + int i = hash_size; + + hash_size *= 2; + hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list)); + memset (hash, 0, hash_size * sizeof (object_list)); + + while (--i >= 0) + { + if (old[i].reference == NULL || old[i].weight == DELETED) + continue; + object_list *newslot = find_slot (old[i].reference); + *newslot = old[i]; + } + + _Jv_Free (old); + } +} + +// Remove a Reference. +static void +remove_from_hash (jobject obj) +{ + java::lang::ref::Reference *ref + = reinterpret_cast<java::lang::ref::Reference *> (obj); + object_list *head = find_slot (ref->copy); + + // We might have found a new slot. We can just ignore that here. + if (head->reference != ref->copy) + return; + + object_list **link = &head->next; + head = head->next; + + while (head && head->reference != ref) + { + link = &head->next; + head = head->next; + } + + // Remove the slot. + if (head) + { + *link = head->next; + _Jv_Free (head); + } +} + +// Return list head if object is in hash, NULL otherwise. +object_list * +in_hash (jobject obj) +{ + // The hash table might not yet be initialized. + if (hash == NULL) + return NULL; + object_list *head = find_slot (obj); + if (head->reference != obj) + return NULL; + return head; +} + +// FIXME what happens if an object's finalizer creates a Reference to +// the object, and the object has never before been added to the hash? +// Madness! + +// Add an item to the hash table. If the item is new, we also add a +// finalizer item. We keep items in the hash table until they are +// completely collected; this lets us know when an item is new, even +// if it has been resurrected after its finalizer has been run. +static void +add_to_hash (java::lang::ref::Reference *the_reference) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + + if (3 * hash_count >= 2 * hash_size) + rehash (); + + // Use `copy' here because the `referent' field has been cleared. + jobject referent = the_reference->copy; + object_list *item = find_slot (referent); + if (item->reference == NULL || item->reference == DELETED_REFERENCE) + { + // New item, so make an entry for the finalizer. + item->reference = referent; + item->weight = HEAD; + + item->next = (object_list *) _Jv_Malloc (sizeof (object_list)); + item->next->reference = NULL; + item->next->weight = FINALIZE; + item->next->next = NULL; + ++hash_count; + } + + object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list)); + n->reference = the_reference; + + enum weight w = PHANTOM; + if (java::lang::ref::SoftReference::class$.isInstance (the_reference)) + w = SOFT; + else if (java::lang::ref::WeakReference::class$.isInstance (the_reference)) + w = WEAK; + n->weight = w; + + object_list **link = &item->next; + object_list *iter = *link; + while (iter && iter->weight < n->weight) + { + link = &iter->next; + iter = *link; + } + n->next = *link; + *link = n; +} + +// Add a FINALIZE entry if one doesn't exist. +static void +maybe_add_finalize (object_list *entry, jobject obj) +{ + object_list **link = &entry->next; + object_list *iter = *link; + while (iter && iter->weight < FINALIZE) + { + link = &iter->next; + iter = *link; + } + + // We want at most one FINALIZE entry in the queue. + if (iter && iter->weight == FINALIZE) + return; + + object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list)); + n->reference = obj; + n->weight = FINALIZE; + n->next = *link; + *link = n; +} + +// This is called when an object is ready to be finalized. This +// actually implements the appropriate Reference semantics. +static void +finalize_referred_to_object (jobject obj) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + + object_list *list = find_slot (obj); + object_list *head = list->next; + if (head == NULL) + { + // We have a truly dead object: the object's finalizer has been + // run, all the object's references have been processed, and the + // object is unreachable. There is, at long last, no way to + // resurrect it. + list->reference = DELETED_REFERENCE; + list->weight = DELETED; + --hash_count; + return; + } + + enum weight w = head->weight; + if (w == FINALIZE) + { + // Update the list first, as _Jv_FinalizeString might end up + // looking at this data structure. + list->next = head->next; + _Jv_Free (head); + + // If we have a Reference A to a Reference B, and B is + // finalized, then we have to take special care to make sure + // that B is properly deregistered. This is super gross. FIXME + // will it fail if B's finalizer resurrects B? + if (java::lang::ref::Reference::class$.isInstance (obj)) + finalize_reference (obj); + else if (obj->getClass() == &java::lang::String::class$) + _Jv_FinalizeString (obj); + else + _Jv_FinalizeObject (obj); + } + else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj)) + { + // If we just decided to reclaim a soft reference, we might as + // well do all the weak references at the same time. + if (w == SOFT) + w = WEAK; + + while (head && head->weight <= w) + { + java::lang::ref::Reference *ref + = reinterpret_cast<java::lang::ref::Reference *> (head->reference); + if (! ref->cleared) + ref->enqueue (); + + object_list *next = head->next; + _Jv_Free (head); + head = next; + } + list->next = head; + } + + // Re-register this finalizer. We always re-register because we + // can't know until the next collection cycle whether or not the + // object is truly unreachable. + _Jv_RegisterFinalizer (obj, finalize_referred_to_object); +} + +// This is called when a Reference object is finalized. If there is a +// Reference pointing to this Reference then that case is handled by +// finalize_referred_to_object. +static void +finalize_reference (jobject ref) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + remove_from_hash (ref); + // The user might have a subclass of Reference with a finalizer. + _Jv_FinalizeObject (ref); +} + +void +_Jv_RegisterStringFinalizer (jobject str) +{ + // This function might be called before any other Reference method, + // so we must ensure the class is initialized. + _Jv_InitClass (&java::lang::ref::Reference::class$); + JvSynchronize sync (java::lang::ref::Reference::lock); + // If the object is in our hash table, then we might need to add a + // new FINALIZE entry. Otherwise, we just register an ordinary + // finalizer. + object_list *entry = in_hash (str); + if (entry) + maybe_add_finalize (entry, str); + else + _Jv_RegisterFinalizer ((void *) str, _Jv_FinalizeString); +} + +void +::java::lang::ref::Reference::create (jobject ref) +{ + // Nothing says you can't make a Reference with a NULL referent. + // But there's nothing to do in such a case. + referent = reinterpret_cast<gnu::gcj::RawData *> (ref); + copy = referent; + if (referent != NULL) + { + JvSynchronize sync (java::lang::ref::Reference::lock); + // `this' is a new Reference object. We register a new + // finalizer for pointed-to object and we arrange a special + // finalizer for ourselves as well. + _Jv_RegisterFinalizer (this, finalize_reference); + _Jv_RegisterFinalizer (referent, finalize_referred_to_object); + gnu::gcj::RawData **p = &referent; + _Jv_GCRegisterDisappearingLink ((jobject *) p); + add_to_hash (this); + } +} + +::java::lang::Object * +::java::lang::ref::Reference::get() +{ + JvSynchronize sync (lock); + return referent; +} diff --git a/libjava/java/lang/reflect/AccessibleObject.h b/libjava/java/lang/reflect/AccessibleObject.h new file mode 100644 index 000000000..d140e300c --- /dev/null +++ b/libjava/java/lang/reflect/AccessibleObject.h @@ -0,0 +1,36 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_AccessibleObject__ +#define __java_lang_reflect_AccessibleObject__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::AccessibleObject : public ::java::lang::Object +{ + +public: // actually protected + AccessibleObject(); +public: + virtual jboolean isAccessible(); + static void setAccessible(JArray< ::java::lang::reflect::AccessibleObject * > *, jboolean); + virtual void setAccessible(jboolean); +private: + static void checkPermission(); + void secureSetAccessible(jboolean); +public: + virtual ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *); + virtual JArray< ::java::lang::annotation::Annotation * > * getAnnotations(); + virtual JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations(); + virtual jboolean isAnnotationPresent(::java::lang::Class *); +public: // actually package-private + jboolean __attribute__((aligned(__alignof__( ::java::lang::Object)))) flag; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_AccessibleObject__ diff --git a/libjava/java/lang/reflect/AnnotatedElement.h b/libjava/java/lang/reflect/AnnotatedElement.h new file mode 100644 index 000000000..5792b75e0 --- /dev/null +++ b/libjava/java/lang/reflect/AnnotatedElement.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_AnnotatedElement__ +#define __java_lang_reflect_AnnotatedElement__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::AnnotatedElement : public ::java::lang::Object +{ + +public: + virtual ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *) = 0; + virtual JArray< ::java::lang::annotation::Annotation * > * getAnnotations() = 0; + virtual JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations() = 0; + virtual jboolean isAnnotationPresent(::java::lang::Class *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_AnnotatedElement__ diff --git a/libjava/java/lang/reflect/Array.h b/libjava/java/lang/reflect/Array.h new file mode 100644 index 000000000..48df7d3fa --- /dev/null +++ b/libjava/java/lang/reflect/Array.h @@ -0,0 +1,46 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Array__ +#define __java_lang_reflect_Array__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::Array : public ::java::lang::Object +{ + + Array(); +public: + static ::java::lang::Object * newInstance(::java::lang::Class *, jint); + static ::java::lang::Object * newInstance(::java::lang::Class *, JArray< jint > *); + static jint getLength(::java::lang::Object *); + static ::java::lang::Object * get(::java::lang::Object *, jint); + static jboolean getBoolean(::java::lang::Object *, jint); + static jbyte getByte(::java::lang::Object *, jint); + static jchar getChar(::java::lang::Object *, jint); + static jshort getShort(::java::lang::Object *, jint); + static jint getInt(::java::lang::Object *, jint); + static jlong getLong(::java::lang::Object *, jint); + static jfloat getFloat(::java::lang::Object *, jint); + static jdouble getDouble(::java::lang::Object *, jint); +private: + static ::java::lang::Class * getElementType(::java::lang::Object *, jint); + static void set(::java::lang::Object *, jint, ::java::lang::Object *, ::java::lang::Class *); +public: + static void set(::java::lang::Object *, jint, ::java::lang::Object *); + static void setBoolean(::java::lang::Object *, jint, jboolean); + static void setByte(::java::lang::Object *, jint, jbyte); + static void setChar(::java::lang::Object *, jint, jchar); + static void setShort(::java::lang::Object *, jint, jshort); + static void setInt(::java::lang::Object *, jint, jint); + static void setLong(::java::lang::Object *, jint, jlong); + static void setFloat(::java::lang::Object *, jint, jfloat); + static void setDouble(::java::lang::Object *, jint, jdouble); + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Array__ diff --git a/libjava/java/lang/reflect/Array.java b/libjava/java/lang/reflect/Array.java new file mode 100644 index 000000000..639cc0e02 --- /dev/null +++ b/libjava/java/lang/reflect/Array.java @@ -0,0 +1,458 @@ +/* java.lang.reflect.Array - manipulate arrays by reflection + Copyright (C) 1998, 1999, 2001, 2003, 2005, 2007 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; + +/** + * Array holds static helper functions that allow you to create and + * manipulate arrays by reflection. Operations know how to perform widening + * conversions, but throw {@link IllegalArgumentException} if you attempt + * a narrowing conversion. Also, when accessing primitive arrays, this + * class performs object wrapping and unwrapping as necessary.<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. Note also that the shorthand <code>Object[].class</code> + * is a convenient way to get array Classes.<p> + * + * <B>Performance note:</B> This class performs best when it does not have + * to convert primitive types. The further along the chain it has to convert, + * the worse performance will be. You're best off using the array as whatever + * type it already is, and then converting the result. You will do even + * worse if you do this and use the generic set() function. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @see java.lang.Boolean#TYPE + * @see java.lang.Byte#TYPE + * @see java.lang.Short#TYPE + * @see java.lang.Character#TYPE + * @see java.lang.Integer#TYPE + * @see java.lang.Long#TYPE + * @see java.lang.Float#TYPE + * @see java.lang.Double#TYPE + * @since 1.1 + * @status updated to 1.4 + */ +public final class Array +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalangreflect"); + } + } + + /** + * This class is uninstantiable. + */ + private Array() + { + } + + /** + * Creates a new single-dimensioned array. + * @param componentType the type of the array to create + * @param length the length of the array to create + * @return the created array, cast to an Object + * @throws NullPointerException if <code>componentType</code> is null + * @throws IllegalArgumentException if <code>componentType</code> is + * <code>Void.TYPE</code> + * @throws NegativeArraySizeException when length is less than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static native Object newInstance(Class<?> componentType, int length); + + /** + * Creates a new multi-dimensioned array. The new array has the same + * component type as the argument class, and the number of dimensions + * in the new array is the sum of the dimensions of the argument class + * and the length of the argument dimensions. Virtual Machine limitations + * forbid too many dimensions (usually 255 is the maximum); but even + * 50 dimensions of 2 elements in each dimension would exceed your memory + * long beforehand! + * + * @param componentType the type of the array to create. + * @param dimensions the dimensions of the array to create. Each element + * in <code>dimensions</code> makes another dimension of the new + * array. Thus, <code>Array.newInstance(java.lang.Boolean, + * new int[]{1,2,3})</code> is the same as + * <code>new java.lang.Boolean[1][2][3]</code> + * @return the created array, cast to an Object + * @throws NullPointerException if componentType or dimension is null + * @throws IllegalArgumentException if the the size of + * <code>dimensions</code> is 0 or exceeds the maximum number of + * array dimensions in the VM; or if componentType is Void.TYPE + * @throws NegativeArraySizeException when any of the dimensions is less + * than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static native Object newInstance(Class<?> elementType, int[] dimensions); + + /** + * Gets the array length. + * @param array the array + * @return the length of the array + * @throws IllegalArgumentException if <code>array</code> is not an array + * @throws NullPointerException if <code>array</code> is null + */ + public static native int getLength(Object array); + + /** + * Gets an element of an array. Primitive elements will be wrapped in + * the corresponding class type. + * + * @param array the array to access + * @param index the array index to access + * @return the element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not an array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #getBoolean(Object, int) + * @see #getByte(Object, int) + * @see #getChar(Object, int) + * @see #getShort(Object, int) + * @see #getInt(Object, int) + * @see #getLong(Object, int) + * @see #getFloat(Object, int) + * @see #getDouble(Object, int) + */ + public static native Object get(Object array, int index); + + /** + * Gets an element of a boolean array. + * + * @param array the array to access + * @param index the array index to access + * @return the boolean element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a boolean + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native boolean getBoolean(Object array, int index); + + /** + * Gets an element of a byte array. + * + * @param array the array to access + * @param index the array index to access + * @return the byte element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native byte getByte(Object array, int index); + + /** + * Gets an element of a char array. + * + * @param array the array to access + * @param index the array index to access + * @return the char element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a char + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native char getChar(Object array, int index); + + /** + * Gets an element of a short array. + * + * @param array the array to access + * @param index the array index to access + * @return the short element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte + * or char array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native short getShort(Object array, int index); + + /** + * Gets an element of an int array. + * + * @param array the array to access + * @param index the array index to access + * @return the int element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, or int array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native int getInt(Object array, int index); + + /** + * Gets an element of a long array. + * + * @param array the array to access + * @param index the array index to access + * @return the long element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, or long array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native long getLong(Object array, int index); + + /** + * Gets an element of a float array. + * + * @param array the array to access + * @param index the array index to access + * @return the float element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, long, or float array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native float getFloat(Object array, int index); + + /** + * Gets an element of a double array. + * + * @param array the array to access + * @param index the array index to access + * @return the double element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native double getDouble(Object array, int index); + + private static native Class getElementType(Object array, int index); + + private static native void set(Object array, int index, + Object value, Class elType); + + /** + * Sets an element of an array. If the array is primitive, then the new + * value is unwrapped and widened. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not an array, + * or the array is primitive and unwrapping value fails, or the + * value is not assignable to the array component type + * @throws NullPointerException if array is null, or if array is primitive + * and value is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #setBoolean(Object, int, boolean) + * @see #setByte(Object, int, byte) + * @see #setChar(Object, int, char) + * @see #setShort(Object, int, short) + * @see #setInt(Object, int, int) + * @see #setLong(Object, int, long) + * @see #setFloat(Object, int, float) + * @see #setDouble(Object, int, double) + */ + public static void set(Object array, int index, Object value) + { + Class elType = getElementType(array, index); + if (! elType.isPrimitive()) + set(array, index, value, elType); + else if (value instanceof Byte) + setByte(array, index, ((Byte) value).byteValue()); + else if (value instanceof Short) + setShort(array, index, ((Short) value).shortValue()); + else if (value instanceof Integer) + setInt(array, index, ((Integer) value).intValue()); + else if (value instanceof Long) + setLong(array, index, ((Long) value).longValue()); + else if (value instanceof Float) + setFloat(array, index, ((Float) value).floatValue()); + else if (value instanceof Double) + setDouble(array, index, ((Double) value).doubleValue()); + else if (value instanceof Character) + setChar(array, index, ((Character) value).charValue()); + else if (value instanceof Boolean) + setBoolean(array, index, ((Boolean) value).booleanValue()); + else + throw new IllegalArgumentException(); + } + + /** + * Sets an element of a boolean array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a boolean + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setBoolean(Object array, int index, boolean value); + + /** + * Sets an element of a byte array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * short, int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setByte(Object array, int index, byte value); + + /** + * Sets an element of a char array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a char, + * int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setChar(Object array, int index, char value); + + /** + * Sets an element of a short array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a short, + * int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setShort(Object array, int index, short value); + + /** + * Sets an element of an int array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not an int, + * long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setInt(Object array, int index, int value); + + /** + * Sets an element of a long array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a long, + * float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setLong(Object array, int index, long value); + + /** + * Sets an element of a float array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a float + * or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setFloat(Object array, int index, float value); + + /** + * Sets an element of a double array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a double + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setDouble(Object array, int index, double value); +} diff --git a/libjava/java/lang/reflect/Constructor.h b/libjava/java/lang/reflect/Constructor.h new file mode 100644 index 000000000..5a200bc11 --- /dev/null +++ b/libjava/java/lang/reflect/Constructor.h @@ -0,0 +1,65 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Constructor__ +#define __java_lang_reflect_Constructor__ + +#pragma interface + +#include <java/lang/reflect/AccessibleObject.h> +#include <gcj/array.h> + + +jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *); +jobject _Jv_JNI_ToReflectedMethod (_Jv_JNIEnv *, jclass, jmethodID, jboolean); + +class java::lang::reflect::Constructor : public ::java::lang::reflect::AccessibleObject +{ + + Constructor(); +public: + ::java::lang::Class * getDeclaringClass(); + ::java::lang::String * getName(); +private: + jint getModifiersInternal(); +public: + jint getModifiers(); + jboolean isSynthetic(); + jboolean isVarArgs(); + JArray< ::java::lang::Class * > * getParameterTypes(); + JArray< ::java::lang::Class * > * getExceptionTypes(); + jboolean equals(::java::lang::Object *); + jint hashCode(); + ::java::lang::String * toString(); +public: // actually package-private + static void addTypeParameters(::java::lang::StringBuilder *, JArray< ::java::lang::reflect::TypeVariable * > *); +public: + ::java::lang::String * toGenericString(); + ::java::lang::Object * newInstance(JArray< ::java::lang::Object * > *); + JArray< ::java::lang::reflect::TypeVariable * > * getTypeParameters(); +private: + ::java::lang::String * getSignature(); +public: + JArray< ::java::lang::reflect::Type * > * getGenericExceptionTypes(); + JArray< ::java::lang::reflect::Type * > * getGenericParameterTypes(); + ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *); + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations(); + JArray< JArray< ::java::lang::annotation::Annotation * > * > * getParameterAnnotations(); +private: + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotationsInternal(); + JArray< JArray< ::java::lang::annotation::Annotation * > * > * getParameterAnnotationsInternal(); + void getType(); + static const jint CONSTRUCTOR_MODIFIERS = 7; + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::reflect::AccessibleObject)))) declaringClass; + JArray< ::java::lang::Class * > * exception_types; + JArray< ::java::lang::Class * > * parameter_types; + jint offset; +public: + static ::java::lang::Class class$; + + friend jmethodID (::_Jv_FromReflectedConstructor) (java::lang::reflect::Constructor *); + friend jobject (::_Jv_JNI_ToReflectedMethod) (_Jv_JNIEnv *, jclass, jmethodID, jboolean); + friend class java::lang::Class; +}; + +#endif // __java_lang_reflect_Constructor__ diff --git a/libjava/java/lang/reflect/Constructor.java b/libjava/java/lang/reflect/Constructor.java new file mode 100644 index 000000000..adebc600a --- /dev/null +++ b/libjava/java/lang/reflect/Constructor.java @@ -0,0 +1,424 @@ +/* java.lang.reflect.Constructor - reflection of Java constructors + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 + 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.java.lang.reflect.MethodSignatureParser; +import java.lang.annotation.Annotation; + +/** + * The Constructor class represents a constructor of a class. It also allows + * dynamic creation of an object, via reflection. Invocation on Constructor + * objects knows how to do widening conversions, but throws + * {@link IllegalArgumentException} if a narrowing conversion would be + * necessary. You can query for information on this Constructor regardless + * of location, but construction 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> + * + * 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 <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getConstructor(Class[]) + * @see java.lang.Class#getDeclaredConstructor(Class[]) + * @see java.lang.Class#getConstructors() + * @see java.lang.Class#getDeclaredConstructors() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Constructor<T> extends AccessibleObject + implements Member, GenericDeclaration +{ + private static final int CONSTRUCTOR_MODIFIERS + = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC; + + /** + * This class is uninstantiable except from native code. + */ + private Constructor () + { + } + + /** + * Gets the class that declared this constructor. + * @return the class that declared this member + */ + public Class<T> getDeclaringClass () + { + return declaringClass; + } + + /** + * Gets the name of this constructor (the non-qualified name of the class + * it was declared in). + * @return the name of this constructor + */ + public String getName() + { + return declaringClass.getName(); + } + + /** + * Return the raw modifiers for this constructor. In particular + * this will include the synthetic and varargs bits. + * @return the constructor's modifiers + */ + private native int getModifiersInternal(); + + /** + * 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 + * following modifiers: public, private, protected. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public int getModifiers () + { + return getModifiersInternal() & CONSTRUCTOR_MODIFIERS; + } + + /** + * Return true if this constructor is synthetic, false otherwise. + * A synthetic member is one which is created by the compiler, + * and which does not appear in the user's source code. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this is a varargs constructor, that is if + * the constructor takes a variable number of arguments. + * @since 1.5 + */ + public boolean isVarArgs() + { + return (getModifiersInternal() & Modifier.VARARGS) != 0; + } + + /** + * Get the parameter list for this constructor, in declaration order. If the + * constructor takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the constructor's parameters + */ + public Class<?>[] getParameterTypes () + { + if (parameter_types == null) + getType (); + return (Class<?>[]) parameter_types.clone(); + } + + /** + * Get the exception types this constructor says it throws, in no particular + * order. If the constructor has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the constructor's throws clause + */ + public Class<?>[] getExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class<?>[]) exception_types.clone(); + } + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Constructors are semantically equivalent if they have the same + * declaring class and the same parameter list. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Constructor)) + return false; + Constructor c = (Constructor) obj; + return declaringClass == c.declaringClass && offset == c.offset; + } + + /** + * Get the hash code for the Constructor. The Constructor hash code is the + * hash code of the declaring class's name. + * + * @return the hash code for the object + */ + public int hashCode () + { + return declaringClass.getName().hashCode(); + } + + /** + * Get a String representation of the Constructor. A Constructor's String + * representation is "<modifier> <classname>(<paramtypes>) + * throws <exceptions>", where everything after ')' is omitted if + * there are no exceptions.<br> Example: + * <code>public java.io.FileInputStream(java.lang.Runnable) + * throws java.io.FileNotFoundException</code> + * + * @return the String representation of the Constructor + */ + public String toString() + { + if (parameter_types == null) + getType (); + StringBuffer b = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, b); + b.append(" "); + } + Method.appendClassName (b, declaringClass); + b.append("("); + for (int i = 0; i < parameter_types.length; ++i) + { + Method.appendClassName (b, parameter_types[i]); + if (i < parameter_types.length - 1) + b.append(","); + } + b.append(")"); + return b.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(); + } + + /** + * Create a new instance by invoking the constructor. Arguments are + * automatically unwrapped and widened, if needed.<p> + * + * If this class is abstract, you will get an + * <code>InstantiationException</code>. If the constructor takes 0 + * arguments, you may use null or a 0-length array for <code>args</code>.<p> + * + * If this Constructor enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not create this object in similar compiled code. If the class + * is uninitialized, you trigger class initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Then, the constructor is invoked. If it completes normally, the return + * value will be the new object. If it completes abruptly, the exception is + * wrapped in an <code>InvocationTargetException</code>. + * + * @param args the arguments to the constructor + * @return the newly created object + * @throws IllegalAccessException if the constructor could not normally be + * called by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * or if the arguments types are wrong even with a widening + * conversion + * @throws InstantiationException if the class is abstract + * @throws InvocationTargetException if the constructor throws an exception + * @throws ExceptionInInitializerError if construction triggered class + * initialization, which then failed + */ + public native T newInstance (Object... args) + throws InstantiationException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException; + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this constructor, in declaration order. + * An array of size zero is returned if this constructor has no type + * variables. + * + * @return the type variables associated with this constructor. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public TypeVariable<Constructor<T>>[] getTypeParameters() + { + String sig = getSignature(); + if (sig == null) + return new TypeVariable[0]; + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Return the String in the Signature attribute for this constructor. If there + * is no Signature attribute, return null. + */ + private native String 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 + * exceptions. + * + * @return the exception types declared by this constructor. + * @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[] getGenericExceptionTypes() + { + String sig = getSignature(); + if (sig == null) + return getExceptionTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericExceptionTypes(); + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the parameter list for this constructor, in declaration order. + * An array of size zero is returned if this constructor takes no + * parameters. + * + * @return a list of the types of the constructor's parameters + * @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[] getGenericParameterTypes() + { + String sig = getSignature(); + if (sig == null) + return getParameterTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericParameterTypes(); + } + + public <T extends Annotation> T getAnnotation(Class<T> annoClass) + { + Annotation[] annos = getDeclaredAnnotations(); + for (int i = 0; i < annos.length; ++i) + if (annos[i].annotationType() == annoClass) + return (T) annos[i]; + return null; + } + + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + public Annotation[][] getParameterAnnotations() + { + // FIXME: should check that we have the right number + // of parameters ...? + Annotation[][] result = getParameterAnnotationsInternal(); + if (result == null) + result = new Annotation[0][0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + private native Annotation[][] getParameterAnnotationsInternal(); + + // Update cached values from method descriptor in class. + private native void getType (); + + // Declaring class. + private Class<T> declaringClass; + + // Exception types. + private Class[] exception_types; + // Parameter types. + private Class[] parameter_types; + + // Offset in bytes from the start of declaringClass's methods array. + private int offset; +} diff --git a/libjava/java/lang/reflect/Field.h b/libjava/java/lang/reflect/Field.h new file mode 100644 index 000000000..0af95652d --- /dev/null +++ b/libjava/java/lang/reflect/Field.h @@ -0,0 +1,98 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Field__ +#define __java_lang_reflect_Field__ + +#pragma interface + +#include <java/lang/reflect/AccessibleObject.h> +#include <gcj/array.h> + + +jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *); +jobject _Jv_JNI_ToReflectedField (_Jv_JNIEnv*, jclass, jfieldID, jboolean); +jobject _Jv_getFieldInternal (java::lang::reflect::Field *f, jclass c, jobject o); + +class java::lang::reflect::Field : public ::java::lang::reflect::AccessibleObject +{ + +public: // actually package-private + Field(); +public: + ::java::lang::Class * getDeclaringClass(); + ::java::lang::String * getName(); +private: + jint getModifiersInternal(); +public: + jint getModifiers(); + jboolean isSynthetic(); + jboolean isEnumConstant(); + ::java::lang::Class * getType(); + jboolean equals(::java::lang::Object *); + jint hashCode(); + ::java::lang::String * toString(); + ::java::lang::String * toGenericString(); + ::java::lang::Object * get(::java::lang::Object *); + jboolean getBoolean(::java::lang::Object *); + jbyte getByte(::java::lang::Object *); + jchar getChar(::java::lang::Object *); + jshort getShort(::java::lang::Object *); + jint getInt(::java::lang::Object *); + jlong getLong(::java::lang::Object *); + jfloat getFloat(::java::lang::Object *); + jdouble getDouble(::java::lang::Object *); +private: + jboolean getBoolean(::java::lang::Class *, ::java::lang::Object *); + jchar getChar(::java::lang::Class *, ::java::lang::Object *); + jbyte getByte(::java::lang::Class *, ::java::lang::Object *); + jshort getShort(::java::lang::Class *, ::java::lang::Object *); + jint getInt(::java::lang::Class *, ::java::lang::Object *); + jlong getLong(::java::lang::Class *, ::java::lang::Object *); + jfloat getFloat(::java::lang::Class *, ::java::lang::Object *); + jdouble getDouble(::java::lang::Class *, ::java::lang::Object *); + ::java::lang::Object * get(::java::lang::Class *, ::java::lang::Object *); +public: + void set(::java::lang::Object *, ::java::lang::Object *); + void setBoolean(::java::lang::Object *, jboolean); + void setByte(::java::lang::Object *, jbyte); + void setChar(::java::lang::Object *, jchar); + void setShort(::java::lang::Object *, jshort); + void setInt(::java::lang::Object *, jint); + void setLong(::java::lang::Object *, jlong); + void setFloat(::java::lang::Object *, jfloat); + void setDouble(::java::lang::Object *, jdouble); + ::java::lang::reflect::Type * getGenericType(); + ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *); + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations(); +private: + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotationsInternal(); + ::java::lang::String * getSignature(); +public: // actually package-private + void setByte(::java::lang::Class *, ::java::lang::Object *, jbyte, jboolean); + void setShort(::java::lang::Class *, ::java::lang::Object *, jshort, jboolean); + void setInt(::java::lang::Class *, ::java::lang::Object *, jint, jboolean); + void setLong(::java::lang::Class *, ::java::lang::Object *, jlong, jboolean); + void setFloat(::java::lang::Class *, ::java::lang::Object *, jfloat, jboolean); + void setDouble(::java::lang::Class *, ::java::lang::Object *, jdouble, jboolean); + void setChar(::java::lang::Class *, ::java::lang::Object *, jchar, jboolean); + void setBoolean(::java::lang::Class *, ::java::lang::Object *, jboolean, jboolean); + void set(::java::lang::Class *, ::java::lang::Object *, ::java::lang::Object *, ::java::lang::Class *, jboolean); +private: + void set(::java::lang::Class *, ::java::lang::Object *, ::java::lang::Object *); + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::reflect::AccessibleObject)))) declaringClass; + ::java::lang::String * name; + jint offset; + ::java::lang::Class * type; +public: // actually package-private + static const jint FIELD_MODIFIERS = 223; +public: + static ::java::lang::Class class$; + + friend jfieldID (::_Jv_FromReflectedField) (java::lang::reflect::Field *); + friend jobject (::_Jv_JNI_ToReflectedField) (_Jv_JNIEnv*, jclass, jfieldID, jboolean); + friend class java::lang::Class; + friend jobject (::_Jv_getFieldInternal) (java::lang::reflect::Field *f, jclass c, jobject o); +}; + +#endif // __java_lang_reflect_Field__ diff --git a/libjava/java/lang/reflect/Field.java b/libjava/java/lang/reflect/Field.java new file mode 100644 index 000000000..61db14df5 --- /dev/null +++ b/libjava/java/lang/reflect/Field.java @@ -0,0 +1,817 @@ +/* java.lang.reflect.Field - reflection of Java fields + Copyright (C) 1998, 2001, 2005, 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 java.lang.reflect; + +import gnu.java.lang.ClassHelper; + +import gnu.java.lang.reflect.FieldSignatureParser; +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> + * + * <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. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Per Bothner <bothner@cygnus.com> + * @see Member + * @see Class + * @see Class#getField(String) + * @see Class#getDeclaredField(String) + * @see Class#getFields() + * @see Class#getDeclaredFields() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Field + extends AccessibleObject implements Member +{ + private Class declaringClass; + private String name; + + // Offset in bytes from the start of declaringClass's fields array. + private int offset; + + // The Class (or primitive TYPE) of this field. + private Class type; + + static final int FIELD_MODIFIERS + = Modifier.FINAL | Modifier.PRIVATE | Modifier.PROTECTED + | Modifier.PUBLIC | Modifier.STATIC | Modifier.TRANSIENT + | Modifier.VOLATILE; + + // This is instantiated by Class sometimes, but it uses C++ and + // avoids the Java protection check. + Field () + { + } + + /** + * 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 declaringClass; + } + + /** + * Gets the name of this field. + * @return the name of this field + */ + public native String getName(); + + /** + * Return the raw modifiers for this field. + * @return the field's modifiers + */ + private native int getModifiersInternal(); + + /** + * 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 + */ + public int getModifiers() + { + return getModifiersInternal() & FIELD_MODIFIERS; + } + + /** + * Return true if this field is synthetic, false otherwise. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this field represents an enum constant, + * false otherwise. + * @since 1.5 + */ + public boolean isEnumConstant() + { + return (getModifiersInternal() & Modifier.ENUM) != 0; + } + + /** + * Gets the type of this field. + * @return the type of this field + */ + public native Class<?> getType(); + + /** + * 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 + */ + public boolean equals (Object fld) + { + if (! (fld instanceof Field)) + return false; + Field f = (Field) fld; + return declaringClass == f.declaringClass && offset == f.offset; + } + + /** + * 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() + { + 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: + * <code>public transient boolean gnu.parse.Parser.parseComplete</code> + * + * @return the String representation of the Field + */ + public String toString () + { + StringBuffer sbuf = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, sbuf); + sbuf.append(' '); + } + Method.appendClassName (sbuf, getType ()); + sbuf.append(' '); + Method.appendClassName (sbuf, getDeclaringClass()); + sbuf.append('.'); + sbuf.append(getName()); + return sbuf.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> + * + * 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> + * + * 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> + * + * Finally, the field is accessed, and primitives are wrapped (but not + * necessarily in new objects). 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 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 <code>o</code> is not an instance of + * the class or interface 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 #getBoolean(Object) + * @see #getByte(Object) + * @see #getChar(Object) + * @see #getShort(Object) + * @see #getInt(Object) + * @see #getLong(Object) + * @see #getFloat(Object) + * @see #getDouble(Object) + */ + public Object get(Object obj) + throws IllegalAccessException + { + return get(null, obj); + } + + /** + * Get the value of this boolean Field. If the field is static, + * <code>o</code> will be ignored. + * + * @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 boolean 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 boolean getBoolean(Object obj) + throws IllegalAccessException + { + return getBoolean(null, obj); + } + + /** + * Get the value of this byte Field. If the field is static, + * <code>o</code> will be ignored. + * + * @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 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 byte getByte(Object obj) + throws IllegalAccessException + { + return getByte(null, obj); + } + + /** + * Get the value of this Field as a char. If the field is static, + * <code>o</code> will be ignored. + * + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a char 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 char getChar(Object obj) + throws IllegalAccessException + { + return getChar(null, obj); + } + + /** + * 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 + * @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 + * @see #get(Object) + */ + public short getShort(Object obj) + throws IllegalAccessException + { + return getShort(null, obj); + } + + /** + * 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 + * @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 + * @see #get(Object) + */ + public int getInt(Object obj) + throws IllegalAccessException + { + return getInt(null, obj); + } + + /** + * 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 + * @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 + * @see #get(Object) + */ + public long getLong(Object obj) + throws IllegalAccessException + { + return getLong(null, obj); + } + + /** + * 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 + * @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 + * @see #get(Object) + */ + public float getFloat(Object obj) + throws IllegalAccessException + { + return getFloat(null, obj); + } + + /** + * 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 + * @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 + * @see #get(Object) + */ + public double getDouble(Object obj) + throws IllegalAccessException + { + return getDouble(null, obj); + } + + private native boolean getBoolean (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native char getChar (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native byte getByte (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native short getShort (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native int getInt (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native long getLong (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native float getFloat (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native double getDouble (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native Object get (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + /** + * 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> + * + * 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 + * initialization, which may end in a + * <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 + * @see #setBoolean(Object, boolean) + * @see #setByte(Object, byte) + * @see #setChar(Object, char) + * @see #setShort(Object, short) + * @see #setInt(Object, int) + * @see #setLong(Object, long) + * @see #setFloat(Object, float) + * @see #setDouble(Object, double) + */ + public void set(Object object, Object value) + throws IllegalAccessException + { + set(null, object, value); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setBoolean(Object obj, boolean b) + throws IllegalAccessException + { + setBoolean(null, obj, b, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setByte(Object obj, byte b) + throws IllegalAccessException + { + setByte(null, obj, b, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setChar(Object obj, char c) + throws IllegalAccessException + { + setChar(null, obj, c, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setShort(Object obj, short s) + throws IllegalAccessException + { + setShort(null, obj, s, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setInt(Object obj, int i) + throws IllegalAccessException + { + setInt(null, obj, i, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setLong(Object obj, long l) + throws IllegalArgumentException, IllegalAccessException + { + setLong(null, obj, l, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setFloat(Object obj, float f) + throws IllegalAccessException + { + setFloat(null, obj, f, true); + } + + /** + * 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 + * @see #set(Object, Object) + */ + public void setDouble(Object obj, double d) + throws IllegalAccessException + { + setDouble(null, obj, d, true); + } + + /** + * 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(); + } + + public <T extends Annotation> T getAnnotation(Class<T> annoClass) + { + Annotation[] annos = getDeclaredAnnotations(); + for (int i = 0; i < annos.length; ++i) + if (annos[i].annotationType() == annoClass) + return (T) annos[i]; + return null; + } + + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + + /** + * Return the String in the Signature attribute for this field. If there + * is no Signature attribute, return null. + */ + private native String getSignature(); + + native void setByte (Class caller, Object obj, byte b, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setShort (Class caller, Object obj, short s, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setInt (Class caller, Object obj, int i, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setLong (Class caller, Object obj, long l, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setFloat (Class caller, Object obj, float f, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setDouble (Class caller, Object obj, double d, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setChar (Class caller, Object obj, char c, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setBoolean (Class caller, Object obj, boolean b, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void set (Class caller, Object obj, Object val, Class type, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + private void set (Class caller, Object object, Object value) + throws IllegalArgumentException, IllegalAccessException + { + Class type = getType(); + if (! type.isPrimitive()) + set(caller, object, value, type, true); + else if (value instanceof Byte) + setByte(caller, object, ((Byte) value).byteValue(), true); + else if (value instanceof Short) + setShort (caller, object, ((Short) value).shortValue(), true); + else if (value instanceof Integer) + setInt(caller, object, ((Integer) value).intValue(), true); + else if (value instanceof Long) + setLong(caller, object, ((Long) value).longValue(), true); + else if (value instanceof Float) + setFloat(caller, object, ((Float) value).floatValue(), true); + else if (value instanceof Double) + setDouble(caller, object, ((Double) value).doubleValue(), true); + else if (value instanceof Character) + setChar(caller, object, ((Character) value).charValue(), true); + else if (value instanceof Boolean) + setBoolean(caller, object, ((Boolean) value).booleanValue(), true); + else + throw new IllegalArgumentException(); + } +} diff --git a/libjava/java/lang/reflect/GenericArrayType.h b/libjava/java/lang/reflect/GenericArrayType.h new file mode 100644 index 000000000..cdeb0b2a3 --- /dev/null +++ b/libjava/java/lang/reflect/GenericArrayType.h @@ -0,0 +1,19 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_GenericArrayType__ +#define __java_lang_reflect_GenericArrayType__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::reflect::GenericArrayType : public ::java::lang::Object +{ + +public: + virtual ::java::lang::reflect::Type * getGenericComponentType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_GenericArrayType__ diff --git a/libjava/java/lang/reflect/GenericDeclaration.h b/libjava/java/lang/reflect/GenericDeclaration.h new file mode 100644 index 000000000..5c484ea96 --- /dev/null +++ b/libjava/java/lang/reflect/GenericDeclaration.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_GenericDeclaration__ +#define __java_lang_reflect_GenericDeclaration__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::GenericDeclaration : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::reflect::TypeVariable * > * getTypeParameters() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_GenericDeclaration__ diff --git a/libjava/java/lang/reflect/GenericSignatureFormatError.h b/libjava/java/lang/reflect/GenericSignatureFormatError.h new file mode 100644 index 000000000..c46c9264a --- /dev/null +++ b/libjava/java/lang/reflect/GenericSignatureFormatError.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_GenericSignatureFormatError__ +#define __java_lang_reflect_GenericSignatureFormatError__ + +#pragma interface + +#include <java/lang/ClassFormatError.h> + +class java::lang::reflect::GenericSignatureFormatError : public ::java::lang::ClassFormatError +{ + +public: + GenericSignatureFormatError(); +private: + static const jlong serialVersionUID = 6709919147137911034LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_GenericSignatureFormatError__ diff --git a/libjava/java/lang/reflect/InvocationHandler.h b/libjava/java/lang/reflect/InvocationHandler.h new file mode 100644 index 000000000..722195321 --- /dev/null +++ b/libjava/java/lang/reflect/InvocationHandler.h @@ -0,0 +1,21 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_InvocationHandler__ +#define __java_lang_reflect_InvocationHandler__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::InvocationHandler : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Object * invoke(::java::lang::Object *, ::java::lang::reflect::Method *, JArray< ::java::lang::Object * > *) = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_InvocationHandler__ diff --git a/libjava/java/lang/reflect/InvocationTargetException.h b/libjava/java/lang/reflect/InvocationTargetException.h new file mode 100644 index 000000000..37e229c29 --- /dev/null +++ b/libjava/java/lang/reflect/InvocationTargetException.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_InvocationTargetException__ +#define __java_lang_reflect_InvocationTargetException__ + +#pragma interface + +#include <java/lang/Exception.h> + +class java::lang::reflect::InvocationTargetException : public ::java::lang::Exception +{ + +public: // actually protected + InvocationTargetException(); +public: + InvocationTargetException(::java::lang::Throwable *); + InvocationTargetException(::java::lang::Throwable *, ::java::lang::String *); + virtual ::java::lang::Throwable * getTargetException(); + virtual ::java::lang::Throwable * getCause(); +private: + static const jlong serialVersionUID = 4085088731926701167LL; + ::java::lang::Throwable * __attribute__((aligned(__alignof__( ::java::lang::Exception)))) target; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_InvocationTargetException__ diff --git a/libjava/java/lang/reflect/MalformedParameterizedTypeException.h b/libjava/java/lang/reflect/MalformedParameterizedTypeException.h new file mode 100644 index 000000000..a48f669c0 --- /dev/null +++ b/libjava/java/lang/reflect/MalformedParameterizedTypeException.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_MalformedParameterizedTypeException__ +#define __java_lang_reflect_MalformedParameterizedTypeException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::reflect::MalformedParameterizedTypeException : public ::java::lang::RuntimeException +{ + +public: + MalformedParameterizedTypeException(); +private: + static const jlong serialVersionUID = -5696557788586220964LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_MalformedParameterizedTypeException__ diff --git a/libjava/java/lang/reflect/Member.h b/libjava/java/lang/reflect/Member.h new file mode 100644 index 000000000..9e3522be0 --- /dev/null +++ b/libjava/java/lang/reflect/Member.h @@ -0,0 +1,24 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Member__ +#define __java_lang_reflect_Member__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::reflect::Member : public ::java::lang::Object +{ + +public: + virtual ::java::lang::Class * getDeclaringClass() = 0; + virtual ::java::lang::String * getName() = 0; + virtual jint getModifiers() = 0; + virtual jboolean isSynthetic() = 0; + static const jint DECLARED = 1; + static const jint PUBLIC = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_Member__ diff --git a/libjava/java/lang/reflect/Method.h b/libjava/java/lang/reflect/Method.h new file mode 100644 index 000000000..8a843d5d1 --- /dev/null +++ b/libjava/java/lang/reflect/Method.h @@ -0,0 +1,84 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Method__ +#define __java_lang_reflect_Method__ + +#pragma interface + +#include <java/lang/reflect/AccessibleObject.h> +#include <gcj/array.h> + + +jmethodID _Jv_FromReflectedMethod (java::lang::reflect::Method *); +jobject _Jv_JNI_ToReflectedMethod (_Jv_JNIEnv *, jclass, jmethodID, jboolean); +::java::lang::reflect::Method *_Jv_GetReflectedMethod (jclass, _Jv_Utf8Const*, _Jv_Utf8Const*); + +class java::lang::reflect::Method : public ::java::lang::reflect::AccessibleObject +{ + + Method(); +public: + ::java::lang::Class * getDeclaringClass(); + ::java::lang::String * getName(); +private: + jint getModifiersInternal(); +public: + jint getModifiers(); + jboolean isBridge(); + jboolean isSynthetic(); + jboolean isVarArgs(); + ::java::lang::Class * getReturnType(); + JArray< ::java::lang::Class * > * getParameterTypes(); +public: // actually package-private + JArray< ::java::lang::Class * > * internalGetParameterTypes(); +public: + JArray< ::java::lang::Class * > * getExceptionTypes(); +public: // actually package-private + JArray< ::java::lang::Class * > * internalGetExceptionTypes(); +public: + jboolean equals(::java::lang::Object *); + jint hashCode(); + ::java::lang::String * toString(); + ::java::lang::String * toGenericString(); + ::java::lang::Object * invoke(::java::lang::Object *, JArray< ::java::lang::Object * > *); + JArray< ::java::lang::reflect::TypeVariable * > * getTypeParameters(); +private: + ::java::lang::String * getSignature(); +public: + JArray< ::java::lang::reflect::Type * > * getGenericExceptionTypes(); + JArray< ::java::lang::reflect::Type * > * getGenericParameterTypes(); + ::java::lang::reflect::Type * getGenericReturnType(); + ::java::lang::Object * getDefaultValue(); + ::java::lang::annotation::Annotation * getAnnotation(::java::lang::Class *); + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotations(); + JArray< JArray< ::java::lang::annotation::Annotation * > * > * getParameterAnnotations(); +private: + JArray< ::java::lang::annotation::Annotation * > * getDeclaredAnnotationsInternal(); + JArray< JArray< ::java::lang::annotation::Annotation * > * > * getParameterAnnotationsInternal(); + void getType(); +public: // actually package-private + static void appendClassName(::java::lang::StringBuffer *, ::java::lang::Class *); + static const jint METHOD_MODIFIERS = 3391; +private: + ::java::lang::Class * __attribute__((aligned(__alignof__( ::java::lang::reflect::AccessibleObject)))) declaringClass; +public: // actually package-private + JArray< ::java::lang::Class * > * exception_types; +private: + ::java::lang::String * name; +public: // actually package-private + JArray< ::java::lang::Class * > * parameter_types; + ::java::lang::Class * return_type; +private: + jint offset; +public: + static ::java::lang::Class class$; + + friend jmethodID (::_Jv_FromReflectedMethod) (java::lang::reflect::Method *); + friend jobject (::_Jv_JNI_ToReflectedMethod) (_Jv_JNIEnv *, jclass, jmethodID, jboolean); + friend class java::lang::Class; + friend class java::io::ObjectInputStream; + friend java::lang::reflect::Method* ::_Jv_GetReflectedMethod (jclass, _Jv_Utf8Const*, _Jv_Utf8Const*); +}; + +#endif // __java_lang_reflect_Method__ diff --git a/libjava/java/lang/reflect/Method.java b/libjava/java/lang/reflect/Method.java new file mode 100644 index 000000000..878210abb --- /dev/null +++ b/libjava/java/lang/reflect/Method.java @@ -0,0 +1,501 @@ +// Method.java - Represent method of class or interface. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2007 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang.reflect; + +import gnu.gcj.RawData; +import gnu.java.lang.reflect.MethodSignatureParser; +import java.lang.annotation.Annotation; + +/** + * The Method class represents a member method of a class. It also allows + * dynamic invocation, via reflection. This works for both static and + * instance methods. Invocation on Method objects knows how to do + * widening conversions, but throws {@link IllegalArgumentException} if + * a narrowing conversion would be necessary. You can query for information + * on this Method regardless of location, but invocation 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> + * + * 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 <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getMethod(String,Class[]) + * @see java.lang.Class#getDeclaredMethod(String,Class[]) + * @see java.lang.Class#getMethods() + * @see java.lang.Class#getDeclaredMethods() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Method + extends AccessibleObject implements Member, GenericDeclaration +{ + static final int METHOD_MODIFIERS + = Modifier.ABSTRACT | Modifier.FINAL | Modifier.NATIVE + | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC + | Modifier.STATIC | Modifier.STRICT | Modifier.SYNCHRONIZED; + + /** + * This class is uninstantiable. + */ + private Method () + { + } + + /** + * Gets the class that declared this method, or the class where this method + * is a non-inherited member. + * @return the class that declared this member + */ + public Class<?> getDeclaringClass() + { + return declaringClass; + } + + /** + * Gets the name of this method. + * @return the name of this method + */ + public native String getName (); + + /** + * Return the raw modifiers for this method. + * @return the method's modifiers + */ + private native int getModifiersInternal(); + + /** + * Gets the modifiers this method uses. Use the <code>Modifier</code> + * class to interpret the values. A method can only have a subset of the + * following modifiers: public, private, protected, abstract, static, + * final, synchronized, native, and strictfp. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public int getModifiers() + { + return getModifiersInternal() & METHOD_MODIFIERS; + } + + /** + * Return true if this method is a bridge method. A bridge method + * is generated by the compiler in some situations involving + * generics and inheritance. + * @since 1.5 + */ + public boolean isBridge() + { + return (getModifiersInternal() & Modifier.BRIDGE) != 0; + } + + /** + * Return true if this method is synthetic, false otherwise. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this is a varargs method, that is if + * the method takes a variable number of arguments. + * @since 1.5 + */ + public boolean isVarArgs() + { + return (getModifiersInternal() & Modifier.VARARGS) != 0; + } + + /** + * Gets the return type of this method. + * @return the type of this method + */ + public Class<?> getReturnType () + { + if (return_type == null) + getType(); + return return_type; + } + + /** + * Get the parameter list for this method, in declaration order. If the + * method takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the method's parameters + */ + public Class<?>[] getParameterTypes () + { + if (parameter_types == null) + getType(); + return (Class<?>[]) parameter_types.clone(); + } + + // Just like getParameterTypes, but don't clone the array. + // Package private for use by VMProxy. + final Class<?>[] internalGetParameterTypes () + { + if (parameter_types == null) + getType(); + return (Class<?>[]) parameter_types; + } + + /** + * Get the exception types this method says it throws, in no particular + * order. If the method has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the method's throws clause + */ + public Class<?>[] getExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class<?>[]) exception_types.clone(); + } + + // Just like getExceptionTypes, but don't clone the array. + // Package private for use by VMProxy. + final Class<?>[] internalGetExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class<?>[]) exception_types; + } + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Methods are semantically equivalent if they have the same declaring + * class, name, and parameter list. This ignores different exception + * clauses or return types. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Method)) + return false; + Method m = (Method) obj; + return declaringClass == m.declaringClass && offset == m.offset; + } + + /** + * Get the hash code for the Method. The Method 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() + { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); + } + + /** + * Get a String representation of the Method. A Method's String + * representation is "<modifiers> <returntype> + * <methodname>(<paramtypes>) throws <exceptions>", where + * everything after ')' is omitted if there are no exceptions.<br> Example: + * <code>public static int run(java.lang.Runnable,int)</code> + * + * @return the String representation of the Method + */ + public String toString() + { + if (parameter_types == null) + getType (); + + StringBuffer b = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, b); + b.append(" "); + } + appendClassName (b, return_type); + b.append(" "); + appendClassName (b, declaringClass); + b.append("."); + b.append(getName()); + b.append("("); + for (int i = 0; i < parameter_types.length; ++i) + { + appendClassName (b, parameter_types[i]); + if (i < parameter_types.length - 1) + b.append(","); + } + b.append(")"); + if (exception_types.length > 0) + { + b.append(" throws "); + for (int i = 0; i < exception_types.length; ++i) + { + appendClassName (b, exception_types[i]); + if (i < exception_types.length - 1) + b.append(","); + } + } + return b.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> + * + * If the method is static, <code>o</code> will be ignored. Otherwise, + * the method uses dynamic lookup as described in JLS 15.12.4.4. You cannot + * mimic the behavior of nonvirtual lookup (as in super.foo()). This means + * you will get a <code>NullPointerException</code> if <code>o</code> is + * null, and an <code>IllegalArgumentException</code> if it is incompatible + * with the declaring class of the method. If the method takes 0 arguments, + * you may use null or a 0-length array for <code>args</code>.<p> + * + * Next, if this Method enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not acces this method in similar compiled code. If the method + * is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Finally, the method is invoked. If it completes normally, the return value + * will be null for a void method, a wrapped object for a primitive return + * method, or the actual return of an Object method. If it completes + * abruptly, the exception is wrapped in an + * <code>InvocationTargetException</code>. + * + * @param o the object to invoke the method on + * @param args the arguments to the method + * @return the return value of the method, wrapped in the appropriate + * wrapper if it is primitive + * @throws IllegalAccessException if the method could not normally be called + * by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * if the arguments types are wrong even with a widening conversion; + * or if <code>o</code> is not an instance of the class or interface + * declaring this method + * @throws InvocationTargetException if the method throws an exception + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static method triggered + * class initialization, which then failed + */ + public native Object invoke (Object obj, Object... args) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException; + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this constructor, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public TypeVariable<Method>[] getTypeParameters() + { + String sig = getSignature(); + if (sig == null) + return new TypeVariable[0]; + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Return the String in the Signature attribute for this method. If there + * is no Signature attribute, return null. + */ + private native String getSignature(); + + /** + * Returns an array of <code>Type</code> objects that represents + * the exception types declared by this method, in declaration order. + * An array of size zero is returned if this method declares no + * exceptions. + * + * @return the exception types declared by this method. + * @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[] getGenericExceptionTypes() + { + String sig = getSignature(); + if (sig == null) + return getExceptionTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericExceptionTypes(); + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the parameter list for this method, in declaration order. + * An array of size zero is returned if this method takes no + * parameters. + * + * @return a list of the types of the method's parameters + * @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[] getGenericParameterTypes() + { + String sig = getSignature(); + if (sig == null) + return getParameterTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericParameterTypes(); + } + + /** + * Returns the return type of this method. + * + * @return the return type of this method + * @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 getGenericReturnType() + { + String sig = getSignature(); + if (sig == null) + return getReturnType(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericReturnType(); + } + + /** + * If this method is an annotation method, returns the default + * value for the method. If there is no default value, or if the + * method is not a member of an annotation type, returns null. + * Primitive types are wrapped. + * + * @throws TypeNotPresentException if the method returns a Class, + * and the class cannot be found + * + * @since 1.5 + */ + public native Object getDefaultValue(); + + public <T extends Annotation> T getAnnotation(Class<T> annoClass) + { + Annotation[] annos = getDeclaredAnnotations(); + for (int i = 0; i < annos.length; ++i) + if (annos[i].annotationType() == annoClass) + return (T) annos[i]; + return null; + } + + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + public Annotation[][] getParameterAnnotations() + { + // FIXME: should check that we have the right number + // of parameters ...? + Annotation[][] result = getParameterAnnotationsInternal(); + if (result == null) + result = new Annotation[0][0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + private native Annotation[][] getParameterAnnotationsInternal(); + + private native void getType (); + + // Append a class name to a string buffer. We try to print the + // fully-qualified name, the way that a Java programmer would expect + // it to be written. Weirdly, Class has no appropriate method for + // this. + static void appendClassName (StringBuffer buf, Class k) + { + if (k.isArray ()) + { + appendClassName (buf, k.getComponentType ()); + buf.append ("[]"); + } + else + { + // This is correct for primitive and reference types. Really + // we'd like `Main$Inner' to be printed as `Main.Inner', I + // think, but that is a pain. + buf.append (k.getName ()); + } + } + + // Declaring class. + private Class declaringClass; + + // Exception types. + Class[] exception_types; + // Name cache. (Initially null.) + private String name; + // Parameter types. + Class[] parameter_types; + // Return type. + Class return_type; + + // Offset in bytes from the start of declaringClass's methods array. + private int offset; +} diff --git a/libjava/java/lang/reflect/Modifier.h b/libjava/java/lang/reflect/Modifier.h new file mode 100644 index 000000000..4ee474a95 --- /dev/null +++ b/libjava/java/lang/reflect/Modifier.h @@ -0,0 +1,58 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Modifier__ +#define __java_lang_reflect_Modifier__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::reflect::Modifier : public ::java::lang::Object +{ + +public: + Modifier(); + static jboolean isAbstract(jint); + static jboolean isFinal(jint); + static jboolean isInterface(jint); + static jboolean isNative(jint); + static jboolean isPrivate(jint); + static jboolean isProtected(jint); + static jboolean isPublic(jint); + static jboolean isStatic(jint); + static jboolean isStrict(jint); + static jboolean isSynchronized(jint); + static jboolean isTransient(jint); + static jboolean isVolatile(jint); + static ::java::lang::String * toString(jint); +public: // actually package-private + static ::java::lang::StringBuilder * toString(jint, ::java::lang::StringBuilder *); + static ::java::lang::StringBuffer * toString(jint, ::java::lang::StringBuffer *); +public: + static const jint PUBLIC = 1; + static const jint PRIVATE = 2; + static const jint PROTECTED = 4; + static const jint STATIC = 8; + static const jint FINAL = 16; + static const jint SYNCHRONIZED = 32; + static const jint VOLATILE = 64; + static const jint TRANSIENT = 128; + static const jint NATIVE = 256; + static const jint INTERFACE = 512; + static const jint ABSTRACT = 1024; + static const jint STRICT = 2048; +public: // actually package-private + static const jint SUPER = 32; + static const jint ALL_FLAGS = 4095; + static const jint BRIDGE = 64; + static const jint VARARGS = 128; + static const jint SYNTHETIC = 4096; + static const jint ENUM = 16384; + static const jint INVISIBLE = 32768; + static const jint INTERPRETED = 4096; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Modifier__ diff --git a/libjava/java/lang/reflect/Modifier.java b/libjava/java/lang/reflect/Modifier.java new file mode 100644 index 000000000..f9a9ca2c9 --- /dev/null +++ b/libjava/java/lang/reflect/Modifier.java @@ -0,0 +1,375 @@ +/* java.lang.reflect.Modifier + Copyright (C) 1998, 1999, 2001, 2002, 2005, 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 java.lang.reflect; + +/** + * Modifier is a helper class with static methods to determine whether an + * int returned from getModifiers() represents static, public, protected, + * native, final, etc... and provides an additional method to print + * out all of the modifiers in an int in order. + * <p> + * The methods in this class use the bitmask values in the VM spec to + * determine the modifiers of an int. This means that a VM must return a + * standard mask, conformant with the VM spec. I don't know if this is how + * Sun does it, but I'm willing to bet money that it is. + * + * @author John Keiser + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Member#getModifiers() + * @see Method#getModifiers() + * @see Field#getModifiers() + * @see Constructor#getModifiers() + * @see Class#getModifiers() + * @since 1.1 + */ +public class Modifier +{ + /** <STRONG>This constructor really shouldn't be here ... there are no + * instance methods or variables of this class, so instantiation is + * worthless. However, this function is in the 1.1 spec, so it is added + * for completeness.</STRONG> + */ + public Modifier() + { + } + + /** + * Public: accessible from any other class. + */ + public static final int PUBLIC = 0x0001; + + /** + * Private: accessible only from the same enclosing class. + */ + public static final int PRIVATE = 0x0002; + + /** + * Protected: accessible only to subclasses, or within the package. + */ + public static final int PROTECTED = 0x0004; + + /** + * Static:<br><ul> + * <li>Class: no enclosing instance for nested class.</li> + * <li>Field or Method: can be accessed or invoked without an + * instance of the declaring class.</li> + * </ul> + */ + public static final int STATIC = 0x0008; + + /** + * Final:<br><ul> + * <li>Class: no subclasses allowed.</li> + * <li>Field: cannot be changed.</li> + * <li>Method: cannot be overriden.</li> + * </ul> + */ + public static final int FINAL = 0x0010; + + /** + * Synchronized: Method: lock the class while calling this method. + */ + public static final int SYNCHRONIZED = 0x0020; + + /** + * Volatile: Field: cannot be cached. + */ + public static final int VOLATILE = 0x0040; + + /** + * Transient: Field: not serialized or deserialized. + */ + public static final int TRANSIENT = 0x0080; + + /** + * Native: Method: use JNI to call this method. + */ + public static final int NATIVE = 0x0100; + + /** + * Interface: Class: is an interface. + */ + public static final int INTERFACE = 0x0200; + + /** + * Abstract:<br><ul> + * <li>Class: may not be instantiated.</li> + * <li>Method: may not be called.</li> + * </ul> + */ + public static final int ABSTRACT = 0x0400; + + /** + * Strictfp: Method: expressions are FP-strict.<p> + * Also used as a modifier for classes, to mean that all initializers + * and constructors are FP-strict, but does not show up in + * Class.getModifiers. + */ + public static final int STRICT = 0x0800; + + + /** + * Super - treat invokespecial as polymorphic so that super.foo() works + * according to the JLS. This is a reuse of the synchronized constant + * to patch a hole in JDK 1.0. *shudder*. + */ + static final int SUPER = 0x0020; + + /** + * All the flags, only used by code in this package. + */ + static final int ALL_FLAGS = 0xfff; + + /** + * Flag indicating a bridge method. + */ + static final int BRIDGE = 0x40; + + /** + * Flag indicating a varargs method. + */ + static final int VARARGS = 0x80; + + /** + * Flag indicating a synthetic member. + */ + static final int SYNTHETIC = 0x1000; + + /** + * Flag indicating an enum constant or an enum class. + */ + static final int ENUM = 0x4000; + + /** + * GCJ-LOCAL: This access flag is set on methods we declare + * internally but which must not be visible to reflection. + */ + static final int INVISIBLE = 0x8000; + + /** + * GCJ-LOCAL: This access flag is set on interpreted classes. + */ + static final int INTERPRETED = 0x1000; + + /** + * Check whether the given modifier is abstract. + * @param mod the modifier. + * @return <code>true</code> if abstract, <code>false</code> otherwise. + */ + public static boolean isAbstract(int mod) + { + return (mod & ABSTRACT) != 0; + } + + /** + * Check whether the given modifier is final. + * @param mod the modifier. + * @return <code>true</code> if final, <code>false</code> otherwise. + */ + public static boolean isFinal(int mod) + { + return (mod & FINAL) != 0; + } + + /** + * Check whether the given modifier is an interface. + * @param mod the modifier. + * @return <code>true</code> if an interface, <code>false</code> otherwise. + */ + public static boolean isInterface(int mod) + { + return (mod & INTERFACE) != 0; + } + + /** + * Check whether the given modifier is native. + * @param mod the modifier. + * @return <code>true</code> if native, <code>false</code> otherwise. + */ + public static boolean isNative(int mod) + { + return (mod & NATIVE) != 0; + } + + /** + * Check whether the given modifier is private. + * @param mod the modifier. + * @return <code>true</code> if private, <code>false</code> otherwise. + */ + public static boolean isPrivate(int mod) + { + return (mod & PRIVATE) != 0; + } + + /** + * Check whether the given modifier is protected. + * @param mod the modifier. + * @return <code>true</code> if protected, <code>false</code> otherwise. + */ + public static boolean isProtected(int mod) + { + return (mod & PROTECTED) != 0; + } + + /** + * Check whether the given modifier is public. + * @param mod the modifier. + * @return <code>true</code> if public, <code>false</code> otherwise. + */ + public static boolean isPublic(int mod) + { + return (mod & PUBLIC) != 0; + } + + /** + * Check whether the given modifier is static. + * @param mod the modifier. + * @return <code>true</code> if static, <code>false</code> otherwise. + */ + public static boolean isStatic(int mod) + { + return (mod & STATIC) != 0; + } + + /** + * Check whether the given modifier is strictfp. + * @param mod the modifier. + * @return <code>true</code> if strictfp, <code>false</code> otherwise. + */ + public static boolean isStrict(int mod) + { + return (mod & STRICT) != 0; + } + + /** + * Check whether the given modifier is synchronized. + * @param mod the modifier. + * @return <code>true</code> if synchronized, <code>false</code> otherwise. + */ + public static boolean isSynchronized(int mod) + { + return (mod & SYNCHRONIZED) != 0; + } + + /** + * Check whether the given modifier is transient. + * @param mod the modifier. + * @return <code>true</code> if transient, <code>false</code> otherwise. + */ + public static boolean isTransient(int mod) + { + return (mod & TRANSIENT) != 0; + } + + /** + * Check whether the given modifier is volatile. + * @param mod the modifier. + * @return <code>true</code> if volatile, <code>false</code> otherwise. + */ + public static boolean isVolatile(int mod) + { + return (mod & VOLATILE) != 0; + } + + /** + * Get a string representation of all the modifiers represented by the + * given int. The keywords are printed in this order: + * <code><public|protected|private> abstract static final transient + * volatile synchronized native strictfp interface</code>. + * + * @param mod the modifier. + * @return the String representing the modifiers. + */ + public static String toString(int mod) + { + return toString(mod, new StringBuffer()).toString(); + } + + /** + * Package helper method that can take a StringBuilder. + * @param mod the modifier + * @param r the StringBuilder to which the String representation is appended + * @return r, with information appended + */ + static StringBuilder toString(int mod, StringBuilder r) + { + r.append(toString(mod, new StringBuffer())); + return r; + } + + /** + * Package helper method that can take a StringBuffer. + * @param mod the modifier + * @param r the StringBuffer to which the String representation is appended + * @return r, with information appended + */ + static StringBuffer toString(int mod, StringBuffer r) + { + if (isPublic(mod)) + r.append("public "); + if (isProtected(mod)) + r.append("protected "); + if (isPrivate(mod)) + r.append("private "); + if (isAbstract(mod)) + r.append("abstract "); + if (isStatic(mod)) + r.append("static "); + if (isFinal(mod)) + r.append("final "); + if (isTransient(mod)) + r.append("transient "); + if (isVolatile(mod)) + r.append("volatile "); + if (isSynchronized(mod)) + r.append("synchronized "); + if (isNative(mod)) + r.append("native "); + if (isStrict(mod)) + r.append("strictfp "); + if (isInterface(mod)) + r.append("interface "); + + // Trim trailing space. + if ((mod & ALL_FLAGS) != 0) + r.setLength(r.length() - 1); + return r; + } +} diff --git a/libjava/java/lang/reflect/ParameterizedType.h b/libjava/java/lang/reflect/ParameterizedType.h new file mode 100644 index 000000000..dab9ad953 --- /dev/null +++ b/libjava/java/lang/reflect/ParameterizedType.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_ParameterizedType__ +#define __java_lang_reflect_ParameterizedType__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::ParameterizedType : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::reflect::Type * > * getActualTypeArguments() = 0; + virtual ::java::lang::reflect::Type * getOwnerType() = 0; + virtual ::java::lang::reflect::Type * getRawType() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_ParameterizedType__ diff --git a/libjava/java/lang/reflect/Proxy$ClassFactory.h b/libjava/java/lang/reflect/Proxy$ClassFactory.h new file mode 100644 index 000000000..c4cfb883d --- /dev/null +++ b/libjava/java/lang/reflect/Proxy$ClassFactory.h @@ -0,0 +1,78 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Proxy$ClassFactory__ +#define __java_lang_reflect_Proxy$ClassFactory__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::Proxy$ClassFactory : public ::java::lang::Object +{ + +public: // actually package-private + Proxy$ClassFactory(::java::lang::reflect::Proxy$ProxyData *); +private: + void emitMethod(jint, JArray< ::java::lang::Class * > *); +public: // actually package-private + ::java::lang::Class * generate(::java::lang::ClassLoader *); +private: + void putU1(jint); + void putU2(jint); + void putU4(jint); + void putConst(jint); + void putLoad(jint, ::java::lang::Class *); + ::java::lang::String * wrapper(::java::lang::Class *); + jchar utf8Info(::java::lang::String *); + jchar classInfo(::java::lang::String *); + jchar classInfo(::java::lang::Class *); + jchar refInfo(jbyte, ::java::lang::String *, ::java::lang::String *, ::java::lang::String *); + jchar nameAndTypeInfo(::java::lang::String *, ::java::lang::String *); + ::java::lang::String * toUtf8(::java::lang::String *); + jchar poolIndex(::java::lang::String *); + static const jbyte FIELD = 1; + static const jbyte METHOD = 2; + static const jbyte INTERFACE = 3; + static ::java::lang::String * CTOR_SIG; + static ::java::lang::String * INVOKE_SIG; + static const jchar ACONST_NULL = 1; + static const jchar ICONST_0 = 3; + static const jchar BIPUSH = 16; + static const jchar SIPUSH = 17; + static const jchar ILOAD = 21; + static const jchar ILOAD_0 = 26; + static const jchar ALOAD_0 = 42; + static const jchar ALOAD_1 = 43; + static const jchar AALOAD = 50; + static const jchar AASTORE = 83; + static const jchar DUP = 89; + static const jchar DUP_X1 = 90; + static const jchar SWAP = 95; + static const jchar IRETURN = 172; + static const jchar LRETURN = 173; + static const jchar FRETURN = 174; + static const jchar DRETURN = 175; + static const jchar ARETURN = 176; + static const jchar RETURN = 177; + static const jchar GETSTATIC = 178; + static const jchar GETFIELD = 180; + static const jchar INVOKEVIRTUAL = 182; + static const jchar INVOKESPECIAL = 183; + static const jchar INVOKEINTERFACE = 185; + static const jchar NEW = 187; + static const jchar ANEWARRAY = 189; + static const jchar ATHROW = 191; + static const jchar CHECKCAST = 192; + ::java::lang::StringBuffer * __attribute__((aligned(__alignof__( ::java::lang::Object)))) pool; + ::java::lang::StringBuffer * stream; + ::java::util::Map * poolEntries; + ::java::lang::String * qualName; + JArray< ::java::lang::reflect::Method * > * methods; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Proxy$ClassFactory__ diff --git a/libjava/java/lang/reflect/Proxy$ProxyData.h b/libjava/java/lang/reflect/Proxy$ProxyData.h new file mode 100644 index 000000000..2c0d91e5e --- /dev/null +++ b/libjava/java/lang/reflect/Proxy$ProxyData.h @@ -0,0 +1,37 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Proxy$ProxyData__ +#define __java_lang_reflect_Proxy$ProxyData__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::Proxy$ProxyData : public ::java::lang::Object +{ + +public: // actually package-private + Proxy$ProxyData(); +private: + static ::java::lang::String * getPackage(::java::lang::Class *); +public: // actually package-private + static ::java::lang::reflect::Proxy$ProxyData * getProxyData(::java::lang::reflect::Proxy$ProxyType *); +private: + static jboolean isCoreObjectMethod(::java::lang::reflect::Method *); +public: // actually package-private + ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) pack; + JArray< ::java::lang::Class * > * interfaces; + JArray< ::java::lang::reflect::Method * > * methods; + JArray< JArray< ::java::lang::Class * > * > * exceptions; +private: + static jint count; +public: // actually package-private + jint id; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Proxy$ProxyData__ diff --git a/libjava/java/lang/reflect/Proxy$ProxySignature.h b/libjava/java/lang/reflect/Proxy$ProxySignature.h new file mode 100644 index 000000000..ae0f028de --- /dev/null +++ b/libjava/java/lang/reflect/Proxy$ProxySignature.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Proxy$ProxySignature__ +#define __java_lang_reflect_Proxy$ProxySignature__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::reflect::Proxy$ProxySignature : public ::java::lang::Object +{ + +public: // actually package-private + Proxy$ProxySignature(::java::lang::reflect::Method *); + void checkCompatibility(::java::lang::reflect::Proxy$ProxySignature *); +public: + jint hashCode(); + jboolean equals(::java::lang::Object *); +public: // actually package-private + static ::java::util::HashMap * coreMethods; + ::java::lang::reflect::Method * __attribute__((aligned(__alignof__( ::java::lang::Object)))) method; + ::java::util::Set * exceptions; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Proxy$ProxySignature__ diff --git a/libjava/java/lang/reflect/Proxy$ProxyType.h b/libjava/java/lang/reflect/Proxy$ProxyType.h new file mode 100644 index 000000000..da7653539 --- /dev/null +++ b/libjava/java/lang/reflect/Proxy$ProxyType.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Proxy$ProxyType__ +#define __java_lang_reflect_Proxy$ProxyType__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::Proxy$ProxyType : public ::java::lang::Object +{ + +public: // actually package-private + Proxy$ProxyType(::java::lang::ClassLoader *, JArray< ::java::lang::Class * > *); +public: + jint hashCode(); + jboolean equals(::java::lang::Object *); +public: // actually package-private + ::java::lang::ClassLoader * __attribute__((aligned(__alignof__( ::java::lang::Object)))) loader; + JArray< ::java::lang::Class * > * interfaces; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Proxy$ProxyType__ diff --git a/libjava/java/lang/reflect/Proxy.h b/libjava/java/lang/reflect/Proxy.h new file mode 100644 index 000000000..4dad2cffd --- /dev/null +++ b/libjava/java/lang/reflect/Proxy.h @@ -0,0 +1,32 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Proxy__ +#define __java_lang_reflect_Proxy__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::Proxy : public ::java::lang::Object +{ + +public: // actually protected + Proxy(::java::lang::reflect::InvocationHandler *); +public: + static ::java::lang::Class * getProxyClass(::java::lang::ClassLoader *, JArray< ::java::lang::Class * > *); + static ::java::lang::Object * newProxyInstance(::java::lang::ClassLoader *, JArray< ::java::lang::Class * > *, ::java::lang::reflect::InvocationHandler *); + static jboolean isProxyClass(::java::lang::Class *); + static ::java::lang::reflect::InvocationHandler * getInvocationHandler(::java::lang::Object *); +private: + static const jlong serialVersionUID = -2222568056686623797LL; + static ::java::util::Map * proxyClasses; +public: // actually protected + ::java::lang::reflect::InvocationHandler * __attribute__((aligned(__alignof__( ::java::lang::Object)))) h; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_Proxy__ diff --git a/libjava/java/lang/reflect/ReflectPermission.h b/libjava/java/lang/reflect/ReflectPermission.h new file mode 100644 index 000000000..0e6a7c32e --- /dev/null +++ b/libjava/java/lang/reflect/ReflectPermission.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_ReflectPermission__ +#define __java_lang_reflect_ReflectPermission__ + +#pragma interface + +#include <java/security/BasicPermission.h> + +class java::lang::reflect::ReflectPermission : public ::java::security::BasicPermission +{ + +public: + ReflectPermission(::java::lang::String *); + ReflectPermission(::java::lang::String *, ::java::lang::String *); +private: + static const jlong serialVersionUID = 7412737110241507485LL; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_ReflectPermission__ diff --git a/libjava/java/lang/reflect/Type.h b/libjava/java/lang/reflect/Type.h new file mode 100644 index 000000000..55c317fa4 --- /dev/null +++ b/libjava/java/lang/reflect/Type.h @@ -0,0 +1,18 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_Type__ +#define __java_lang_reflect_Type__ + +#pragma interface + +#include <java/lang/Object.h> + +class java::lang::reflect::Type : public ::java::lang::Object +{ + +public: + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_Type__ diff --git a/libjava/java/lang/reflect/TypeVariable.h b/libjava/java/lang/reflect/TypeVariable.h new file mode 100644 index 000000000..6029c0190 --- /dev/null +++ b/libjava/java/lang/reflect/TypeVariable.h @@ -0,0 +1,23 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_TypeVariable__ +#define __java_lang_reflect_TypeVariable__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::TypeVariable : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::reflect::Type * > * getBounds() = 0; + virtual ::java::lang::reflect::GenericDeclaration * getGenericDeclaration() = 0; + virtual ::java::lang::String * getName() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_TypeVariable__ diff --git a/libjava/java/lang/reflect/UndeclaredThrowableException.h b/libjava/java/lang/reflect/UndeclaredThrowableException.h new file mode 100644 index 000000000..01b969b0e --- /dev/null +++ b/libjava/java/lang/reflect/UndeclaredThrowableException.h @@ -0,0 +1,26 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_UndeclaredThrowableException__ +#define __java_lang_reflect_UndeclaredThrowableException__ + +#pragma interface + +#include <java/lang/RuntimeException.h> + +class java::lang::reflect::UndeclaredThrowableException : public ::java::lang::RuntimeException +{ + +public: + UndeclaredThrowableException(::java::lang::Throwable *); + UndeclaredThrowableException(::java::lang::Throwable *, ::java::lang::String *); + virtual ::java::lang::Throwable * getUndeclaredThrowable(); + virtual ::java::lang::Throwable * getCause(); +private: + static const jlong serialVersionUID = 330127114055056639LL; + ::java::lang::Throwable * __attribute__((aligned(__alignof__( ::java::lang::RuntimeException)))) undeclaredThrowable; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_UndeclaredThrowableException__ diff --git a/libjava/java/lang/reflect/VMProxy.h b/libjava/java/lang/reflect/VMProxy.h new file mode 100644 index 000000000..e48e8e4e8 --- /dev/null +++ b/libjava/java/lang/reflect/VMProxy.h @@ -0,0 +1,28 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_VMProxy__ +#define __java_lang_reflect_VMProxy__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::VMProxy : public ::java::lang::Object +{ + +public: // actually package-private + VMProxy(); + static ::java::lang::Class * getProxyClass(::java::lang::ClassLoader *, JArray< ::java::lang::Class * > *); + static ::java::lang::reflect::Proxy$ProxyData * getProxyData(::java::lang::ClassLoader *, JArray< ::java::lang::Class * > *); + static ::java::lang::Class * generateProxyClass(::java::lang::ClassLoader *, ::java::lang::reflect::Proxy$ProxyData *); + static jboolean HAVE_NATIVE_GET_PROXY_CLASS; + static jboolean HAVE_NATIVE_GET_PROXY_DATA; + static jboolean HAVE_NATIVE_GENERATE_PROXY_CLASS; +public: + static ::java::lang::Class class$; +}; + +#endif // __java_lang_reflect_VMProxy__ diff --git a/libjava/java/lang/reflect/VMProxy.java b/libjava/java/lang/reflect/VMProxy.java new file mode 100644 index 000000000..ea1c88506 --- /dev/null +++ b/libjava/java/lang/reflect/VMProxy.java @@ -0,0 +1,140 @@ +/* VMProxy.java -- VM interface for proxy class + Copyright (C) 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; + +final class VMProxy +{ + /** + * Set to true if the VM provides a native method to implement + * Proxy.getProxyClass completely, including argument verification. + * If this is true, HAVE_NATIVE_GET_PROXY_DATA and + * HAVE_NATIVE_GENERATE_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GET_PROXY_CLASS = false; + + /** + * Set to true if the VM provides a native method to implement + * the first part of Proxy.getProxyClass: generation of the array + * of methods to convert, and verification of the arguments. + * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GET_PROXY_DATA = false; + + /** + * Set to true if the VM provides a native method to implement + * the second part of Proxy.getProxyClass: conversion of an array of + * methods into an actual proxy class. + * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = true; + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyClass. Only needed if + * VMProxy.HAVE_NATIVE_GET_PROXY_CLASS is true, this does the + * work of both getProxyData and generateProxyClass with no + * intermediate form in Java. The native code may safely assume that + * this class must be created, and does not already exist. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return the generated proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration#HAVE_NATIVE_GET_PROXY_CLASS + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyData(ClassLoader, Class[]) + * @see #generateProxyClass(ProxyData) + */ + static Class getProxyClass(ClassLoader loader, Class[] interfaces) + { + return null; + } + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyData. Only needed if + * Configuration.HAVE_NATIVE_GET_PROXY_DATA is true. The native code + * may safely assume that a new ProxyData object must be created which + * does not duplicate any existing ones. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return all data that is required to make this proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration.HAVE_NATIVE_GET_PROXY_DATA + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass(ClassLoader, Class[]) + * @see ProxyType#getProxyData() + */ + static Proxy.ProxyData getProxyData(ClassLoader loader, Class[] interfaces) + { + return null; + } + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of generateProxyClass. Only needed if + * Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS is true. The native + * code may safely assume that a new Class must be created, and that + * the ProxyData object does not describe any existing class. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param data the struct of information to convert to a Class. This + * has already been verified for all problems except exceeding + * VM limitations + * @return the newly generated class + * @throws IllegalArgumentException if VM limitations are exceeded + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass(ClassLoader, Class[]) + * @see ProxyData#generateProxyClass(ClassLoader) + */ + static native Class generateProxyClass(ClassLoader loader, Proxy.ProxyData data); +} diff --git a/libjava/java/lang/reflect/WildcardType.h b/libjava/java/lang/reflect/WildcardType.h new file mode 100644 index 000000000..2c5b93d65 --- /dev/null +++ b/libjava/java/lang/reflect/WildcardType.h @@ -0,0 +1,22 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __java_lang_reflect_WildcardType__ +#define __java_lang_reflect_WildcardType__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + + +class java::lang::reflect::WildcardType : public ::java::lang::Object +{ + +public: + virtual JArray< ::java::lang::reflect::Type * > * getLowerBounds() = 0; + virtual JArray< ::java::lang::reflect::Type * > * getUpperBounds() = 0; + static ::java::lang::Class class$; +} __attribute__ ((java_interface)); + +#endif // __java_lang_reflect_WildcardType__ diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc new file mode 100644 index 000000000..b7bc8beff --- /dev/null +++ b/libjava/java/lang/reflect/natArray.cc @@ -0,0 +1,360 @@ +// natField.cc - Implementation of java.lang.reflect.Field native methods. + +/* Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <jvm.h> +#include <gcj/cni.h> +#include <java-stack.h> +#include <java/lang/reflect/Array.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> + +jobject +java::lang::reflect::Array::newInstance (jclass componentType, jint length) +{ + if (componentType->isPrimitive()) + { + // We could check for this in _Jv_NewPrimArray, but that seems + // like needless overhead when the only real route to this + // problem is here. + if (componentType == JvPrimClass (void)) + throw new java::lang::IllegalArgumentException (); + return _Jv_NewPrimArray (componentType, length); + } + else + // FIXME: class loader? + return JvNewObjectArray (length, componentType, NULL); +} + +jobject +java::lang::reflect::Array::newInstance (jclass componentType, + jintArray dimensions) +{ + jint ndims = dimensions->length; + if (ndims == 0) + throw new java::lang::IllegalArgumentException (); + jint* dims = elements (dimensions); + if (ndims == 1) + return newInstance (componentType, dims[0]); + + Class *caller = _Jv_StackTrace::GetCallingClass (&Array::class$); + ClassLoader *caller_loader = NULL; + if (caller) + caller_loader = caller->getClassLoaderInternal(); + + jclass arrayType = componentType; + for (int i = 0; i < ndims; i++) + arrayType = _Jv_GetArrayClass (arrayType, caller_loader); + + return _Jv_NewMultiArray (arrayType, ndims, dims); +} + +jint +java::lang::reflect::Array::getLength (jobject array) +{ + jclass arrayType = array->getClass(); + if (! arrayType->isArray ()) + throw new java::lang::IllegalArgumentException; + return ((__JArray*) array)->length; +} + +jclass +java::lang::reflect::Array::getElementType (jobject array, jint index) +{ + jclass arrayType = array->getClass(); + if (! arrayType->isArray ()) + throw new java::lang::IllegalArgumentException; + jint length = ((__JArray*) array)->length; + if ((_Jv_uint) index >= (_Jv_uint) length) + _Jv_ThrowBadArrayIndex(index); + return arrayType->getComponentType (); +} + +jboolean +java::lang::reflect::Array::getBoolean (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (boolean)) + return elements ((jbooleanArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jchar +java::lang::reflect::Array::getChar (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jbyte +java::lang::reflect::Array::getByte (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jshort +java::lang::reflect::Array::getShort (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jint +java::lang::reflect::Array::getInt (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jlong +java::lang::reflect::Array::getLong (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jfloat +java::lang::reflect::Array::getFloat (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (float)) + return elements ((jfloatArray) array) [index]; + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jdouble +java::lang::reflect::Array::getDouble (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (double)) + return elements ((jdoubleArray) array) [index]; + if (elementType == JvPrimClass (float)) + return elements ((jfloatArray) array) [index]; + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jobject +java::lang::reflect::Array::get (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (! elementType->isPrimitive ()) + return elements ((jobjectArray) array) [index]; + if (elementType == JvPrimClass (double)) + return new java::lang::Double (elements ((jdoubleArray) array) [index]); + if (elementType == JvPrimClass (float)) + return new java::lang::Float (elements ((jfloatArray) array) [index]); + if (elementType == JvPrimClass (long)) + return new java::lang::Long (elements ((jlongArray) array) [index]); + if (elementType == JvPrimClass (int)) + return new java::lang::Integer (elements ((jintArray) array) [index]); + if (elementType == JvPrimClass (short)) + return new java::lang::Short (elements ((jshortArray) array) [index]); + if (elementType == JvPrimClass (byte)) + return new java::lang::Byte (elements ((jbyteArray) array) [index]); + if (elementType == JvPrimClass (char)) + return new java::lang::Character (elements ((jcharArray) array) [index]); + if (elementType == JvPrimClass (boolean)) + { + _Jv_InitClass (&java::lang::Boolean::class$); + if (elements ((jbooleanArray) array) [index]) + return java::lang::Boolean::TRUE; + else + return java::lang::Boolean::FALSE; + } + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setChar (jobject array, jint index, jchar value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (char)) + elements ((jcharArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setByte (jobject array, jint index, jbyte value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (byte)) + elements ((jbyteArray) array) [index] = value; + else if (elementType == JvPrimClass (short)) + elements ((jshortArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setShort (jobject array, jint index, jshort value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (short)) + elements ((jshortArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setInt (jobject array, jint index, jint value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setLong (jobject array, jint index, jlong value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setFloat (jobject array, jint index, jfloat value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setDouble (jobject array, jint index, jdouble value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setBoolean (jobject array, + jint index, jboolean value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (boolean)) + elements ((jbooleanArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::set (jobject array, jint index, + jobject value, jclass elType) +{ + // We don't have to call getElementType here, or check INDEX, + // because it was already done in the Java wrapper. + if (value != NULL && ! _Jv_IsInstanceOf (value, elType)) + throw new java::lang::IllegalArgumentException; + elements ((jobjectArray) array) [index] = value; +} diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc new file mode 100644 index 000000000..953d86dd4 --- /dev/null +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -0,0 +1,93 @@ +// natConstructor.cc - Native code for Constructor class. + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/InvocationTargetException.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/InstantiationException.h> +#include <gcj/method.h> + +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; +typedef JArray< JArray< ::java::lang::annotation::Annotation * > *> * anno_aa_t; + +jint +java::lang::reflect::Constructor::getModifiersInternal () +{ + return _Jv_FromReflectedConstructor (this)->accflags; +} + +jstring +java::lang::reflect::Constructor::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +anno_a_t +java::lang::reflect::Constructor::getDeclaredAnnotationsInternal() +{ + return (anno_a_t) declaringClass->getDeclaredAnnotations(this, false); +} + +anno_aa_t +java::lang::reflect::Constructor::getParameterAnnotationsInternal() +{ + return (anno_aa_t) declaringClass->getDeclaredAnnotations(this, true); +} + +void +java::lang::reflect::Constructor::getType () +{ + _Jv_GetTypesFromSignature (_Jv_FromReflectedConstructor (this), + declaringClass, + ¶meter_types, + NULL); + + // FIXME: for now we have no way to get exception information. + exception_types = + (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$, NULL); +} + +jobject +java::lang::reflect::Constructor::newInstance (jobjectArray args) +{ + using namespace java::lang::reflect; + + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedConstructor (this); + + // Check accessibility, if required. + if (! (Modifier::isPublic (meth->accflags) || this->isAccessible())) + { + Class *caller = _Jv_StackTrace::GetCallingClass (&Constructor::class$); + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) + throw new IllegalAccessException; + } + + if (Modifier::isAbstract (declaringClass->getModifiers())) + throw new InstantiationException; + + _Jv_InitClass (declaringClass); + + // In the constructor case the return type is the type of the + // constructor. + return _Jv_CallAnyMethodA (NULL, declaringClass, meth, true, + parameter_types, args); +} diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc new file mode 100644 index 000000000..734f65316 --- /dev/null +++ b/libjava/java/lang/reflect/natField.cc @@ -0,0 +1,449 @@ +// natField.cc - Implementation of java.lang.reflect.Field native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <jvm.h> +#include <java-stack.h> +#include <java/lang/reflect/Field.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> + +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; + +jint +java::lang::reflect::Field::getModifiersInternal () +{ + return _Jv_FromReflectedField (this)->flags; +} + +jstring +java::lang::reflect::Field::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +anno_a_t +java::lang::reflect::Field::getDeclaredAnnotationsInternal() +{ + return (anno_a_t) declaringClass->getDeclaredAnnotations(this); +} + +jstring +java::lang::reflect::Field::getName () +{ + if (name == NULL) + name = _Jv_NewStringUtf8Const (_Jv_FromReflectedField (this)->name); + return name; +} + +jclass +java::lang::reflect::Field::getType () +{ + if (type == NULL) + { + jfieldID fld = _Jv_FromReflectedField (this); + JvSynchronize sync (declaringClass); + _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ()); + type = fld->type; + } + return type; +} + +static void* +getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj, + jboolean checkFinal) +{ + using namespace java::lang::reflect; + + jfieldID fld = _Jv_FromReflectedField (field); + _Jv_ushort flags = fld->getModifiers(); + + // Setting a final field is usually not allowed. + if (checkFinal + // As of 1.5, you can set a non-static final field if it is + // accessible. + && (! field->isAccessible() + || (field->getModifiers() & java::lang::reflect::Modifier::STATIC)) + && (field->getModifiers() & java::lang::reflect::Modifier::FINAL)) + throw new java::lang::IllegalAccessException(JvNewStringUTF + ("Field is final")); + + // Check accessibility, if required. + if (! (Modifier::isPublic (flags) || field->isAccessible())) + { + if (! caller) + caller = _Jv_StackTrace::GetCallingClass (&Field::class$); + if (! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags)) + throw new java::lang::IllegalAccessException; + } + + if (flags & Modifier::STATIC) + { + jclass fldClass = field->getDeclaringClass (); + JvInitClass(fldClass); + return fld->u.addr; + } + else + { + if (obj == NULL) + throw new java::lang::NullPointerException; + if (! _Jv_IsInstanceOf (obj, field->getDeclaringClass())) + throw new java::lang::IllegalArgumentException; + return (void*) ((char*) obj + fld->getOffset ()); + } +} + +static jboolean +getBoolean (jclass cls, void* addr) +{ + if (cls == JvPrimClass (boolean)) + return * (jboolean *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jchar +getChar (jclass cls, void* addr) +{ + if (cls == JvPrimClass (char)) + return * (jchar *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jbyte +getByte (jclass cls, void* addr) +{ + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jshort +getShort (jclass cls, void* addr) +{ + if (cls == JvPrimClass (short)) + return * (jshort *) addr; + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jint +getInt (jclass cls, void* addr) +{ + if (cls == JvPrimClass (int)) + return * (jint *) addr; + if (cls == JvPrimClass (short)) + return * (jshort *) addr; + if (cls == JvPrimClass (char)) + return * (jchar *) addr; + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jlong +getLong (jclass cls, void* addr) +{ + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +static jfloat +getFloat (jclass cls, void* addr) +{ + if (cls == JvPrimClass (float)) + return * (jfloat *) addr; + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +static jdouble +getDouble (jclass cls, void* addr) +{ + if (cls == JvPrimClass (double)) + return * (jdouble *) addr; + if (cls == JvPrimClass (float)) + return * (jfloat *) addr; + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +jboolean +java::lang::reflect::Field::getBoolean (jclass caller, jobject obj) +{ + return ::getBoolean (this->getType(), getAddr (this, caller, obj, false)); +} + +jchar +java::lang::reflect::Field::getChar (jclass caller, jobject obj) +{ + return ::getChar (this->getType(), getAddr (this, caller, obj, false)); +} + +jbyte +java::lang::reflect::Field::getByte (jclass caller, jobject obj) +{ + return ::getByte (this->getType(), getAddr (this, caller, obj, false)); +} + +jshort +java::lang::reflect::Field::getShort (jclass caller, jobject obj) +{ + return ::getShort (this->getType(), getAddr (this, caller, obj, false)); +} + +jint +java::lang::reflect::Field::getInt (jclass caller, jobject obj) +{ + return ::getInt (this->getType(), getAddr (this, caller, obj, false)); +} + +jlong +java::lang::reflect::Field::getLong (jclass caller, jobject obj) +{ + return ::getLong (this->getType(), getAddr (this, caller, obj, false)); +} + +jfloat +java::lang::reflect::Field::getFloat (jclass caller, jobject obj) +{ + return ::getFloat (this->getType(), getAddr (this, caller, obj, false)); +} + +jdouble +java::lang::reflect::Field::getDouble (jclass caller, jobject obj) +{ + return ::getDouble (this->getType(), getAddr (this, caller, obj, false)); +} + +jobject +java::lang::reflect::Field::get (jclass caller, jobject obj) +{ + jclass type = this->getType(); + void* addr = getAddr (this, caller, obj, false); + if (! type->isPrimitive ()) + return * (jobject*) addr; + if (type == JvPrimClass (double)) + return new java::lang::Double (* (jdouble*) addr); + if (type == JvPrimClass (float)) + return new java::lang::Float (* (jfloat*) addr); + if (type == JvPrimClass (long)) + return new java::lang::Long (* (jlong*) addr); + if (type == JvPrimClass (int)) + return new java::lang::Integer (* (jint*) addr); + if (type == JvPrimClass (short)) + return new java::lang::Short (* (jshort*) addr); + if (type == JvPrimClass (byte)) + return new java::lang::Byte (* (jbyte*) addr); + if (type == JvPrimClass (char)) + return new java::lang::Character (* (jchar*) addr); + if (type == JvPrimClass (boolean)) + { + _Jv_InitClass (&java::lang::Boolean::class$); + if (* (jboolean*) addr) + return java::lang::Boolean::TRUE; + else + return java::lang::Boolean::FALSE; + } + throw new java::lang::IllegalArgumentException; +} + +static void +setBoolean (jclass type, void *addr, jboolean value) +{ + if (type == JvPrimClass (boolean)) + * (jboolean *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setChar (jclass type, void *addr, jchar value) +{ + if (type == JvPrimClass (char)) + * (jchar *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setByte (jclass type, void *addr, jbyte value) +{ + if (type == JvPrimClass (byte)) + * (jbyte *) addr = value; + else if (type == JvPrimClass (short)) + * (jshort *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setShort (jclass type, void *addr, jshort value) +{ + if (type == JvPrimClass (short)) + * (jshort *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setInt (jclass type, void *addr, jint value) +{ + if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setLong (jclass type, void *addr, jlong value) +{ + if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setFloat (jclass type, void *addr, jfloat value) +{ + if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setDouble (jclass type, void *addr, jdouble value) +{ + if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b, + jboolean checkFinal) +{ + ::setBoolean (this->getType(), getAddr (this, caller, obj, checkFinal), b); +} + +void +java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c, + jboolean checkFinal) +{ + ::setChar (this->getType(), getAddr (this, caller, obj, checkFinal), c); +} + +void +java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b, + jboolean checkFinal) +{ + ::setByte (this->getType(), getAddr (this, caller, obj, checkFinal), b); +} + +void +java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s, + jboolean checkFinal) +{ + ::setShort (this->getType(), getAddr (this, caller, obj, checkFinal), s); +} + +void +java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i, + jboolean checkFinal) +{ + ::setInt (this->getType(), getAddr (this, caller, obj, checkFinal), i); +} + +void +java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l, + jboolean checkFinal) +{ + ::setLong (this->getType(), getAddr (this, caller, obj, checkFinal), l); +} + +void +java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f, + jboolean checkFinal) +{ + ::setFloat (this->getType(), getAddr (this, caller, obj, checkFinal), f); +} + +void +java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d, + jboolean checkFinal) +{ + ::setDouble (this->getType(), getAddr (this, caller, obj, checkFinal), d); +} + +void +java::lang::reflect::Field::set (jclass caller, jobject object, jobject value, + jclass type, jboolean checkFinal) +{ + void* addr = getAddr (this, caller, object, checkFinal); + if (value != NULL && ! _Jv_IsInstanceOf (value, type)) + throw new java::lang::IllegalArgumentException; + * (jobject*) addr = value; +} diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc new file mode 100644 index 000000000..d95c92f84 --- /dev/null +++ b/libjava/java/lang/reflect/natMethod.cc @@ -0,0 +1,701 @@ +// natMethod.cc - Native code for Method class. + +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <jni.h> +#include <java-stack.h> + +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/reflect/InvocationTargetException.h> +#include <java/lang/reflect/Modifier.h> + +#include <java/lang/Void.h> +#include <java/lang/Byte.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/Class.h> +#include <gcj/method.h> +#include <gnu/gcj/RawData.h> +#include <java/lang/NoClassDefFoundError.h> + +#include <stdlib.h> + +#if USE_LIBFFI +#include <ffi.h> +#else +#include <java/lang/UnsupportedOperationException.h> +#endif + +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; +typedef JArray< JArray< ::java::lang::annotation::Annotation * > *> * anno_aa_t; + + + +struct cpair +{ + jclass prim; + jclass wrap; +}; + +// This is used to determine when a primitive widening conversion is +// allowed. +static cpair primitives[] = +{ +#define BOOLEAN 0 + { JvPrimClass (boolean), &java::lang::Boolean::class$ }, + { JvPrimClass (byte), &java::lang::Byte::class$ }, +#define SHORT 2 + { JvPrimClass (short), &java::lang::Short::class$ }, +#define CHAR 3 + { JvPrimClass (char), &java::lang::Character::class$ }, + { JvPrimClass (int), &java::lang::Integer::class$ }, + { JvPrimClass (long), &java::lang::Long::class$ }, + { JvPrimClass (float), &java::lang::Float::class$ }, + { JvPrimClass (double), &java::lang::Double::class$ }, + { NULL, NULL } +}; + +static inline jboolean +can_widen (jclass from, jclass to) +{ + int fromx = -1, tox = -1; + + for (int i = 0; primitives[i].prim; ++i) + { + if (primitives[i].wrap == from) + fromx = i; + if (primitives[i].prim == to) + tox = i; + } + + // Can't handle a miss. + if (fromx == -1 || tox == -1) + return false; + // Boolean arguments may not be widened. + if (fromx == BOOLEAN && tox != BOOLEAN) + return false; + // Nothing promotes to char. + if (tox == CHAR && fromx != CHAR) + return false; + + return fromx <= tox; +} + +#ifdef USE_LIBFFI +static inline ffi_type * +get_ffi_type (jclass klass) +{ + // A special case. + if (klass == NULL) + return &ffi_type_pointer; + + ffi_type *r; + if (klass == JvPrimClass (byte)) + r = &ffi_type_sint8; + else if (klass == JvPrimClass (short)) + r = &ffi_type_sint16; + else if (klass == JvPrimClass (int)) + r = &ffi_type_sint32; + else if (klass == JvPrimClass (long)) + r = &ffi_type_sint64; + else if (klass == JvPrimClass (float)) + r = &ffi_type_float; + else if (klass == JvPrimClass (double)) + r = &ffi_type_double; + else if (klass == JvPrimClass (boolean)) + { + // On some platforms a bool is a byte, on others an int. + if (sizeof (jboolean) == sizeof (jbyte)) + r = &ffi_type_sint8; + else + { + JvAssert (sizeof (jboolean) == sizeof (jint)); + r = &ffi_type_sint32; + } + } + else if (klass == JvPrimClass (char)) + r = &ffi_type_uint16; + else + { + JvAssert (! klass->isPrimitive()); + r = &ffi_type_pointer; + } + + return r; +} +#endif // USE_LIBFFI + +jobject +java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) +{ + using namespace java::lang::reflect; + jclass iface = NULL; + + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedMethod (this); + + if (Modifier::isStatic(meth->accflags)) + { + // We have to initialize a static class. It is safe to do this + // here and not in _Jv_CallAnyMethodA because JNI initializes a + // class whenever a method lookup is done. + _Jv_InitClass (declaringClass); + } + else + { + jclass objClass = JV_CLASS (obj); + if (! _Jv_IsAssignableFrom (objClass, declaringClass)) + throw new java::lang::IllegalArgumentException; + } + + // Check accessibility, if required. + if (! this->isAccessible()) + { + if (! (Modifier::isPublic (meth->accflags))) + { + Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$); + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) + throw new IllegalAccessException; + } + else + // Method is public, check to see if class is accessible. + { + jint flags = (declaringClass->accflags + & (Modifier::PUBLIC + | Modifier::PROTECTED + | Modifier::PRIVATE)); + if (flags == 0) // i.e. class is package private + { + Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$); + if (! _Jv_ClassNameSamePackage (caller->name, + declaringClass->name)) + throw new IllegalAccessException; + } + } + } + + if (declaringClass->isInterface()) + iface = declaringClass; + + return _Jv_CallAnyMethodA (obj, return_type, meth, false, + parameter_types, args, iface); +} + +jint +java::lang::reflect::Method::getModifiersInternal () +{ + return _Jv_FromReflectedMethod (this)->accflags; +} + +jstring +java::lang::reflect::Method::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +jobject +java::lang::reflect::Method::getDefaultValue() +{ + return declaringClass->getMethodDefaultValue(this); +} + +anno_a_t +java::lang::reflect::Method::getDeclaredAnnotationsInternal() +{ + return (anno_a_t) declaringClass->getDeclaredAnnotations(this, false); +} + +anno_aa_t +java::lang::reflect::Method::getParameterAnnotationsInternal() +{ + return (anno_aa_t) declaringClass->getDeclaredAnnotations(this, true); +} + +jstring +java::lang::reflect::Method::getName () +{ + if (name == NULL) + name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name); + return name; +} + +/* Internal method to set return_type and parameter_types fields. */ + +void +java::lang::reflect::Method::getType () +{ + _Jv_Method *method = _Jv_FromReflectedMethod (this); + _Jv_GetTypesFromSignature (method, + declaringClass, + ¶meter_types, + &return_type); + + int count = 0; + if (method->throws != NULL) + { + while (method->throws[count] != NULL) + ++count; + } + + exception_types + = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$, + NULL); + jclass *elts = elements (exception_types); + for (int i = 0; i < count; ++i) + elts[i] = _Jv_FindClass (method->throws[i], + declaringClass->getClassLoaderInternal ()); +} + +void +_Jv_GetTypesFromSignature (jmethodID method, + jclass declaringClass, + JArray<jclass> **arg_types_out, + jclass *return_type_out) +{ + + _Jv_Utf8Const* sig = method->signature; + java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal(); + char *ptr = sig->chars(); + int numArgs = 0; + /* First just count the number of parameters. */ + // FIXME: should do some validation here, e.g., that there is only + // one return type. + for (; ; ptr++) + { + switch (*ptr) + { + case 0: + case ')': + case 'V': + break; + case '[': + case '(': + continue; + case 'B': + case 'C': + case 'D': + case 'F': + case 'S': + case 'I': + case 'J': + case 'Z': + numArgs++; + continue; + case 'L': + numArgs++; + do + ptr++; + while (*ptr != ';' && ptr[1] != '\0'); + continue; + } + break; + } + + JArray<jclass> *args = (JArray<jclass> *) + JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL); + jclass* argPtr = elements (args); + for (ptr = sig->chars(); *ptr != '\0'; ptr++) + { + if (*ptr == '(') + continue; + if (*ptr == ')') + { + argPtr = return_type_out; + continue; + } + + char *end_ptr; + jclass type = _Jv_FindClassFromSignature (ptr, loader, &end_ptr); + if (type == NULL) + // FIXME: This isn't ideal. + throw new java::lang::NoClassDefFoundError (sig->toString()); + + // ARGPTR can be NULL if we are processing the return value of a + // call from Constructor. + if (argPtr) + *argPtr++ = type; + + ptr = end_ptr; + } + *arg_types_out = args; +} + +// This is a very rough analog of the JNI CallNonvirtual<type>MethodA +// functions. It handles both Methods and Constructors, and it can +// handle any return type. In the Constructor case, the `obj' +// argument is unused and should be NULL; also, the `return_type' is +// the class that the constructor will construct. RESULT is a pointer +// to a `jvalue' (see jni.h); for a void method this should be NULL. +// This function returns an exception (if one was thrown), or NULL if +// the call went ok. +void +_Jv_CallAnyMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + jboolean is_virtual_call, + JArray<jclass> *parameter_types, + const jvalue *args, + jvalue *result, + jboolean is_jni_call, + jclass iface) +{ + using namespace java::lang::reflect; + +#ifdef USE_LIBFFI + JvAssert (! is_constructor || ! obj); + JvAssert (! is_constructor || return_type); + + // See whether call needs an object as the first argument. A + // constructor does need a `this' argument, but it is one we create. + jboolean needs_this = false; + if (is_constructor + || ! Modifier::isStatic(meth->accflags)) + needs_this = true; + + int param_count = parameter_types->length; + if (needs_this) + ++param_count; + + ffi_type *rtype; + // A constructor itself always returns void. + if (is_constructor || return_type == JvPrimClass (void)) + rtype = &ffi_type_void; + else + rtype = get_ffi_type (return_type); + ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count + * sizeof (ffi_type *)); + + jclass *paramelts = elements (parameter_types); + + // Special case for the `this' argument of a constructor. Note that + // the JDK 1.2 docs specify that the new object must be allocated + // before argument conversions are done. + if (is_constructor) + obj = _Jv_AllocObject (return_type); + + const int size_per_arg = sizeof(jvalue); + ffi_cif cif; + + char *p = (char *) __builtin_alloca (param_count * size_per_arg); + // Overallocate to get correct alignment. + void **values = (void **) + __builtin_alloca (param_count * sizeof (void *)); + + int i = 0; + if (needs_this) + { + // The `NULL' type is `Object'. + argtypes[i] = get_ffi_type (NULL); + values[i] = p; + memcpy (p, &obj, sizeof (jobject)); + p += size_per_arg; + ++i; + } + + for (int arg = 0; i < param_count; ++i, ++arg) + { + int tsize; + + argtypes[i] = get_ffi_type (paramelts[arg]); + if (paramelts[arg]->isPrimitive()) + tsize = paramelts[arg]->size(); + else + tsize = sizeof (jobject); + + // Copy appropriate bits from the jvalue into the ffi array. + // FIXME: we could do this copying all in one loop, above, by + // over-allocating a bit. + // How do we do this without breaking big-endian platforms? + values[i] = p; + memcpy (p, &args[arg], tsize); + p += size_per_arg; + } + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, + rtype, argtypes) != FFI_OK) + throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed")); + + using namespace java::lang; + using namespace java::lang::reflect; + + union + { + ffi_arg i; + jobject o; + jlong l; + jfloat f; + jdouble d; + } ffi_result; + + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = 0; + break; + case FFI_TYPE_SINT16: + result->s = 0; + break; + case FFI_TYPE_UINT16: + result->c = 0; + break; + case FFI_TYPE_SINT32: + result->i = 0; + break; + case FFI_TYPE_SINT64: + result->j = 0; + break; + case FFI_TYPE_FLOAT: + result->f = 0; + break; + case FFI_TYPE_DOUBLE: + result->d = 0; + break; + case FFI_TYPE_POINTER: + result->l = 0; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + + void *ncode; + + // FIXME: If a vtable index is -1 at this point it is invalid, so we + // have to use the ncode. + // + // This can happen because methods in final classes don't have + // vtable entries, but _Jv_isVirtualMethod() doesn't know that. We + // could solve this problem by allocating a vtable index for methods + // in final classes. + if (is_virtual_call + && ! Modifier::isFinal (meth->accflags) + && (_Jv_ushort)-1 != meth->index) + { + _Jv_VTable *vtable = *(_Jv_VTable **) obj; + if (iface == NULL) + { + if (is_jni_call && Modifier::isAbstract (meth->accflags)) + { + // With JNI we don't know if this is an interface call + // or a call to an abstract method. Look up the method + // by name, the slow way. + _Jv_Method *concrete_meth + = _Jv_LookupDeclaredMethod (vtable->clas, + meth->name, + meth->signature, + NULL); + if (concrete_meth == NULL + || concrete_meth->ncode == NULL + || Modifier::isAbstract(concrete_meth->accflags)) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (vtable->clas, meth)); + ncode = concrete_meth->ncode; + } + else + ncode = vtable->get_method (meth->index); + } + else + ncode = _Jv_LookupInterfaceMethodIdx (vtable->clas, iface, + meth->index); + } + else + { + ncode = meth->ncode; + } + + try + { + ffi_call (&cif, (void (*)()) ncode, &ffi_result, values); + } + catch (Throwable *ex) + { + // For JNI we just throw the real error. For reflection, we + // wrap the underlying method's exception in an + // InvocationTargetException. + if (! is_jni_call) + ex = new InvocationTargetException (ex); + throw ex; + } + + // Since ffi_call returns integer values promoted to a word, use + // a narrowing conversion for jbyte, jchar, etc. results. + // Note that boolean is handled either by the FFI_TYPE_SINT8 or + // FFI_TYPE_SINT32 case. + if (is_constructor) + result->l = obj; + else + { + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = (jbyte)ffi_result.i; + break; + case FFI_TYPE_SINT16: + result->s = (jshort)ffi_result.i; + break; + case FFI_TYPE_UINT16: + result->c = (jchar)ffi_result.i; + break; + case FFI_TYPE_SINT32: + result->i = (jint)ffi_result.i; + break; + case FFI_TYPE_SINT64: + result->j = (jlong)ffi_result.l; + break; + case FFI_TYPE_FLOAT: + result->f = (jfloat)ffi_result.f; + break; + case FFI_TYPE_DOUBLE: + result->d = (jdouble)ffi_result.d; + break; + case FFI_TYPE_POINTER: + result->l = (jobject)ffi_result.o; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + } +#else + throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build")); +#endif // USE_LIBFFI +} + +// This is another version of _Jv_CallAnyMethodA, but this one does +// more checking and is used by the reflection (and not JNI) code. +jobject +_Jv_CallAnyMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + JArray<jclass> *parameter_types, + jobjectArray args, + jclass iface) +{ + if (parameter_types->length == 0 && args == NULL) + { + // The JDK accepts this, so we do too. + } + else if (parameter_types->length != args->length) + throw new java::lang::IllegalArgumentException; + + int param_count = parameter_types->length; + + jclass *paramelts = elements (parameter_types); + jobject *argelts = args == NULL ? NULL : elements (args); + jvalue argvals[param_count]; + +#define COPY(Where, What, Type) \ + do { \ + Type val = (What); \ + memcpy ((Where), &val, sizeof (Type)); \ + } while (0) + + for (int i = 0; i < param_count; ++i) + { + jclass k = argelts[i] ? argelts[i]->getClass() : NULL; + if (paramelts[i]->isPrimitive()) + { + if (! argelts[i] + || ! k + || ! can_widen (k, paramelts[i])) + throw new java::lang::IllegalArgumentException; + + if (paramelts[i] == JvPrimClass (boolean)) + COPY (&argvals[i], + ((java::lang::Boolean *) argelts[i])->booleanValue(), + jboolean); + else if (paramelts[i] == JvPrimClass (char)) + COPY (&argvals[i], + ((java::lang::Character *) argelts[i])->charValue(), + jchar); + else + { + java::lang::Number *num = (java::lang::Number *) argelts[i]; + if (paramelts[i] == JvPrimClass (byte)) + COPY (&argvals[i], num->byteValue(), jbyte); + else if (paramelts[i] == JvPrimClass (short)) + COPY (&argvals[i], num->shortValue(), jshort); + else if (paramelts[i] == JvPrimClass (int)) + COPY (&argvals[i], num->intValue(), jint); + else if (paramelts[i] == JvPrimClass (long)) + COPY (&argvals[i], num->longValue(), jlong); + else if (paramelts[i] == JvPrimClass (float)) + COPY (&argvals[i], num->floatValue(), jfloat); + else if (paramelts[i] == JvPrimClass (double)) + COPY (&argvals[i], num->doubleValue(), jdouble); + } + } + else + { + if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) + throw new java::lang::IllegalArgumentException; + COPY (&argvals[i], argelts[i], jobject); + } + } + + jvalue ret_value; + _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor, + _Jv_isVirtualMethod (meth), + parameter_types, argvals, &ret_value, + false, iface); + + jobject r; +#define VAL(Wrapper, Field) (new Wrapper (ret_value.Field)) + if (is_constructor) + r = ret_value.l; + else if (return_type == JvPrimClass (byte)) + r = VAL (java::lang::Byte, b); + else if (return_type == JvPrimClass (short)) + r = VAL (java::lang::Short, s); + else if (return_type == JvPrimClass (int)) + r = VAL (java::lang::Integer, i); + else if (return_type == JvPrimClass (long)) + r = VAL (java::lang::Long, j); + else if (return_type == JvPrimClass (float)) + r = VAL (java::lang::Float, f); + else if (return_type == JvPrimClass (double)) + r = VAL (java::lang::Double, d); + else if (return_type == JvPrimClass (boolean)) + r = VAL (java::lang::Boolean, z); + else if (return_type == JvPrimClass (char)) + r = VAL (java::lang::Character, c); + else if (return_type == JvPrimClass (void)) + r = NULL; + else + { + JvAssert (return_type == NULL || ! return_type->isPrimitive()); + r = ret_value.l; + } + + return r; +} diff --git a/libjava/java/lang/reflect/natVMProxy.cc b/libjava/java/lang/reflect/natVMProxy.cc new file mode 100644 index 000000000..4c3fd74f9 --- /dev/null +++ b/libjava/java/lang/reflect/natVMProxy.cc @@ -0,0 +1,459 @@ +// natVMProxy.cc -- Implementation of VMProxy methods. + +/* Copyright (C) 2006, 2007 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// The idea of behind this code is to utilize libffi's ability to +// create closures to provide a fast "cut-through" way to generate +// proxy classes. Instead of generating bytecode and then +// interpreting that, we copy the method definitions for each of the +// methods we're supposed to be prxying and generate a libffi closure +// for each one. + +#include <config.h> +#include <platform.h> +#include <sysdep/descriptor.h> + +#include <limits.h> +#include <string.h> +#include <stddef.h> +#include <stdio.h> + +#include <gcj/cni.h> +#include <gcj/javaprims.h> +#include <jvm.h> +#include <jni.h> +#include <java-threads.h> +#include <java-interp.h> +#include <ffi.h> +#include <execution.h> +#include <gcj/method.h> + +#include <gnu/gcj/runtime/BootClassLoader.h> +#include <java/lang/Class.h> +#include <java/lang/ClassCastException.h> +#include <java/lang/Error.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/Integer.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/UnsupportedOperationException.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/VMCompiler.h> +#include <java/lang/reflect/InvocationHandler.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Proxy$ClassFactory.h> +#include <java/lang/reflect/Proxy$ProxyData.h> +#include <java/lang/reflect/Proxy.h> +#include <java/lang/reflect/UndeclaredThrowableException.h> +#include <java/lang/reflect/VMProxy.h> + +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> + + +using namespace java::lang::reflect; +using namespace java::lang; + +#ifndef INTERPRETER +jclass +java::lang::reflect::VMProxy::generateProxyClass + (ClassLoader *, Proxy$ProxyData *) +{ + throw new UnsupportedOperationException ( + JvNewStringLatin1 ("Interpreter not available")); +} +#else +typedef void (*closure_fun) (ffi_cif*, void*, void**, void*); +static void *ncode (int method_index, jclass klass, _Jv_Method *self, closure_fun fun); +static void run_proxy (ffi_cif*, void*, void**, void*); + +typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *); + +// True if pc points to a proxy frame. + +bool +_Jv_is_proxy (void *pc) +{ + return pc == UNWRAP_FUNCTION_DESCRIPTOR ((void*)&run_proxy); +} + +// Generate a proxy class by using libffi closures for each entry +// point. + +jclass +java::lang::reflect::VMProxy::generateProxyClass + (ClassLoader *loader, Proxy$ProxyData *d) +{ + // If we're precompiling, generate bytecode and allow VMCompiler to + // precompile it. + if (VMCompiler::precompiles ()) + return (new Proxy$ClassFactory(d))->generate(loader); + + jclass klass = new Class (); + + // Synchronize on the class, so that it is not attempted initialized + // until we're done. + JvSynchronize sync (klass); + + klass->superclass = &Proxy::class$; + klass->engine = &_Jv_soleIndirectCompiledEngine; + klass->size_in_bytes = -1; + klass->vtable_method_count = -1; + + // Declare private static transient java.lang.reflect.Method[] $Proxy0.m + klass->field_count = klass->static_field_count = 1; + klass->fields = (_Jv_Field*)_Jv_AllocRawObj (sizeof (_Jv_Field)); + klass->fields[0].name = _Jv_makeUtf8Const ("m"); + klass->fields[0].type = d->methods->getClass(); + klass->fields[0].flags = (Modifier::PRIVATE | Modifier::STATIC + | Modifier::TRANSIENT); + + // Record the defining loader. For the bootstrap class loader, + // we record NULL. + if (loader != VMClassLoader::bootLoader) + klass->loader = loader; + + { + StringBuffer *sb = new StringBuffer(); + sb->append(JvNewStringLatin1 ("$Proxy")); + sb->append(Integer::toString (d->id)); + klass->name = _Jv_makeUtf8Const (sb->toString()); + } + + // Allocate space for the interfaces. + klass->interface_count = d->interfaces->length; + klass->interfaces = (jclass*) _Jv_AllocRawObj (klass->interface_count + *sizeof (jclass)); + for (int i = 0; i < klass->interface_count; i++) + klass->interfaces[i] = elements(d->interfaces)[i]; + + size_t count = d->methods->length; + + { + size_t total_count = count + Proxy::class$.method_count + 1; + if (total_count >= 65536) + throw new IllegalArgumentException (); + // Allocate space for the methods. This is a worst case + // estimate. + klass->methods + = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method) + * total_count); + } + + jshort &method_count = klass->method_count; + + // Copy all reachable methods from Proxy. + for (int i = 0; i < Proxy::class$.method_count; i++) + { + if (_Jv_CheckAccess (klass, &Proxy::class$, + Proxy::class$.methods[i].accflags)) + { + klass->methods[method_count] = Proxy::class$.methods[i]; + method_count++; + } + } + + _Jv_Method *init_method + = (_Jv_Linker::search_method_in_class + (klass, klass, + _Jv_makeUtf8Const ("<init>"), + _Jv_makeUtf8Const ("(Ljava.lang.reflect.InvocationHandler;)V"), + false)); + init_method->accflags |= Modifier::PUBLIC; + + // Create the methods for all of the interfaces. + for (size_t i = 0; i < count; i++) + { + _Jv_Method &method = klass->methods[method_count++]; + const _Jv_Method &imethod + = *_Jv_FromReflectedMethod (elements(d->methods)[i]); + // We use a shallow copy of IMETHOD rather than a deep copy; + // this means that the pointer fields of METHOD point into the + // interface. As long as this subclass of Proxy is reachable, + // the interfaces of which it is a proxy will also be reachable, + // so this is safe. + method = imethod; + method.ncode = ncode (i, klass, &method, run_proxy); + method.accflags &= ~Modifier::ABSTRACT; + } + + _Jv_Linker::layout_vtable_methods (klass); + _Jv_RegisterInitiatingLoader (klass, klass->loader); + + // Set $Proxy0.m to point to the methods arrray + java::lang::reflect::Field *f + = klass->getDeclaredField (JvNewStringLatin1 ("m")); + f->flag = true; + f->set(NULL, d->methods); + + return klass; +} + + +// Box things with primitive types. +static inline jobject +box (void *thing, jclass klass, FFI_TYPE type) +{ + jobject o; + + switch (type) + { + case FFI_TYPE_VOID: + return NULL; + + case FFI_TYPE_POINTER: + o = *(jobject*)thing; + return o; + + default: + ; + } + + if (klass == JvPrimClass (byte)) + o = new Byte (*(jbyte*)thing); + else if (klass == JvPrimClass (short)) + o = new Short (*(jshort*)thing); + else if (klass == JvPrimClass (int)) + o = new Integer (*(jint*)thing); + else if (klass == JvPrimClass (long)) + o = new Long (*(jlong*)thing); + else if (klass == JvPrimClass (float)) + o = new Float (*(jfloat*)thing); + else if (klass == JvPrimClass (double)) + o = new Double (*(jdouble*)thing); + else if (klass == JvPrimClass (boolean)) + o = new Boolean (*(jboolean*)thing); + else if (klass == JvPrimClass (char)) + o = new Character (*(jchar*)thing); + else + JvFail ("Bad ffi type in proxy"); + + return o; +} + + +// Unbox things with primitive types. +static inline void +unbox (jobject o, jclass klass, void *rvalue, FFI_TYPE type) +{ + switch (type) + { + case FFI_TYPE_VOID: + return; + + case FFI_TYPE_POINTER: + _Jv_CheckCast (klass, o); + *(jobject*)rvalue = o; + return; + + default: + ; + } + + // If the value returned ... is null and the interface method's + // return type is primitive, then a NullPointerException will be + // thrown ... + if (klass == JvPrimClass (byte)) + { + _Jv_CheckCast (&Byte::class$, o); + *(jbyte*)rvalue = ((Byte*)o)->byteValue(); + } + else if (klass == JvPrimClass (short)) + { + _Jv_CheckCast (&Short::class$, o); + *(jshort*)rvalue = ((Short*)o)->shortValue(); + } + else if (klass == JvPrimClass (int)) + { + _Jv_CheckCast (&Integer::class$, o); + *(jint*)rvalue = ((Integer*)o)->intValue(); + } + else if (klass == JvPrimClass (long)) + { + _Jv_CheckCast (&Long::class$, o); + *(jlong*)rvalue = ((Long*)o)->longValue(); + } + else if (klass == JvPrimClass (float)) + { + _Jv_CheckCast (&Float::class$, o); + *(jfloat*)rvalue = ((Float*)o)->floatValue(); + } + else if (klass == JvPrimClass (double)) + { + _Jv_CheckCast (&Double::class$, o); + *(jdouble*)rvalue = ((Double*)o)->doubleValue(); + } + else if (klass == JvPrimClass (boolean)) + { + _Jv_CheckCast (&Boolean::class$, o); + *(jboolean*)rvalue = ((Boolean*)o)->booleanValue(); + } + else if (klass == JvPrimClass (char)) + { + _Jv_CheckCast (&Character::class$, o); + *(jchar*)rvalue = ((Character*)o)->charValue(); + } + else + JvFail ("Bad ffi type in proxy"); +} + +// _Jv_getFieldInternal is declared as a friend of reflect.Field in +// libjava/headers.txt. This gives us a way to call the private +// method Field.get (Class caller, Object obj). +extern inline jobject +_Jv_getFieldInternal (java::lang::reflect::Field *f, jclass c, jobject o) +{ + return f->get(c, o); +} + +// run_proxy is the entry point for all proxy methods. It boxes up +// all the arguments and then invokes the invocation handler's invoke() +// method. Exceptions are caught and propagated. + +typedef struct { + ffi_closure closure; + _Jv_ClosureList list; + ffi_cif cif; + _Jv_Method *self; + int method_index; + ffi_type *arg_types[0]; +} ncode_closure; + +static void +run_proxy (ffi_cif *cif, + void *rvalue, + void **args, + void*user_data) +{ + using namespace java::lang::reflect; + + Proxy *proxy = *(Proxy**)args[0]; + ncode_closure *self = (ncode_closure *) user_data; + + jclass proxyClass = proxy->getClass(); + + // FRAME_DESC registers this particular invocation as the top-most + // interpreter frame. This lets the stack tracing code (for + // Throwable) print information about the Proxy being run rather + // than about Proxy.class itself. FRAME_DESC has a destructor so it + // cleans up automatically when this proxy invocation returns. + Thread *thread = Thread::currentThread(); + _Jv_InterpFrame frame_desc (self->self, thread, proxyClass, + NULL, frame_proxy); + + // The method to invoke is saved in $Proxy0.m[method_index]. + // FIXME: We could somewhat improve efficiency by storing a pointer + // to the method (rather than its index) in ncode_closure. This + // would avoid the lookup, but it probably wouldn't make a huge + // difference. We'd still have to save the method array because + // ncode structs are not scanned by the gc. + Field *f = proxyClass->getDeclaredField (JvNewStringLatin1 ("m")); + JArray<Method*> *methods + = (JArray<Method*>*)_Jv_getFieldInternal (f, proxyClass, NULL); + Method *meth = elements(methods)[self->method_index]; + + JArray<jclass> *parameter_types = meth->internalGetParameterTypes (); + JArray<jclass> *exception_types = meth->internalGetExceptionTypes (); + + InvocationHandler *handler = proxy->h; + JArray<jobject> *argsArray = NULL; + jobject *jargs = NULL; + if (parameter_types->length) + { + void *poo + = _Jv_NewObjectArray (parameter_types->length, &Object::class$, NULL); + argsArray = (JArray<jobject> *) poo; + jargs = elements(argsArray); + } + + // FIXME: It must be possible to use fast interface dispatch here, + // but I've not quite figured out how to do it. + invoke_t *invoke + = (invoke_t *)(_Jv_LookupInterfaceMethod + (handler->getClass (), + _Jv_makeUtf8Const ("invoke"), + (_Jv_makeUtf8Const + ("(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;)" + "Ljava.lang.Object;")))); + + // Copy and box all the args. + int index = 1; + for (int i = 0; i < parameter_types->length; i++, index++) + jargs[i] = box (args[index], elements(parameter_types)[i], + cif->arg_types[index]->type); + + jobject ret; + try + { + ret = invoke (handler, proxy, meth, argsArray); + } + catch (Throwable *t) + { + if (_Jv_IsInstanceOf (t, &RuntimeException::class$) + || _Jv_IsInstanceOf (t, &Error::class$)) + throw t; + + Class **throwables = elements (exception_types); + for (int i = 0; i < exception_types->length; i++) + if (_Jv_IsInstanceOf (t, throwables[i])) + throw t; + + throw new UndeclaredThrowableException (t); + } + + unbox (ret, meth->return_type, rvalue, cif->rtype->type); +} + + +// Given a method and a closure function, create libffi CIF and return +// the address of its closure. + +static void * +ncode (int method_index, jclass klass, _Jv_Method *self, closure_fun fun) +{ + using namespace java::lang::reflect; + + jboolean staticp = (self->accflags & Modifier::STATIC) != 0; + int arg_count = _Jv_count_arguments (self->signature, staticp); + + void *code; + ncode_closure *closure = + (ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure) + + arg_count * sizeof (ffi_type*), + &code); + closure->method_index = method_index; + closure->list.registerClosure (klass, closure); + + _Jv_init_cif (self->signature, + arg_count, + staticp, + &closure->cif, + &closure->arg_types[0], + NULL); + closure->self = self; + + JvAssert ((self->accflags & Modifier::NATIVE) == 0); + + ffi_prep_closure_loc (&closure->closure, + &closure->cif, + fun, + code, + code); + + self->ncode = code; + return self->ncode; +} + +#endif // INTERPRETER |