diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 740d5199c6..abc7684634 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -37,10 +37,12 @@ # define OPEN_MASK O_BINARY # ifdef _MSC_VER -# define S_ISREG(x) ((x) | _S_IFREG) -# define S_ISDIR(x) ((x) | _S_IFDIR) +# define S_ISREG(x) ((x) & _S_IFREG) +# define S_ISDIR(x) ((x) & _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE +# define W_OK 2 +# define R_OK 4 # else # define OPEN _wopen # define CREAT _wcreat @@ -331,7 +333,7 @@ Java_java_io_File_length(JNIEnv* e, jclass, jstring path) } } - return -1; + return 0; } extern "C" JNIEXPORT void JNICALL diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index 520b676a29..a720fac6a0 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -39,10 +39,34 @@ public class PrintStream extends OutputStream { print(String.valueOf(o)); } + public void print(boolean v) { + print(String.valueOf(v)); + } + public void print(char c) { print(String.valueOf(c)); } + public void print(int v) { + print(String.valueOf(v)); + } + + public void print(long v) { + print(String.valueOf(v)); + } + + public void print(float v) { + print(String.valueOf(v)); + } + + public void print(double v) { + print(String.valueOf(v)); + } + + public void print(char[] s) { + print(String.valueOf(s)); + } + public synchronized void println(String s) { try { out.write(s.getBytes()); @@ -62,9 +86,33 @@ public class PrintStream extends OutputStream { println(String.valueOf(o)); } + public void println(boolean v) { + println(String.valueOf(v)); + } + public void println(char c) { println(String.valueOf(c)); } + + public void println(int v) { + println(String.valueOf(v)); + } + + public void println(long v) { + println(String.valueOf(v)); + } + + public void println(float v) { + println(String.valueOf(v)); + } + + public void println(double v) { + println(String.valueOf(v)); + } + + public void println(char[] s) { + println(String.valueOf(s)); + } public void write(int c) throws IOException { out.write(c); diff --git a/classpath/java/io/Reader.java b/classpath/java/io/Reader.java index acbf42ffd2..a09c8a24e9 100644 --- a/classpath/java/io/Reader.java +++ b/classpath/java/io/Reader.java @@ -28,5 +28,17 @@ public abstract class Reader { public abstract int read(char[] buffer, int offset, int length) throws IOException; + public boolean markSupported() { + return false; + } + + public void mark(int readAheadLimit) throws IOException { + throw new IOException("mark not supported"); + } + + public void reset() throws IOException { + throw new IOException("reset not supported"); + } + public abstract void close() throws IOException; } diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index f696037561..88025280e8 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -109,6 +109,15 @@ public final class Character implements Comparable { } } + public static char forDigit(int digit, int radix) { + if (MIN_RADIX <= radix && radix <= MAX_RADIX) { + if (0 <= digit && digit < radix) { + return (char) (digit < 10 ? digit + '0' : digit + 'a' - 10); + } + } + return 0; + } + public static boolean isLetter(int c) { return canCastToChar(c) && isLetter((char) c); } diff --git a/classpath/java/lang/Package.java b/classpath/java/lang/Package.java index 507a240a3e..5cd9b9547e 100644 --- a/classpath/java/lang/Package.java +++ b/classpath/java/lang/Package.java @@ -43,4 +43,8 @@ public class Package { this.sealed = sealed; this.loader = loader; } + + public String getName() { + return name; + } } diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 5a1d4a8c47..16f291a134 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -33,6 +33,14 @@ public class TreeSet extends AbstractSet implements Collection { } }); } + + public TreeSet(Collection collection) { + this(); + + for (T item: collection) { + add(item); + } + } public Iterator iterator() { return new MyIterator(set.first()); diff --git a/makefile b/makefile index ef5fb8b04e..5b34b5051b 100644 --- a/makefile +++ b/makefile @@ -353,7 +353,8 @@ ifdef msvc ld = "$(msvc)/BIN/link.exe" mt = "mt.exe" cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ - -DUSE_ATOMIC_OPERATIONS \ + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" shared = -dll diff --git a/readme.txt b/readme.txt index f8b7a51e06..0f0ad44bb7 100644 --- a/readme.txt +++ b/readme.txt @@ -187,7 +187,7 @@ C++ portions of the VM, while the assembly code and helper tools are built using GCC. The MSVC build has been tested with Visual Studio Express Edition -versions 8 and 9. Other versions may also work. +versions 8, 9, and 10. Other versions may also work. To build with MSVC, install Cygwin as described above and set the following environment variables: @@ -442,7 +442,10 @@ For boot image builds: space in the executable than the equivalent class files. In practice, this can make the executable 30-50% larger. Also, AOT compilation does not yet yield significantly faster or smaller code - than JIT compilation. + than JIT compilation. Finally, floating point code may be slower + on 32-bit x86 since the compiler cannot assume SSE2 support will be + available at runtime, and the x87 FPU is not supported except via + out-of-line helper functions. Note you can use ProGuard without using a boot image and vice-versa, as desired. @@ -462,7 +465,7 @@ Step 2: Create a stage1 directory and extract the contents of the class library jar into it. $ mkdir stage1 - $ (cd stage1 && jar xf ../../build/${platform}-${arch}/classpath.jar) + $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) Step 3: Build the Java code and add it to stage1. @@ -498,10 +501,10 @@ Step 6: Build the boot image. Step 7: Make an object file out of the boot image. - $ ../build/${platform}-${arch}/binaryToObject \ + $ ../build/linux-i386-bootimage/binaryToObject \ bootimage.bin bootimage-bin.o \ _binary_bootimage_bin_start _binary_bootimage_bin_end \ - ${platform} ${arch} 8 writable executable + linux i386 8 writable executable Step 8: Write a driver which starts the VM and runs the desired main method. Note the bootimageBin function, which will be called by the diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 4bd1f8a33d..f267232ee3 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -405,6 +405,41 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, set(t, type(t, Machine::JdoubleType), ClassName, name); } + // resolve primitive array classes in case they are needed at + // runtime: + { resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[B"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[Z"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[S"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[C"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[I"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[J"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[F"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[D"), true); + if (t->exception) return; + } + collect(t, Heap::MajorCollection); uintptr_t* heap = static_cast diff --git a/src/finder.cpp b/src/finder.cpp index 543c45e312..b0e25ef82a 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -458,7 +458,7 @@ class JarIndex { RUNTIME_ARRAY_BODY(n)[length] = '/'; RUNTIME_ARRAY_BODY(n)[length + 1] = 0; - node = findNode(n); + node = findNode(RUNTIME_ARRAY_BODY(n)); if (node) { return System::TypeDirectory; } else { diff --git a/src/machine.cpp b/src/machine.cpp index 9a8116d165..cd7c40cf51 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1842,7 +1842,16 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) return c; } else { - return makeArrayClass(t, loader, spec, throw_); + PROTECT(t, loader); + PROTECT(t, spec); + + c = findLoadedClass(t, root(t, Machine::BootLoader), spec); + + if (c) { + return c; + } else { + return makeArrayClass(t, loader, spec, throw_); + } } } diff --git a/src/main.cpp b/src/main.cpp index 8cdb435dd0..9996e6078d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,13 @@ extern "C" void __cxa_pure_virtual(void) { abort(); } // we link against a System implmentation, which requires this at link // time, but it should not be used at runtime: extern "C" uint64_t -vmNativeCall(void*, void*, unsigned, unsigned) { abort(); } +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); + // abort is not declared __declspec(noreturn) on MSVC, so we have to + // pretend it might return to make the compiler happy: + return 0; +} #endif // BOOT_LIBRARY diff --git a/src/process.cpp b/src/process.cpp index b364598eb5..b3a25ebe8e 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -206,12 +206,12 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, object resolveNativeMethod(Thread* t, object method) { - void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3); + void* p = resolveNativeMethod(t, method, "Avian_", 6, 3); if (p) { return makeNative(t, p, true); } - p = ::resolveNativeMethod(t, method, "Java_", 5, -1); + p = resolveNativeMethod(t, method, "Java_", 5, -1); if (p) { return makeNative(t, p, false); } diff --git a/test/DefineClass.java b/test/DefineClass.java index 0b72cd5b95..ea3b6362ae 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -4,7 +4,6 @@ import java.io.FileInputStream; public class DefineClass { private static File findClass(String name, File directory) { - File[] files = directory.listFiles(); for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().equals(name + ".class")) { @@ -50,7 +49,7 @@ public class DefineClass { } public static void main(String[] args) throws Exception { - testStatic(); + //testStatic(); testDerived(); } @@ -72,6 +71,7 @@ public class DefineClass { public abstract static class Base { public int foo; + public int[] array; public void bar() { } diff --git a/test/FileOutput.java b/test/FileOutput.java index fa2cc0965e..539b73fc59 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -4,6 +4,10 @@ import java.io.File; import java.io.IOException; public class FileOutput { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + private static void test(boolean appendFirst) throws IOException { try { FileOutputStream f = new FileOutputStream("test.txt", appendFirst); @@ -21,6 +25,7 @@ public class FileOutput { while ((c = in.read(buffer, offset, buffer.length - offset)) != -1) { offset += c; } + in.close(); if (! "Hello world!\nHello world again!".equals (new String(buffer, 0, offset))) @@ -28,11 +33,13 @@ public class FileOutput { throw new RuntimeException(); } } finally { - new File("test.txt").delete(); + expect(new File("test.txt").delete()); } } public static void main(String[] args) throws IOException { + expect(new File("nonexistent-file").length() == 0); + test(false); test(true); } diff --git a/test/Misc.java b/test/Misc.java index 8a501392c7..7ff2f25378 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -227,5 +227,13 @@ public class Misc { } System.out.println(new java.util.Date().toString()); + + System.out.println('x'); + System.out.println(true); + System.out.println(42); + System.out.println(123456789012345L); + System.out.println(75.62); + System.out.println(75.62d); + System.out.println(new char[] { 'h', 'i' }); } } diff --git a/test/Strings.java b/test/Strings.java index 6b993bcb4f..d98c1f13f9 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -71,5 +71,11 @@ public class Strings { sb.append('$'); sb.append('2'); expect(sb.substring(1).equals("2")); + + expect(Character.forDigit(Character.digit('0', 10), 10) == '0'); + expect(Character.forDigit(Character.digit('9', 10), 10) == '9'); + expect(Character.forDigit(Character.digit('b', 16), 16) == 'b'); + expect(Character.forDigit(Character.digit('f', 16), 16) == 'f'); + expect(Character.forDigit(Character.digit('z', 36), 36) == 'z'); } } diff --git a/test/Tree.java b/test/Tree.java index ded42a27ea..12f1e8fa08 100644 --- a/test/Tree.java +++ b/test/Tree.java @@ -1,6 +1,8 @@ import java.util.Comparator; import java.util.TreeSet; import java.util.TreeMap; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Iterator; @@ -87,5 +89,13 @@ public class Tree { map.put("y", "Y"); isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); + + Collection list = new ArrayList(); + list.add(7); + list.add(2); + list.add(9); + list.add(2); + + isEqual(printList(new TreeSet(list)), "2, 7, 9"); } } diff --git a/test/Zip.java b/test/Zip.java index 8862e767c7..9b34444023 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -7,7 +7,6 @@ import java.util.zip.ZipEntry; public class Zip { private static String findJar(File directory) { - File[] files = directory.listFiles(); for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().endsWith(".jar")) { diff --git a/vm.pro b/vm.pro index e382722b5a..2cdd1baef5 100644 --- a/vm.pro +++ b/vm.pro @@ -117,3 +117,9 @@ -keepclassmembers class java.lang.Object { protected java.lang.Object clone(); } + +# called by name in the VM: + +-keepclassmembers class java.lang.ClassLoader { + public java.lang.Class loadClass(java.lang.String); + }