From cabad6926f56943ad58a08b409e11fe02f72d9b5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Nov 2010 11:02:09 -0600 Subject: [PATCH] enable standalone OpenJDK builds As described in readme.txt, a standalone OpenJDK build embeds all libraries, classes, and other files needed at runtime in the resulting binary, eliminating dependencies on external resources. --- makefile | 110 +++++++++++++++---------- openjdk-src.mk | 166 ++++++++++++++++++++++++++++++++++++++ readme.txt | 48 +++++++++++ src/classpath-openjdk.cpp | 142 +++++++++++++++++++++++++++----- src/compile.cpp | 14 +--- src/jnienv.cpp | 12 ++- src/machine.cpp | 14 +--- src/machine.h | 62 +++++++++++++- src/openjdk/jni_md.h | 29 +++++++ src/types.def | 4 + 10 files changed, 509 insertions(+), 92 deletions(-) create mode 100644 openjdk-src.mk create mode 100644 src/openjdk/jni_md.h diff --git a/makefile b/makefile index 0109e672a6..edaecb7ff8 100644 --- a/makefile +++ b/makefile @@ -52,22 +52,31 @@ classpath = avian test-executable = $(executable) boot-classpath = $(classpath-build) -java-home = /tmp +java-home = /avian-embedded ifdef openjdk + ifdef openjdk-src + include openjdk-src.mk + options := $(options)-openjdk-src + classpath-objects = $(openjdk-objects) + classpath-cflags = -DAVIAN_OPENJDK_SRC + openjdk-jar-dep = $(build)/openjdk-jar.dep + classpath-jar-dep = $(openjdk-jar-dep) + else + options := $(options)-openjdk + test-executable = $(executable-dynamic) + library-path = LD_LIBRARY_PATH=$(build) + java-home = $(openjdk)/jre + endif + classpath = openjdk - options := $(options)-openjdk - java-home = $(openjdk)/jre - test-executable = $(executable-dynamic) boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar endif -ifneq ($(classpath),avian) - classpath-object-dep = $(build)/classpath-object.dep - classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") -else +ifeq ($(classpath),avian) jni-sources := $(shell find $(classpath-src) -name '*.cpp') jni-objects = $(call cpp-objects,$(jni-sources),$(classpath-src),$(build)) + classpath-objects = $(jni-objects) endif input = List @@ -95,6 +104,7 @@ vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000 vg += --leak-check=full --suppressions=valgrind.supp db = gdb --args javac = "$(JAVA_HOME)/bin/javac" +javah = "$(JAVA_HOME)/bin/javah" jar = "$(JAVA_HOME)/bin/jar" strip = strip strip-all = --strip-all @@ -108,7 +118,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ - "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) \ + "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(java-home)\" @@ -222,28 +232,30 @@ ifeq ($(platform),windows) endif ifeq ($(mode),debug) - cflags += -O0 -g3 + optimization-cflags = -O0 -g3 strip = : endif ifeq ($(mode),debug-fast) - cflags += -O0 -g3 -DNDEBUG + optimization-cflags = -O0 -g3 -DNDEBUG strip = : endif ifeq ($(mode),stress) - cflags += -O0 -g3 -DVM_STRESS + optimization-cflags = -O0 -g3 -DVM_STRESS strip = : endif ifeq ($(mode),stress-major) - cflags += -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR + optimization-cflags = -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR strip = : endif ifeq ($(mode),fast) - cflags += -O3 -g3 -DNDEBUG + optimization-cflags = -O3 -g3 -DNDEBUG endif ifeq ($(mode),small) - cflags += -Os -g3 -DNDEBUG + optimization-cflags = -Os -g3 -DNDEBUG endif +cflags += $(optimization-cflags) + ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: @@ -467,15 +479,15 @@ $(test-extra-dep): $(classpath-dep) .PHONY: run run: build - LD_LIBRARY_PATH=$(build) $(test-executable) $(test-args) + $(library-path) $(test-executable) $(test-args) .PHONY: debug debug: build - LD_LIBRARY_PATH=$(build) gdb --args $(test-executable) $(test-args) + $(library-path) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build - LD_LIBRARY_PATH=$(build) $(vg) $(test-executable) $(test-args) + $(library-path) $(vg) $(test-executable) $(test-args) .PHONY: test test: build @@ -581,7 +593,8 @@ $(driver-dynamic-object): $(driver-source) $(boot-object): $(boot-source) $(compile-object) -$(build)/classpath.jar: $(classpath-dep) +$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) + @echo "creating $(@)" (wd=$$(pwd) && \ cd $(classpath-build) && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) @@ -622,11 +635,10 @@ $(generator-objects): $(build)/%-build.o: $(src)/%.cpp $(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(classpath-object-dep) -$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) +$(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call classpath-objects) + $(ar) cru $(@) $(^) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -638,16 +650,10 @@ $(bootimage-object): $(bootimage-bin) $(converter) _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ writable executable -$(classpath-object-dep): $(classpath-libraries) - @mkdir -p $(build)/classpath-objects - (cd $(build)/classpath-objects && \ - for x in $(classpath-libraries); do ar x $${x}; done) - @touch $(@) - -executable-objects = $(vm-objects) $(jni-objects) $(driver-object) \ +executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) -$(executable): $(classpath-object-dep) $(executable-objects) +$(executable): $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -655,14 +661,12 @@ ifdef msvc -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(executable-objects) $(call classpath-objects) + $(dlltool) -z $(@).def $(executable-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(executable-objects) $(call classpath-objects) $(lflags) \ - -o $(@) + $(ld) $(@).exp $(executable-objects) $(lflags) -o $(@) endif else - $(ld) $(executable-objects) $(call classpath-objects) $(rdynamic) $(lflags) \ - $(bootimage-lflags) -o $(@) + $(ld) $(executable-objects) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -675,8 +679,8 @@ $(bootimage-generator): $(bootimage-generator) $(build-bootimage-generator): \ - $(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \ - $(bootimage-generator-objects) + $(vm-objects) $(classpath-object) $(classpath-objects) \ + $(heapwalk-objects) $(bootimage-generator-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -692,11 +696,11 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -dynamic-library-objects = $(vm-objects) $(dynamic-object) $(jni-objects) \ - $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ - $(classpath-libraries) +dynamic-library-objects = $(vm-objects) $(dynamic-object) \ + $(classpath-objects) $(vm-heapwalk-objects) $(boot-object) \ + $(vm-classpath-object) $(classpath-libraries) -$(dynamic-library): $(classpath-object-dep) $(dynamic-library-objects) +$(dynamic-library): $(dynamic-library-objects) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(dynamic-library-objects) -out:$(@) \ @@ -704,7 +708,7 @@ ifdef msvc $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else $(ld) $(dynamic-library-objects) -Wl,--version-script=openjdk.ld \ - $(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@) + $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -722,3 +726,25 @@ endif $(generator): $(generator-objects) @echo "linking $(@)" $(build-ld) $(^) $(build-lflags) -o $(@) + +$(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ + $(openjdk-headers-dep) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cc) -fPIC -fvisibility=hidden $(openjdk-cflags) $(optimization-cflags) \ + -w -c $(<) $(call output,$(@)) + +$(openjdk-headers-dep): $(openjdk)/jre/lib/rt.jar + @echo "generating openjdk headers" + @mkdir -p $(dir $(@)) + $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ + $(openjdk-headers-classes) + @touch $(@) + +$(openjdk-jar-dep): $(openjdk)/jre/lib/rt.jar $(openjdk)/jre/lib/jsse.jar \ + $(openjdk)/jre/lib/jce.jar $(openjdk)/jre/lib/resources.jar + @echo "extracting openjdk classes" + @mkdir -p $(dir $(@)) + @mkdir -p $(classpath-build) + (cd $(classpath-build) && for x in $(^); do jar xf $${x}; done) + @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk new file mode 100644 index 0000000000..5ee6a46096 --- /dev/null +++ b/openjdk-src.mk @@ -0,0 +1,166 @@ +openjdk-sources = \ + $(openjdk-src)/share/native/common/check_code.c \ + $(openjdk-src)/share/native/common/check_format.c \ + $(openjdk-src)/share/native/common/check_version.c \ + $(openjdk-src)/share/native/common/jdk_util.c \ + $(openjdk-src)/share/native/common/jio.c \ + $(openjdk-src)/share/native/common/jni_util.c \ + $(openjdk-src)/share/native/common/verify_stub.c \ + $(openjdk-src)/share/native/java/io/FileInputStream.c \ + $(openjdk-src)/share/native/java/io/io_util.c \ + $(openjdk-src)/share/native/java/io/ObjectInputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectOutputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectStreamClass.c \ + $(openjdk-src)/share/native/java/io/RandomAccessFile.c \ + $(openjdk-src)/share/native/java/lang/Class.c \ + $(openjdk-src)/share/native/java/lang/ClassLoader.c \ + $(openjdk-src)/share/native/java/lang/Compiler.c \ + $(openjdk-src)/share/native/java/lang/Double.c \ + $(openjdk-src)/share/native/java/lang/Float.c \ + $(openjdk-src)/share/native/java/lang/Object.c \ + $(openjdk-src)/share/native/java/lang/Package.c \ + $(openjdk-src)/share/native/java/lang/ref/Finalizer.c \ + $(openjdk-src)/share/native/java/lang/reflect/Array.c \ + $(openjdk-src)/share/native/java/lang/reflect/Proxy.c \ + $(openjdk-src)/share/native/java/lang/ResourceBundle.c \ + $(openjdk-src)/share/native/java/lang/Runtime.c \ + $(openjdk-src)/share/native/java/lang/SecurityManager.c \ + $(openjdk-src)/share/native/java/lang/Shutdown.c \ + $(openjdk-src)/share/native/java/lang/StrictMath.c \ + $(openjdk-src)/share/native/java/lang/String.c \ + $(openjdk-src)/share/native/java/lang/System.c \ + $(openjdk-src)/share/native/java/lang/Thread.c \ + $(openjdk-src)/share/native/java/lang/Throwable.c \ + $(wildcard $(openjdk-src)/share/native/java/lang/fdlibm/src/*.c) \ + $(openjdk-src)/share/native/java/nio/Bits.c \ + $(openjdk-src)/share/native/java/security/AccessController.c \ + $(openjdk-src)/share/native/java/sql/DriverManager.c \ + $(openjdk-src)/share/native/java/util/concurrent/atomic/AtomicLong.c \ + $(openjdk-src)/share/native/java/util/TimeZone.c \ + $(openjdk-src)/share/native/java/util/zip/Adler32.c \ + $(openjdk-src)/share/native/java/util/zip/CRC32.c \ + $(openjdk-src)/share/native/java/util/zip/Deflater.c \ + $(openjdk-src)/share/native/java/util/zip/Inflater.c \ + $(openjdk-src)/share/native/java/util/zip/ZipEntry.c \ + $(openjdk-src)/share/native/java/util/zip/ZipFile.c \ + $(openjdk-src)/share/native/java/util/zip/zip_util.c \ + $(openjdk-src)/share/native/sun/misc/GC.c \ + $(openjdk-src)/share/native/sun/misc/MessageUtils.c \ + $(openjdk-src)/share/native/sun/misc/NativeSignalHandler.c \ + $(openjdk-src)/share/native/sun/misc/Signal.c \ + $(openjdk-src)/share/native/sun/misc/Version.c \ + $(openjdk-src)/share/native/sun/misc/VM.c \ + $(openjdk-src)/share/native/sun/misc/VMSupport.c \ + $(openjdk-src)/share/native/sun/reflect/ConstantPool.c \ + $(openjdk-src)/share/native/sun/reflect/NativeAccessors.c \ + $(openjdk-src)/share/native/sun/reflect/Reflection.c + +openjdk-headers-classes = \ + java.io.Console \ + java.io.FileDescriptor \ + java.io.FileInputStream \ + java.io.FileOutputStream \ + java.io.FileSystem \ + java.io.ObjectInputStream \ + java.io.ObjectOutputStream \ + java.io.ObjectStreamClass \ + java.io.RandomAccessFile \ + java.lang.Class \ + java.lang.ClassLoader \ + java.lang.Compiler \ + java.lang.Double \ + java.lang.Float \ + java.lang.Object \ + java.lang.Package \ + java.lang.Runtime \ + java.lang.SecurityManager \ + java.lang.Shutdown \ + java.lang.StrictMath \ + java.lang.String \ + java.lang.System \ + java.lang.Thread \ + java.lang.Throwable \ + java.lang.ref.Finalizer \ + java.lang.reflect.Array \ + java.lang.reflect.Proxy \ + java.security.AccessController \ + java.util.ResourceBundle \ + java.util.TimeZone \ + java.util.concurrent.atomic.AtomicLong \ + java.util.jar.JarFile \ + java.util.zip.Adler32 \ + java.util.zip.CRC32 \ + java.util.zip.Deflater \ + java.util.zip.Inflater \ + java.util.zip.ZipEntry \ + java.util.zip.ZipFile \ + sun.misc.GC \ + sun.misc.MessageUtils \ + sun.misc.NativeSignalHandler \ + sun.misc.Signal \ + sun.misc.VM \ + sun.misc.VMSupport \ + sun.misc.Version \ + sun.reflect.ConstantPool \ + sun.reflect.NativeConstructorAccessorImpl \ + sun.reflect.NativeMethodAccessorImpl \ + sun.reflect.Reflection \ + +# todo: set properties according to architecture targeted and OpenJDK +# version used: +openjdk-cflags = \ + "-I$(src)/openjdk" \ + "-I$(build)/openjdk" \ + "-I$(openjdk-src)/share/javavm/export" \ + "-I$(openjdk-src)/share/native/common" \ + "-I$(openjdk-src)/share/native/java/io" \ + "-I$(openjdk-src)/share/native/java/lang" \ + "-I$(openjdk-src)/share/native/java/lang/fdlibm/include" \ + "-I$(openjdk-src)/share/native/java/util/zip" \ + "-I$(openjdk-src)/share/javavm/include" \ + -D_LITTLE_ENDIAN \ + -DARCHPROPNAME=\"x86\" \ + -DRELEASE=\"1.6.0\" \ + -DJDK_MAJOR_VERSION=\"1\" \ + -DJDK_MINOR_VERSION=\"6\" \ + -DJDK_MICRO_VERSION=\"0\" \ + -DJDK_BUILD_NUMBER=\"0\" \ + -D_GNU_SOURCE + +ifeq ($(platform),windows) +# todo +else + openjdk-sources += \ + $(openjdk-src)/solaris/native/common/jdk_util_md.c \ + $(openjdk-src)/solaris/native/java/io/canonicalize_md.c \ + $(openjdk-src)/solaris/native/java/io/Console_md.c \ + $(openjdk-src)/solaris/native/java/io/FileDescriptor_md.c \ + $(openjdk-src)/solaris/native/java/io/FileInputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileOutputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileSystem_md.c \ + $(openjdk-src)/solaris/native/java/io/io_util_md.c \ + $(openjdk-src)/solaris/native/java/io/RandomAccessFile_md.c \ + $(openjdk-src)/solaris/native/java/io/UnixFileSystem_md.c \ + $(openjdk-src)/solaris/native/java/lang/java_props_md.c \ + $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ + $(openjdk-src)/solaris/native/java/util/FileSystemPreferences.c \ + $(openjdk-src)/solaris/native/java/util/logging.c \ + $(openjdk-src)/solaris/native/java/util/TimeZone_md.c + + openjdk-headers-classes += \ + java.io.UnixFileSystem + + openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ + "-I$(openjdk-src)/solaris/native/common" \ + "-I$(openjdk-src)/solaris/native/java/io" \ + "-I$(openjdk-src)/solaris/native/java/util" \ + "-I$(openjdk-src)/solaris/javavm/include" +endif + +c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) + +openjdk-objects = \ + $(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) + +openjdk-headers-dep = $(build)/openjdk/headers.dep diff --git a/readme.txt b/readme.txt index e90201703a..57b978c1fc 100644 --- a/readme.txt +++ b/readme.txt @@ -191,6 +191,54 @@ 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-6-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-6-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)/../jdk6/build/linux-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../jdk6/jdk/src + +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). + + Installing ---------- diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 0c13971f4a..5dd2c32c68 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -35,6 +35,9 @@ # define CREAT _wcreat # endif +# define LIBRARY_PREFIX "" +# define LIBRARY_SUFFIX ".dll" + #else // not PLATFORM_WINDOWS # include @@ -53,6 +56,9 @@ # define FSTAT fstat # define LSEEK lseek +# define LIBRARY_PREFIX "lib" +# define LIBRARY_SUFFIX ".so" + #endif // not PLATFORM_WINDOWS using namespace vm; @@ -139,6 +145,72 @@ makeClassNameString(Thread* t, object name) return makeString(t, "%s", s); } +#ifdef AVIAN_OPENJDK_SRC +// only safe to call during bootstrap when there's only one thread +// running: +void +intercept(Thread* t, object c, const char* name, const char* spec, + void* function) +{ + object m = findMethodOrNull(t, c, name, spec); + if (m) { + PROTECT(t, m); + + object clone = methodClone(t, m); + + // make clone private to prevent vtable updates at compilation + // time. Otherwise, our interception might be bypassed by calls + // through the vtable. + methodFlags(t, clone) |= ACC_PRIVATE; + + methodFlags(t, m) |= ACC_NATIVE; + + object native = makeNativeIntercept(t, function, true, clone); + + set(t, m, MethodCode, native); + } +} + +const char* +zipLibrary(Thread*); + +int64_t JNICALL +getFileAttributes +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Exists = 1; + const unsigned Regular = 2; + + object file = reinterpret_cast(arguments[1]); + + object pathField = findFieldInClass2 + (t, objectClass(t, file), "path", "Ljava/lang/String;"); + + if (pathField) { + object path = cast(file, fieldOffset(t, pathField)); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + + if (strcmp(zipLibrary(t), p) == 0) { + return Exists | Regular; + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), + reinterpret_cast(arguments[0]), file); + return (r ? intValue(t, r) : 0); + } + } else { + object message = makeString + (t, "path Ljava/lang/String; not found in %s", + &byteArrayBody(t, className(t, objectClass(t, file)), 0)); + t->exception = t->m->classpath->makeThrowable + (t, Machine::RuntimeExceptionType, message); + return 0; + } +} +#endif // AVIAN_OPENJDK_SRC + class MyClasspath : public Classpath { public: static const unsigned BufferSize = 1024; @@ -205,6 +277,14 @@ class MyClasspath : public Classpath { // todo: handle other architectures sb.append("/lib/i386"); #endif + sb.append('\0'); + + this->zipLibrary = sb.pointer; + sb.append(this->libraryPath); + sb.append("/"); + sb.append(LIBRARY_PREFIX); + sb.append("zip"); + sb.append(LIBRARY_SUFFIX); } virtual object @@ -296,9 +376,20 @@ class MyClasspath : public Classpath { { globalMachine = t->m; +#ifdef AVIAN_OPENJDK_SRC + { object c = resolveClass + (t, root(t, Machine::BootLoader), "java/io/UnixFileSystem"); + + if (c) { + intercept(t, c, "getBooleanAttributes0", "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); + } + } +#else // not AVIAN_OPENJDK_SRC if (loadLibrary(t, libraryPath, "java", true, true) == 0) { abort(t); } +#endif // not AVIAN_OPENJDK_SRC t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", @@ -351,6 +442,7 @@ class MyClasspath : public Classpath { const char* javaHome; const char* classpath; const char* libraryPath; + const char* zipLibrary; char buffer[BufferSize]; }; @@ -374,6 +466,12 @@ struct jvm_version_info { unsigned int: 32; }; +const char* +zipLibrary(Thread* t) +{ + return static_cast(t->m->classpath)->zipLibrary; +} + unsigned countMethods(Thread* t, object c, bool publicOnly) { @@ -1205,7 +1303,13 @@ extern "C" JNIEXPORT void* JNICALL JVM_LoadLibrary(const char* name) { Thread* t = static_cast(local::globalMachine->localThread->get()); - + +#ifdef AVIAN_OPENJDK_SRC + if (strcmp(local::zipLibrary(t), name) == 0) { + return t->m->libraries; + } +#endif // AVIAN_OPENJDK_SRC + ENTER(t, Thread::ActiveState); return loadLibrary @@ -2597,18 +2701,18 @@ jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) return vm::vsnprintf(dst, size, format, a); } -extern "C" JNIEXPORT int -jio_snprintf(char* dst, size_t size, const char* format, ...) -{ - va_list a; - va_start(a, format); +// extern "C" JNIEXPORT int +// jio_snprintf(char* dst, size_t size, const char* format, ...) +// { +// va_list a; +// va_start(a, format); - int r = jio_vsnprintf(dst, size, format, a); +// int r = jio_vsnprintf(dst, size, format, a); - va_end(a); +// va_end(a); - return r; -} +// return r; +// } extern "C" JNIEXPORT int jio_vfprintf(FILE* stream, const char* format, va_list a) @@ -2616,15 +2720,15 @@ jio_vfprintf(FILE* stream, const char* format, va_list a) return vfprintf(stream, format, a); } -extern "C" JNIEXPORT int -jio_fprintf(FILE* stream, const char* format, ...) -{ - va_list a; - va_start(a, format); +// extern "C" JNIEXPORT int +// jio_fprintf(FILE* stream, const char* format, ...) +// { +// va_list a; +// va_start(a, format); - int r = jio_vfprintf(stream, format, a); +// int r = jio_vfprintf(stream, format, a); - va_end(a); +// va_end(a); - return r; -} +// return r; +// } diff --git a/src/compile.cpp b/src/compile.cpp index e0b3ee8586..280cb3f2fc 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8601,19 +8601,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, // method so that we won't be confused if another thread updates the // original while we're working. - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodAddendum(t, method), - methodClass(t, method), - methodCode(t, method)); + object clone = methodClone(t, method); loadMemoryBarrier(); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 0e249d2aba..680992c4df 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1928,10 +1928,16 @@ RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, for (int i = 0; i < methodCount; ++i) { if (methods[i].function) { - object method = findMethod(t, c, methods[i].name, methods[i].signature); - if (UNLIKELY(t->exception)) return -1; + object method = findMethodOrNull + (t, jclassVmClass(t, *c), methods[i].name, methods[i].signature); - registerNative(t, method, methods[i].function); + if (method == 0 or (methodFlags(t, method) & ACC_NATIVE) == 0) { + // The JNI spec says we must throw a NoSuchMethodError in this + // case, but that would prevent using a code shrinker like + // ProGuard effectively. Instead, we just ignore it. + } else { + registerNative(t, method, methods[i].function); + } } } diff --git a/src/machine.cpp b/src/machine.cpp index b9e849f6b4..184649e0e5 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3546,9 +3546,8 @@ findInTable(Thread* t, object table, object name, object spec, } object -findInHierarchy(Thread* t, object class_, object name, object spec, - object (*find)(Thread*, object, object, object), - Machine::Type errorType) +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)) { object originalClass = class_; @@ -3570,15 +3569,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec, } } - if (o == 0) { - object message = makeString - (t, "%s %s not found in %s", - &byteArrayBody(t, name, 0), - &byteArrayBody(t, spec, 0), - &byteArrayBody(t, className(t, originalClass), 0)); - t->exception = t->m->classpath->makeThrowable(t, errorType, message); - } - return o; } diff --git a/src/machine.h b/src/machine.h index 772bcd864c..1955adadb8 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2127,11 +2127,11 @@ object resolveClass(Thread* t, object loader, object name, bool throw_ = true); inline object -resolveClass(Thread* t, object loader, const char* name) +resolveClass(Thread* t, object loader, const char* name, bool throw_ = true) { PROTECT(t, loader); object n = makeByteArray(t, "%s", name); - return resolveClass(t, loader, n); + return resolveClass(t, loader, n, throw_); } object @@ -2211,6 +2211,16 @@ findFieldInClass(Thread* t, object class_, object name, object spec) (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); } +inline object +findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findFieldInClass(t, class_, n, s); +} + inline object findMethodInClass(Thread* t, object class_, object name, object spec) { @@ -2219,9 +2229,27 @@ findMethodInClass(Thread* t, object class_, object name, object spec) } object +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)); + +inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - Machine::Type errorType); + Machine::Type errorType) +{ + object o = findInHierarchyOrNull(t, class_, name, spec, find); + + if (o == 0) { + object message = makeString + (t, "%s %s not found in %s", + &byteArrayBody(t, name, 0), + &byteArrayBody(t, spec, 0), + &byteArrayBody(t, className(t, class_), 0)); + t->exception = t->m->classpath->makeThrowable(t, errorType, message); + } + + return o; +} inline object findMethod(Thread* t, object class_, object name, object spec) @@ -2230,6 +2258,16 @@ findMethod(Thread* t, object class_, object name, object spec) (t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType); } +inline object +findMethodOrNull(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findInHierarchyOrNull(t, class_, n, s, findMethodInClass); +} + inline object findVirtualMethod(Thread* t, object method, object class_) { @@ -3066,6 +3104,24 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); void dumpHeap(Thread* t, FILE* out); +inline object +methodClone(Thread* t, object method) +{ + return makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodName(t, method), + methodSpec(t, method), + methodAddendum(t, method), + methodClass(t, method), + methodCode(t, method)); +} + } // namespace vm void diff --git a/src/openjdk/jni_md.h b/src/openjdk/jni_md.h new file mode 100644 index 0000000000..3ddc8b9460 --- /dev/null +++ b/src/openjdk/jni_md.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef JNI_MD_H +#define JNI_MD_H + +#include "stdint.h" + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __declspec(dllexport) +#else // not (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __attribute__ ((visibility("default"))) +#endif // not (defined __MINGW32__) || (defined _MSC_VER) + +#define JNIIMPORT +#define JNICALL + +typedef int32_t jint; +typedef int64_t jlong; +typedef int8_t jbyte; + +#endif//JNI_MD_H diff --git a/src/types.def b/src/types.def index 996b99e377..158483115a 100644 --- a/src/types.def +++ b/src/types.def @@ -44,6 +44,10 @@ (void* function) (uint8_t fast)) +(type nativeIntercept + (extends native) + (object original)) + (pod exceptionHandler (uint16_t start) (uint16_t end)