GithubHelp home page GithubHelp logo

readytalk / avian Goto Github PK

View Code? Open in Web Editor NEW
1.2K 97.0 172.0 20.01 MB

[INACTIVE] 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.

Home Page: https://readytalk.github.io/avian/

License: Other

Shell 0.15% CMake 0.09% Java 33.67% C++ 61.67% C 0.20% Makefile 2.49% Assembly 1.54% Dockerfile 0.18%
java jit-compiler openjdk jvm portable

avian's Introduction

Avian - A lightweight Java Virtual Machine (JVM)

PLEASE NOTE: This project is not currently being developed, maintained, or supported. Feel free to use and/or fork it, but any issues filed here will probably be ignored.

Build Status

Quick Start

These are examples of building Avian on various operating systems for the x86_64 architecture. You may need to modify JAVA_HOME according to where the JDK is installed on your system. In all cases, be sure to use forward slashes in the path.

on Linux:

$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
$ make
$ build/linux-x86_64/avian -cp build/linux-x86_64/test Hello

on Mac OS X:

$ export JAVA_HOME=$(/usr/libexec/java_home)
$ make
$ build/macosx-x86_64/avian -cp build/macosx-x86_64/test Hello

on Windows (Cygwin):

$ git clone [email protected]:ReadyTalk/win64.git ../win64
$ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.7.0_45"
$ make
$ build/windows-x86_64/avian -cp build/windows-x86_64/test Hello

on FreeBSD:

$ export JAVA_HOME=/usr/local/openjdk7
$ gmake
$ build/freebsd-x86_64/avian -cp build/freebsd-x86_64/test Hello

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.

Supported Platforms

Avian can currently target the following platforms:

  • Linux (i386, x86_64, ARM, and ARM64)
  • Windows (i386 and x86_64)
  • Mac OS X (i386 and x86_64)
  • Apple iOS (i386, x86_64, ARM, and ARM64)
  • FreeBSD (i386, x86_64)

Building

Build requirements include:

  • GNU make 3.80 or later
  • GCC 4.6 or later or LLVM Clang 3.1 or later (see use-clang option below)
  • JDK 1.6 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,macosx,ios,freebsd} \
    arch={i386,x86_64,arm,arm64} \
    process={compile,interpret} \
    mode={debug,debug-fast,fast,small} \
    lzma=<lzma source directory> \
    bootimage={true,false} \
    tails={true,false} \
    continuations={true,false} \
    use-clang={true,false} \
    openjdk=<openjdk installation directory> \
    openjdk-src=<openjdk source directory> \
    android=<android source directory> \
    ios-version=<iOS minimum version>
  • 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). Currently, only version 9.20 of the SDK has been tested, but other versions might work.

    • default: not set
  • armv6 - if true, don't use any instructions newer than armv6. By default, we assume the target is armv7 or later, and thus requires explicit memory barrier instructions to ensure cache coherency

  • 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
  • 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 the 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
  • android - if set, use the Android class library instead of the default Avian class library. See "Building with the Android Class Library" below for details.

    • default: not set
  • ios-version - the minimum iOS SDK version which will be used when compiling for ios target. Do not use a value 11.0 or larger, if you want to support 32 bit version. This option is only valid for platform=ios .

    • default: 8.0

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/x86_64 would be built in build/linux-x86_64-debug-bootimage. This allows you to build with several different sets of options independently and even simultaneously without doing a clean build each time.

Note that not all combinations of these flags are valid. For instance, non-jailbroken iOS devices do not allow JIT compilation, so only process=interpret or bootimage=true builds will run on such devices. See here for an example of an Xcode project for iOS which uses Avian.

If you are compiling for Windows, you may either cross-compile using MinGW or build natively on Windows under Cygwin.

Installing Cygwin:

1. Download and run setup.exe from cygwin's website, 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 [email protected]: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 [email protected]: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.

Note that the MSVC build isn't tested regularly, so is fairly likely to be broken.

Avian targets MSVC 11 and above (it uses c++ features not available in older versions).

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 11.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 11.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 11.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 11.0\VC\LIB;"
$ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 11.0\VC"
$ export LIB="C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;"
$ export INCLUDE="C:\Program Files\Microsoft Visual Studio 11.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 11.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. Note that you must use an absolute path here, or else the result will not work when run from other directories. In this configuration, OpenJDK needs to remain installed for Avian to work, and you can run applications like this:

$ 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 the avian-swt-examples project 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.

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. Alternatively, use https://github.com/alexkasko/openjdk-unofficial-builds.

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.

Building with the Android Class Library

As an alternative to both the Avian and OpenJDK class libaries, you can also build with the Android class library. Now it should work on Linux, OS X and Windows.

The simpliest way to build Avian with Android classpath is to use avian-pack project: https://github.com/bigfatbrowncat/avian-pack

Avian-pack consists of Avian itself with some Android components (such as libcore and icu4c).

Note that we use the upstream OpenSSL repository and apply the Android patches to it. This is because it is not clear how to build the Android fork of OpenSSL directly without checking out and building the entire platform. As of this writing, the patches apply cleanly against OpenSSL 1.0.1h, so that's the tag we check out, but this may change in the future when the Android fork rebases against a new OpenSSL version.

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"
#include "stdlib.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(size_t* size)
  {
    *size = SYMBOL(end) - SYMBOL(start);
    return SYMBOL(start);
  }

} // extern "C"

extern "C" void __cxa_pure_virtual(void) { abort(); }

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 -I$JAVA_HOME/include/darwin \
     -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o

on Windows:

 $ g++ -fno-exceptions -fno-rtti -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
