diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index f700dc69dd..481032209a 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "jni.h" #include "jni-util.h" @@ -202,6 +203,42 @@ Java_java_io_File_exists(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jlong JNICALL +Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + jlong handle = reinterpret_cast(opendir(chars)); + e->ReleaseStringUTFChars(path, chars); + return handle; + } else { + return 0; + } +} + +extern "C" JNIEXPORT jstring JNICALL +Java_java_io_File_readDir(JNIEnv* e, jclass, jlong handle) +{ + struct dirent * directoryEntry; + + if (handle!=0) { + directoryEntry = readdir(reinterpret_cast(handle)); + if (directoryEntry == NULL) { + return NULL; + } + return e->NewStringUTF(directoryEntry->d_name); + } + return NULL; +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_File_closeDir(JNIEnv* , jclass, jlong handle) +{ + if (handle!=0) { + closedir(reinterpret_cast(handle)); + } +} + extern "C" JNIEXPORT jint JNICALL Java_java_io_FileInputStream_open(JNIEnv* e, jclass, jstring path) { diff --git a/classpath/java/io/BufferedReader.java b/classpath/java/io/BufferedReader.java index 6d67e71c29..3db923c5e9 100644 --- a/classpath/java/io/BufferedReader.java +++ b/classpath/java/io/BufferedReader.java @@ -38,16 +38,18 @@ public class BufferedReader extends Reader { } if (position >= limit) { - return sb.toString(); + return sb.length() == 0 ? null : sb.toString(); } for (int i = position; i < limit; ++i) { if (buffer[i] == '\n') { - sb.append(buffer, position, i); + sb.append(buffer, position, i - position); position = i + 1; return sb.toString(); } } + sb.append(buffer, position, limit-position); + position = limit; } } diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index ec74eb157c..0f91ebb746 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -14,9 +14,9 @@ public class File { private static final String FileSeparator = System.getProperty("file.separator"); -// static { -// System.loadLibrary("natives"); -// } + // static { + // System.loadLibrary("natives"); + // } private final String path; @@ -126,4 +126,64 @@ public class File { return false; } } + + public boolean mkdirs() { + File parent = getParentFile(); + if (parent != null) { + if (!parent.exists()) { + if (!parent.mkdirs()) { + return false; + } + } + } + return mkdir(); + } + + public String[] list() { + return list(null); + } + + public String[] list(FilenameFilter filter) { + long handle = 0; + try { + handle = openDir(path); + Pair list = null; + int count = 0; + for (String s = readDir(handle); s != null; s = readDir(handle)) { + if (filter == null || filter.accept(this, s)) { + list = new Pair(s, list); + ++ count; + } + } + + String[] result = new String[count]; + for (int i = count; i >= 0; --i) { + result[i] = list.value; + list = list.next; + } + + return result; + } finally { + if (handle != 0) { + closeDir(handle); + } + } + } + + private static native long openDir(String path); + + private static native String readDir(long handle); + + private static native long closeDir(long handle); + + private static class Pair { + public final String value; + public final Pair next; + + public Pair(String value, Pair next) { + this.value = value; + this.next = next; + } + } + } diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index 5a141c82a6..1c7a6c9532 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -11,9 +11,9 @@ package java.io; public class FileInputStream extends InputStream { -// static { -// System.loadLibrary("natives"); -// } + // static { + // System.loadLibrary("natives"); + // } private int fd; diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index 4083512656..4d50412414 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -11,9 +11,9 @@ package java.io; public class FileOutputStream extends OutputStream { -// static { -// System.loadLibrary("natives"); -// } + // static { + // System.loadLibrary("natives"); + // } private int fd; diff --git a/classpath/java/io/FilenameFilter.java b/classpath/java/io/FilenameFilter.java new file mode 100644 index 0000000000..718f3973d8 --- /dev/null +++ b/classpath/java/io/FilenameFilter.java @@ -0,0 +1,17 @@ +/* Copyright (c) 2008, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.io; + +public interface FilenameFilter { + + boolean accept(File dir, String name); + +} diff --git a/classpath/java/io/InputStream.java b/classpath/java/io/InputStream.java index ade4c81015..a225432044 100644 --- a/classpath/java/io/InputStream.java +++ b/classpath/java/io/InputStream.java @@ -41,8 +41,7 @@ public abstract class InputStream { int c; while ((c = read(buffer, 0, (int) (size < remaining ? size : remaining))) >= 0 - && remaining > 0) - { + && remaining > 0) { remaining -= c; } return count - remaining; diff --git a/classpath/java/io/PushbackReader.java b/classpath/java/io/PushbackReader.java index b75e963773..c1d8dd5091 100644 --- a/classpath/java/io/PushbackReader.java +++ b/classpath/java/io/PushbackReader.java @@ -38,11 +38,11 @@ public class PushbackReader extends Reader { if (length > 0) { int c = in.read(b, offset, length); if (c == -1) { - if (count == 0) { - count = -1; - } + if (count == 0) { + count = -1; + } } else { - count += c; + count += c; } } diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index a51008cf7d..6627ae3170 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -58,6 +58,14 @@ public final class Character implements Comparable { } } + public static int toLowerCase(int codePoint) { + if (isSupplementaryCodePoint(codePoint)) { + return codePoint; + } else { + return toLowerCase((char) codePoint); + } + } + public static char toUpperCase(char c) { if (c >= 'a' && c <= 'z') { return (char) ((c - 'a') + 'A'); @@ -66,10 +74,22 @@ public final class Character implements Comparable { } } + public static int toUpperCase(int codePoint) { + if (isSupplementaryCodePoint(codePoint)) { + return codePoint; + } else { + return toUpperCase((char) codePoint); + } + } + public static boolean isDigit(char c) { return c >= '0' && c <= '9'; } + public static boolean isDigit(int c) { + return c >= '0' && c <= '9'; + } + public static int digit(char c, int radix) { int digit = 0; if ((c >= '0') && (c <= '9')) { @@ -87,6 +107,10 @@ public final class Character implements Comparable { } } + public static boolean isLetter(int c) { + return canCastToChar(c) && isLetter((char) c); + } + public static boolean isLetter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } @@ -95,6 +119,14 @@ public final class Character implements Comparable { return isDigit(c) || isLetter(c); } + public static boolean isLetterOrDigit(int c) { + return canCastToChar(c) && (isDigit((char) c) || isLetter((char) c)); + } + + public static boolean isLowerCase(int c) { + return canCastToChar(c) && isLowerCase((char) c); + } + public static boolean isLowerCase(char c) { return (c >= 'a' && c <= 'z'); } @@ -103,6 +135,14 @@ public final class Character implements Comparable { return (c >= 'A' && c <= 'Z'); } + public static boolean isUpperCase(int c) { + return canCastToChar(c) && isUpperCase((char) c); + } + + public static boolean isWhitespace(int c) { + return canCastToChar(c) && isWhitespace((char) c); + } + public static boolean isWhitespace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } @@ -110,4 +150,39 @@ public final class Character implements Comparable { public static boolean isSpaceChar(char c) { return isWhitespace(c); } + + public static boolean isHighSurrogate(char ch) { + return ch >= '\uD800' && ch <= '\uDBFF'; + } + + public static boolean isLowSurrogate(char ch) { + return ch >= '\uDC00' && ch <= '\uDFFF'; + } + + public static int toCodePoint(char high, char low) { + return (((high & 0x3FF) << 10) | (low & 0x3FF)) + 0x10000; + } + + public static boolean isSupplementaryCodePoint(int codePoint) { + return codePoint >= 0x10000 && codePoint <= 0x10FFFF; + } + + private static boolean canCastToChar(int codePoint) { + return (codePoint >= 0 && codePoint <= 0xFFFF); + } + + public static char[] toChars(int codePoint) { + if (isSupplementaryCodePoint(codePoint)) { + int cpPrime = codePoint - 0x10000; + int high = 0xD800 | ((cpPrime >> 10) & 0x3FF); + int low = 0xDC00 | (cpPrime & 0x3FF); + return new char[] { (char) high, (char) low }; + } + return new char[] { (char) codePoint }; + } + + public static boolean isSurrogatePair(char high, char low) { + return isHighSurrogate(high) && isLowSurrogate(low); + } + } diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index bfa2c28396..76366be3ac 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -60,16 +60,17 @@ public final class Long extends Number implements Comparable { } boolean negative = v < 0; - if (negative) v = -v; int size = (negative ? 1 : 0); - for (long n = v; n > 0; n /= radix) ++size; + for (long n = v; n != 0; n /= radix) ++size; char[] array = new char[size]; int i = array.length - 1; - for (long n = v; n > 0; n /= radix) { + for (long n = v; n != 0; n /= radix) { long digit = n % radix; + if (negative) digit = -digit; + if (digit >= 0 && digit <= 9) { array[i] = (char) ('0' + digit); } else { diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index afec95c50b..74f05c4d55 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -11,6 +11,7 @@ package java.lang; import java.io.UnsupportedEncodingException; +import java.util.regex.Pattern; public final class String implements Comparable, CharSequence { private Object data; @@ -199,14 +200,8 @@ public final class String implements Comparable, CharSequence { return -1; } - public int lastIndexOf(int c) { - for (int i = length - 1; i >= 0; --i) { - if (charAt(i) == c) { - return i; - } - } - - return -1; + public int lastIndexOf(int ch) { + return lastIndexOf(ch, length-1); } public int indexOf(String s) { @@ -303,6 +298,14 @@ public final class String implements Comparable, CharSequence { } } + public boolean startsWith(String s, int start) { + if (length >= s.length + start) { + return substring(start, s.length).compareTo(s) == 0; + } else { + return false; + } + } + public boolean endsWith(String s) { if (length >= s.length) { return substring(length - s.length).compareTo(s) == 0; @@ -429,6 +432,10 @@ public final class String implements Comparable, CharSequence { return substring(start, end); } + public boolean matches(String regex) { + return Pattern.matches(regex, this); + } + public native String intern(); public static String valueOf(Object s) { @@ -466,4 +473,14 @@ public final class String implements Comparable, CharSequence { public static String valueOf(double v) { return Double.toString(v); } + + public int lastIndexOf(int ch, int lastIndex) { + for (int i = lastIndex ; i >= 0; --i) { + if (charAt(i) == ch) { + return i; + } + } + + return -1; + } } diff --git a/classpath/java/lang/StringBuffer.java b/classpath/java/lang/StringBuffer.java index 2d7a1ff8cc..c3de7b00da 100644 --- a/classpath/java/lang/StringBuffer.java +++ b/classpath/java/lang/StringBuffer.java @@ -70,6 +70,11 @@ public class StringBuffer implements CharSequence { return this; } + public synchronized StringBuffer append(char[] b) { + sb.append(b, 0, b.length); + return this; + } + public synchronized StringBuffer insert(int i, String s) { sb.insert(i, s); return this; diff --git a/classpath/java/lang/StringBuilder.java b/classpath/java/lang/StringBuilder.java index 78cfc8c287..5b4987ec4b 100644 --- a/classpath/java/lang/StringBuilder.java +++ b/classpath/java/lang/StringBuilder.java @@ -209,6 +209,29 @@ public class StringBuilder implements CharSequence { insert(start, str); return this; } + + public int indexOf(String s) { + return indexOf(s, 0); + } + + public int indexOf(String s, int start) { + int slength = s.length(); + if (slength == 0) return start; + + for (int i = start; i < length - slength + 1; ++i) { + int j = 0; + for (; j < slength; ++j) { + if (charAt(i + j) != s.charAt(j)) { + break; + } + } + if (j == slength) { + return i; + } + } + + return -1; + } public int length() { return length; diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index 78cecb92ff..ac3ee11b3a 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -17,6 +17,7 @@ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileDescriptor; +import java.util.Properties; public abstract class System { private static Property properties; @@ -76,6 +77,14 @@ public abstract class System { return null; } + public static Properties getProperties () { + Properties prop = new Properties(); + for (Property p = properties; p != null; p = p.next) { + prop.put(p.name, p.value); + } + return prop; + } + private static native String getProperty(String name, boolean[] found); private static native String getVMProperty(String name, boolean[] found); diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 2f7826d32c..731331051d 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -20,9 +20,11 @@ public class Thread implements Runnable { private boolean interrupted; private Object sleepLock; private ClassLoader classLoader; + private String name; - public Thread(Runnable task) { + public Thread(Runnable task, String name) { this.task = task; + this.name = name; Thread current = currentThread(); @@ -39,8 +41,8 @@ public class Thread implements Runnable { classLoader = current.classLoader; } - public Thread(Runnable task, String name) { - this(task); + public Thread(Runnable task) { + this(task, "Thread["+task+"]"); } public synchronized void start() { @@ -118,4 +120,9 @@ public class Thread implements Runnable { public static native int activeCount(); public static native int enumerate(Thread[] array); + + public String getName() { + return name; + } + } diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index 4a1f577873..bf2174c447 100644 --- a/classpath/java/net/URL.java +++ b/classpath/java/net/URL.java @@ -100,6 +100,10 @@ public final class URL { super(url); } + public int getContentLength() { + return ResourceInputStream.getContentLength(url.getFile()); + } + public InputStream getInputStream() throws IOException { return new ResourceInputStream(url.getFile()); } @@ -116,6 +120,8 @@ public final class URL { } } + private static native int getContentLength(String path); + private static native long open(String path) throws IOException; private static native int read(long peer, int position) throws IOException; diff --git a/classpath/java/net/URLConnection.java b/classpath/java/net/URLConnection.java index b0c6e8a235..ab8f5619e4 100644 --- a/classpath/java/net/URLConnection.java +++ b/classpath/java/net/URLConnection.java @@ -25,6 +25,10 @@ public abstract class URLConnection { return getInputStream(); } + public int getContentLength() { + return -1; + } + public InputStream getInputStream() throws IOException { throw new UnknownServiceException(); } diff --git a/classpath/java/security/AccessController.java b/classpath/java/security/AccessController.java new file mode 100644 index 0000000000..804dfe70a7 --- /dev/null +++ b/classpath/java/security/AccessController.java @@ -0,0 +1,25 @@ +/* Copyright (c) 2008, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.security; + +/** + * No real access control is implemented here. + * + * @author zsombor + * + */ +public class AccessController { + + public static Object doPrivileged (PrivilegedAction action) { + return action.run(); + } + +} diff --git a/classpath/java/security/PrivilegedAction.java b/classpath/java/security/PrivilegedAction.java new file mode 100644 index 0000000000..5a5e54aa20 --- /dev/null +++ b/classpath/java/security/PrivilegedAction.java @@ -0,0 +1,17 @@ +/* Copyright (c) 2008, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.security; + +public interface PrivilegedAction { + + T run(); + +} diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index d51b8e6b7a..af87139c8f 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -106,4 +106,17 @@ public class Arrays { } }; } + + public static void fill(int[] array, int value) { + for (int i=0;i> BITS_PER_LONG_SHIFT; + } + + private static long bitPosition(int index) { + return 1L << (index % BITS_PER_LONG); + } + + public BitSet(int bitLength) { + if (bitLength % BITS_PER_LONG == 0) { + enlarge(longPosition(bitLength)); + } else { + enlarge(longPosition(bitLength) + 1); + } + } + + public BitSet() { + enlarge(1); + } + + public void and(BitSet otherBits) { + int max = Math.max(bits.length, otherBits.bits.length); + for (int i = 0; i < max; i++) { + bits[i] &= otherBits.bits[i]; + } + } + + public void andNot(BitSet otherBits) { + int max = Math.max(bits.length, otherBits.bits.length); + enlarge(max); + for (int i = 0; i < max; i++) { + bits[i] &= ~otherBits.bits[i]; + } + } + + public void or(BitSet otherBits) { + int max = Math.max(bits.length, otherBits.bits.length); + enlarge(max); + for (int i = 0; i < max; i++) { + bits[i] |= otherBits.bits[i]; + } + } + + public void xor(BitSet otherBits) { + int max = Math.max(bits.length, otherBits.bits.length); + enlarge(max); + for (int i = 0; i < max; i++) { + bits[i] ^= otherBits.bits[i]; + } + } + + private void enlarge(int newSize) { + if (bits == null || bits.length <= newSize) { + long[] newBits = new long[newSize + 1]; + if (bits != null) { + System.arraycopy(bits, 0, newBits, 0, bits.length); + } + bits = newBits; + } + } + + public void clear(int index) { + int pos = longPosition(index); + if (pos < bits.length) { + bits[pos] &= (MASK ^ bitPosition(index)); + } + } + + public boolean get(int index) { + int pos = longPosition(index); + if (pos < bits.length) { + return (bits[pos] & bitPosition(index)) != 0; + } + return false; + } + + public void set(int index) { + int pos = longPosition(index); + enlarge(pos); + bits[pos] |= bitPosition(index); + } + + public void set(int start, int end) { + for (int i = start; i < end; i++) { + set(i); + } + } + + public void clear(int start, int end) { + for (int i = start; i < end; i++) { + clear(i); + } + } + + public boolean isEmpty() { + for (int i = 0; i < bits.length; i++) { + if (bits[i] != 0) { + return false; + } + } + return true; + } + + public boolean intersects(BitSet otherBits) { + int max = Math.max(bits.length, otherBits.bits.length); + for (int i = 0; i < max; i++) { + if ((bits[i] & otherBits.bits[i]) != 0) { + return true; + } + } + return false; + } + + public int length() { + return bits.length << BITS_PER_LONG_SHIFT; + } + + public int nextSetBit(int fromIndex) { + return nextBit(fromIndex, false); + } + + private int nextBit(int fromIndex, boolean bitClear) { + int pos = longPosition(fromIndex); + if (pos >= bits.length) { + return -1; + } + int current = fromIndex; + do { + long currValue = bits[pos]; + if (currValue == 0) { + pos++; + current = pos << BITS_PER_LONG_SHIFT; + } else { + do { + long bitPos = bitPosition(current); + if (((currValue & bitPos) != 0) ^ bitClear) { + return current; + } else { + current++; + } + } while (current % BITS_PER_LONG != 0); + } + pos++; + } while (pos < bits.length); + + return -1; + } + + public int nextClearBit(int fromIndex) { + return nextBit(fromIndex, true); + } + +} diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 06c3b0b07b..310665567f 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -37,6 +37,14 @@ public class Properties extends Hashtable { return (String)get(key); } + public String getProperty(String key, String defaultValue) { + String value = (String) get(key); + if (value == null) { + return defaultValue; + } + return value; + } + public void setProperty(String key, String value) { put(key, value); } diff --git a/classpath/java/util/regex/Matcher.java b/classpath/java/util/regex/Matcher.java new file mode 100644 index 0000000000..58af1a707d --- /dev/null +++ b/classpath/java/util/regex/Matcher.java @@ -0,0 +1,106 @@ +/* Copyright (c) 2008, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.regex; + +/** + * This implementation is a skeleton, useful only for compilation. At runtime it + * is need to be replaced by a working implementation, for example one from the + * Apache Harmony project. + * + * @author zsombor + * + */ +public class Matcher { + + public boolean matches() { + throw new UnsupportedOperationException(); + } + + public boolean requireEnd() { + throw new UnsupportedOperationException(); + } + + public boolean hitEnd() { + throw new UnsupportedOperationException(); + } + + public boolean lookingAt() { + throw new UnsupportedOperationException(); + } + + public Matcher reset() { + throw new UnsupportedOperationException(); + } + + public Matcher reset(CharSequence input) { + throw new UnsupportedOperationException(); + } + + public int start() { + throw new UnsupportedOperationException(); + } + + public int start(int group) { + throw new UnsupportedOperationException(); + } + + public Pattern pattern() { + throw new UnsupportedOperationException(); + } + + public Matcher region(int start, int end) { + throw new UnsupportedOperationException(); + } + + public int regionEnd() { + throw new UnsupportedOperationException(); + } + + public int regionStart() { + throw new UnsupportedOperationException(); + } + + public String replaceAll(String replacement) { + throw new UnsupportedOperationException(); + } + + public String replaceFirst(String replacement) { + throw new UnsupportedOperationException(); + } + + public int end() { + throw new UnsupportedOperationException(); + } + + public int end(int group) { + throw new UnsupportedOperationException(); + } + + public boolean find() { + throw new UnsupportedOperationException(); + } + + public boolean find(int start) { + throw new UnsupportedOperationException(); + } + + public int groupCount() { + throw new UnsupportedOperationException(); + } + + public String group() { + throw new UnsupportedOperationException(); + } + + public String group(int group) { + throw new UnsupportedOperationException(); + } +} diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java new file mode 100644 index 0000000000..972f93de37 --- /dev/null +++ b/classpath/java/util/regex/Pattern.java @@ -0,0 +1,75 @@ +/* Copyright (c) 2008, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.regex; + +/** + * This implementation is a skeleton, useful only for compilation. At runtime it + * is need to be replaced by a working implementation, for example one from the + * Apache Harmony project. + * + * @author zsombor + * + */ +public class Pattern { + + public static final int UNIX_LINES = 1; + public static final int CASE_INSENSITIVE = 2; + public static final int COMMENTS = 4; + public static final int MULTILINE = 8; + public static final int LITERAL = 16; + public static final int DOTALL = 32; + public static final int UNICODE_CASE = 64; + public static final int CANON_EQ = 128; + + private int patternFlags; + private String pattern; + + protected Pattern(String pattern, int flags) { + this.pattern = pattern; + this.patternFlags = flags; + } + + public static Pattern compile(String regex) { + return new Pattern(regex, 0); + } + + public static Pattern compile(String regex, int flags) { + return new Pattern(regex, flags); + } + + public int flags() { + return patternFlags; + } + + public Matcher matcher(CharSequence input) { + throw new UnsupportedOperationException(); + } + + public static boolean matches(String regex, CharSequence input) { + return Pattern.compile(regex).matcher(input).matches(); + } + + public String pattern() { + return pattern; + } + + public static String quote(String s) { + throw new UnsupportedOperationException(); + } + + public String[] split(CharSequence input) { + throw new UnsupportedOperationException(); + } + + public String[] split(CharSequence input, int limit) { + throw new UnsupportedOperationException(); + } +} diff --git a/readme.txt b/readme.txt index fd4d549fbc..2efc5b8c84 100644 --- a/readme.txt +++ b/readme.txt @@ -142,7 +142,7 @@ for darwin-i386: (objcopy is not currently supported on this platform, so we use the binaryToMacho utility instead) $ ../build/darwin-i386-compile-fast/binaryToMacho boot.jar \ - __binary_boot_jar_start __binary_boot_jar_size > boot-jar.o + __binary_boot_jar_start __binary_boot_jar_end > boot-jar.o Step 4: Write a driver which starts the VM and runs the desired main @@ -176,40 +176,18 @@ extern "C" { } // extern "C" -#ifdef JNI_VERSION_1_6 -typedef struct JDK1_1InitArgs { - jint version; - - char **properties; - jint checkSource; - jint nativeStackSize; - jint javaStackSize; - jint minHeapSize; - jint maxHeapSize; - jint verifyMode; - char *classpath; - - jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args); - void (JNICALL *exit)(jint code); - void (JNICALL *abort)(void); - - jint enableClassGC; - jint enableVerboseGC; - jint disableAsyncGC; - jint verbose; - jboolean debugging; - jint debugPort; -} JDK1_1InitArgs; -#endif - int main(int ac, const char** av) { - JDK1_1InitArgs vmArgs; - vmArgs.version = 0x00010001; - JNI_GetDefaultJavaVMInitArgs(&vmArgs); + JavaVMInitArgs vmArgs; + vmArgs.version = JNI_VERSION_1_2; + vmArgs.nOptions = 1; + vmArgs.ignoreUnrecognized = JNI_TRUE; - vmArgs.classpath = const_cast("[bootJar]"); + JavaVMOption options[vmArgs.nOptions]; + vmArgs.options = options; + + options[0].optionString = const_cast("-Djava.class.path=[bootJar]"); JavaVM* vm; void* env; diff --git a/src/builtin.cpp b/src/builtin.cpp index df32700e42..396088dc56 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -741,6 +741,26 @@ Java_java_lang_Thread_enumerate(Thread* t, jclass, jobjectArray array) return count; } +extern "C" JNIEXPORT jint JNICALL +Java_java_net_URL_00024ResourceInputStream_getContentLength +(Thread* t, jclass, jstring path) +{ + ENTER(t, Thread::ActiveState); + + if (LIKELY(path)) { + char p[stringLength(t, *path) + 1]; + stringChars(t, *path, p); + + System::Region* r = t->m->finder->find(p); + if (r) { + jint rSize = r->length(); + r->dispose(); + return rSize; + } + } + return -1; +} + extern "C" JNIEXPORT jlong JNICALL Java_java_net_URL_00024ResourceInputStream_open (Thread* t, jclass, jstring path) diff --git a/src/common.h b/src/common.h index a02627b5d8..f0ac8f60cf 100644 --- a/src/common.h +++ b/src/common.h @@ -23,8 +23,10 @@ #undef JNIEXPORT #ifdef __MINGW32__ # define JNIEXPORT __declspec(dllexport) +# define PATH_SEPARATOR ';' #else # define JNIEXPORT __attribute__ ((visibility("default"))) +# define PATH_SEPARATOR ':' #endif #ifdef __i386__ diff --git a/src/compile.cpp b/src/compile.cpp index 3feffa8b05..6eaea5014d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2623,6 +2623,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object target = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + unsigned parameterFootprint = methodParameterFootprint(t, target); unsigned instance = parameterFootprint - 1; @@ -2661,6 +2663,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, target = findMethod(t, target, classSuper(t, class_)); } + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + compileDirectInvoke(t, frame, target); } break; @@ -2670,6 +2674,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object target = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; + assert(t, methodFlags(t, target) & ACC_STATIC); + compileDirectInvoke(t, frame, target); } break; @@ -2679,6 +2685,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object target = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + unsigned parameterFootprint = methodParameterFootprint(t, target); unsigned offset = ClassVtable + (methodOffset(t, target) * BytesPerWord); @@ -3610,21 +3618,6 @@ compareTraceElementPointers(const void* va, const void* vb) } } -intptr_t -compareMethodBounds(Thread* t, object a, object b) -{ - if (DebugMethodTree) { - fprintf(stderr, "compare %p to %p\n", - &singletonValue(t, methodCompiled(t, a), 0), - &singletonValue(t, methodCompiled(t, b), 0)); - } - - return reinterpret_cast - (&singletonValue(t, methodCompiled(t, a), 0)) - - reinterpret_cast - (&singletonValue(t, methodCompiled(t, b), 0)); -} - unsigned frameObjectMapSize(MyThread* t, object method, object map) { @@ -4255,7 +4248,7 @@ visitStack(MyThread* t, Heap::Visitor* v) } else { break; } - } + } } void @@ -5084,13 +5077,56 @@ compile(MyThread* t, object method) if (UNLIKELY(t->exception)) return; if (methodCompiled(t, method) == p->defaultThunk) { + object node; object compiled; if (methodFlags(t, method) & ACC_NATIVE) { + node = 0; compiled = p->nativeThunk; } else { Context context(t, method); compiled = compile(t, &context); if (UNLIKELY(t->exception)) return; + + PROTECT(t, compiled); + + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", + &singletonValue(t, compiled, 0)); + } + + // We can't set the MethodCompiled field on the original + // method before it is placed into the method tree, since + // another thread might call the method, from which stack + // unwinding would fail (since there is not yet an entry in + // the method tree). However, we can't insert the original + // method into the tree before setting the MethodCompiled + // field on it since we rely on that field to determine its + // position in the tree. Therefore, we insert a clone in + // its place. Later, we'll replace the clone with the + // original to save memory. + + object clone = makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodName(t, method), + methodSpec(t, method), + methodClass(t, method), + methodCode(t, method), + compiled); + + node = makeTreeNode + (t, clone, methodTreeSentinal(t), methodTreeSentinal(t)); + + PROTECT(t, node); + + methodTree(t) = treeInsertNode + (t, methodTree(t), reinterpret_cast + (&singletonValue(t, compiled, 0)), node, methodTreeSentinal(t), + compareIpToMethodBounds); } set(t, method, MethodCompiled, compiled); @@ -5100,15 +5136,8 @@ compile(MyThread* t, object method) = &singletonValue(t, compiled, 0); } - if ((methodFlags(t, method) & ACC_NATIVE) == 0) { - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", - &singletonValue(t, methodCompiled(t, method), 0)); - } - - methodTree(t) = treeInsert - (t, methodTree(t), method, methodTreeSentinal(t), - compareMethodBounds); + if (node) { + set(t, node, TreeNodeValue, method); } } } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 9d2147e432..ab0f18a304 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1845,30 +1845,49 @@ IsSameObject(Thread* t, jobject a, jobject b) } } -struct JDK1_1InitArgs { +struct JavaVMOption { + char* optionString; + void* extraInfo; +}; + +struct JavaVMInitArgs { jint version; - const char** properties; - jint checkSource; - jint nativeStackSize; - jint javaStackSize; - jint minHeapSize; - jint maxHeapSize; - jint verifyMode; - const char* classpath; - - jint (JNICALL *vfprintf)(FILE* fp, const char* format, va_list args); - void (JNICALL *exit)(jint code); - void (JNICALL *abort)(void); - - jint enableClassGC; - jint enableVerboseGC; - jint disableAsyncGC; - jint verbose; - jboolean debugging; - jint debugPort; + jint nOptions; + JavaVMOption* options; + jboolean ignoreUnrecognized; }; +int +parseSize(const char* s) +{ + unsigned length = strlen(s); + char buffer[length + 1]; + if (length == 0) { + return 0; + } else if (s[length - 1] == 'k') { + memcpy(buffer, s, length - 1); + buffer[length] = 0; + return atoi(buffer) * 1024; + } else if (s[length - 1] == 'm') { + memcpy(buffer, s, length - 1); + buffer[length] = 0; + return atoi(buffer) * 1024 * 1024; + } else { + return atoi(s); + } +} + +void +append(char** p, const char* value, unsigned length, char tail) +{ + if (length) { + memcpy(*p, value, length); + *p += length; + *((*p)++) = tail; + } +} + } // namespace namespace vm { @@ -2040,43 +2059,91 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) } // namespace vm -extern "C" JNIEXPORT jint JNICALL -JNI_GetDefaultJavaVMInitArgs(void* args) -{ - JDK1_1InitArgs* a = static_cast(args); - a->maxHeapSize = 128 * 1024 * 1024; - a->classpath = "."; - a->properties = 0; - return 0; -} - #define BUILTINS_PROPERTY "avian.builtins" #define BOOTSTRAP_PROPERTY "avian.bootstrap" +#define CLASSPATH_PROPERTY "java.class.path" +#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" +#define BOOTCLASSPATH_OPTION "bootclasspath" +#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" + +extern "C" JNIEXPORT jint JNICALL +JNI_GetDefaultJavaVMInitArgs(void*) +{ + return 0; +} extern "C" JNIEXPORT jint JNICALL JNI_CreateJavaVM(Machine** m, Thread** t, void* args) { - JDK1_1InitArgs* a = static_cast(args); + JavaVMInitArgs* a = static_cast(args); + unsigned heapLimit = 0; const char* builtins = 0; const char* bootLibrary = 0; - if (a->properties) { - for (const char** p = a->properties; *p; ++p) { - if (strncmp(*p, BUILTINS_PROPERTY "=", + const char* classpath = 0; + const char* bootClasspathPrepend = ""; + const char* bootClasspath = ""; + const char* bootClasspathAppend = ""; + + for (int i = 0; i < a->nOptions; ++i) { + if (strncmp(a->options[i].optionString, "-X", 2) == 0) { + const char* p = a->options[i].optionString + 2; + if (strncmp(p, "mx", 2) == 0) { + heapLimit = parseSize(p + 2); + } else if (strncmp(p, BOOTCLASSPATH_PREPEND_OPTION ":", + sizeof(BOOTCLASSPATH_PREPEND_OPTION)) == 0) + { + bootClasspathPrepend = p + sizeof(BOOTCLASSPATH_PREPEND_OPTION); + } else if (strncmp(p, BOOTCLASSPATH_OPTION ":", + sizeof(BOOTCLASSPATH_OPTION)) == 0) + { + bootClasspath = p + sizeof(BOOTCLASSPATH_OPTION); + } else if (strncmp(p, BOOTCLASSPATH_APPEND_OPTION ":", + sizeof(BOOTCLASSPATH_APPEND_OPTION)) == 0) + { + bootClasspathAppend = p + sizeof(BOOTCLASSPATH_APPEND_OPTION); + } + } else if (strncmp(a->options[i].optionString, "-D", 2) == 0) { + const char* p = a->options[i].optionString + 2; + if (strncmp(p, BUILTINS_PROPERTY "=", sizeof(BUILTINS_PROPERTY)) == 0) { - builtins = (*p) + sizeof(BUILTINS_PROPERTY); - } else if (strncmp(*p, BOOTSTRAP_PROPERTY "=", + builtins = p + sizeof(BUILTINS_PROPERTY); + } else if (strncmp(p, BOOTSTRAP_PROPERTY "=", sizeof(BOOTSTRAP_PROPERTY)) == 0) { - bootLibrary = (*p) + sizeof(BOOTSTRAP_PROPERTY); + bootLibrary = p + sizeof(BOOTSTRAP_PROPERTY); + } else if (strncmp(p, CLASSPATH_PROPERTY "=", + sizeof(CLASSPATH_PROPERTY)) == 0) + { + classpath = p + sizeof(CLASSPATH_PROPERTY); } + + // todo: add properties to VM } } + if (heapLimit == 0) heapLimit = 128 * 1024 * 1024; + + if (classpath == 0) classpath = "."; + + unsigned bcppl = strlen(bootClasspathPrepend); + unsigned bcpl = strlen(bootClasspath); + unsigned bcpal = strlen(bootClasspathAppend); + unsigned cpl = strlen(classpath); + + unsigned classpathBufferSize = bcppl + bcpl + bcpal + cpl + 4; + char classpathBuffer[classpathBufferSize]; + char* classpathPointer = classpathBuffer; + + append(&classpathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); + append(&classpathPointer, bootClasspath, bcpl, PATH_SEPARATOR); + append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR); + append(&classpathPointer, classpath, cpl, 0); + System* s = makeSystem(); - Heap* h = makeHeap(s, a->maxHeapSize); - Finder* f = makeFinder(s, a->classpath, bootLibrary); + Heap* h = makeHeap(s, heapLimit); + Finder* f = makeFinder(s, classpathBuffer, bootLibrary); Processor* p = makeProcessor(s, h); *m = new (h->allocate(sizeof(Machine))) diff --git a/src/machine.cpp b/src/machine.cpp index fd52aa486b..1e6556e3f5 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -168,7 +168,7 @@ killZombies(Thread* t, Thread* o) unsigned footprint(Thread* t) { - unsigned n = t->heapOffset + t->heapIndex; + unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex; for (Thread* c = t->child; c; c = c->peer) { n += footprint(c); @@ -1847,7 +1847,7 @@ Thread::init() threadPeer(this, javaThread) = reinterpret_cast(this); } else { this->javaThread = makeThread - (this, reinterpret_cast(this), 0, 0, 0, 0, m->loader); + (this, reinterpret_cast(this), 0, 0, 0, 0, m->loader, 0); } } diff --git a/src/main.cpp b/src/main.cpp index f2557e3a68..b784314579 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,40 +20,20 @@ # define PATH_SEPARATOR ':' #endif -#ifdef JNI_VERSION_1_6 -// todo: use JavaVMInitArgs instead -typedef struct JDK1_1InitArgs { - jint version; - - char **properties; - jint checkSource; - jint nativeStackSize; - jint javaStackSize; - jint minHeapSize; - jint maxHeapSize; - jint verifyMode; - char *classpath; - - jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args); - void (JNICALL *exit)(jint code); - void (JNICALL *abort)(void); - - jint enableClassGC; - jint enableVerboseGC; - jint disableAsyncGC; - jint verbose; - jboolean debugging; - jint debugPort; -} JDK1_1InitArgs; -#endif - namespace { void usageAndExit(const char* name) { - fprintf(stderr, "usage: %s [-cp ] [-Xmx] " - " [ ...]\n", name); + fprintf + (stderr, "usage: %s\n" + "\t[{-cp|-classpath} ]\n" + "\t[-Xmx]\n" + "\t[-Xbootclasspath/p:]\n" + "\t[-Xbootclasspath:]\n" + "\t[-Xbootclasspath/a:]\n" + "\t[-D= ...]\n" + "\t [ ...]\n", name); exit(-1); } @@ -62,22 +42,25 @@ usageAndExit(const char* name) int main(int ac, const char** av) { - JDK1_1InitArgs vmArgs; - vmArgs.version = 0x00010001; - JNI_GetDefaultJavaVMInitArgs(&vmArgs); + JavaVMInitArgs vmArgs; + vmArgs.version = JNI_VERSION_1_2; + vmArgs.nOptions = 1; + vmArgs.ignoreUnrecognized = JNI_TRUE; const char* class_ = 0; int argc = 0; const char** argv = 0; - int propertyCount = 0; + const char* classpath = "."; for (int i = 1; i < ac; ++i) { - if (strcmp(av[i], "-cp") == 0) { - vmArgs.classpath = const_cast(av[++i]); - } else if (strncmp(av[i], "-Xmx", 4) == 0) { - vmArgs.maxHeapSize = atoi(av[i] + 4); - } else if (strncmp(av[i], "-D", 2) == 0) { - ++ propertyCount; + if (strcmp(av[i], "-cp") == 0 + or strcmp(av[i], "-classpath") == 0) + { + classpath = av[++i]; + } else if (strncmp(av[i], "-X", 2) == 0 + or strncmp(av[i], "-D", 2) == 0) + { + ++ vmArgs.nOptions; } else { class_ = av[i++]; if (i < ac) { @@ -88,35 +71,53 @@ main(int ac, const char** av) } } +#ifdef BOOT_LIBRARY + ++ vmArgs.nOptions; +#endif + #ifdef BOOT_CLASSPATH - unsigned size = sizeof(BOOT_CLASSPATH) + 1 + strlen(vmArgs.classpath); - char classpath[size]; - snprintf(classpath, size, "%s%c%s", - BOOT_CLASSPATH, PATH_SEPARATOR, vmArgs.classpath); - vmArgs.classpath = classpath; + ++ vmArgs.nOptions; +#endif + + JavaVMOption options[vmArgs.nOptions]; + vmArgs.options = options; + + unsigned optionIndex = 0; + +#ifdef BOOT_CLASSPATH + options[optionIndex++].optionString + = const_cast("-Xbootclasspath:" BOOT_CLASSPATH); #endif #ifdef BOOT_LIBRARY - const int BootPropertyCount = 1; -#else - const int BootPropertyCount = 0; + options[optionIndex++].optionString + = const_cast("-Davian.bootstrap=" BOOT_LIBRARY); #endif - const char* properties[propertyCount + BootPropertyCount + 1]; - properties[propertyCount + BootPropertyCount] = 0; +#define CLASSPATH_PROPERTY "-Djava.class.path=" + + unsigned classpathSize = strlen(classpath); + unsigned classpathPropertyBufferSize + = sizeof(CLASSPATH_PROPERTY) + classpathSize; + + char classpathPropertyBuffer[classpathPropertyBufferSize]; + memcpy(classpathPropertyBuffer, + CLASSPATH_PROPERTY, + sizeof(CLASSPATH_PROPERTY) - 1); + memcpy(classpathPropertyBuffer + sizeof(CLASSPATH_PROPERTY) - 1, + classpath, + classpathSize + 1); + + options[optionIndex++].optionString = classpathPropertyBuffer; + for (int i = 1; i < ac; ++i) { - if (strncmp(av[i], "-D", 2) == 0) { - properties[--propertyCount] = av[i] + 2; + if (strncmp(av[i], "-X", 2) == 0 + or strncmp(av[i], "-D", 2) == 0) + { + options[optionIndex++].optionString = const_cast(av[i]); } } -#ifdef BOOT_LIBRARY - properties[propertyCount + BootPropertyCount - 1] - = "avian.bootstrap=" BOOT_LIBRARY; -#endif - - vmArgs.properties = const_cast(properties); - if (class_ == 0) { usageAndExit(av[0]); } diff --git a/src/util.cpp b/src/util.cpp index a929c9e153..f1a47206c1 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -59,8 +59,8 @@ cloneTreeNode(Thread* t, object n) } object -treeFind(Thread* t, object old, object node, object sentinal, - intptr_t (*compare)(Thread* t, object a, object b)) +treeFind(Thread* t, object old, intptr_t key, object node, object sentinal, + intptr_t (*compare)(Thread* t, intptr_t key, object b)) { PROTECT(t, old); PROTECT(t, node); @@ -78,8 +78,7 @@ treeFind(Thread* t, object old, object node, object sentinal, while (old != sentinal) { ancestors = makePair(t, new_, ancestors); - intptr_t difference = compare - (t, getTreeNodeValue(t, node), getTreeNodeValue(t, old)); + intptr_t difference = compare(t, key, getTreeNodeValue(t, old)); if (difference < 0) { old = treeNodeLeft(t, old); @@ -302,6 +301,12 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), newArray = makeArray(t, newLength, true); + if (oldArray != hashMapArray(t, map)) { + // a resize was performed during a GC via the makeArray call + // above; nothing left to do + return; + } + if (oldArray) { bool weak = objectClass(t, map) == arrayBody(t, t->m->types, Machine::WeakHashMapType); @@ -333,7 +338,7 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), void hashMapInsert(Thread* t, object map, object key, object value, - uint32_t (*hash)(Thread*, object)) + uint32_t (*hash)(Thread*, object)) { // note that we reinitialize the array and index variables whenever // an allocation (and thus possibly a collection) occurs, in case @@ -536,20 +541,16 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal, } object -treeInsert(Thread* t, object tree, object value, object sentinal, - intptr_t (*compare)(Thread* t, object a, object b)) +treeInsertNode(Thread* t, object tree, intptr_t key, object node, + object sentinal, + intptr_t (*compare)(Thread* t, intptr_t key, object b)) { PROTECT(t, tree); PROTECT(t, sentinal); - object node = makeTreeNode(t, value, sentinal, sentinal); - - object path = treeFind(t, tree, node, sentinal, compare); - if (treePathFresh(t, path)) { - return treeAdd(t, path); - } else { - return tree; - } + object path = treeFind(t, tree, key, node, sentinal, compare); + expect(t, treePathFresh(t, path)); + return treeAdd(t, path); } } // namespace vm diff --git a/src/util.h b/src/util.h index ce0f81a63b..adf8487723 100644 --- a/src/util.h +++ b/src/util.h @@ -88,8 +88,9 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); object -treeInsert(Thread* t, object tree, object value, object sentinal, - intptr_t (*compare)(Thread* t, object a, object b)); +treeInsertNode(Thread* t, object tree, intptr_t key, object node, + object sentinal, + intptr_t (*compare)(Thread* t, intptr_t key, object b)); } // vm diff --git a/test/BitsetTest.java b/test/BitsetTest.java new file mode 100644 index 0000000000..5f4793e205 --- /dev/null +++ b/test/BitsetTest.java @@ -0,0 +1,64 @@ +import java.util.BitSet; + +public class BitsetTest { + + public static void main(String[] args) { + BitSet bits = new BitSet(16); + bits.set(5); + bits.set(1); + + BitSet other = new BitSet(16); + other.set(5); + + assertTrue("bit 1 is set", bits.get(1)); + assertTrue("bit 5 is set", bits.get(5)); + assertTrue("bit 0 is not set", !bits.get(0)); + assertTrue("bit 16 is not set", !bits.get(16)); + + bits.and(other); + + assertTrue("bit 5 is set", bits.get(5)); + assertTrue("bit 1 is not set", !bits.get(1)); + + bits.set(100); + + assertTrue("bit 100 is set", bits.get(100)); + assertTrue("bit 101 is not set", !bits.get(101)); + + other.set(101); + + bits.or(other); + + assertTrue("bit 101 is set", bits.get(101)); + + assertEquals("first bit is 5", 5, bits.nextSetBit(0)); + assertEquals("first bit is 5 from 3", 5, bits.nextSetBit(4)); + assertEquals("first bit is 5 from 5", 5, bits.nextSetBit(5)); + assertEquals("second bit is 100", 100, bits.nextSetBit(6)); + assertEquals("second bit is 100 from 100", 100, bits.nextSetBit(100)); + assertEquals("third bit is 101", 101, bits.nextSetBit(101)); + assertEquals("there is no 4th bit", -1, bits.nextSetBit(102)); + + assertEquals("first empty bit is 0", 0, bits.nextClearBit(0)); + assertEquals("after 5, 6 is empty", 6, bits.nextClearBit(5)); + assertEquals("after 100, 102 is empty", 102, bits.nextClearBit(100)); + + } + + static void assertTrue(String msg, boolean flag) { + if (flag) { + System.out.println(msg + " : OK."); + } else { + throw new RuntimeException("Error:"+msg); + } + } + + static void assertEquals(String msg, int expected, int actual) { + if (expected==actual) { + System.out.println(msg + " : OK. ["+actual+']'); + } else { + throw new RuntimeException("Error:"+msg+" expected:"+expected+", actual:"+actual); + } + } + +} diff --git a/test/Misc.java b/test/Misc.java index c9ce726936..5be739c5d5 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -102,7 +102,10 @@ public class Misc { expect(foo > 0); } - expect(String.valueOf(25214903884l).equals("25214903884")); + expect(String.valueOf(25214903884L).equals("25214903884")); + + expect(String.valueOf(-9223372036854775808L).equals + ("-9223372036854775808")); { boolean p = true; int[] array = new int[] { 1, 2 };