mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
Merge remote-tracking branch 'readytalk/master'
This commit is contained in:
commit
5b051f5138
2
.travis.yml
Normal file
2
.travis.yml
Normal file
@ -0,0 +1,2 @@
|
||||
language: cpp
|
||||
script: "make test"
|
732
README.md
Normal file
732
README.md
Normal file
@ -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=<lzma source directory> \
|
||||
ios={true,false} \
|
||||
bootimage={true,false} \
|
||||
heapdump={true,false} \
|
||||
tails={true,false} \
|
||||
continuations={true,false} \
|
||||
use-clang={true,false} \
|
||||
openjdk=<openjdk installation directory> \
|
||||
openjdk-src=<openjdk source directory>
|
||||
|
||||
* `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 <<EOF
|
||||
public class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello, world!");
|
||||
}
|
||||
}
|
||||
EOF
|
||||
$ javac -bootclasspath boot.jar Hello.java
|
||||
$ jar u0f boot.jar Hello.class
|
||||
|
||||
__3.__ Make an object file out of the jar.
|
||||
|
||||
$ ../build/${platform}-${arch}/binaryToObject/binaryToObject boot.jar \
|
||||
boot-jar.o _binary_boot_jar_start _binary_boot_jar_end ${platform} ${arch}
|
||||
|
||||
If you've built Avian using the `lzma` option, you may optionally
|
||||
compress the jar before generating the object:
|
||||
|
||||
../build/$(platform}-${arch}-lzma/lzma/lzma encode boot.jar boot.jar.lzma
|
||||
&& ../build/${platform}-${arch}-lzma/binaryToObject/binaryToObject \
|
||||
boot.jar.lzma boot-jar.o _binary_boot_jar_start _binary_boot_jar_end \
|
||||
${platform} ${arch}
|
||||
|
||||
Note that you'll need to specify "-Xbootclasspath:[lzma:bootJar]"
|
||||
instead of "-Xbootclasspath:[bootJar]" in the next step if you've used
|
||||
LZMA to compress the jar.
|
||||
|
||||
__4.__ Write a driver which starts the VM and runs the desired main
|
||||
method. Note the bootJar function, which will be called by the VM to
|
||||
get a handle to the embedded jar. We tell the VM about this jar by
|
||||
setting the boot classpath to "[bootJar]".
|
||||
|
||||
$ cat >embedded-jar-main.cpp <<EOF
|
||||
#include "stdint.h"
|
||||
#include "jni.h"
|
||||
|
||||
#if (defined __MINGW32__) || (defined _MSC_VER)
|
||||
# define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define EXPORT __attribute__ ((visibility("default"))) \
|
||||
__attribute__ ((used))
|
||||
#endif
|
||||
|
||||
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
|
||||
# define SYMBOL(x) binary_boot_jar_##x
|
||||
#else
|
||||
# define SYMBOL(x) _binary_boot_jar_##x
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern const uint8_t SYMBOL(start)[];
|
||||
extern const uint8_t SYMBOL(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
bootJar(unsigned* size)
|
||||
{
|
||||
*size = SYMBOL(end) - SYMBOL(start);
|
||||
return SYMBOL(start);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int
|
||||
main(int ac, const char** av)
|
||||
{
|
||||
JavaVMInitArgs vmArgs;
|
||||
vmArgs.version = JNI_VERSION_1_2;
|
||||
vmArgs.nOptions = 1;
|
||||
vmArgs.ignoreUnrecognized = JNI_TRUE;
|
||||
|
||||
JavaVMOption options[vmArgs.nOptions];
|
||||
vmArgs.options = options;
|
||||
|
||||
options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");
|
||||
|
||||
JavaVM* vm;
|
||||
void* env;
|
||||
JNI_CreateJavaVM(&vm, &env, &vmArgs);
|
||||
JNIEnv* e = static_cast<JNIEnv*>(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 <<EOF
|
||||
public class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello, world!");
|
||||
}
|
||||
}
|
||||
EOF
|
||||
$ javac -bootclasspath stage1 -d stage1 Hello.java
|
||||
|
||||
__4.__ Create a ProGuard configuration file specifying Hello.main as
|
||||
the entry point.
|
||||
|
||||
$ cat >hello.pro <<EOF
|
||||
-keep class Hello {
|
||||
public static void main(java.lang.String[]);
|
||||
}
|
||||
EOF
|
||||
|
||||
__5.__ Run ProGuard with stage1 as input and stage2 as output.
|
||||
|
||||
$ java -jar ../../proguard4.6/lib/proguard.jar \
|
||||
-dontusemixedcaseclassnames -injars stage1 -outjars stage2 \
|
||||
@../vm.pro @hello.pro
|
||||
|
||||
(note: The -dontusemixedcaseclassnames option is only needed when
|
||||
building on systems with case-insensitive filesystems such as Windows
|
||||
and OS X. Also, you'll need to add -ignorewarnings if you use the
|
||||
OpenJDK class library since the openjdk-src build does not include all
|
||||
the JARs from OpenJDK, and thus ProGuard will not be able to resolve
|
||||
all referenced classes. If you actually plan to use such classes at
|
||||
runtime, you'll need to add them to stage1 before running ProGuard.
|
||||
Finally, you'll need to add @../openjdk.pro to the above command when
|
||||
using the OpenJDK library.)
|
||||
|
||||
__6.__ Build the boot and code images.
|
||||
|
||||
$ ../build/linux-i386-bootimage/bootimage-generator
|
||||
-cp stage2 \
|
||||
-bootimage bootimage-bin.o \
|
||||
-codeimage codeimage-bin.o
|
||||
|
||||
Note that you can override the default names for the start and end
|
||||
symbols in the boot/code image by also passing:
|
||||
|
||||
-bootimage-symbols my_bootimage_start:my_bootimage_end \
|
||||
-codeimage-symbols my_codeimage_start:my_codeimage_end
|
||||
|
||||
__7.__ Write a driver which starts the VM and runs the desired main
|
||||
method. Note the bootimageBin function, which will be called by the
|
||||
VM to get a handle to the embedded boot image. We tell the VM about
|
||||
this function via the "avian.bootimage" property.
|
||||
|
||||
Note also that this example includes no resources besides class files.
|
||||
If our application loaded resources such as images and properties
|
||||
files via the classloader, we would also need to embed the jar file
|
||||
containing them. See the previous example for instructions.
|
||||
|
||||
$ cat >bootimage-main.cpp <<EOF
|
||||
#include "stdint.h"
|
||||
#include "jni.h"
|
||||
|
||||
#if (defined __MINGW32__) || (defined _MSC_VER)
|
||||
# define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define EXPORT __attribute__ ((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
|
||||
# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x
|
||||
# define CODEIMAGE_BIN(x) binary_codeimage_bin_##x
|
||||
#else
|
||||
# define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x
|
||||
# define CODEIMAGE_BIN(x) _binary_codeimage_bin_##x
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern const uint8_t BOOTIMAGE_BIN(start)[];
|
||||
extern const uint8_t BOOTIMAGE_BIN(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
bootimageBin(unsigned* size)
|
||||
{
|
||||
*size = BOOTIMAGE_BIN(end) - BOOTIMAGE_BIN(start);
|
||||
return BOOTIMAGE_BIN(start);
|
||||
}
|
||||
|
||||
extern const uint8_t CODEIMAGE_BIN(start)[];
|
||||
extern const uint8_t CODEIMAGE_BIN(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
codeimageBin(unsigned* size)
|
||||
{
|
||||
*size = CODEIMAGE_BIN(end) - CODEIMAGE_BIN(start);
|
||||
return CODEIMAGE_BIN(start);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int
|
||||
main(int ac, const char** av)
|
||||
{
|
||||
JavaVMInitArgs vmArgs;
|
||||
vmArgs.version = JNI_VERSION_1_2;
|
||||
vmArgs.nOptions = 2;
|
||||
vmArgs.ignoreUnrecognized = JNI_TRUE;
|
||||
|
||||
JavaVMOption options[vmArgs.nOptions];
|
||||
vmArgs.options = options;
|
||||
|
||||
options[0].optionString
|
||||
= const_cast<char*>("-Davian.bootimage=bootimageBin");
|
||||
|
||||
options[1].optionString
|
||||
= const_cast<char*>("-Davian.codeimage=codeimageBin");
|
||||
|
||||
JavaVM* vm;
|
||||
void* env;
|
||||
JNI_CreateJavaVM(&vm, &env, &vmArgs);
|
||||
JNIEnv* e = static_cast<JNIEnv*>(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.
|
@ -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");
|
||||
// }
|
||||
|
@ -37,7 +37,8 @@ import java.security.Permissions;
|
||||
import java.security.AllPermission;
|
||||
|
||||
public final class Class <T> 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 <T> 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 <T> 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];
|
||||
|
@ -30,7 +30,9 @@ public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
|
||||
}
|
||||
|
||||
public static <T extends Enum<T>> T valueOf(Class<T> 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<E extends Enum<E>> implements Comparable<E> {
|
||||
}
|
||||
}
|
||||
} 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() {
|
||||
|
@ -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<Integer> {
|
||||
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);
|
||||
}
|
||||
|
@ -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<Long> {
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
44
classpath/java/math/BigInteger.java
Normal file
44
classpath/java/math/BigInteger.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
71
classpath/java/math/MathContext.java
Normal file
71
classpath/java/math/MathContext.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
36
classpath/java/math/RoundingMode.java
Normal file
36
classpath/java/math/RoundingMode.java
Normal file
@ -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];
|
||||
}
|
||||
}
|
27
classpath/java/util/jar/Attributes.java
Normal file
27
classpath/java/util/jar/Attributes.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
3
makefile
3
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
|
||||
|
40
openjdk.pro
40
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;
|
||||
}
|
||||
|
727
readme.txt
727
readme.txt
@ -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=<lzma source directory> \
|
||||
ios={true,false} \
|
||||
bootimage={true,false} \
|
||||
heapdump={true,false} \
|
||||
tails={true,false} \
|
||||
continuations={true,false} \
|
||||
use-clang={true,false} \
|
||||
openjdk=<openjdk installation directory> \
|
||||
openjdk-src=<openjdk source directory>
|
||||
|
||||
* 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 <<EOF
|
||||
public class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello, world!");
|
||||
}
|
||||
}
|
||||
EOF
|
||||
$ javac -bootclasspath boot.jar Hello.java
|
||||
$ jar u0f boot.jar Hello.class
|
||||
|
||||
Step 3: Make an object file out of the jar.
|
||||
|
||||
$ ../build/${platform}-${arch}/binaryToObject/binaryToObject boot.jar \
|
||||
boot-jar.o _binary_boot_jar_start _binary_boot_jar_end ${platform} ${arch}
|
||||
|
||||
If you've built Avian using the lzma option, you may optionally
|
||||
compress the jar before generating the object:
|
||||
|
||||
$ ../build/$(platform}-${arch}-lzma/lzma/lzma encode boot.jar boot.jar.lzma
|
||||
&& ../build/${platform}-${arch}-lzma/binaryToObject/binaryToObject \
|
||||
boot.jar.lzma boot-jar.o _binary_boot_jar_start _binary_boot_jar_end \
|
||||
${platform} ${arch}
|
||||
|
||||
Note that you'll need to specify "-Xbootclasspath:[lzma:bootJar]"
|
||||
instead of "-Xbootclasspath:[bootJar]" in the next step if you've used
|
||||
LZMA to compress the jar.
|
||||
|
||||
Step 4: Write a driver which starts the VM and runs the desired main
|
||||
method. Note the bootJar function, which will be called by the VM to
|
||||
get a handle to the embedded jar. We tell the VM about this jar by
|
||||
setting the boot classpath to "[bootJar]".
|
||||
|
||||
$ cat >embedded-jar-main.cpp <<EOF
|
||||
#include "stdint.h"
|
||||
#include "jni.h"
|
||||
|
||||
#if (defined __MINGW32__) || (defined _MSC_VER)
|
||||
# define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define EXPORT __attribute__ ((visibility("default"))) \
|
||||
__attribute__ ((used))
|
||||
#endif
|
||||
|
||||
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
|
||||
# define SYMBOL(x) binary_boot_jar_##x
|
||||
#else
|
||||
# define SYMBOL(x) _binary_boot_jar_##x
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern const uint8_t SYMBOL(start)[];
|
||||
extern const uint8_t SYMBOL(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
bootJar(unsigned* size)
|
||||
{
|
||||
*size = SYMBOL(end) - SYMBOL(start);
|
||||
return SYMBOL(start);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int
|
||||
main(int ac, const char** av)
|
||||
{
|
||||
JavaVMInitArgs vmArgs;
|
||||
vmArgs.version = JNI_VERSION_1_2;
|
||||
vmArgs.nOptions = 1;
|
||||
vmArgs.ignoreUnrecognized = JNI_TRUE;
|
||||
|
||||
JavaVMOption options[vmArgs.nOptions];
|
||||
vmArgs.options = options;
|
||||
|
||||
options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");
|
||||
|
||||
JavaVM* vm;
|
||||
void* env;
|
||||
JNI_CreateJavaVM(&vm, &env, &vmArgs);
|
||||
JNIEnv* e = static_cast<JNIEnv*>(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 <<EOF
|
||||
public class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello, world!");
|
||||
}
|
||||
}
|
||||
EOF
|
||||
$ javac -bootclasspath stage1 -d stage1 Hello.java
|
||||
|
||||
Step 4: Create a ProGuard configuration file specifying Hello.main as
|
||||
the entry point.
|
||||
|
||||
$ cat >hello.pro <<EOF
|
||||
-keep class Hello {
|
||||
public static void main(java.lang.String[]);
|
||||
}
|
||||
EOF
|
||||
|
||||
Step 5: Run ProGuard with stage1 as input and stage2 as output.
|
||||
|
||||
$ java -jar ../../proguard4.6/lib/proguard.jar \
|
||||
-dontusemixedcaseclassnames -injars stage1 -outjars stage2 \
|
||||
@../vm.pro @hello.pro
|
||||
|
||||
(note: The -dontusemixedcaseclassnames option is only needed when
|
||||
building on systems with case-insensitive filesystems such as Windows
|
||||
and OS X. Also, you'll need to add -ignorewarnings if you use the
|
||||
OpenJDK class library since the openjdk-src build does not include all
|
||||
the JARs from OpenJDK, and thus ProGuard will not be able to resolve
|
||||
all referenced classes. If you actually plan to use such classes at
|
||||
runtime, you'll need to add them to stage1 before running ProGuard.
|
||||
Finally, you'll need to add @../openjdk.pro to the above command when
|
||||
using the OpenJDK library.)
|
||||
|
||||
Step 6: Build the boot and code images.
|
||||
|
||||
$ ../build/linux-i386-bootimage/bootimage-generator
|
||||
-cp stage2 \
|
||||
-bootimage bootimage-bin.o \
|
||||
-codeimage codeimage-bin.o
|
||||
|
||||
Note that you can override the default names for the start and end
|
||||
symbols in the boot/code image by also passing:
|
||||
|
||||
-bootimage-symbols my_bootimage_start:my_bootimage_end \
|
||||
-codeimage-symbols my_codeimage_start:my_codeimage_end
|
||||
|
||||
Step 7: Write a driver which starts the VM and runs the desired main
|
||||
method. Note the bootimageBin function, which will be called by the
|
||||
VM to get a handle to the embedded boot image. We tell the VM about
|
||||
this function via the "avian.bootimage" property.
|
||||
|
||||
Note also that this example includes no resources besides class files.
|
||||
If our application loaded resources such as images and properties
|
||||
files via the classloader, we would also need to embed the jar file
|
||||
containing them. See the previous example for instructions.
|
||||
|
||||
$ cat >bootimage-main.cpp <<EOF
|
||||
#include "stdint.h"
|
||||
#include "jni.h"
|
||||
|
||||
#if (defined __MINGW32__) || (defined _MSC_VER)
|
||||
# define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define EXPORT __attribute__ ((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
|
||||
# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x
|
||||
# define CODEIMAGE_BIN(x) binary_codeimage_bin_##x
|
||||
#else
|
||||
# define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x
|
||||
# define CODEIMAGE_BIN(x) _binary_codeimage_bin_##x
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern const uint8_t BOOTIMAGE_BIN(start)[];
|
||||
extern const uint8_t BOOTIMAGE_BIN(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
bootimageBin(unsigned* size)
|
||||
{
|
||||
*size = BOOTIMAGE_BIN(end) - BOOTIMAGE_BIN(start);
|
||||
return BOOTIMAGE_BIN(start);
|
||||
}
|
||||
|
||||
extern const uint8_t CODEIMAGE_BIN(start)[];
|
||||
extern const uint8_t CODEIMAGE_BIN(end)[];
|
||||
|
||||
EXPORT const uint8_t*
|
||||
codeimageBin(unsigned* size)
|
||||
{
|
||||
*size = CODEIMAGE_BIN(end) - CODEIMAGE_BIN(start);
|
||||
return CODEIMAGE_BIN(start);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int
|
||||
main(int ac, const char** av)
|
||||
{
|
||||
JavaVMInitArgs vmArgs;
|
||||
vmArgs.version = JNI_VERSION_1_2;
|
||||
vmArgs.nOptions = 2;
|
||||
vmArgs.ignoreUnrecognized = JNI_TRUE;
|
||||
|
||||
JavaVMOption options[vmArgs.nOptions];
|
||||
vmArgs.options = options;
|
||||
|
||||
options[0].optionString
|
||||
= const_cast<char*>("-Davian.bootimage=bootimageBin");
|
||||
|
||||
options[1].optionString
|
||||
= const_cast<char*>("-Davian.codeimage=codeimageBin");
|
||||
|
||||
JavaVM* vm;
|
||||
void* env;
|
||||
JNI_CreateJavaVM(&vm, &env, &vmArgs);
|
||||
JNIEnv* e = static_cast<JNIEnv*>(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.
|
@ -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;
|
||||
|
@ -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<const int8_t*>("<null>"), &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<jobject>(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<uint64_t>
|
||||
(makeLocalReference
|
||||
|
@ -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<MemorySite*>(site->copyHigh(c));
|
||||
low = static_cast<MemorySite*>(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<int>(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) {
|
||||
|
@ -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;
|
||||
|
44
src/heap.cpp
44
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) {
|
||||
|
10
src/heap.h
10
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;
|
||||
|
114
src/machine.cpp
114
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<uint8_t*>(&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<uintptr_t>(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<object>
|
||||
(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<object>
|
||||
(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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -3,7 +3,7 @@
|
||||
PreferredToolkit
|
||||
getPreferredToolkit()
|
||||
{
|
||||
return unset;
|
||||
return XToolkit;
|
||||
}
|
||||
|
||||
void
|
||||
|
30
src/stream.h
30
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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user