diff --git a/makefile b/makefile index 26b4b75b2f..ca220ec3aa 100644 --- a/makefile +++ b/makefile @@ -56,7 +56,8 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self common-cflags = $(warnings) -fno-rtti -fno-exceptions \ -I$(JAVA_HOME)/include -idirafter $(src) -I$(native-build) \ - -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" + -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ + -DBOOT_CLASSPATH=\"[classpathJar]\" build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ -I$(JAVA_HOME)/include/linux -I$(src) -pthread @@ -65,7 +66,7 @@ cflags = $(build-cflags) common-lflags = -lm -lz -lflags = $(common-lflags) -lpthread -ldl -rdynamic +lflags = $(common-lflags) -lpthread -ldl system = posix asm = x86 @@ -74,6 +75,11 @@ object-arch = i386:x86-64 object-format = elf64-x86-64 pointer-size = 8 +so-prefix = lib +so-suffix = .so + +shared = -shared + ifeq ($(arch),i386) object-arch = i386 object-format = elf32-i386 @@ -86,6 +92,8 @@ ifeq ($(platform),darwin) lflags = $(common-lflags) -ldl -framework CoreFoundation strip-all = -S -x binaryToMacho = $(native-build)/binaryToMacho + so-suffix = .jnilib + shared = -dynamiclib endif ifeq ($(platform),windows) @@ -95,6 +103,9 @@ ifeq ($(platform),windows) system = windows object-format = pe-i386 + so-prefix = + so-suffix = .dll + cxx = i586-mingw32msvc-g++ cc = i586-mingw32msvc-gcc dlltool = i586-mingw32msvc-dlltool @@ -181,9 +192,12 @@ vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build)) vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build)) vm-objects = $(vm-cpp-objects) $(vm-asm-objects) -driver-sources = $(src)/main.cpp +driver-source = $(src)/main.cpp +driver-object = $(native-build)/main.o +driver-dynamic-object = $(native-build)/main-dynamic.o -driver-object = $(call cpp-objects,$(driver-sources),$(src),$(native-build)) +boot-source = $(src)/boot.cpp +boot-object = $(native-build)/boot.o generator-headers = $(src)/constants.h generator-sources = $(src)/type-generator.cpp @@ -191,8 +205,10 @@ generator-objects = \ $(call cpp-objects,$(generator-sources),$(src),$(native-build)) generator = $(native-build)/generator -libvm = $(native-build)/lib$(name).a -vm = $(native-build)/$(name) +static-library = $(native-build)/lib$(name).a +executable = $(native-build)/$(name) +dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix) +executable-dynamic = $(native-build)/$(name)-dynamic classpath-sources = $(shell find $(classpath) -name '*.java') classpath-classes = \ @@ -212,26 +228,27 @@ flags = -cp $(test-build) args = $(flags) $(input) .PHONY: build -build: $(vm) $(libvm) $(classpath-dep) $(test-dep) +build: $(static-library) $(executable) $(dynamic-library) \ + $(executable-dynamic) $(classpath-dep) $(test-dep) $(test-classes): $(classpath-dep) .PHONY: run run: build - $(vm) $(args) + $(executable) $(args) .PHONY: debug debug: build - gdb --args $(vm) $(args) + gdb --args $(executable) $(args) .PHONY: vg vg: build - $(vg) $(vm) $(args) + $(vg) $(executable) $(args) .PHONY: test test: build /bin/bash $(test)/test.sh 2>/dev/null \ - $(vm) $(mode) "$(flags)" \ + $(executable) $(mode) "$(flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: javadoc @@ -293,7 +310,15 @@ $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) $(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S $(compile-object) -$(driver-object): $(native-build)/%.o: $(src)/%.cpp +$(driver-object): $(driver-source) + $(compile-object) + +$(driver-dynamic-object): $(driver-source) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(name)\" -c $(<) -o $(@) + +$(boot-object): $(boot-source) $(compile-object) $(build)/classpath.jar: $(classpath-dep) @@ -307,7 +332,7 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp $(classpath-object): $(build)/classpath.jar $(binaryToMacho) ifeq ($(platform),darwin) $(binaryToMacho) $(build)/classpath.jar \ - __binary_classpath_jar_start __binary_classpath_jar_size > $(@) + __binary_classpath_jar_start __binary_classpath_jar_end > $(@) else (wd=$$(pwd); \ cd $(build); \ @@ -324,23 +349,37 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp $(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp $(compile-object) -$(libvm): $(vm-objects) $(jni-objects) +$(static-library): $(vm-objects) $(jni-objects) @echo "creating $(@)" rm -rf $(@) $(ar) cru $(@) $(^) $(ranlib) $(@) -$(vm): $(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) +$(executable): \ + $(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \ + $(boot-object) @echo "linking $(@)" ifeq ($(platform),windows) $(dlltool) -z $(@).def $(^) $(dlltool) -k -d $(@).def -e $(@).exp $(cc) $(@).exp $(^) $(lflags) -o $(@) else - $(cc) $(^) $(lflags) -o $(@) + $(cc) $(^) $(rdynamic) $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) +$(dynamic-library): \ + $(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \ + $(boot-object) + @echo "linking $(@)" + $(cc) $(^) $(shared) $(lflags) -o $(@) + $(strip) $(@) + +$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) + @echo "linking $(@)" + $(cc) $(^) $(lflags) -o $(@) + $(strip) $(strip-all) $(@) + $(generator): $(generator-objects) @echo "linking $(@)" $(build-cc) $(^) -o $(@) diff --git a/readme.txt b/readme.txt index 608e7cc42b..7aa9f8cec6 100644 --- a/readme.txt +++ b/readme.txt @@ -165,12 +165,12 @@ setting the classpath to "[bootJar]". extern "C" { extern const uint8_t SYMBOL(start)[]; - extern const uint8_t SYMBOL(size)[]; + extern const uint8_t SYMBOL(end)[]; EXPORT const uint8_t* bootJar(unsigned* size) { - *size = reinterpret_cast(SYMBOL(size)); + *size = SYMBOL(end) - SYMBOL(start); return SYMBOL(start); } diff --git a/src/binaryToMacho.cpp b/src/binaryToMacho.cpp index 0e99e71fbb..c295470782 100644 --- a/src/binaryToMacho.cpp +++ b/src/binaryToMacho.cpp @@ -30,10 +30,10 @@ pad(unsigned n) void writeObject(FILE* out, const uint8_t* data, unsigned size, - const char* dataName, const char* sizeName) + const char* startName, const char* endName) { - unsigned dataNameLength = strlen(dataName) + 1; - unsigned sizeNameLength = strlen(sizeName) + 1; + unsigned startNameLength = strlen(startName) + 1; + unsigned endNameLength = strlen(endName) + 1; mach_header header = { MH_MAGIC, // magic @@ -42,7 +42,7 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, MH_OBJECT, // filetype, 2, // ncmds sizeof(segment_command) - + sizeof(section) + + (sizeof(section) * 2) + sizeof(symtab_command), // sizeofcmds 0 // flags }; @@ -55,23 +55,23 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, pad(size), // vmsize sizeof(mach_header) + sizeof(segment_command) - + sizeof(section) + + (sizeof(section) * 2) + sizeof(symtab_command), // fileoff pad(size), // filesize 7, // maxprot 7, // initprot - 1, // nsects + 2, // nsects 0 // flags }; - section sect = { + section sect1 = { "__const", // sectname "__TEXT", // segname 0, // addr pad(size), // size sizeof(mach_header) + sizeof(segment_command) - + sizeof(section) + + (sizeof(section) * 2) + sizeof(symtab_command), // offset 0, // align 0, // reloff @@ -81,12 +81,30 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, 0, // reserved2 }; + section sect2 = { + "__const", // sectname + "__TEXT", // segname + 0, // addr + 0, // size + sizeof(mach_header) + + sizeof(segment_command) + + (sizeof(section) * 2) + + sizeof(symtab_command) + + size, // offset + 0, // align + 0, // reloff + 0, // nreloc + S_REGULAR, // flags + 0, // reserved1 + 0, // reserved2 + }; + symtab_command symbolTable = { LC_SYMTAB, // cmd sizeof(symtab_command), // cmdsize sizeof(mach_header) + sizeof(segment_command) - + sizeof(section) + + (sizeof(section) * 2) + sizeof(symtab_command) + pad(size), // symoff 2, // nsyms @@ -96,7 +114,7 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, + sizeof(symtab_command) + pad(size) + (sizeof(struct nlist) * 2), // stroff - 1 + dataNameLength + sizeNameLength, // strsize + 1 + startNameLength + endNameLength, // strsize }; struct nlist symbolList[] = { @@ -108,17 +126,18 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, 0 // n_value }, { - reinterpret_cast(1 + dataNameLength), // n_un - N_ABS | N_EXT, // n_type - NO_SECT, // n_sect + reinterpret_cast(1 + startNameLength), // n_un + N_SECT | N_EXT, // n_type + 2, // n_sect 0, // n_desc - size // n_value + 0 // n_value } }; fwrite(&header, 1, sizeof(header), out); fwrite(&segment, 1, sizeof(segment), out); - fwrite(§, 1, sizeof(sect), out); + fwrite(§1, 1, sizeof(sect1), out); + fwrite(§2, 1, sizeof(sect2), out); fwrite(&symbolTable, 1, sizeof(symbolTable), out); fwrite(data, 1, size, out); @@ -127,8 +146,8 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, fwrite(&symbolList, 1, sizeof(symbolList), out); fputc(0, out); - fwrite(dataName, 1, dataNameLength, out); - fwrite(sizeName, 1, sizeNameLength, out); + fwrite(startName, 1, startNameLength, out); + fwrite(endName, 1, endNameLength, out); } } // namespace @@ -138,7 +157,7 @@ main(int argc, const char** argv) { if (argc != 4) { fprintf(stderr, - "usage: %s \n", + "usage: %s \n", argv[0]); return -1; } diff --git a/src/boot.cpp b/src/boot.cpp new file mode 100644 index 0000000000..7673e51735 --- /dev/null +++ b/src/boot.cpp @@ -0,0 +1,29 @@ +#include "stdint.h" +#include "stdlib.h" + +// since we don't link against libstdc++, we must implement some dummy +// functions: +extern "C" void __cxa_pure_virtual(void) { abort(); } +void operator delete(void*) { abort(); } + +#ifdef __MINGW32__ +# define EXPORT __declspec(dllexport) +# define SYMBOL(x) binary_classpath_jar_##x +#else +# define EXPORT __attribute__ ((visibility("default"))) +# define SYMBOL(x) _binary_classpath_jar_##x +#endif + +extern "C" { + + extern const uint8_t SYMBOL(start)[]; + extern const uint8_t SYMBOL(end)[]; + + EXPORT const uint8_t* + classpathJar(unsigned* size) + { + *size = SYMBOL(end) - SYMBOL(start); + return SYMBOL(start); + } + +} diff --git a/src/finder.cpp b/src/finder.cpp index fb8cb0c353..dadfb9dadb 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -440,14 +440,15 @@ class JarElement: public Element { class BuiltinElement: public JarElement { public: - BuiltinElement(System* s, const char* name, unsigned nameLength): - JarElement(s, name, nameLength) + BuiltinElement(System* s, const char* name, unsigned nameLength, + const char* libraryName): + JarElement(s, name, nameLength), + libraryName(libraryName) { } virtual void init() { if (index == 0) { - System::Library* library; - if (s->success(s->load(&library, 0, false))) { + if (s->success(s->load(&library, libraryName, true))) { void* p = library->resolve(name); if (p) { uint8_t* (*function)(unsigned*); @@ -461,14 +462,21 @@ class BuiltinElement: public JarElement { index = JarIndex::open(s, region); } } - library->disposeAll(); } } } + + virtual void dispose() { + JarElement::dispose(); + library->disposeAll(); + } + + System::Library* library; + const char* libraryName; }; Element* -parsePath(System* s, const char* path) +parsePath(System* s, const char* path, const char* bootLibrary) { class Tokenizer { public: @@ -509,7 +517,7 @@ parsePath(System* s, const char* path) name[token.length - 2] = 0; e = new (allocate(s, sizeof(BuiltinElement))) - BuiltinElement(s, name, token.length - 2); + BuiltinElement(s, name, token.length - 2, bootLibrary); } else { char* name = static_cast(allocate(s, token.length + 1)); memcpy(name, token.s, token.length); @@ -548,9 +556,9 @@ parsePath(System* s, const char* path) class MyFinder: public Finder { public: - MyFinder(System* system, const char* path): + MyFinder(System* system, const char* path, const char* bootLibrary): system(system), - path_(parsePath(system, path)), + path_(parsePath(system, path, bootLibrary)), pathString(copy(system, &pathStringLength, path)) { } @@ -600,9 +608,9 @@ class MyFinder: public Finder { namespace vm { Finder* -makeFinder(System* s, const char* path) +makeFinder(System* s, const char* path, const char* bootLibrary) { - return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path); + return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary); } } // namespace vm diff --git a/src/finder.h b/src/finder.h index e9022d17d9..6b3a868f68 100644 --- a/src/finder.h +++ b/src/finder.h @@ -27,7 +27,7 @@ class Finder { }; Finder* -makeFinder(System* s, const char* path); +makeFinder(System* s, const char* path, const char* bootLibrary); } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 696d7f45c8..bbd9ef74b2 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1986,28 +1986,38 @@ JNI_GetDefaultJavaVMInitArgs(void* args) return 0; } -#define BUILTINS_PROPERTY "vm.builtins" +#define BUILTINS_PROPERTY "avian.builtins" +#define BOOTSTRAP_PROPERTY "avian.bootstrap" extern "C" JNIEXPORT jint JNICALL JNI_CreateJavaVM(Machine** m, Thread** t, void* args) { JDK1_1InitArgs* a = static_cast(args); - System* s = makeSystem(); - Heap* h = makeHeap(s, a->maxHeapSize); - Finder* f = makeFinder(s, a->classpath); - Processor* p = makeProcessor(s, h); - - *m = new (h->allocate(sizeof(Machine), false)) Machine(s, h, f, p); - + const char* builtins = 0; + const char* bootLibrary = 0; if (a->properties) { for (const char** p = a->properties; *p; ++p) { - if (strncmp(*p, BUILTINS_PROPERTY "=", sizeof(BUILTINS_PROPERTY)) == 0) { - (*m)->builtins = (*p) + sizeof(BUILTINS_PROPERTY); + if (strncmp(*p, BUILTINS_PROPERTY "=", + sizeof(BUILTINS_PROPERTY)) == 0) + { + builtins = (*p) + sizeof(BUILTINS_PROPERTY); + } else if (strncmp(*p, BOOTSTRAP_PROPERTY "=", + sizeof(BOOTSTRAP_PROPERTY)) == 0) + { + bootLibrary = (*p) + sizeof(BOOTSTRAP_PROPERTY); } } } + System* s = makeSystem(); + Heap* h = makeHeap(s, a->maxHeapSize); + Finder* f = makeFinder(s, a->classpath, bootLibrary); + Processor* p = makeProcessor(s, h); + + *m = new (h->allocate(sizeof(Machine), false)) + Machine(s, h, f, p, bootLibrary, builtins); + *t = p->makeThread(*m, 0, 0); enter(*t, Thread::ActiveState); diff --git a/src/machine.cpp b/src/machine.cpp index 848b111588..17f6bb129e 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1644,7 +1644,8 @@ class HeapClient: public Heap::Client { namespace vm { Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor): + Processor* processor, const char* bootLibrary, + const char* builtins): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient), false)) @@ -1655,7 +1656,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, rootThread(0), exclusive(0), jniReferences(0), - builtins(0), + builtins(builtins), activeCount(0), liveCount(0), fixedFootprint(0), @@ -1688,7 +1689,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or not system->success(system->make(&referenceLock)) or - not system->success(system->load(&libraries, 0, false))) + not system->success(system->load(&libraries, bootLibrary, true))) { system->abort(); } diff --git a/src/machine.h b/src/machine.h index 33af90fa2e..e1600fa496 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1121,7 +1121,8 @@ class Machine { ImmortalAllocation }; - Machine(System* system, Heap* heap, Finder* finder, Processor* processor); + Machine(System* system, Heap* heap, Finder* finder, Processor* processor, + const char* bootLibrary, const char* builtins); ~Machine() { dispose(); diff --git a/src/main.cpp b/src/main.cpp index e52f4edcf5..f2557e3a68 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,37 +14,12 @@ #include "stdint.h" #include "jni.h" -// since we don't link against libstdc++, we must implement some dummy -// functions: -extern "C" void __cxa_pure_virtual(void) { abort(); } -void operator delete(void*) { abort(); } - #ifdef __MINGW32__ # define PATH_SEPARATOR ';' -# define EXPORT __declspec(dllexport) -# define SYMBOL(x) binary_classpath_jar_##x #else # define PATH_SEPARATOR ':' -# define EXPORT __attribute__ ((visibility("default"))) -# define SYMBOL(x) _binary_classpath_jar_##x #endif -#define BOOT_CLASSPATH "[classpathJar]" - -extern "C" { - - extern const uint8_t SYMBOL(start)[]; - extern const uint8_t SYMBOL(size)[]; - - EXPORT const uint8_t* - classpathJar(unsigned* size) - { - *size = reinterpret_cast(SYMBOL(size)); - return SYMBOL(start); - } - -} - #ifdef JNI_VERSION_1_6 // todo: use JavaVMInitArgs instead typedef struct JDK1_1InitArgs { @@ -121,14 +96,25 @@ main(int ac, const char** av) vmArgs.classpath = classpath; #endif - const char* properties[propertyCount + 1]; - properties[propertyCount] = 0; +#ifdef BOOT_LIBRARY + const int BootPropertyCount = 1; +#else + const int BootPropertyCount = 0; +#endif + + const char* properties[propertyCount + BootPropertyCount + 1]; + properties[propertyCount + BootPropertyCount] = 0; for (int i = 1; i < ac; ++i) { if (strncmp(av[i], "-D", 2) == 0) { properties[--propertyCount] = av[i] + 2; } } +#ifdef BOOT_LIBRARY + properties[propertyCount + BootPropertyCount - 1] + = "avian.bootstrap=" BOOT_LIBRARY; +#endif + vmArgs.properties = const_cast(properties); if (class_ == 0) { diff --git a/src/posix.cpp b/src/posix.cpp index 1ef8bfcc27..2a60146e1e 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -687,18 +687,18 @@ class MySystem: public System { bool alreadyAllocated = false; bool isMain = false; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName) { + if (mapName and name) { unsigned size = nameLength + 3 + sizeof(SO_SUFFIX); char buffer[size]; snprintf(buffer, size, "lib%s" SO_SUFFIX, name); - p = dlopen(buffer, RTLD_LAZY); + p = dlopen(buffer, RTLD_LAZY | RTLD_LOCAL); } else { if (!name) { pathOfExecutable(this, &name, &nameLength); alreadyAllocated = true; isMain = true; } - p = dlopen(name, RTLD_LAZY); + p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); } if (p) { diff --git a/src/windows.cpp b/src/windows.cpp index af375437f8..650edf1008 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -623,7 +623,7 @@ class MySystem: public System { { HMODULE handle; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName) { + if (mapName and name) { unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX); char buffer[size]; snprintf(buffer, size, SO_PREFIX "%s" SO_SUFFIX, name);