diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..e2d152d5f2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +language: cpp +script: "make test" diff --git a/README.md b/README.md new file mode 100644 index 0000000000..f01811b4e1 --- /dev/null +++ b/README.md @@ -0,0 +1,732 @@ +Avian - A lightweight Java Virtual Machine (JVM) +================================================ + +[![Build Status](https://travis-ci.org/ReadyTalk/avian.png?branch=master)](https://travis-ci.org/ReadyTalk/avian) + +Quick Start +----------- + +#### on Linux: + $ export JAVA_HOME=/usr/local/java # or wherever you have the JDK installed + $ make + $ build/linux-i386/avian -cp build/linux-i386/test Hello + +#### on Mac OS X: + $ export JAVA_HOME=/Library/Java/Home + $ make + $ build/darwin-i386/avian -cp build/darwin-i386/test Hello + +#### on Windows (MSYS): + $ git clone git@github.com:ReadyTalk/win32.git ../win32 + $ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07" + $ make + $ build/windows-i386/avian -cp build/windows-i386/test Hello + +#### on Windows (Cygwin): + $ git clone git@github.com:ReadyTalk/win32.git ../win32 + $ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07" + $ make + $ build/windows-i386/avian -cp build/windows-i386/test Hello + +Adjust JAVA_HOME according to your system, but be sure to use forward +slashes in the path. + + +Introduction +------------ + +Avian is a lightweight virtual machine and class library designed to +provide a useful subset of Java's features, suitable for building +self-contained applications. More information is available at the +project [web site](http://oss.readytalk.com/avian). + +If you have any trouble building, running, or embedding Avian, please +post a message to our [discussion group](http://groups.google.com/group/avian). + +That's also the place for any other questions, comments, or +suggestions you might have. + + +Supported Platforms +------------------- + +Avian can currently target the following platforms: + + * Linux (i386, x86_64, ARM, and 32-bit PowerPC) + * Windows (i386 and x86_64) + * Mac OS X (i386, x86_64 and 32-bit PowerPC) + * Apple iOS (i386 and ARM) + + +Building +-------- + +Build requirements include: + + * GNU make 3.80 or later + * GCC 3.4 or later (4.5.1 or later for Windows/x86_64) + or LLVM Clang 3.1 or later (see use-clang option below) + * JDK 1.5 or later + * MinGW 3.4 or later (only if compiling for Windows) + * zlib 1.2.3 or later + +Earlier versions of some of these packages may also work but have not +been tested. + +The build is directed by a single makefile and may be influenced via +certain flags described below, all of which are optional. + + $ make \ + platform={linux,windows,darwin} \ + arch={i386,x86_64,powerpc,arm} \ + process={compile,interpret} \ + mode={debug,debug-fast,fast,small} \ + lzma= \ + ios={true,false} \ + bootimage={true,false} \ + heapdump={true,false} \ + tails={true,false} \ + continuations={true,false} \ + use-clang={true,false} \ + openjdk= \ + openjdk-src= + + * `platform` - the target platform + * _default:_ output of $(uname -s | tr [:upper:] [:lower:]), +normalized in some cases (e.g. CYGWIN_NT-5.1 -> windows) + + * `arch` - the target architecture + * _default:_ output of $(uname -m), normalized in some cases +(e.g. i686 -> i386) + + * `process` - choice between pure interpreter or JIT compiler + * _default:_ compile + + * `mode` - which set of compilation flags to use to determine +optimization level, debug symbols, and whether to enable +assertions + * _default:_ fast + + * `lzma` - if set, support use of LZMA to compress embedded JARs and +boot images. The value of this option should be a directory +containing a recent LZMA SDK (available [here](http://www.7-zip.org/sdk.html)). Currently, only version 9.20 of +the SDK has been tested, but other versions might work. + * _default:_ not set + + * `ios` - if true, cross-compile for iOS on OS X. Note that +non-jailbroken iOS devices do not allow JIT compilation, so only +process=interpret or bootimage=true builds will run on such +devices. See [here](https://github.com/ReadyTalk/hello-ios) for an +example of an Xcode project for iOS which uses Avian. + * _default:_ false + + * `bootimage` - if true, create a boot image containing the pre-parsed +class library and ahead-of-time compiled methods. This option is +only valid for process=compile builds. Note that you may need to +specify both build-arch=x86_64 and arch=x86_64 on 64-bit systems +where "uname -m" prints "i386". + * _default:_ false + + * `heapdump` - if true, implement avian.Machine.dumpHeap(String), +which, when called, will generate a snapshot of the heap in a +simple, ad-hoc format for memory profiling purposes. See +heapdump.cpp for details. + * _default:_ false + + * `tails` - if true, optimize each tail call by replacing the caller's +stack frame with the callee's. This convention ensures proper +tail recursion, suitable for languages such as Scheme. This +option is only valid for process=compile builds. + * _default:_ false + + * `continuations` - if true, support continuations via the +avian.Continuations methods callWithCurrentContinuation and +dynamicWind. See Continuations.java for details. This option is +only valid for process=compile builds. + * _default:_ false + + * `use-clang` - if true, use LLVM's clang instead of GCC to build. +Note that this does not currently affect cross compiles, only +native builds. + * _default:_ false + + * `openjdk` - if set, use OpenJDK class library instead of the default +Avian class library. See "Building with the OpenJDK Class +Library" below for details. + * _default:_ not set + + * `openjdk-src` - if this and the openjdk option above are both set, +build an embeddable VM using the OpenJDK class library. The JNI +components of the OpenJDK class library will be built from the +sources found under the specified directory. See "Building with +the OpenJDK Class Library" below for details. + * _default:_ not set + +These flags determine the name of the directory used for the build. +The name always starts with _${platform}-${arch}_, and each non-default +build option is appended to the name. For example, a debug build with +bootimage enabled on Linux/i386 would be built in +_build/linux-i386-debug-bootimage_. This allows you to build with +several different sets of options independently and even +simultaneously without doing a clean build each time. + +If you are compiling for Windows, you may either cross-compile using +MinGW or build natively on Windows under MSYS or Cygwin. + +#### Installing MSYS: + + __1.__ Download and install the current MinGW and MSYS packages from + mingw.org, selecting the C and C++ compilers when prompted. Use the + post-install script to create the filesystem link to the compiler. + + __2.__ Download GNU Make 3.81 from the MSYS download page + (make-3.81-MSYS-1.0.11-2.tar.bz2) and extract the tar file into + _e.g. c:/msys/1.0_. + +#### Installing Cygwin: + + __1.__ Download and run setup.exe from [cygwin's website](http://www.cygwin.com), installing the base + system and these packages: make, gcc-mingw-g++, + mingw64-i686-gcc-g++, mingw64-x86_64-gcc-g++, and (optionally) git. + +You may also find our win32 repository useful: (run this from the +directory containing the avian directory) + + $ git clone git@github.com:ReadyTalk/win32.git + +This gives you the Windows JNI headers, zlib headers and library, and +a few other useful libraries like OpenSSL, libjpeg, and libpng. +There's also a win64 repository for 64-bit builds: + + $ git clone git@github.com:ReadyTalk/win64.git + + +Building with the Microsoft Visual C++ Compiler +----------------------------------------------- + +You can also build using the MSVC compiler, which makes debugging with +tools like WinDbg and Visual Studio much easier. Note that you will +still need to have GCC installed - MSVC is only used to compile the +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, 9, and 10. Other versions may also work. + +To build with MSVC, install Cygwin as described above and set the +following environment variables: + + $ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/VCPackages:/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem" + $ export LIBPATH="C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;" + $ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 9.0\VC" + $ export LIB="C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;" + $ export INCLUDE="C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include;" + +Adjust these definitions as necessary according to your MSVC +installation. + +Finally, build with the msvc flag set to the MSVC tool directory: + + $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" + +Building with the OpenJDK Class Library +--------------------------------------- + +By default, Avian uses its own lightweight class library. However, +that library only contains a relatively small subset of the classes +and methods included in the JRE. If your application requires +features beyond that subset, you may want to tell Avian to use +OpenJDK's class library instead. To do so, specify the directory +where OpenJDK is installed, e.g.: + + $ make openjdk=/usr/lib/jvm/java-7-openjdk + +This will build Avian as a conventional JVM (e.g. libjvm.so) which +loads its boot class library and native libraries (e.g. libjava.so) +from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. To run an +application in this configuration, you'll need to make sure the VM is +in your library search path. For example: + + $ LD_LIBRARY_PATH=build/linux-x86_64-openjdk \ + build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ + com.example.MyApplication + +Alternatively, you can enable a stand-alone build using OpenJDK by +specifying the location of the OpenJDK source code, e.g.: + + $ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../jdk7/jdk/src + +You must ensure that the path specified for openjdk-src does not have +any spaces in it; make gets confused when dependency paths include +spaces, and we haven't found away around that except to avoid paths +with spaces entirely. + +The result of such a build is a self-contained binary which does not +depend on external libraries, jars, or other files. In this case, the +specified paths are used only at build time; anything needed at +runtime is embedded in the binary. Thus, the process of running an +application is simplified: + + $ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \ + com.example.MyApplication + +Note that the resulting binary will be very large due to the size of +OpenJDK's class library. This can be mitigated using UPX, preferably +an LZMA-enabled version: + + $ upx --lzma --best build/linux-x86_64-openjdk-src/avian + +You can reduce the size futher for embedded builds by using ProGuard +and the supplied openjdk.pro configuration file (see "Embedding with +ProGuard and a Boot Image" below). Note that you'll still need to use +vm.pro in that case -- openjdk.pro just adds additional constraints +specific to the OpenJDK port. Also see app.mk in +_git://oss.readytalk.com/avian-swt-examples.git_ for an example of using +Avian, OpenJDK, ProGuard, and UPX in concert. + +Here are some examples of how to install OpenJDK and build Avian with +it on various OSes: + +#### Debian-based Linux: +_Conventional build:_ + + $ apt-get install openjdk-7-jdk + $ make openjdk=/usr/lib/jvm/java-7-openjdk test + +_Stand-alone build:_ + + $ apt-get install openjdk-7-jdk + $ apt-get source openjdk-7-jdk + $ apt-get build-dep openjdk-7-jdk + (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage) + $ make openjdk=/usr/lib/jvm/java-7-openjdk \ + openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \ + test + +####Mac OS X: +_Prerequisite:_ Build OpenJDK 7 according to [this site](https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port). + +_Conventional build:_ + + $ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test + +_Stand-alone build:_ + + $ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test + +####Windows (Cygwin): +_Prerequisite:_ Build OpenJDK 7 according to [this site](http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction). + +_Conventional build:_ + + $ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test + +_Stand-alone build:_ + + $ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \ + openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test + +Currently, only OpenJDK 7 is supported. Later versions might work, +but have not yet been tested. + + +Installing +---------- + +Installing Avian is as simple as copying the executable to the desired +directory: + + $ cp build/${platform}-${arch}/avian ~/bin/ + + +Embedding +--------- + +The following series of commands illustrates how to produce a +stand-alone executable out of a Java application using Avian. + +Note: if you are building on Cygwin, prepend "x86_64-w64-mingw32-" or +"i686-w64-mingw32-" to the ar, g++, gcc, strip, and dlltool commands +below (e.g. x86_64-w64-mingw32-gcc). + +__1.__ Build Avian, create a new directory, and populate it with the +VM object files and bootstrap classpath jar. + + $ make + $ mkdir hello + $ cd hello + $ ar x ../build/${platform}-${arch}/libavian.a + $ cp ../build/${platform}-${arch}/classpath.jar boot.jar + +__2.__ Build the Java code and add it to the jar. + + $ cat >Hello.java <embedded-jar-main.cpp <("-Xbootclasspath:[bootJar]"); + + JavaVM* vm; + void* env; + JNI_CreateJavaVM(&vm, &env, &vmArgs); + JNIEnv* e = static_cast(env); + + jclass c = e->FindClass("Hello"); + if (not e->ExceptionCheck()) { + jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); + if (not e->ExceptionCheck()) { + jclass stringClass = e->FindClass("java/lang/String"); + if (not e->ExceptionCheck()) { + jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); + if (not e->ExceptionCheck()) { + for (int i = 1; i < ac; ++i) { + e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); + } + + e->CallStaticVoidMethod(c, m, a); + } + } + } + } + + int exitCode = 0; + if (e->ExceptionCheck()) { + exitCode = -1; + e->ExceptionDescribe(); + } + + vm->DestroyJavaVM(); + + return exitCode; + } + EOF + +__on Linux:__ + + $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ + -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o + +__on Mac OS X:__ + + $ g++ -I$JAVA_HOME/include -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp \ + -o main.o + +__on Windows:__ + + $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/win32 \ + -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o + +__5.__ Link the objects produced above to produce the final +executable, and optionally strip its symbols. + +__on Linux:__ + + $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello + $ strip --strip-all hello + +__on Mac OS X:__ + + $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation + $ strip -S -x hello + +__on Windows:__ + + $ dlltool -z hello.def *.o + $ dlltool -d hello.def -e hello.exp + $ g++ hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \ + -mwindows -mconsole -o hello.exe + $ strip --strip-all hello.exe + +Embedding with ProGuard and a Boot Image +---------------------------------------- + +The following illustrates how to embed an application as above, except +this time we preprocess the code using ProGuard and build a boot image +from it for quicker startup. The pros and cons of using ProGuard are +as follow: + + * Pros: ProGuard will eliminate unused code, optimize the rest, and + obfuscate it as well for maximum space savings + + * Cons: increased build time, especially for large applications, and + extra effort needed to configure it for applications which rely + heavily on reflection and/or calls to Java from native code + +For boot image builds: + + * Pros: the boot image build pre-parses all the classes and compiles + all the methods, obviating the need for JIT compilation at runtime. + This also makes garbage collection faster, since the pre-parsed + classes are never visited. + + * Cons: the pre-parsed classes and AOT-compiled methods take up more + 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. 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. + +The following instructions assume we are building for Linux/i386. +Please refer to the previous example for guidance on other platforms. + +__1.__ Build Avian, create a new directory, and populate it with the +VM object files. + + $ make bootimage=true + $ mkdir hello + $ cd hello + $ ar x ../build/linux-i386-bootimage/libavian.a + +__2.__ Create a stage1 directory and extract the contents of the +class library jar into it. + + $ mkdir stage1 + $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) + +__3.__ Build the Java code and add it to stage1. + + $ cat >Hello.java <hello.pro <bootimage-main.cpp <("-Davian.bootimage=bootimageBin"); + + options[1].optionString + = const_cast("-Davian.codeimage=codeimageBin"); + + JavaVM* vm; + void* env; + JNI_CreateJavaVM(&vm, &env, &vmArgs); + JNIEnv* e = static_cast(env); + + jclass c = e->FindClass("Hello"); + if (not e->ExceptionCheck()) { + jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); + if (not e->ExceptionCheck()) { + jclass stringClass = e->FindClass("java/lang/String"); + if (not e->ExceptionCheck()) { + jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); + if (not e->ExceptionCheck()) { + for (int i = 1; i < ac; ++i) { + e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); + } + + e->CallStaticVoidMethod(c, m, a); + } + } + } + } + + int exitCode = 0; + if (e->ExceptionCheck()) { + exitCode = -1; + e->ExceptionDescribe(); + } + + vm->DestroyJavaVM(); + + return exitCode; + } + EOF + + $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ + -D_JNI_IMPLEMENTATION_ -c bootimage-main.cpp -o main.o + +__8.__ Link the objects produced above to produce the final + executable, and optionally strip its symbols. + + $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello + $ strip --strip-all hello + + +Trademarks +---------- + +Oracle and Java are registered trademarks of Oracle and/or its +affiliates. Other names may be trademarks of their respective owners. + +The Avian project is not affiliated with Oracle. diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 187549ebfd..b66aa03ff9 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2012, Avian Contributors +/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -16,6 +16,11 @@ public class File implements Serializable { public static final String separator = FileSeparator; + private static final String PathSeparator + = System.getProperty("path.separator"); + + public static final String pathSeparator = PathSeparator; + // static { // System.loadLibrary("natives"); // } diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index eb183260d6..dcef601f12 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -37,7 +37,8 @@ import java.security.Permissions; import java.security.AllPermission; public final class Class implements Type, AnnotatedElement { - private static final int PrimitiveFlag = 1 << 5; + private static final int PrimitiveFlag = 1 << 5; + private static final int EnumFlag = 1 << 14; public final VMClass vmClass; @@ -555,6 +556,10 @@ public final class Class implements Type, AnnotatedElement { return (vmClass.vmFlags & PrimitiveFlag) != 0; } + public boolean isEnum() { + return getSuperclass() == Enum.class && (vmClass.flags & EnumFlag) != 0; + } + public URL getResource(String path) { if (! path.startsWith("/")) { String name = new String @@ -626,7 +631,7 @@ public final class Class implements Type, AnnotatedElement { for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { Classes.link(c, c.loader); - + Object[] table = (Object[]) c.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index 8d0d4756b0..a70b2074a9 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -30,7 +30,9 @@ public abstract class Enum> implements Comparable { } public static > T valueOf(Class enumType, String name) { - if (name == null) throw new NullPointerException(); + if (name == null) throw new NullPointerException("name"); + if (!enumType.isEnum()) + throw new IllegalArgumentException(enumType.getCanonicalName() + " is not an enum."); try { Method method = enumType.getMethod("values"); @@ -41,10 +43,11 @@ public abstract class Enum> implements Comparable { } } } catch (Exception ex) { - throw new RuntimeException(ex); + // Cannot happen + throw new Error(ex); } - throw new IllegalArgumentException(name); + throw new IllegalArgumentException(enumType.getCanonicalName() + "." + name + " is not an enum constant."); } public int ordinal() { diff --git a/classpath/java/lang/Integer.java b/classpath/java/lang/Integer.java index 8ea8668ddc..9bd399f227 100644 --- a/classpath/java/lang/Integer.java +++ b/classpath/java/lang/Integer.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -94,6 +94,27 @@ public final class Integer extends Number implements Comparable { return (double) value; } + public static int signum(int v) { + if (v == 0) return 0; + else if (v > 0) return 1; + else return -1; + } + + // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + public static int bitCount(int v) { + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; + } + + public static int reverseBytes(int v) { + int byte3 = v >>> 24; + int byte2 = (v >>> 8) & 0xFF00; + int byte1 = (v << 8) & 0xFF00; + int byte0 = v << 24; + return (byte0 | byte1 | byte2 | byte3); + } + public static int parseInt(String s) { return parseInt(s, 10); } diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index b7569951b7..425e68383a 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -126,6 +126,12 @@ public final class Long extends Number implements Comparable { return (double) value; } + public static int signum(long v) { + if (v == 0) return 0; + else if (v > 0) return 1; + else return -1; + } + private static long pow(long a, long b) { long c = 1; for (int i = 0; i < b; ++i) c *= a; diff --git a/classpath/java/lang/Package.java b/classpath/java/lang/Package.java index ed1e4e2985..0b4be0d78f 100644 --- a/classpath/java/lang/Package.java +++ b/classpath/java/lang/Package.java @@ -17,34 +17,66 @@ public class Package { private final String implementationTitle; private final String implementationVendor; private final String implementationVersion; - private final String specementationTitle; - private final String specementationVendor; - private final String specementationVersion; + private final String specificationTitle; + private final String specificationVendor; + private final String specificationVersion; private final URL sealed; private final ClassLoader loader; Package(String name, - String implementationTitle, - String implementationVendor, - String implementationVersion, - String specementationTitle, - String specementationVendor, - String specementationVersion, - URL sealed, + String implementationTitle, + String implementationVendor, + String implementationVersion, + String specificationTitle, + String specificationVendor, + String specificationVersion, + URL sealed, ClassLoader loader) { - this.name = name; - this.implementationTitle = implementationTitle; - this.implementationVendor = implementationVendor; + this.name = name; + this.implementationTitle = implementationTitle; + this.implementationVendor = implementationVendor; this.implementationVersion = implementationVersion; - this.specementationTitle = specementationTitle; - this.specementationVendor = specementationVendor; - this.specementationVersion = specementationVersion; - this.sealed = sealed; - this.loader = loader; + this.specificationTitle = specificationTitle; + this.specificationVendor = specificationVendor; + this.specificationVersion = specificationVersion; + this.sealed = sealed; + this.loader = loader; } public String getName() { return name; } + + public String getImplementationTitle() { + return implementationTitle; + } + + public String getImplementationVendor() { + return implementationVendor; + } + + public String getImplementationVersion() { + return implementationVersion; + } + + public String getSpecificationTitle() { + return specificationTitle; + } + + public String getSpecificationVendor() { + return specificationVendor; + } + + public String getSpecificationVersion() { + return specificationVersion; + } + + public boolean isSealed() { + return sealed != null; + } + + public boolean isSealed(URL url) { + return sealed.equals(url); + } } diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 936351c809..3abfd3238e 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -151,8 +151,8 @@ public class Thread implements Runnable { private static native boolean interrupted(long peer); - public static boolean isInterrupted() { - return currentThread().interrupted; + public boolean isInterrupted() { + return interrupted; } public static void sleep(long milliseconds) throws InterruptedException { diff --git a/classpath/java/math/BigInteger.java b/classpath/java/math/BigInteger.java new file mode 100644 index 0000000000..319b01707b --- /dev/null +++ b/classpath/java/math/BigInteger.java @@ -0,0 +1,44 @@ +/* Copyright (c) 2013, 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.math; + +import java.io.Serializable; + +public class BigInteger implements Serializable { + + private int sign; + private int[] value; + + private BigInteger(int sign, long value) { + this.sign = sign; + int upperBits = (int) (value >>> 32); + if (upperBits == 0) + // Array with one element + this.value = new int[] { (int) value }; + else + // Array with two elements + this.value = new int[] { (int) value, upperBits }; + } + + public static final BigInteger ZERO = new BigInteger(0, 0); + public static final BigInteger ONE = new BigInteger(1, 1); + public static final BigInteger TEN = new BigInteger(1, 10); + + public static BigInteger valueOf(long num) { + int signum = Long.signum(num); + if (signum == 0) + return BigInteger.ZERO; + else if (signum > 0) + return new BigInteger(signum, num); + else + return new BigInteger(signum, -num); + } +} diff --git a/classpath/java/math/MathContext.java b/classpath/java/math/MathContext.java new file mode 100644 index 0000000000..7ff24d8b12 --- /dev/null +++ b/classpath/java/math/MathContext.java @@ -0,0 +1,71 @@ +/* Copyright (c) 2013, 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.math; + +import java.io.Serializable; + +public final class MathContext implements Serializable { + + public static final MathContext DECIMAL32 = new MathContext( 7, RoundingMode.HALF_EVEN); + public static final MathContext DECIMAL64 = new MathContext(16, RoundingMode.HALF_EVEN); + public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN); + public static final MathContext UNLIMITED = new MathContext(0, RoundingMode.HALF_UP); + + private int precision; + private RoundingMode roundingMode; + + public MathContext(int precision, RoundingMode roundingMode) { + if (precision < 0) + throw new IllegalArgumentException(); + if (roundingMode == null) + throw new NullPointerException(); + this.precision = precision; + this.roundingMode = roundingMode; + } + + public MathContext(int precision) { + this(precision, RoundingMode.HALF_UP); + } + + public int getPrecision() { + return precision; + } + + public RoundingMode getRoundingMode() { + return roundingMode; + } + + @Override + public boolean equals(Object that) { + return + (that instanceof MathContext) && + (precision == ((MathContext) that).getPrecision()) && + (roundingMode == ((MathContext) that).getRoundingMode()); + } + + @Override + public int hashCode() { + return + roundingMode.ordinal() | + (precision << 4); + } + + private final static String precisionString = "precision="; + private final static String roundingModeString = " roundingMode="; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(48); + sb.append(precisionString).append(precision); + sb.append(roundingModeString).append(roundingMode); + return sb.toString(); + } +} diff --git a/classpath/java/math/RoundingMode.java b/classpath/java/math/RoundingMode.java new file mode 100644 index 0000000000..22bfd69757 --- /dev/null +++ b/classpath/java/math/RoundingMode.java @@ -0,0 +1,36 @@ +/* Copyright (c) 2013, 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.math; + +public enum RoundingMode { + + UP (0), + DOWN (1), + CEILING (2), + FLOOR (3), + HALF_UP (4), + HALF_DOWN (5), + HALF_EVEN (6), + UNNECESSARY(7); + + RoundingMode(int rm) { + roundingMode = rm; + } + + private final int roundingMode; + + public static RoundingMode valueOf(int roundingMode) { + final RoundingMode[] values = values(); + if (roundingMode < 0 || roundingMode >= values.length) + throw new IllegalArgumentException(); + return values[roundingMode]; + } +} diff --git a/classpath/java/util/jar/Attributes.java b/classpath/java/util/jar/Attributes.java new file mode 100644 index 0000000000..806fdb5b98 --- /dev/null +++ b/classpath/java/util/jar/Attributes.java @@ -0,0 +1,27 @@ +/* Copyright (c) 2013, 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.jar; + +public class Attributes { + public static class Name { + private final String name; + + private static final int MAX_NAME_LENGTH = 70; + + public Name(String s) { + int len = s.length(); + if (len == 0 || len > MAX_NAME_LENGTH) + throw new IllegalArgumentException(); + + name = s; + } + } +} diff --git a/makefile b/makefile index f006ba0bf9..b3cbd88a57 100755 --- a/makefile +++ b/makefile @@ -1158,7 +1158,8 @@ $(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ $(ar) cru $(@) $(^) $(ranlib) $(@) -$(bootimage-object) $(codeimage-object): $(bootimage-generator) +$(bootimage-object) $(codeimage-object): $(bootimage-generator) \ + $(build)/classpath.jar $(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \ -bootimage-symbols _binary_bootimage_bin_start:_binary_bootimage_bin_end \ -codeimage-symbols _binary_codeimage_bin_start:_binary_codeimage_bin_end diff --git a/openjdk.pro b/openjdk.pro index d0b8de812f..69b4646090 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -14,6 +14,10 @@ public static void setProperties(java.util.Properties); } +-keep class sun.misc.Launcher { + public static sun.misc.Launcher getLauncher(); + } + -keep class java.lang.ClassLoader { private static java.lang.ClassLoader scl; private static boolean sclSet; @@ -246,3 +250,39 @@ } -keep class sun.net.www.protocol.jar.Handler + +# These concurrent classes refer to certain members reflectively in their static initializers +-keepclassmembers class java.util.concurrent.ConcurrentHashMap$HashEntry { + *** next; +} + +-keepclassmembers class java.util.concurrent.CopyOnWriteArrayList { + *** lock; +} + +-keepclassmembers class java.util.concurrent.CountDownLatch { + *** allocationSpinLock; +} + +-keepclassmembers class java.util.concurrent.PriorityBlockingQueue { + *** allocationSpinLock; +} + +-keepclassmembers class java.util.concurrent.SynchronousQueue$TransferStack { + *** head; +} + +-keepclassmembers class java.util.concurrent.ConcurrentLinkedQueue { + *** head; + *** tail; +} + +-keepclassmembers class java.util.concurrent.ConcurrentLinkedQueue$Node { + *** item; + *** next; +} + +-keepclassmembers class java.util.concurrent.SynchronousQueue$TransferStack$SNode { + *** match; + *** next; +} diff --git a/readme.txt b/readme.txt deleted file mode 100644 index e9185b2c85..0000000000 --- a/readme.txt +++ /dev/null @@ -1,727 +0,0 @@ -Quick Start ------------ - -on Linux: - $ export JAVA_HOME=/usr/local/java # or wherever you have the JDK installed - $ make - $ build/linux-i386/avian -cp build/linux-i386/test Hello - -on Mac OS X: - $ export JAVA_HOME=/Library/Java/Home - $ make - $ build/darwin-i386/avian -cp build/darwin-i386/test Hello - -on Windows (MSYS): - $ git clone git://oss.readytalk.com/win32.git ../win32 - $ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07" - $ make - $ build/windows-i386/avian -cp build/windows-i386/test Hello - -on Windows (Cygwin): - $ git clone git://oss.readytalk.com/win32.git ../win32 - $ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07" - $ make - $ build/windows-i386/avian -cp build/windows-i386/test Hello - -Adjust JAVA_HOME according to your system, but be sure to use forward -slashes in the path. - - -Introduction ------------- - -Avian is a lightweight virtual machine and class library designed to -provide a useful subset of Java's features, suitable for building -self-contained applications. More information is available at the -project web site: - - http://oss.readytalk.com/avian - -If you have any trouble building, running, or embedding Avian, please -post a message to our discussion group: - - http://groups.google.com/group/avian - -That's also the place for any other questions, comments, or -suggestions you might have. - - -Supported Platforms -------------------- - -Avian can currently target the following platforms: - - Linux (i386, x86_64, ARM, and 32-bit PowerPC) - Windows (i386 and x86_64) - Mac OS X (i386, x86_64 and 32-bit PowerPC) - Apple iOS (i386 and ARM) - -Building --------- - -Build requirements include: - - * GNU make 3.80 or later - * GCC 3.4 or later (4.5.1 or later for Windows/x86_64) - or LLVM Clang 3.1 or later (see use-clang option below) - * JDK 1.5 or later - * MinGW 3.4 or later (only if compiling for Windows) - * zlib 1.2.3 or later - -Earlier versions of some of these packages may also work but have not -been tested. - -The build is directed by a single makefile and may be influenced via -certain flags described below, all of which are optional. - - $ make \ - platform={linux,windows,darwin} \ - arch={i386,x86_64,powerpc,arm} \ - process={compile,interpret} \ - mode={debug,debug-fast,fast,small} \ - lzma= \ - ios={true,false} \ - bootimage={true,false} \ - heapdump={true,false} \ - tails={true,false} \ - continuations={true,false} \ - use-clang={true,false} \ - openjdk= \ - openjdk-src= - - * platform - the target platform - default: output of $(uname -s | tr [:upper:] [:lower:]), - normalized in some cases (e.g. CYGWIN_NT-5.1 -> windows) - - * arch - the target architecture - default: output of $(uname -m), normalized in some cases - (e.g. i686 -> i386) - - * process - choice between pure interpreter or JIT compiler - default: compile - - * mode - which set of compilation flags to use to determine - optimization level, debug symbols, and whether to enable - assertions - default: fast - - * lzma - if set, support use of LZMA to compress embedded JARs and - boot images. The value of this option should be a directory - containing a recent LZMA SDK (available at - http://www.7-zip.org/sdk.html). Currently, only version 9.20 of - the SDK has been tested, but other versions might work. - default: not set - - * ios - if true, cross-compile for iOS on OS X. Note that - non-jailbroken iOS devices do not allow JIT compilation, so only - process=interpret or bootimage=true builds will run on such - devices. See https://github.com/ReadyTalk/hello-ios for an - example of an Xcode project for iOS which uses Avian. - default: false - - * bootimage - if true, create a boot image containing the pre-parsed - class library and ahead-of-time compiled methods. This option is - only valid for process=compile builds. Note that you may need to - specify both build-arch=x86_64 and arch=x86_64 on 64-bit systems - where "uname -m" prints "i386". - default: false - - * heapdump - if true, implement avian.Machine.dumpHeap(String), - which, when called, will generate a snapshot of the heap in a - simple, ad-hoc format for memory profiling purposes. See - heapdump.cpp for details. - default: false - - * tails - if true, optimize each tail call by replacing the caller's - stack frame with the callee's. This convention ensures proper - tail recursion, suitable for languages such as Scheme. This - option is only valid for process=compile builds. - default: false - - * continuations - if true, support continuations via the - avian.Continuations methods callWithCurrentContinuation and - dynamicWind. See Continuations.java for details. This option is - only valid for process=compile builds. - default: false - - * use-clang - if true, use LLVM's clang instead of GCC to build. - Note that this does not currently affect cross compiles, only - native builds. - default: false - - * openjdk - if set, use OpenJDK class library instead of the default - Avian class library. See "Building with the OpenJDK Class - Library" below for details. - default: not set - - * openjdk-src - if this and the openjdk option above are both set, - build an embeddable VM using the OpenJDK class library. The JNI - components of the OpenJDK class library will be built from the - sources found under the specified directory. See "Building with - the OpenJDK Class Library" below for details. - default: not set - -These flags determine the name of the directory used for the build. -The name always starts with ${platform}-${arch}, and each non-default -build option is appended to the name. For example, a debug build with -bootimage enabled on Linux/i386 would be built in -build/linux-i386-debug-bootimage. This allows you to build with -several different sets of options independently and even -simultaneously without doing a clean build each time. - -If you are compiling for Windows, you may either cross-compile using -MinGW or build natively on Windows under MSYS or Cygwin. - -Installing MSYS: - - 1. Download and install the current MinGW and MSYS packages from - mingw.org, selecting the C and C++ compilers when prompted. Use the - post-install script to create the filesystem link to the compiler. - - 2. Download GNU Make 3.81 from the MSYS download page - (make-3.81-MSYS-1.0.11-2.tar.bz2) and extract the tar file into - e.g. c:/msys/1.0. - -Installing Cygwin: - - 1. Download and run setup.exe from cygwin.com, installing the base - system and these packages: make, gcc-mingw-g++, - mingw64-i686-gcc-g++, mingw64-x86_64-gcc-g++, and (optionally) git. - -You may also find our win32 repository useful: (run this from the -directory containing the avian directory) - - $ git clone git://oss.readytalk.com/win32.git - -This gives you the Windows JNI headers, zlib headers and library, and -a few other useful libraries like OpenSSL, libjpeg, and libpng. -There's also a win64 repository for 64-bit builds: - - $ git clone git://oss.readytalk.com/win64.git - - -Building with the Microsoft Visual C++ Compiler ------------------------------------------------ - -You can also build using the MSVC compiler, which makes debugging with -tools like WinDbg and Visual Studio much easier. Note that you will -still need to have GCC installed - MSVC is only used to compile the -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, 9, and 10. Other versions may also work. - -To build with MSVC, install Cygwin as described above and set the -following environment variables: - - $ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/VCPackages:/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem" - - $ export LIBPATH="C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;" - - $ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 9.0\VC" - - $ export LIB="C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;" - - $ export INCLUDE="C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include;" - -Adjust these definitions as necessary according to your MSVC -installation. - -Finally, build with the msvc flag set to the MSVC tool directory: - - $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" - - -Building with the OpenJDK Class Library ---------------------------------------- - -By default, Avian uses its own lightweight class library. However, -that library only contains a relatively small subset of the classes -and methods included in the JRE. If your application requires -features beyond that subset, you may want to tell Avian to use -OpenJDK's class library instead. To do so, specify the directory -where OpenJDK is installed, e.g.: - - $ make openjdk=/usr/lib/jvm/java-7-openjdk - -This will build Avian as a conventional JVM (e.g. libjvm.so) which -loads its boot class library and native libraries (e.g. libjava.so) -from /usr/lib/jvm/java-7-openjdk/jre at runtime. To run an -application in this configuration, you'll need to make sure the VM is -in your library search path. For example: - - $ LD_LIBRARY_PATH=build/linux-x86_64-openjdk \ - build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ - com.example.MyApplication - -Alternatively, you can enable a stand-alone build using OpenJDK by -specifying the location of the OpenJDK source code, e.g.: - - $ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \ - openjdk-src=$(pwd)/../jdk7/jdk/src - -You must ensure that the path specified for openjdk-src does not have -any spaces in it; make gets confused when dependency paths include -spaces, and we haven't found away around that except to avoid paths -with spaces entirely. - -The result of such a build is a self-contained binary which does not -depend on external libraries, jars, or other files. In this case, the -specified paths are used only at build time; anything needed at -runtime is embedded in the binary. Thus, the process of running an -application is simplified: - - $ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \ - com.example.MyApplication - -Note that the resulting binary will be very large due to the size of -OpenJDK's class library. This can be mitigated using UPX, preferably -an LZMA-enabled version: - - $ upx --lzma --best build/linux-x86_64-openjdk-src/avian - -You can reduce the size futher for embedded builds by using ProGuard -and the supplied openjdk.pro configuration file (see "Embedding with -ProGuard and a Boot Image" below). Note that you'll still need to use -vm.pro in that case -- openjdk.pro just adds additional constraints -specific to the OpenJDK port. Also see app.mk in -git://oss.readytalk.com/avian-swt-examples.git for an example of using -Avian, OpenJDK, ProGuard, and UPX in concert. - -Here are some examples of how to install OpenJDK and build Avian with -it on various OSes: - - Debian-based Linux: - # conventional build: - apt-get install openjdk-7-jdk - make openjdk=/usr/lib/jvm/java-7-openjdk test - - # stand-alone build: - apt-get install openjdk-7-jdk - apt-get source openjdk-7-jdk - apt-get build-dep openjdk-7-jdk - (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage) - make openjdk=/usr/lib/jvm/java-7-openjdk \ - openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \ - test - - Mac OS X: - # Prerequisite: build OpenJDK 7 according to - # https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port - - # conventional build: - make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test - - # stand-alone build: - make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \ - openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test - - Windows (Cygwin): - # Prerequisite: build OpenJDK 7 according to - # http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction - - # conventional build: - make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test - - # stand-alone build: - make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \ - openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test - -Currently, only OpenJDK 7 is supported. Later versions might work, -but have not yet been tested. - - -Installing ----------- - -Installing Avian is as simple as copying the executable to the desired -directory: - - $ cp build/${platform}-${arch}/avian ~/bin/ - - -Embedding ---------- - -The following series of commands illustrates how to produce a -stand-alone executable out of a Java application using Avian. - -Note: if you are building on Cygwin, prepend "x86_64-w64-mingw32-" or -"i686-w64-mingw32-" to the ar, g++, gcc, strip, and dlltool commands -below (e.g. x86_64-w64-mingw32-gcc). - -Step 1: Build Avian, create a new directory, and populate it with the -VM object files and bootstrap classpath jar. - - $ make - $ mkdir hello - $ cd hello - $ ar x ../build/${platform}-${arch}/libavian.a - $ cp ../build/${platform}-${arch}/classpath.jar boot.jar - -Step 2: Build the Java code and add it to the jar. - - $ cat >Hello.java <embedded-jar-main.cpp <("-Xbootclasspath:[bootJar]"); - - JavaVM* vm; - void* env; - JNI_CreateJavaVM(&vm, &env, &vmArgs); - JNIEnv* e = static_cast(env); - - jclass c = e->FindClass("Hello"); - if (not e->ExceptionCheck()) { - jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); - if (not e->ExceptionCheck()) { - jclass stringClass = e->FindClass("java/lang/String"); - if (not e->ExceptionCheck()) { - jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); - if (not e->ExceptionCheck()) { - for (int i = 1; i < ac; ++i) { - e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); - } - - e->CallStaticVoidMethod(c, m, a); - } - } - } - } - - int exitCode = 0; - if (e->ExceptionCheck()) { - exitCode = -1; - e->ExceptionDescribe(); - } - - vm->DestroyJavaVM(); - - return exitCode; -} -EOF - -on Linux: - $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ - -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o - -on Mac OS X: - $ g++ -I$JAVA_HOME/include -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp \ - -o main.o - -on Windows: - $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/win32 \ - -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o - -Step 5: Link the objects produced above to produce the final -executable, and optionally strip its symbols. - -on Linux: - $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello - $ strip --strip-all hello - -on Mac OS X: - $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation - $ strip -S -x hello - -on Windows: - $ dlltool -z hello.def *.o - $ dlltool -d hello.def -e hello.exp - $ g++ hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \ - -mwindows -mconsole -o hello.exe - $ strip --strip-all hello.exe - - -Embedding with ProGuard and a Boot Image ----------------------------------------- - -The following illustrates how to embed an application as above, except -this time we preprocess the code using ProGuard and build a boot image -from it for quicker startup. The pros and cons of using ProGuard are -as follow: - - * Pros: ProGuard will eliminate unused code, optimize the rest, and - obfuscate it as well for maximum space savings - - * Cons: increased build time, especially for large applications, and - extra effort needed to configure it for applications which rely - heavily on reflection and/or calls to Java from native code - -For boot image builds: - - * Pros: the boot image build pre-parses all the classes and compiles - all the methods, obviating the need for JIT compilation at runtime. - This also makes garbage collection faster, since the pre-parsed - classes are never visited. - - * Cons: the pre-parsed classes and AOT-compiled methods take up more - 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. 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. - -The following instructions assume we are building for Linux/i386. -Please refer to the previous example for guidance on other platforms. - -Step 1: Build Avian, create a new directory, and populate it with the -VM object files. - - $ make bootimage=true - $ mkdir hello - $ cd hello - $ ar x ../build/linux-i386-bootimage/libavian.a - -Step 2: Create a stage1 directory and extract the contents of the -class library jar into it. - - $ mkdir stage1 - $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) - -Step 3: Build the Java code and add it to stage1. - - $ cat >Hello.java <hello.pro <bootimage-main.cpp <("-Davian.bootimage=bootimageBin"); - - options[1].optionString - = const_cast("-Davian.codeimage=codeimageBin"); - - JavaVM* vm; - void* env; - JNI_CreateJavaVM(&vm, &env, &vmArgs); - JNIEnv* e = static_cast(env); - - jclass c = e->FindClass("Hello"); - if (not e->ExceptionCheck()) { - jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); - if (not e->ExceptionCheck()) { - jclass stringClass = e->FindClass("java/lang/String"); - if (not e->ExceptionCheck()) { - jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); - if (not e->ExceptionCheck()) { - for (int i = 1; i < ac; ++i) { - e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); - } - - e->CallStaticVoidMethod(c, m, a); - } - } - } - } - - int exitCode = 0; - if (e->ExceptionCheck()) { - exitCode = -1; - e->ExceptionDescribe(); - } - - vm->DestroyJavaVM(); - - return exitCode; -} -EOF - - $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ - -D_JNI_IMPLEMENTATION_ -c bootimage-main.cpp -o main.o - -Step 8: Link the objects produced above to produce the final -executable, and optionally strip its symbols. - - $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello - $ strip --strip-all hello - - -Trademarks ----------- - -Oracle and Java are registered trademarks of Oracle and/or its -affiliates. Other names may be trademarks of their respective owners. - -The Avian project is not affiliated with Oracle. diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 492366f6c2..f82e73f9f5 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1991,7 +1991,8 @@ main(int ac, const char** av) // in a branch instruction for the target architecture (~32MB on // PowerPC and ARM). When that limitation is removed, we'll be able // to specify a capacity as large as we like here: -#if (defined ARCH_x86_64) || (defined ARCH_x86_32) +#if (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86_64) \ + || (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86) const unsigned CodeCapacity = 128 * 1024 * 1024; #else const unsigned CodeCapacity = 30 * 1024 * 1024; diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 4842ab8581..cab2d85ba0 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -46,7 +46,8 @@ # define O_RDONLY _O_RDONLY -# ifdef AVIAN_OPENJDK_SRC +# if (defined AVIAN_OPENJDK_SRC) \ + || ((defined __x86_64__) && (defined __MINGW32__)) # define EXPORT(x) x # else # define EXPORT(x) _##x @@ -450,9 +451,14 @@ class MyClasspath : public Classpath { // todo: handle other architectures # define LIB_DIR "/lib/i386" #endif + +#ifdef PLATFORM_WINDOWS + sb.append(LIB_DIR); +#else sb.append(LIB_DIR ":"); sb.append(javaHome); sb.append(LIB_DIR "/xawt"); +#endif sb.append('\0'); unsigned tzMappingsOffset = sb.offset; @@ -498,6 +504,8 @@ class MyClasspath : public Classpath { object charArray = makeCharArray(t, length); for (int i = 0; i < length; ++i) { + expect(t, (byteArrayBody(t, array, offset + i) & 0x80) == 0); + charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); } @@ -596,15 +604,21 @@ class MyClasspath : public Classpath { virtual void runThread(Thread* t) { + // force monitor creation so we don't get an OutOfMemory error + // later when we try to acquire it: + objectMonitor(t, t->javaThread, true); + + THREAD_RESOURCE0(t, { + vm::acquire(t, t->javaThread); + t->flags &= ~Thread::ActiveFlag; + vm::notifyAll(t, t->javaThread); + vm::release(t, t->javaThread); + }); + object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); t->m->processor->invoke(t, method, t->javaThread); - - acquire(t, t->javaThread); - t->flags &= ~Thread::ActiveFlag; - notifyAll(t, t->javaThread); - release(t, t->javaThread); } virtual void @@ -638,7 +652,9 @@ class MyClasspath : public Classpath { #else // not AVIAN_OPENJDK_SRC expect(t, loadLibrary(t, libraryPath, "verify", true, true)); expect(t, loadLibrary(t, libraryPath, "java", true, true)); +# ifndef PLATFORM_WINDOWS loadLibrary(t, libraryPath, "mawt", true, true); +# endif #endif // not AVIAN_OPENJDK_SRC { object assertionLock = resolveField @@ -740,13 +756,27 @@ class MyClasspath : public Classpath { RUNTIME_ARRAY_BODY(packageName)[length] = 0; object key = vm::makeByteArray(t, "%s", packageName); + PROTECT(t, key); hashMapRemove (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); object source = classSource(t, class_); - if (source == 0) { + if (source) { + // note that we strip the "file:" prefix, since + // Package.defineSystemPackage expects an unadorned + // filename: + const unsigned PrefixLength = 5; + unsigned sourceNameLength = byteArrayLength(t, source) + - PrefixLength; + THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength); + memcpy(RUNTIME_ARRAY_BODY(sourceName), + &byteArrayBody(t, source, PrefixLength), + sourceNameLength); + + source = vm::makeByteArray(t, "%s", sourceName); + } else { source = vm::makeByteArray(t, "avian-dummy-package-source"); } @@ -2347,6 +2377,8 @@ makeJmethod(Thread* t, object vmMethod, int index) if (addendum) { signature = addendumSignature(t, addendum); if (signature) { + PROTECT(t, addendum); + signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } @@ -2414,6 +2446,8 @@ makeJconstructor(Thread* t, object vmMethod, int index) if (addendum) { signature = addendumSignature(t, addendum); if (signature) { + PROTECT(t, addendum); + signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } @@ -2479,6 +2513,8 @@ makeJfield(Thread* t, object vmField, int index) if (addendum) { signature = addendumSignature(t, addendum); if (signature) { + PROTECT(t, addendum); + signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } @@ -4782,6 +4818,59 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) instance = 0; } + if ((args == 0 ? 0 : objectArrayLength(t, *args)) + != methodParameterCount(t, vmMethod)) + { + throwNew(t, Machine::IllegalArgumentExceptionType); + } + + if (methodParameterCount(t, vmMethod)) { + PROTECT(t, vmMethod); + + unsigned specLength = byteArrayLength(t, methodSpec(t, vmMethod)); + THREAD_RUNTIME_ARRAY(t, char, spec, specLength); + memcpy(spec, &byteArrayBody(t, methodSpec(t, vmMethod), 0), specLength); + unsigned i = 0; + for (MethodSpecIterator it(t, spec); it.hasNext();) { + object type; + bool objectType = false; + const char* p = it.next(); + switch (*p) { + case 'Z': type = vm::type(t, Machine::BooleanType); break; + case 'B': type = vm::type(t, Machine::ByteType); break; + case 'S': type = vm::type(t, Machine::ShortType); break; + case 'C': type = vm::type(t, Machine::CharType); break; + case 'I': type = vm::type(t, Machine::IntType); break; + case 'F': type = vm::type(t, Machine::FloatType); break; + case 'J': type = vm::type(t, Machine::LongType); break; + case 'D': type = vm::type(t, Machine::DoubleType); break; + + case 'L': ++ p; + case '[': { + objectType = true; + unsigned nameLength = it.s - p; + THREAD_RUNTIME_ARRAY(t, char, name, nameLength); + memcpy(name, p, nameLength - 1); + name[nameLength - 1] = 0; + type = resolveClass + (t, classLoader(t, methodClass(t, vmMethod)), name); + } break; + + default: + abort(); + } + + object arg = objectArrayBody(t, *args, i++); + if ((arg == 0 and (not objectType)) + or (arg and (not instanceOf(t, type, arg)))) + { + // fprintf(stderr, "%s is not a %s\n", arg ? &byteArrayBody(t, className(t, objectClass(t, arg)), 0) : reinterpret_cast(""), &byteArrayBody(t, className(t, type), 0)); + + throwNew(t, Machine::IllegalArgumentExceptionType); + } + } + } + unsigned returnCode = methodReturnCode(t, vmMethod); THREAD_RESOURCE0(t, { @@ -4965,7 +5054,7 @@ jvmConstantPoolGetUTF8At(Thread* t, uintptr_t* arguments) jobject pool = reinterpret_cast(arguments[0]); jint index = arguments[1]; - object array = singletonObject(t, *pool, index - 1); + object array = parseUtf8(t, singletonObject(t, *pool, index - 1)); return reinterpret_cast (makeLocalReference diff --git a/src/compiler.cpp b/src/compiler.cpp index 8e118008bb..8d0c1bd2f9 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -672,6 +672,8 @@ class Event { virtual bool allExits() { return false; } + virtual Local* locals() { return localsBefore; } + Event* next; Stack* stackBefore; Local* localsBefore; @@ -2003,6 +2005,13 @@ class MemorySite: public Site { } } + bool conflicts(const SiteMask& mask) { + return (mask.typeMask & (1 << RegisterOperand)) != 0 + and (((1 << base) & mask.registerMask) == 0 + or (index != NoRegister + and ((1 << index) & mask.registerMask) == 0)); + } + virtual bool match(Context* c, const SiteMask& mask) { assert(c, acquired); @@ -4574,8 +4583,20 @@ class OperationEvent: public Event { void appendOperation(Context* c, Operation op) { - append - (c, new(c->zone) OperationEvent(c, op)); + append(c, new(c->zone) OperationEvent(c, op)); +} + +void +moveIfConflict(Context* c, Value* v, MemorySite* s) +{ + if (v->reads) { + SiteMask mask(1 << RegisterOperand, ~0, AnyFrameIndex); + v->reads->intersect(&mask); + if (s->conflicts(mask)) { + maybeMove(c, v->reads, true, false); + removeSite(c, v, s); + } + } } class MemoryEvent: public Event { @@ -4626,22 +4647,24 @@ class MemoryEvent: public Event { popRead(c, this, index); } - Site* site = memorySite + MemorySite* site = memorySite (c, baseRegister, displacement, indexRegister, scale); - Site* low; + MemorySite* low; if (result->nextWord != result) { - Site* high = site->copyHigh(c); - low = site->copyLow(c); + MemorySite* high = static_cast(site->copyHigh(c)); + low = static_cast(site->copyLow(c)); result->nextWord->target = high; addSite(c, result->nextWord, high); + moveIfConflict(c, result->nextWord, high); } else { low = site; } result->target = low; addSite(c, result, low); + moveIfConflict(c, result, low); } Value* base; @@ -5162,8 +5185,9 @@ appendSaveLocals(Context* c) class DummyEvent: public Event { public: - DummyEvent(Context* c): - Event(c) + DummyEvent(Context* c, Local* locals): + Event(c), + locals_(locals) { } virtual const char* name() { @@ -5171,6 +5195,12 @@ class DummyEvent: public Event { } virtual void compile(Context*) { } + + virtual Local* locals() { + return locals_; + } + + Local* locals_; }; void @@ -5183,7 +5213,7 @@ appendDummy(Context* c) c->stack = i->stack; c->locals = i->locals; - append(c, new(c->zone) DummyEvent(c)); + append(c, new(c->zone) DummyEvent(c, locals)); c->stack = stack; c->locals = locals; @@ -6428,14 +6458,14 @@ class MyCompiler: public Compiler { Event* e = c.logicalCode[logicalIp]->firstEvent; for (int i = 0; i < static_cast(c.localFootprint); ++i) { - Local* local = e->localsBefore + i; + Local* local = e->locals() + i; if (local->value) { initLocal (1, i, local->value->type == ValueGeneral ? IntegerType : FloatType); } } - linkLocals(&c, e->localsBefore, newLocals); + linkLocals(&c, e->locals(), newLocals); } virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) { diff --git a/src/embed.cpp b/src/embed.cpp index a4a32bb6d7..293169ce78 100644 --- a/src/embed.cpp +++ b/src/embed.cpp @@ -17,8 +17,14 @@ #include "embed.h" -extern "C" const uint8_t binary_loader_start[]; -extern "C" const uint8_t binary_loader_end[]; +#ifdef __x86_64__ +# define BINARY_LOADER(x) _binary_loader_##x +#else +# define BINARY_LOADER(x) binary_loader_##x +#endif + +extern "C" const uint8_t BINARY_LOADER(start)[]; +extern "C" const uint8_t BINARY_LOADER(end)[]; __declspec(noreturn) void printUsage(const wchar_t* executableName) @@ -31,8 +37,8 @@ void writeDestinationFile(const wchar_t* filename) { if(FILE* file = _wfopen(filename, L"wb")) { - size_t count = binary_loader_end - binary_loader_start; - if(count == fwrite(binary_loader_start, sizeof(binary_loader_start[0]), count, file)) + size_t count = BINARY_LOADER(end) - BINARY_LOADER(start); + if(count == fwrite(BINARY_LOADER(start), sizeof(BINARY_LOADER(start)[0]), count, file)) { fclose(file); return; diff --git a/src/heap.cpp b/src/heap.cpp index 2dc23e904e..0cc13ba7dc 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1895,21 +1895,43 @@ class MyHeap: public Heap { local::collect(&c); } - virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, - bool objectMask, unsigned* totalInBytes) + void* tryAllocateFixed(Allocator* allocator, unsigned sizeInWords, + bool objectMask, unsigned* totalInBytes, + Fixie** handle, bool immortal) { - *totalInBytes = Fixie::totalSize(sizeInWords, objectMask); - return (new (allocator->allocate(*totalInBytes)) - Fixie(&c, sizeInWords, objectMask, &(c.fixies), false))->body(); + *totalInBytes = 0; + + if (limitExceeded()) { + return 0; + } + + unsigned total = Fixie::totalSize(sizeInWords, objectMask); + void* p = allocator->tryAllocate(total); + if (p == 0) { + return 0; + } else if (limitExceeded()) { + allocator->free(p, total); + return 0; + } else { + *totalInBytes = total; + return (new (p) Fixie(&c, sizeInWords, objectMask, handle, immortal)) + ->body(); + } } - virtual void* allocateImmortalFixed(Allocator* allocator, - unsigned sizeInWords, bool objectMask, - unsigned* totalInBytes) + virtual void* tryAllocateFixed(Allocator* allocator, unsigned sizeInWords, + bool objectMask, unsigned* totalInBytes) { - *totalInBytes = Fixie::totalSize(sizeInWords, objectMask); - return (new (allocator->allocate(*totalInBytes)) - Fixie(&c, sizeInWords, objectMask, 0, true))->body(); + return tryAllocateFixed + (allocator, sizeInWords, objectMask, totalInBytes, &(c.fixies), false); + } + + virtual void* tryAllocateImmortalFixed(Allocator* allocator, + unsigned sizeInWords, bool objectMask, + unsigned* totalInBytes) + { + return tryAllocateFixed + (allocator, sizeInWords, objectMask, totalInBytes, 0, true); } bool needsMark(void* p) { diff --git a/src/heap.h b/src/heap.h index 0ee4699914..2a6734438d 100644 --- a/src/heap.h +++ b/src/heap.h @@ -62,11 +62,11 @@ class Heap: public Allocator { virtual unsigned limit() = 0; virtual bool limitExceeded() = 0; virtual void collect(CollectionType type, unsigned footprint) = 0; - virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, - bool objectMask, unsigned* totalInBytes) = 0; - virtual void* allocateImmortalFixed(Allocator* allocator, - unsigned sizeInWords, bool objectMask, - unsigned* totalInBytes) = 0; + virtual void* tryAllocateFixed(Allocator* allocator, unsigned sizeInWords, + bool objectMask, unsigned* totalInBytes) = 0; + virtual void* tryAllocateImmortalFixed(Allocator* allocator, + unsigned sizeInWords, bool objectMask, + unsigned* totalInBytes) = 0; virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void pad(void* p) = 0; virtual void* follow(void* p) = 0; diff --git a/src/machine.cpp b/src/machine.cpp index 828de31fc0..c06d8c8159 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -727,7 +727,7 @@ finalizeObject(Thread* t, object o, const char* name) } unsigned -readByte(Stream& s, unsigned* value) +readByte(AbstractStream& s, unsigned* value) { if (*value == NoByte) { return s.read1(); @@ -739,8 +739,9 @@ readByte(Stream& s, unsigned* value) } object -parseUtf8NonAscii(Thread* t, Stream& s, object bytesSoFar, unsigned byteCount, - unsigned sourceIndex, unsigned byteA, unsigned byteB) +parseUtf8NonAscii(Thread* t, AbstractStream& s, object bytesSoFar, + unsigned byteCount, unsigned sourceIndex, unsigned byteA, + unsigned byteB) { PROTECT(t, bytesSoFar); @@ -792,7 +793,7 @@ parseUtf8NonAscii(Thread* t, Stream& s, object bytesSoFar, unsigned byteCount, } object -parseUtf8(Thread* t, Stream& s, unsigned length) +parseUtf8(Thread* t, AbstractStream& s, unsigned length) { object value = makeByteArray(t, length + 1); unsigned vi = 0; @@ -830,6 +831,14 @@ parseUtf8(Thread* t, Stream& s, unsigned length) return value; } +object +makeByteArray(Thread* t, Stream& s, unsigned length) +{ + object value = makeByteArray(t, length + 1); + s.read(reinterpret_cast(&byteArrayBody(t, value, 0)), length); + return value; +} + void removeByteArray(Thread* t, object o) { @@ -885,10 +894,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) case CONSTANT_Utf8: { if (singletonObject(t, pool, i) == 0) { - object value = parseUtf8(t, s, s.read2()); - if (objectClass(t, value) == type(t, Machine::ByteArrayType)) { - value = internByteArray(t, value); - } + object value = internByteArray(t, makeByteArray(t, s, s.read2())); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { @@ -916,7 +922,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) unsigned si = s.read2() - 1; parsePoolEntry(t, s, index, pool, si); - object value = singletonObject(t, pool, si); + object value = parseUtf8(t, singletonObject(t, pool, si)); value = t->m->classpath->makeString (t, value, 0, cast(value, BytesPerWord) - 1); value = intern(t, value); @@ -3513,7 +3519,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, break; } - if (t->heap == 0) { + if (t->heap == 0 or t->m->heap->limitExceeded()) { // fprintf(stderr, "gc"); // vmPrintTrace(t); collect(t, Heap::MinorCollection); @@ -3525,7 +3531,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, } while (type == Machine::MovableAllocation and t->heapIndex + ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords); - + switch (type) { case Machine::MovableAllocation: { return allocateSmall(t, sizeInBytes); @@ -3534,29 +3540,37 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, case Machine::FixedAllocation: { unsigned total; object o = static_cast - (t->m->heap->allocateFixed + (t->m->heap->tryAllocateFixed (allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total)); - memset(o, 0, sizeInBytes); + if (o) { + memset(o, 0, sizeInBytes); - alias(o, 0) = FixedMark; - - t->m->fixedFootprint += total; - - return o; + alias(o, 0) = FixedMark; + + t->m->fixedFootprint += total; + + return o; + } else { + throw_(t, root(t, Machine::OutOfMemoryError)); + } } case Machine::ImmortalAllocation: { unsigned total; object o = static_cast - (t->m->heap->allocateImmortalFixed + (t->m->heap->tryAllocateImmortalFixed (allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total)); - memset(o, 0, sizeInBytes); + if (o) { + memset(o, 0, sizeInBytes); - alias(o, 0) = FixedMark; + alias(o, 0) = FixedMark; - return o; + return o; + } else { + throw_(t, root(t, Machine::OutOfMemoryError)); + } } default: abort(t); @@ -4886,6 +4900,62 @@ parseUtf8(Thread* t, const char* data, unsigned length) return ::parseUtf8(t, s, length); } +object +parseUtf8(Thread* t, object array) +{ + for (unsigned i = 0; i < byteArrayLength(t, array) - 1; ++i) { + if (byteArrayBody(t, array, i) & 0x80) { + goto slow_path; + } + } + + return array; + + slow_path: + class Client: public Stream::Client { + public: + Client(Thread* t): t(t) { } + + virtual void handleError() { + // vm::abort(t); + } + + private: + Thread* t; + } client(t); + + class MyStream: public AbstractStream { + public: + class MyProtector: public Thread::Protector { + public: + MyProtector(Thread* t, MyStream* s): + Protector(t), s(s) + { } + + virtual void visit(Heap::Visitor* v) { + v->visit(&(s->array)); + } + + MyStream* s; + }; + + MyStream(Thread* t, Client* client, object array): + AbstractStream(client, byteArrayLength(t, array) - 1), + array(array), + protector(t, this) + { } + + virtual void copy(uint8_t* dst, unsigned offset, unsigned size) { + memcpy(dst, &byteArrayBody(protector.t, array, offset), size); + } + + object array; + MyProtector protector; + } s(t, &client, array); + + return ::parseUtf8(t, s, byteArrayLength(t, array) - 1); +} + object getCaller(Thread* t, unsigned target, bool skipMethodInvoke) { diff --git a/src/machine.h b/src/machine.h index f71788572d..2924a13fb7 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1784,8 +1784,8 @@ class FixedAllocator: public Allocator { s(s), base(base), offset(0), capacity(capacity) { } - virtual void* tryAllocate(unsigned) { - abort(s); + virtual void* tryAllocate(unsigned size) { + return allocate(size); } void* allocate(unsigned size, unsigned padAlignment) { @@ -2525,6 +2525,9 @@ emptyMethod(Thread* t, object method) object parseUtf8(Thread* t, const char* data, unsigned length); +object +parseUtf8(Thread* t, object array); + object parseClass(Thread* t, object loader, const uint8_t* data, unsigned length, Machine::Type throwType = Machine::NoClassDefFoundErrorType); diff --git a/src/openjdk/my_java_props_macosx.c b/src/openjdk/my_java_props_macosx.c index 8a1850010f..19de63cb35 100644 --- a/src/openjdk/my_java_props_macosx.c +++ b/src/openjdk/my_java_props_macosx.c @@ -3,7 +3,7 @@ PreferredToolkit getPreferredToolkit() { - return unset; + return XToolkit; } void diff --git a/src/stream.h b/src/stream.h index a08bf3b1a0..a46ad315d8 100644 --- a/src/stream.h +++ b/src/stream.h @@ -15,15 +15,15 @@ namespace vm { -class Stream { +class AbstractStream { public: class Client { public: virtual void handleError() = 0; }; - Stream(Client* client, const uint8_t* data, unsigned size): - client(client), data(data), size(size), position_(0) + AbstractStream(Client* client, unsigned size): + client(client), size(size), position_(0) { } unsigned position() { @@ -42,13 +42,13 @@ class Stream { } } - void read(uint8_t* data, unsigned size) { + void read(uint8_t* dst, unsigned size) { if (size > this->size - position_) { - memset(data, 0, size); + memset(dst, 0, size); client->handleError(); } else { - memcpy(data, this->data + position_, size); + copy(dst, position_, size); position_ += size; } } @@ -85,13 +85,29 @@ class Stream { return read8(); } + protected: + virtual void copy(uint8_t* dst, unsigned offset, unsigned size) = 0; + private: Client* client; - const uint8_t* data; unsigned size; unsigned position_; }; +class Stream: public AbstractStream { + public: + Stream(Client* client, const uint8_t* data, unsigned size): + AbstractStream(client, size), data(data) + { } + + private: + virtual void copy(uint8_t* dst, unsigned offset, unsigned size) { + memcpy(dst, data + offset, size); + } + + const uint8_t* data; +}; + } // namespace vm #endif//STREAM_H diff --git a/test/Misc.java b/test/Misc.java index 450f23d2b0..620897332f 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -1,4 +1,12 @@ public class Misc { + private static class μClass { + public int μField; + + public void μMethod(int i) { + μField = i; + } + } + private interface Bar { public int baz(); } @@ -237,5 +245,10 @@ public class Misc { System.out.println(new char[] { 'h', 'i' }); expect(! (((Object) new int[0]) instanceof Object[])); + + { μClass μInstance = new μClass(); + μInstance.μMethod(8933); + expect(μInstance.μField == 8933); + } } }