$ gcc hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \
    -lIphlpapi -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/x86_64. 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-x86_64-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-x86_64-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-x86_64-bootimage/bootimage-generator \
    -cp stage2 \
    -bootimage bootimage-bin.o \
    -codeimage codeimage-bin.o \
    -hostvm ../build/linux-x86_64-interpret/libjvm.so

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(size_t* 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(size_t* 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.

avian's People

Contributors

alexey-pelykh avatar anonymouscommitter avatar bgould avatar bigfatbrowncat avatar bonifaido avatar chrisr3 avatar csoren avatar damjanjovanovic avatar dazaar avatar dicej avatar dscho avatar elementalvoid avatar ericscharff avatar gzsombor avatar jentfoo avatar joshuawarner32 avatar keinhaar avatar leonardvanderstel avatar lostdj avatar lwahlmeier avatar maartenr avatar mikehearn avatar mkeesey avatar polivar3 avatar sgoings avatar soc avatar tarotanaka0 avatar teras avatar terekcampbell avatar xranby avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avian's Issues

Running helloworld.rb using JRuby on Avian: ExceptionInInitializerError

Using
Ubuntu 12.04x86
jruby 1.5.6

log:
"root@sdkie:/home/sdkie/Desktop/# jruby hello.rb
java/lang/ExceptionInInitializerError
at org/jruby/Main.main (line 89)
caused by: java/lang/NoSuchMethodError: format (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; not found in java/lang/String
at org/jruby/platform/Platform. (line 105)
at org/jruby/Main.main (line 89)"

VM deadlock on iOS

Deadlock happens with following Hello.java only on arm-ios-avianclasslib and arm-ios-libcore64.
There is no problem on arm-android, x64-osx and x86-linux.

public class Hello {
  public Hello(long peer) throws Exception {
      final int[] counter = new int[2];
      new Thread() {
          @Override
          public void run() {
              while (true) { // frequent monitorenter/exit
                  synchronized (this) {
                      counter[0]++;
                  }
              }
          }
      }.start();
      new Thread() {
          @Override
          public void run() {
              while (true) { // frequent class metadata search
                  try {
                      Class.forName("java.lang.Object");
                  } catch (ClassNotFoundException e) {
                      e.printStackTrace();
                  }
                  synchronized (this) {
                      counter[1]++;
                  }
              }
          }
      }.start();
      new Thread() {
          @Override
          public void run() {
              while (true) { // watchdog
                  System.err.println(counter[0] + " / " + counter[1]);
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }.start();
  }

  public void draw(int x, int y, int width, int height) {
  }

  public void dispose() {
  }
}

Problem with System.out buffer on UTF-8 character output (avian 0.6)

The program:

public class Application
{
public static void main(String... args)
{
System.out.println("a");
System.out.println("b");
System.out.println("ะน"); // <--- This character produces the problem
System.out.println("c");
System.out.println("d");
}
}

creates the output:

a
b
รยน
รยน
c
รยน
c
d

which looks like the buffer never cleans after println tries to print a character "รยน" (which seems to be the UTF-8 representation of "ะน")

If we add System.out.flush() here:

public class Application
{
public static void main(String... args)
{
System.out.println("a");
System.out.println("b");
System.out.println("ะน");
System.out.println("c");
System.out.println("d");
System.out.flush();
}
}

the output changes! Now it looks like:

a
b
รยน
รยน
c
รยน
c
d
รยน
c
d

Each buffer repeats twice!

Specify formatting style for C++ code

We should choose a consistent formatting style for C++.

Desirable characteristics (from my perspective):

  • Tool driven, with checked-in specification
  • Not tied to any particular editor
  • Not too different from exiting style
    • However, I'm personally not a big fan of the parens-on-the-next-line style
    • If possible, I'd prefer to go with an existing, built-in style that's close, rather than a highly-customized style spec that's a little closer.

I propose clang-format, which has a variety of built-in styles, is moderately customizable, can format small sub-sections of files and has plugins for a variety of editors (emacs, sublime text, ... (and a very simple command-line interface if there's not already a plugin)). Most importantly, from my perspective, it's much smarter about where to place line breaks than most (all?) other tools I've used; it uses a LATEX-style line-break optimization algorithm.

I'm of course open to other suggestions.

Also, to be clear, I'm not suggesting a bulk reformat of existing code (yet) - just a consistent format to use for new code.

Reorganize Android build process

It would be nice to organize the Android build of Avian so it can plug directly into a checked-out Android tree. This makes it convenient for users with a checked-out Android tree, but is should also make it easier for people that don't have an Android tree.

It can use a smaller repo manifest (e.g., "repo init -u http://...") to avoid the long setup instructions.

Building problem under mingw-w64

I'm using the official build of mingw-w64 from http://mingw-w64.sourceforge.net/download.php#mingw-builds

There are 2 problems with building for x86_64 platform.

Problem 1:
At first if you want to get an x86_64 version you have to specify it like

make arch=x86_64

If you just run "make", it fails on linkage cause it builds i386 binaries and tries to link them against system x86_64 libraries. Probably it's a problem in the mingw-w64 platform self-definition, but maybe there should be a workaround in avian makefile...

Problem 2:
The build script can't link avian.exe cause in mingw-w64 there are no tools named

x86_64-w64-mingw32-ar
x86_64-w64-mingw32-dlltool
x86_64-w64-mingw32-ranlib
x86_64-w64-mingw32-strip

There are only

ar
dlltool
ranlib
strip

and when I have modified Avian makefile removing prefixes for these tools like this:

...........
ifeq ($(arch),x86_64)
    ifeq ($(build-platform),cygwin)
        build-cxx = x86_64-w64-mingw32-g++
        build-cc = x86_64-w64-mingw32-gcc
    endif
    cxx = x86_64-w64-mingw32-g++ $(mflag)
    cc = x86_64-w64-mingw32-gcc $(mflag)
    dlltool = dlltool
    ar = ar
    ranlib = ranlib
    strip = strip
    inc = "$(win64)/include"
    lib = "$(win64)/lib"
else
...........

...it builds successfully. Maybe I'm wrong here, but as I understand, such tools are universal and work with any platform, are they? Maybe the difference should be moved from prefix to command line arguments?

I understand that my workaround is dirty and could break something (maybe some other mingw builds) but I want to draw your attention to this problem, since mingw-w64 is very popular.

Investigate moving to Drone.io

It looks like drone.io, being based on docker, might offer some significant advantages over travis ci. In particular, we could add windows, 32-bit linux, arm and powerpc cross-compiler toolchains to the docker images. We might even be able to boot a powerpc/arm qemu machine inside the container to run tests on. Also, it's open-source.

See: http://blog.drone.io/2014/2/5/open-source-ci-docker.html

test/Reflection.java compilation errors

Make output:

compiling test classes
test/Reflection.java:147: set(java.lang.Object,long) has private access in java.lang.reflect.Field
      Reflection.class.getDeclaredField("egads").set(r, 42);
                                                ^
test/Reflection.java:148: inconvertible types
found   : java.lang.Object
required: int
      expect(((int) Reflection.class.getDeclaredField("egads").get(r)) == 42);
                                                                  ^
test/Reflection.java:213: set(java.lang.Object,long) has private access in java.lang.reflect.Field
      Foo.class.getField("foo").set(null, 42);
                               ^
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
3 errors
make: *** [build/linux-x86_64/test.dep] Error 1

My system is Ubuntu linux 13.10 x86-64
JDK version is 1.6.0_45

arch=i386 mode=debug tests are broken

            ------- Unit tests -------
        RegisterIterator: success
          BasicAssembler: success
        ArchitecturePlan: success
               ArgParser: success

            ------- Java tests -------
               AllFloats: success
             Annotations: success
              ArraysTest: success
             AtomicTests: success
              BitsetTest: fail
                 Buffers: fail
                    Busy: success
             Collections: success
               Datagrams: success
                   Dates: success
             DefineClass: success
            DivideByZero: success
             EnumSetTest: fail
                   Enums: success
              Exceptions: success
              FileOutput: success
                   Files: success
              Finalizers: success
                  Floats: success
                      GC: success
                   Hello: success
            Initializers: success
                Integers: success
                     JNI: success
             LazyLoading: success
                    List: success
                 Logging: success
                   Longs: fail
       MessageFormatTest: success
                    Misc: success
             NullPointer: success
                 Observe: success
             OutOfMemory: success
               Processes: success
                 Proxies: success
              References: success
              Reflection: success
                   Regex: success
               Serialize: fail
                  Simple: success
           StackOverflow: success
                 Strings: success
              Subroutine: success
                  Switch: success
                 Threads: success
     TimeUnitConversions: success
                   Trace: success
                    Tree: success
              UnsafeTest: success
                 UrlTest: success
                     Zip: success
     ZipOutputStreamTest: success

see log.txt for output

All these tests segfault rather anonymously:

Program received signal SIGSEGV, Segmentation fault.
0x0000002b in ?? ()
(gdb) bt
#0  0x0000002b in ?? ()
#1  0x0028fac0 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Error to start an embedded tomcat 7 server.

I got this when I try to start an embedded tomcat 7 server using avian:

D:\.techs\launch4j\target>avian -jar xxx.jar
java/lang/NoClassDefFoundError: javax/management/MBeanRegistration
  at org/apache/catalina/startup/Tomcat.getHost (line 435)
  at org/apache/catalina/startup/Tomcat.addWebapp (line 201)
  at com/xxx/xxx/desktop/Bootstrapper.main (line 20)

Serialize TreeMap test is broken on Android build

The test in Serialize.java, which serializes a java.util.TreeMap and then compares the result to a specific byte pattern, is too fragile because it assumes TreeMap will have a certain, fixed set of fields. It breaks when using Android's TreeMap, since that has several additional fields which must be serialized.

I humbly suggest we use a class specifically written for this purpose so we can control what fields it has and not make assumptions about the class library's implementation.

busy wait can block entire VM

In order for a thread to enter the "exclusive" state such that no other threads are active in the VM, it must wait for all active threads to enter the "idle" state. In order for this to happen in a timely manner, threads must check frequently to see if a thread is waiting to enter the exclusive state. These checks happen at every memory allocation, wait, sleep, native call, etc. However, if a thread is in a busy loop that does none of those things, it will block any other thread from entering that state and eventually cause all other threads to block.

The proper way to address this is to detect such loops (or tail recursion in tail-call-optimized builds) at compile or interpret time and insert explicit checks.

See also 5d3dc70

Does not compile with newer versions of clang and gcc

Compiling avian with newer compilers results in a bunch of error messages
such as:

raichoo@lain avianยป make use-clang=true
compiling build/linux-x86_64/tools/type-generator/main-build.o
In file included from src/tools/type-generator/main.cpp:11:
/usr/include/stdlib.h:139:8: error: unknown type name 'size_t'
extern size_t __ctype_get_mb_cur_max (void) __THROW __wur;

I'm under a current version of arch linux. Compiler versions are:

clang version 3.2 (tags/RELEASE_32/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix

and

g++ (GCC) 4.8.0 20130411 (prerelease)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Both compilers result in the same error messages.

Kind regards

Pointer being freed was not allocated -- avian-dynamic & openjdk7 & OSX

I've recently been making Avian work for Clojure.
I went back to try another/fresh openjdk7 build, which completes, but I get:
error for object 0x28: pointer being freed was not allocated

when running:
./avian-dynamic -jar helloworldclj-0.1.0-SNAPSHOT-standalone.jar

... where the jar above is an uberjar of a simple helloworld application.
I did not previously see this happen with an early experiment I was running.

Please let me know what additional information you need.
OSX 10.7.5
2 Ghz Intel Core i7 with 8Gb Ram
java version: openjdk version "1.7.0-u40-b30" (fresh for this build)
Apple clang version 4.0 (tags/Apple/clang-421.0.60) (based on LLVM 3.1svn)
On the latest avian master
JAVA_HOME aliased to the fresh build ala:
JAVA_HOME=/Users/paul/scratch/avian/jdk1.7.0.jdk/Contents/Home/ make openjdk=/Users/paul/scratch/avian/jdk1.7.0.jdk/Contents/Home/

I'm more than happy to jump in the code and work through this issue with you.

Thread.join() hangs with Android classpath

public class ThreadTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {

            }
        });

        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

This simple class makes Avian hang under OS X if it's built with Android classpath.

Actually, I found this bug while porting Android classpath to Windows, so firstly it was discovered under Windows. But it looks like this problem is cross platform.

How to list loaded classes?

In the case of advanced reflection usage, one of the most common tasks is searching for a class, which implements an interface, extends other class or contains a specific attribute.

In Oracle JVM there is a hack which (as far as I know) is exploited with almostly all such programs - ClassLoader contains "classes" hidden variable inside which is a list of all loaded classes. You should just open it and list them.

How to achieve the same goal in Avian using it's default library?

I accept any solution either via Java or JNI. Just tell me how to do it.

0.7 macos build with openjdk claims test failures (misc/datagrams)

I'm getting test errors when I try to build avain v0.7 for macos (10.8.4):

            ------- Java tests -------
               AllFloats: success
             Annotations: success
                  Arrays: success
              BitsetTest: success
                 Buffers: success
               Datagrams: fail
             DefineClass: success
            DivideByZero: success
             EnumSetTest: success
                   Enums: success
              Exceptions: success
              FileOutput: success
                   Files: success
              Finalizers: success
                  Floats: success
                      GC: success
                   Hello: success
            Initializers: success
                Integers: success
                     JNI: success
             LazyLoading: success
                    List: success
                 Logging: success
                   Longs: success
                    Misc: fail
             NullPointer: success
             OutOfMemory: success
               Processes: success
                 Proxies: success
              References: success
              Reflection: success
                  Simple: success
           StackOverflow: success
                 Strings: success
              Subroutine: success
                  Switch: success
                 Threads: success
                   Trace: success
                    Tree: success
              UnsafeTest: success
                 UrlTest: success
                     Zip: success

see log.txt for output
make: *** [test] Error 255

JAVA_HOME is:

JAVA_HOME=/Users/swade/compile/openjdk/build/macosx-x86_64/j2sdk-image

Running make like this:

make openjdk="$(pwd)/../openjdk/build/macosx-x86_64/j2sdk-image" openjdk-src="$(pwd)/../openjdk/jdk/src" test

Is this expected?

Error occured when compile avian using cygwin 1.7 on Win 7 sp1

Edison@admin-PC /local/src/avian
$ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_45"

Edison@admin-PC /local/src/avian
$ make
compiling build/windows-i386/tools/type-generator/main-build.o
src/tools/type-generator/main.cpp:11:20: fatal error: stdlib.h: No such file or                  directory
compilation terminated.
makefile:1717: recipe for target `build/windows-i386/tools/type-generator/main-b                 uild.o' failed
make: *** [build/windows-i386/tools/type-generator/main-build.o] Error 1

Edison@admin-PC /local/src/avian
$ apt-cyg show
The following packages are installed:
_autorebase
_update-info-dir
alternatives
base-cygwin
base-files
bash
bzip2
coreutils
cygutils
cygwin
dash
diffutils
dos2unix
editrights
file
findutils
gawk
gcc-mingw-g++
gettext
grep
groff
gzip
ipc-utils
less
libattr1
libbz2_1
libffi6
libgcc1
libgcrypt11
libgmp10
libgmp3
libgnutls26
libgpg-error0
libiconv2
libidn11
libintl8
liblzma5
liblzo2_2
libmpc3
libmpfr4
libncurses10
libncursesw10
libp11-kit0
libpcre0
libpopt0
libreadline7
libstdc++6
libtasn1_3
login
make
man
mingw-binutils
mingw-gcc-core
mingw-gcc-g++
mingw-pthreads
mingw-runtime
mingw-w32api
mingw64-i686-binutils
mingw64-i686-gcc-core
mingw64-i686-gcc-g++
mingw64-i686-runtime
mingw64-i686-winpthreads
mingw64-x86_64-binutils
mingw64-x86_64-gcc-core
mingw64-x86_64-gcc-g++
mingw64-x86_64-runtime
mingw64-x86_64-winpthreads
mintty
rebase
run
sed
tar
terminfo
texinfo
tzcode
vim-minimal
wget
which
xz
zlib0

Please implement Unsafe.getObjectVolatile

I am trying to implement some of java.util.concurrent.locks. In order to do that I need Unsafe.getObjectVolatile to be implemented. That is the only function I saw that I needed to fully implement java.util.concurrent.locks.LockSupport (and thus I think I can do the rest of the locks after that).

Add putOrderedLong and putOrderedObject to sun.misc.Unsafe

I am in progress with implementing the atomic package, and recognized that putOrderedLong is not implemented in avian's unsafe implementation. There may be others I will run into, but this is at least the first one I found that we need.

** Edit added putOrderedObject to the list of what is needed to be added (for AtomicReference).

Regex test fails on OpenJDK and with Avian using the OpenJDK classpath

On OpenJDK, we see this:

$ java -cp build/linux-x86_64/test Regex
Exception in thread "main" java.util.regex.PatternSyntaxException: Look-behind group does not have an obvious maximum length near index 19
.(o)(?<=[A-Z][a-z])
^
at java.util.regex.Pattern.error(Pattern.java:1924)
at java.util.regex.Pattern.group0(Pattern.java:2812)
at java.util.regex.Pattern.sequence(Pattern.java:2018)
at java.util.regex.Pattern.expr(Pattern.java:1964)
at java.util.regex.Pattern.compile(Pattern.java:1665)
at java.util.regex.Pattern.(Pattern.java:1337)
at java.util.regex.Pattern.compile(Pattern.java:1022)
at Regex.getMatcher(Regex.java:10)
at Regex.expectGroups(Regex.java:23)
at Regex.main(Regex.java:73)

On Avian using the OpenJDK classpath, we see this:

$ ./build/linux-x86_64-openjdk/avian-dynamic -cp build/linux-x86_64-openjdk/test Regex
java/util/regex/PatternSyntaxException
at java/util/regex/Pattern.error (line 1924)
at java/util/regex/Pattern.group0 (line 2812)
at java/util/regex/Pattern.sequence (line 2018)
at java/util/regex/Pattern.expr (line 1964)
at java/util/regex/Pattern.compile (line 1665)
at java/util/regex/Pattern. (line 1337)
at java/util/regex/Pattern.compile (line 1022)
at Regex.getMatcher (line 10)
at Regex.expectGroups (line 23)
at Regex.main (line 73)

Problem with string constant encoding in Avian

As far as I understand, Avian converts strings into UTF-8. That leads to some problems. Let me show:

public static void main(String[] args)
{
    System.out.println("Hello! ะŸั€ะธะฒะตั‚!");
}

The file is encoded in Codepage 866 (old cyrillic Russian encoding, used in Windows console).

Oracle JVM output in console:

Hello! ะŸั€ะธะฒะตั‚!

Avian output in console:

Hello! โ•จะŸโ•จโ–‘โ•จะ‘โ•คะฎโ•ฅะ โ•จโ–“!

I thing the root cause is that the Oracle JVM takes string constants AS IS and just puts it into output, while Avian converts all constants from the current system encoding into UTF-8. This behaviour leads to a mess.

Let me show it: let's encode our source file in Windows-1251 (default Windows Cyrillic codepage) and run again.

Oracle JVM output in console:

Hello! โ•งะัˆั‚ั…ะ„!

That strange output is correct! We loaded string from a file with Cp1251 and written it into Cp866 (console encoding). This is a default Russian Windows developers curse. We use two different encodings for Win32 UI and for console windows.

Avian output in console:

Hello! โ•จะฏโ•คะโ•จโ••โ•จโ–“โ•จโ•กโ•คะ’!

Here we see a different result. What's this? We could answer easily. Let's change console window codepage to UTF-8

>chcp 65001

After that Avian output would be:

Hello! ะŸั€ะธะฒะตั‚!

If we change console encoding to Cp1251 with

>chcp 1251

Oracle JVM output would be correct:

Hello! ะŸั€ะธะฒะตั‚!

So just as I said before, Oracle JVM just copies text as is, but Avian converts it from Cp1251 to UTF-8.

Could you change this behavior to improve compatibility between VMs?

And, in addition, Avian default classpath doesn't support a simple way to change the I/O encoding. No methods that are recommended here: http://stackoverflow.com/questions/2415597/java-how-to-detect-and-change-encoding-of-system-console work for Avian.

  1. There is no System.console() by default
  2. You can't write PrintStream out = new PrintStream(System.out, true, "UTF-8"); cause there is no such constructor for PrintStream.
  3. As far as I see, Avian doesn't support -Dfile.encoding (maybe I'm wrong)

If you could implement encoding conversion for PrintStream, that would be a great present...

Avian can't use more than ~2GB of heap space

We're using 32-bit integers (signed in some cases) all over heap.cpp to represent sizes, so we overflow when we get close to 2^31. We should replace these fields and variables with 64-bit integers.

Crash with OpenJDK 7 classpath and JNA

I have updated my JNA example project, it now demonstrates a new problem where Avian is hitting an assert.

The example can be found at https://github.com/csoren/avian-jna

The project demonstrates a problem with using JNA on Avian/OpenJDK 7 on Windows. I have used https://github.com/alexkasko/openjdk-unofficial-builds#openjdk-7-update-45-build-31-icedtea-243 as classpath

This example works with the OpenJDK 7 VM.

To reproduce:

mvn package
cd target
avian -jar avian-jna.jar

Observe the result: Crash!

The native callstack is

#0  0x00403770 in avian::system::crash () at src/system/windows/signal.cpp:269
#1  0x004032b4 in (anonymous namespace)::MySystem::abort (this=0x3f1eb0) at src/system/windows.cpp:942
#2  0x04327f19 in avian::util::abort<vm::Thread*> (t=0x3f5b94) at include/avian/util/abort.h:33
#3  0x043280e6 in avian::util::expect<vm::Thread*> (t=0x3f5b94, v=false) at include/avian/util/abort.h:40
#4  0x04328004 in avian::util::assert<vm::Thread*> (t=0x3f5b94, v=false) at include/avian/util/abort.h:49
#5  0x0431cfe8 in vm::byteArrayLength (t=0x3f5b94, o=0x0) at build/windows-i386-debug-openjdk-src/type-declarations.cpp:2943
#6  0x0431a8f1 in vm::byteArrayHash (t=0x3f5b94, array=0x0) at src/avian/machine.h:2325
#7  0x0042872d in vm::hashMapFindNode (t=0x3f5b94, map=0xb791fac, key=0x0, hash=0x431a8d8 <vm::byteArrayHash(vm::Thread*, vm::Object*)>, equal=0x431bb70 <vm::byteArrayEqual(vm::Thread*, vm::Object*, vm::Object*)>) at src/util.cpp:326
#8  0x0431879d in vm::hashMapFind (t=0x3f5b94, map=0xb791fac, key=0x0, hash=0x431a8d8 <vm::byteArrayHash(vm::Thread*, vm::Object*)>, equal=0x431bb70 <vm::byteArrayEqual(vm::Thread*, vm::Object*, vm::Object*)>) at src/avian/util.h:29
#9  0x004187d0 in vm::resolveSystemClass (t=0x3f5b94, loader=0xb791db0, spec=0x0, throw_=true, throwType=vm::Machine::NoClassDefFoundErrorType) at src/machine.cpp:4207
#10 0x00418e2b in vm::resolveClass (t=0x3f5b94, loader=0xb791db0, spec=0x0, throw_=true, throwType=vm::Machine::NoClassDefFoundErrorType) at src/machine.cpp:4324
#11 0x00458f58 in vm::getDeclaringClass (t=0x3f5b94, c=0xb7ccdf0) at src/avian/classpath-common.h:740
#12 0x00464056 in (anonymous namespace)::local::jvmGetDeclaringClass (t=0x3f5b94, arguments=0x28f6ac) at src/classpath-openjdk.cpp:4143
#13 0x004873b4 in vmRun ()
#14 0x043260d8 in vm::runRaw (t=0x3f5b94, function=0x464029 <(anonymous namespace)::local::jvmGetDeclaringClass(vm::Thread*, uintptr_t*)>, arguments=0x28f6ac) at src/avian/machine.h:1914
#15 0x04324894 in vm::run (t=0x3f5b94, function=0x464029 <(anonymous namespace)::local::jvmGetDeclaringClass(vm::Thread*, uintptr_t*)>, arguments=0x28f6ac) at src/avian/machine.h:1921
#16 0x00464092 in JVM_GetDeclaringClass@8 (t=0x3f5b94, c=0x28f870) at src/classpath-openjdk.cpp:4151
#17 0x00487342 in vmNativeCall ()
#18 0x04318626 in vm::dynamicCall (function=0x46406c <JVM_GetDeclaringClass@8>, arguments=0x28f718, argumentsSize=8, returnType=7) at src/avian/x86.h:97
#19 0x00446a47 in (anonymous namespace)::local::invokeNativeSlow (t=0x3f5b94, method=0xb59788c, function=0x46406c <JVM_GetDeclaringClass@8>) at src/compile.cpp:7439
#20 0x00446cbe in (anonymous namespace)::local::invokeNative2 (t=0x3f5b94, method=0xb59788c) at src/compile.cpp:7511
#21 0x00446e27 in (anonymous namespace)::local::invokeNative (t=0x3f5b94) at src/compile.cpp:7543
#22 0x07d60051 in ?? ()

It seems to start going wrong when #10 vm::resolveClass receives 0 in the spec parameter.

VM callstack is:

debug trace for thread 003F5B94
  at java/lang/Class.getDeclaringClass0 (native)
  at java/lang/Class.getDeclaringClass (line 1101)
  at com/sun/jna/Native.findEnclosingLibraryClass (line 471)
  at com/sun/jna/Native.getLibraryOptions (line 496)
  at com/sun/jna/Native.getTypeMapper (line 562)
  at com/sun/jna/CallbackReference.<init> (line 147)
  at com/sun/jna/CallbackReference.getFunctionPointer (line 399)
  at com/sun/jna/CallbackReference.getFunctionPointer (line 381)
  at com/sun/jna/Pointer.setValue (line 960)
  at com/sun/jna/Structure.writeField (line 784)
  at com/sun/jna/Structure.write (line 702)
  at com/example/Main.run (line 32)
  at com/example/Main.main (line 37)

java/util/Collections$UnmodifiableMap.values makes wrong assumptions about underlying map

$ cat ex/Test.java
import java.util.Collections;

public class Test {
    public static void main(String[] args) {
        Collections.unmodifiableMap(Collections.<String, String>emptyMap()).values();
    }
}
$ build/linux-x86_64/avian -cp ex Test
java/lang/ClassCastException: java.util.HashMap$Values cannot be cast to java.util.Set
  at java/util/Collections$UnmodifiableMap.values (line 474)
  at java/util/Collections$UnmodifiableMap.values (line 474)
  at Test.main (line 5)

dcmp fails on arm compiler mode

The following code prints 'false' on arm-android and arm-ios.
On x86-win32, correctly prints 'true'.

public class TestDCMP {
  public static void main(String[] args) {
    System.out.println(test(0));
  }
  private static boolean test(double x) {
    return x < 1.0;
  }
}

Improve usability of assert/abort

The current requirement to have a System instance in order to call abort on makes it very difficult to write "clean", modular utilities. Anything that could possibly want to assert needs to have either an Aborter (of which System is the only current implementation) or a System parameter. If we want to add an assert somewhere that we don't have one of those, we need to add such a parameter.

Let's make the choice of abort functionality a link-time option rather than a runtime option.

We make sure to include our abort function (which I've called "crash" in #171) in a separate .cpp file from most everything else. Anyone wanting to swap out the implementation can do so at compile time. We can even build a library that has that symbol undefined and expects the executable itself to define it.

The only thing we lose in that case is the context of which VM instance this abort is associated with - and that can be solved pretty simply with thread locals.

Lower overhead of safe points

Currently, we add calls to idleIfNecessary on every backwards branch so that no thread can run indefinitely without yielding control (at a safe point) to the VM, mostly in order to perform a GC cycle. This likely has a moderate overhead (unmeasured, as of yet), and we should try to reduce that.

Instead of generating a call, we could (for instance) issue a store to a fixed address at possible pause points in the generated code. The VM then controls the protection status of the memory (writable or not), and catches the signal. When a thread in the VM wants to enter the exclusive state, it simply changes the permissions on the page from writable to read-only, and waits for all threads to get the signal. When the original thread wants to release the exclusive state, it makes the page writable again, and resumes each of the threads.

Files test fails with latest openjdk 7

The files test fails thusly:

java/lang/UnsatisfiedLinkError: java/io/FileInputStream.read()I
at java/io/FileInputStream.read (native)
at java/io/FileInputStream.read (native)
at Files.main (line 64)

Note that this was originally discussed in #74

Exception with JNA on Avian/OpenJDK7

JNA structures with Avian using the OpenJDK 7 classpath throws an exception under certain conditions. I have created a tiny test case that works with straight OpenJDK 7, but fails with Avian using OpenJDK 7 classpath.

It seems that com.sun.jna.Structure is unable to read fields that are defined in a subclass, when the subclass is protected.

https://github.com/csoren/avian-jna

The code is

public class Main {

    protected static class MyStructure extends Structure {

        public int myField = 42;

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("myField");
        }
    }

    public static void main(String[] args) {
        Structure s = new MyStructure();
        s.write();
        System.out.println("Yay, no exceptions");
    }
}

which will throw this exception:

java/lang/Error: Exception reading field 'myField' in class com.example.Main$MyStructure: java.lang.IllegalAccessException: Class com.sun.jna.Structure can not access a member of class com.example.Main$MyStructure with modifiers "public"
  at com/sun/jna/Structure.getFieldValue (line 562)
  at com/sun/jna/Structure.deriveLayout (line 1095)
  at com/sun/jna/Structure.calculateSize (line 966)
  at com/sun/jna/Structure.calculateSize (line 933)
  at com/sun/jna/Structure.allocateMemory (line 360)
  at com/sun/jna/Structure.<init> (line 184)
  at com/sun/jna/Structure.<init> (line 172)
  at com/sun/jna/Structure.<init> (line 159)
  at com/sun/jna/Structure.<init> (line 151)
  at com/example/Main$MyStructure.<init> (line 10)
  at com/example/Main.main (line 21)```

If the MyStructure class is changed to public, the problem goes away.

I don't know if this is related to issue #185. I have applied the patch that supposedly fixed #185, the problem persists.

org.eclipse.swt.SWTException: Invalid thread access

I got this exception accidentally and can't understand, why. It's on OS X. Could you help me and tell, how could I make Avian run main() in the first app thread? Does it support -XrunOnFirstThread option?

Avian's File.mkdir() implementation uses 700 permissions, while openJDK uses 777

In investigating an internal issue, @joshuawarner32 and I noticed that the Avian implementation of File.mkdir() calls mkdir with permissions 700, whereas the openJDK uses 777.

Avian:

extern "C" JNIEXPORT void JNICALL
Java_java_io_File_mkdir(JNIEnv* e, jclass, jstring path)
{
  string_t chars = getChars(e, path);
  if (chars) {
    if (not exists(chars)) {
      int r = ::MKDIR(chars, 0700);
      if (r != 0) {
        throwNewErrno(e, "java/io/IOException");
      }
    }
    releaseChars(e, path, chars);
  }
}

OpenJDK:

JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_createDirectory(JNIEnv *env, jobject this,
                                            jobject file)
{
    jboolean rv = JNI_FALSE;

    WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
        if (mkdir(path, 0777) == 0) {
            rv = JNI_TRUE;
        }
    } END_PLATFORM_STRING(env, path);
    return rv;
}

Though this wasn't causing the issue I was originally investigating, I think it might be worth a conversation about whether or not we want to match the OpenJDK with regards to the permissions we create directories with.

For what it's worth, 700 seems pretty reasonable to me. 777 is a bit "fast-and-loose", but it's possible that this could cause some strange issues if we don't match the behavior.

git repo is way too big

The git repo now weighs in at over 100MB, even though the master working copy is only 4.9MB. That's ridiculous.

I propose we do the following:

  • move obsolete branches to forks (e.g. move the invokeinterface branch to dicej/avian, since it will probably never be merged, but I want to preserve it for later reference)
  • remove gh-pages and figure out a different way to store the website outside the repo without breaking it like we did last time we tried
  • rewrite history to delete accidentally-checked in binaries, e.g. http://www.rallydev.com/community/engineering/shrinking-git-repository-move-githubcom

Guice dependency injection doesn't appear to work with Avian

I can't get Guice dependency injection to work with Avian using the OpenJDK7 classpath. I have put together a very short sample with instructions on how to reproduce here: https://github.com/csoren/avian-guice

In short, the example works with OpenJDK 7 but fails with Avian.

The result with Avian is
com/google/inject/CreationException
at com/google/inject/internal/Errors.throwCreationExceptionIfErrorsExist (line 435)
at com/google/inject/internal/InternalInjectorCreator.initializeStatically (line 154)
at com/google/inject/internal/InternalInjectorCreator.build (line 106)
at com/google/inject/Guice.createInjector (line 95)
at com/google/inject/Guice.createInjector (line 72)
at com/google/inject/Guice.createInjector (line 62)
at com/example/Main.main (line 36)

OpenJDK 7 produces the expected result: Hello, world!

Delegate Java portions of the build process to Gradle

I'd like to see Gradle take control over the pure Java build portions of this project's build infrastructure in order to reap signifcant benefits in code quality and structure flexibility.

Specifically:

  • Let's move the home-built unit tests to JUnit or TestNG and kick them off with Gradle instead of make. Framework familiarity and ease of integration/addition of more tests is key to having confidence in the quality of Avian's deliverables.

local::getFinder missing for openjdk-src build

When compiling an openjdk-src build for Windows I get the following error:

compiling build/windows-i386-small-openjdk-src/classpath-openjdk.o
src/classpath-openjdk.cpp: In function 'int64_t Avian_java_util_TimeZone_getSystemTimeZoneID(vm::Thread*, vm::object, uintptr_t*)':
src/classpath-openjdk.cpp:5592:20: error: 'getFinder' is not a member of '{anonymous}::local'
src/classpath-openjdk.cpp:5592:20: note: suggested alternatives:
In file included from src/classpath-openjdk.cpp:12:0:
src/avian/classpath-common.h:621:1: note:   'vm::getFinder'
src/avian/classpath-common.h:621:1: note:   'vm::getFinder'
In file included from src/avian/bootimage.h:63:0,
                 from src/avian/processor.h:17,
                 from src/avian/machine.h:19,
                 from src/classpath-openjdk.cpp:11:
src/bootimage-template.cpp: At global scope:
src/bootimage-template.cpp:6:1: error: 'vm::TargetBootFlatConstant' defined but not used [-Werror=unused-variable]
src/bootimage-template.cpp:7:1: error: 'vm::TargetBootHeapOffset' defined but not used [-Werror=unused-variable]
In file included from src/avian/bootimage.h:69:0,
                 from src/avian/processor.h:17,
                 from src/avian/machine.h:19,
                 from src/classpath-openjdk.cpp:11:
src/bootimage-template.cpp:6:16: error: 'vm::BootFlatConstant' defined but not used [-Werror=unused-variable]
src/bootimage-template.cpp:7:16: error: 'vm::BootHeapOffset' defined but not used [-Werror=unused-variable]
cc1plus.exe: all warnings being treated as errors
make: *** [build/windows-i386-small-openjdk-src/classpath-openjdk.o] Error 1

JNI NewString crashes when char length is zero

The following code will crash in Avian:

jstring javaStr = (*jni)->NewString(jni, (jchar *)buffer, 0);

This patch will fix it:

diff --git a/VM/avian/jnienv.cpp b/VM/avian/jnienv.cpp
index 9e1d7e9..52da955 100644
--- a/VM/avian/jnienv.cpp
+++ b/VM/avian/jnienv.cpp
@@ -241,9 +241,8 @@ newString(Thread* t, uintptr_t* arguments)
   const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
   jsize size = arguments[1];

-  object a = 0;
+  object a = makeCharArray(t, size);
   if (size) {
-    a = makeCharArray(t, size);
     memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
   }

Compiling with clang: src/arm.S:59:3: error: invalid instruction

Everything seems to compile fine in Avian if you use clang on Mac OS 10.8.2 instead of gcc, with the exception of arm.S, which gives the one error:

09:29 avian$ clang -x assembler-with-cpp -arch armv7 -Isrc -DTARGET_BYTES_PER_WORD=4 -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/ -c src/arm.S -o build/darwin-arm-interpret-openjdk-src/arm-asm.o
src/arm.S:59:3: error: invalid instruction
  ldmneia r6, {r0-r3}
  ^

Looking at per-gron/silk-arm-ios#1 , it seems that some of the instructions need to be massaged for clang. The following preprocessor hack ("-Dldmneia=ldmiane") makes it compile successfully, so maybe it can be worked into the arm.S with an "#ifdef clang":

clang -Dldmneia=ldmiane -x assembler-with-cpp -arch armv7 -Isrc -DTARGET_BYTES_PER_WORD=4 -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/ -c src/arm.S -o build/darwin-arm-interpret-openjdk-src/arm-asm.o

Fixed buffer size in MyClasspath can crash when JAVA_HOME is in a long path

The buffer size in classpath-openjdk.cpp for JVM arguments is 1024, which can cause a crash when JAVA_HOME is in a really deep path:

15:14 avian$ avian/build/darwin-x86_64-interpret-openjdk-src/avian -Djava.home=/tmp/java_home_folder_path_long_enough_to_overflow_the_avian_openjdk_classpath_buffer_size foobar

java/lang/NoClassDefFoundError: foobar

15:14 avian$ avian/build/darwin-x86_64-interpret-openjdk-src/avian -Djava.home=/tmp/java_home_folder_path_long_enough_to_overflow_the_avian_openjdk_classpath_buffer_size_needs_to_be_really_really_long foobar

Abort trap: 6

The offending code is the BufferSize here:

class MyClasspath : public Classpath {
 public:
  static const unsigned BufferSize = 1024;

  MyClasspath(System* s, Allocator* allocator, const char* javaHome,
              const char* embedPrefix):
    allocator(allocator), ranNetOnLoad(0), ranManagementOnLoad(0)
  {

The buffer should be dynamic, but if needs to be a fixed size, we should at least fail gracefully if it is overflowed.

<Not an issue, just a propose> Adding some classes from the abandoned Apache Harmony project.

Hi! As far as I know, the weakest point of Avian at the moment is its poor and incomplete class library.

Recently I was attempting to improve it a bit (I was adding ServerSocket implementation and some other stuff) and found that a very hard work. Eventually I found out that there is a free and open source (but not GPL-ed) implementation of Java basic classpath containing java.net, java.text and all other pretty good old tested classes. I'm talking about the Apache Harmony project.

It's abandoned now and licensed under Apache v2 license. I took a look at its source code and found it pretty simple to understand.

I want to ask for a permission to grab some code from this source, adapt it for Avian and contribute here. The only disadvantage for you is a need to include some notices about the licensed files (http://www.apache.org/licenses/). As far as I understand, Apache License v2 doesn't restrict developers and end-users in any way excepting that.

If you accept my Idea, at first I'm going to take java.net package from AH and put it here instead of my homemade poor implementation.

As for me it's a better option than using of the OpenJDK classpath...

WinRT in AOT mode

Do you have plans of supporting WinRT or WP8 in AOT mode?

Currently I'm trying to do that on my own, but unfortunately I'm completely lost in makefile, since it seems that when bootimage=true, libavian for target platform still compiles code that supports JIT. Is there any option to split AOT and JIT mode during compilation: e.g. completely ifdef-out JIT code when AOT is requested, or something like that.

openjdk-src problems on osx 10.9

After getting past sever build problems (pull request to come), I'm running into a very strange problem with the openjdk-src build on osx 10.9. When initializing avian (very early in the startup process), osx prompts me to install Java, which it clearly shouldn't be doing. Here's the stack trace:

#0  0x00007fff8318fadb in exit ()
#1  0x00000001077cc76c in CheckForInstalledJavaRuntimes ()
#2  0x00007fff5fc11c2e in __dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE ()
#3  0x00007fff5fc11dba in __dyld__ZN16ImageLoaderMachO16doInitializationERKN11ImageLoader11LinkContextE ()
#4  0x00007fff5fc0ea62 in __dyld__ZN11ImageLoader23recursiveInitializationERKNS_11LinkContextEjRNS_21InitializerTimingListE ()
#5  0x00007fff5fc0e9eb in __dyld__ZN11ImageLoader23recursiveInitializationERKNS_11LinkContextEjRNS_21InitializerTimingListE ()
#6  0x00007fff5fc0e9eb in __dyld__ZN11ImageLoader23recursiveInitializationERKNS_11LinkContextEjRNS_21InitializerTimingListE ()
#7  0x00007fff5fc0e8f6 in __dyld__ZN11ImageLoader15runInitializersERKNS_11LinkContextERNS_21InitializerTimingListE ()
#8  0x00007fff5fc04b0e in __dyld__ZN4dyld15runInitializersEP11ImageLoader ()
#9  0x00007fff5fc0b7cf in __dyld_dlopen ()
#10 0x00007fff844257ef in dlopen ()
#11 0x000000010011c9b6 in getJRSFramework () at build/darwin-x86_64-debug-openjdk-src/openjdk/java_props_macosx.c:42
#12 0x000000010011bb81 in setOSNameAndVersion (sprops=0x104374260) at build/darwin-x86_64-debug-openjdk-src/openjdk/java_props_macosx.c:135
#13 0x0000000100100579 in GetJavaProperties (env=0x105002208) at build/darwin-x86_64-debug-openjdk-src/openjdk/java_props_md.c:459
#14 0x00000001000e0391 in Java_java_lang_System_initProperties (env=0x105002208, cla=0x7fff5fbfeb48, props=0x7fff5fbfec80) at build/darwin-x86_64-debug-openjdk-src/openjdk/System.c:172
#15 0x00000001000ca33e in .Lcall () at allocator.h:18
#16 0x0000000100004599 in vm::dynamicCall (function=0x1000e0360, arguments=0x7fff5fbfe9d0, argumentTypes=0x7fff5fbfe9c0 "\a\a\a\001\001", argumentCount=3, returnType=7) at x86.h:195
#17 0x0000000100001d02 in (anonymous namespace)::MySystem::call (this=0x104600000, function=0x1000e0360, arguments=0x7fff5fbfe9d0, types=0x7fff5fbfe9c0 "\a\a\a\001\001", count=3, size=24, returnType=7) at src/vm/system/posix.cpp:782
#18 0x000000010007a16b in (anonymous namespace)::local::invokeNativeSlow (t=0x105002208, method=0x1048a56e8, function=0x1000e0360) at src/compile.cpp:7774
#19 0x0000000100079a63 in (anonymous namespace)::local::invokeNative2 (t=0x105002208, method=0x1048a56e8) at src/compile.cpp:7852
#20 0x000000010004945d in (anonymous namespace)::local::invokeNative (t=0x105002208) at src/compile.cpp:7884
#21 0x000000010580007b in ?? ()
#22 0x0000000100074aa4 in (anonymous namespace)::local::invoke (thread=0x105002208, method=0x1048a65f0, arguments=0x7fff5fbfef18) at src/compile.cpp:8669
#23 0x000000010004d6cc in (anonymous namespace)::local::MyProcessor::invokeList (this=0x104600a08, t=0x105002208, loader=0x105002cf0, className=0x104368a92 "java/lang/System", methodName=0x104368bd5 "initializeSystemClass", methodSpec=0x10436734f "()V", this_=0x0, arguments=0x7fff5fbff190) at src/compile.cpp:9202
#24 0x000000010009499c in vm::Processor::invoke (this=0x104600a08, t=0x105002208, loader=0x105002cf0, className=0x104368a92 "java/lang/System", methodName=0x104368bd5 "initializeSystemClass", methodSpec=0x10436734f "()V", this_=0x0) at processor.h:202
#25 0x000000010008dd9e in (anonymous namespace)::local::MyClasspath::boot (this=0x1046003f8, t=0x105002208) at src/classpath-openjdk.cpp:769
#26 0x00000001000a1a4a in (anonymous namespace)::local::boot (t=0x105002208) at src/jnienv.cpp:3549
#27 0x00000001000ca3af in vmRun () at allocator.h:18
#28 0x0000000100030fb8 in vm::runRaw (t=0x105002208, function=0x1000a17d0 <(anonymous namespace)::local::boot(vm::Thread*, unsigned long*)>, arguments=0x0) at machine.h:1950
#29 0x000000010002feac in vm::run (t=0x105002208, function=0x1000a17d0 <(anonymous namespace)::local::boot(vm::Thread*, unsigned long*)>, arguments=0x0) at machine.h:1957
#30 0x00000001000a153d in JNI_CreateJavaVM (m=0x7fff5fbff9b0, t=0x7fff5fbff9a8, args=0x7fff5fbffa00) at src/jnienv.cpp:3944
#31 0x000000010011e49e in main (ac=4, av=0x7fff5fbffa58) at src/main.cpp:259

Looking at getJRSFramework, I don't see how this could ever not have been the case:

static void *getJRSFramework() {
    static void *jrsFwk = NULL;
    if (jrsFwk == NULL) {
       jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
    }
    return jrsFwk;
}

Can't find class under Windows

I managed to build Avian with the Android classpath on Windows x86_64 (using mingw-w64), but now I have a strange problem.

If I run such code:

jclass c = e->FindClass("packagename/ClassName");
if (e->ExceptionCheck())
{
    exitCode = -1;
    e->ExceptionDescribe();
}

I get an error report:

java/lang/NoClassDefFoundError: packagename/ClassName

Everything's linked correctly with all jar files (I use static linkage everywhere and build a single executable embedding everything).

This code works like a charm on OS X. And it worked well everywhere with Avian default classpath. I have no idea about how the changing of classpath libraries could influence VM core behavior.

I used some small hacks and tricks to build Android classpath on Windows, for example I changed the definition for jchar from unsigned short to wchar_t (I hope they are the same on Windows) in order to avoid many conversion errors.

I understand that there is too few information, but I just don't know where to find the bug. Debugging everything (including android classpath C++ sources) looks a bit scary.

Performance

Getting back to my previous question: is it truly possible that application under avian in AOT mode works much slower than under OpenJDK? Or maybe it's just me doing something wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.