From 17f495eb270bee5cddf1e449aad3d6abd53c5f05 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Sep 2010 17:31:23 -0600 Subject: [PATCH] rework OpenJDK build to derive classpath and library path from environment We now consult the JAVA_HOME environment variable to determine where to find the system library JARs and SOs. Ultimately, we'll want to support self-contained build, but this allows Avian to behave like a conventional libjvm.so. --- makefile | 86 +++++++---------- src/classpath-avian.cpp | 8 +- src/classpath-common.h | 119 ++++++++++++++++------- src/classpath-openjdk.cpp | 102 +++++++++++++++++--- src/finder.cpp | 44 +++------ src/jnienv.cpp | 17 ++-- src/machine.cpp | 2 +- src/machine.h | 3 + src/posix.cpp | 52 +++++----- src/system.h | 6 +- src/tokenizer.h | 45 +++++++++ src/type-generator.cpp | 196 +++++++++++++++++--------------------- 12 files changed, 403 insertions(+), 277 deletions(-) create mode 100644 src/tokenizer.h diff --git a/makefile b/makefile index a48d4dbf9f..2c48a069a5 100644 --- a/makefile +++ b/makefile @@ -40,26 +40,20 @@ ifeq ($(continuations),true) options := $(options)-continuations endif +root := $(shell (cd .. && pwd)) +build = build/$(platform)-$(arch)$(options) +classpath-build = $(build)/classpath +test-build = $(build)/test +src = src +classpath-src = classpath +test = test + classpath = avian -test-library-path = . test-executable = $(executable) +generator-classpath = $(classpath-build) +boot-classpath = $(classpath-build) -ifdef gnu - classpath = gnu - options := $(options)-gnu - classapth-jar = $(gnu)/share/classpath/glibj.zip - classpath-libraries = \ - $(gnu)/lib/classpath/libjavaio.a \ - $(gnu)/lib/classpath/libjavalang.a \ - $(gnu)/lib/classpath/libjavalangreflect.a \ - $(gnu)/lib/classpath/libjavamath.a \ - $(gnu)/lib/classpath/libjavanet.a \ - $(gnu)/lib/classpath/libjavanio.a \ - $(gnu)/lib/classpath/libjavautil.a - classpath-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU - classpath-lflags = -lgmp -endif ifdef openjdk classpath = openjdk options := $(options)-openjdk @@ -68,19 +62,12 @@ ifdef openjdk else openjdk-lib-dir = $(openjdk)/jre/lib endif - classpath-jar = $(openjdk)/jre/lib/rt.jar - test-library-path = $(openjdk-lib-dir):$(build) + classpath-cflags = -DAVIAN_OPENJDK_JAVA_HOME=\"$(openjdk)\" test-executable = $(executable-dynamic) + generator-classpath := $(generator-classpath):$(openjdk)/jre/lib/rt.jar + boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar endif -root := $(shell (cd .. && pwd)) -build = build/$(platform)-$(arch)$(options) -classpath-build = $(build)/classpath -test-build = $(build)/test -src = src -classpath-src = classpath -test = test - ifneq ($(classpath),avian) classpath-object-dep = $(build)/classpath-object.dep classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") @@ -138,7 +125,7 @@ cflags = $(build-cflags) common-lflags = -lm -lz $(classpath-lflags) -build-lflags = +build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl @@ -401,10 +388,15 @@ driver-dynamic-object = $(build)/main-dynamic.o boot-source = $(src)/boot.cpp boot-object = $(build)/boot.o -generator-headers = $(src)/constants.h -generator-sources = $(src)/type-generator.cpp +generator-depends := $(wildcard $(src)/*.h) +generator-sources = \ + $(src)/type-generator.cpp \ + $(src)/$(system).cpp \ + $(src)/finder.cpp +generator-cpp-objects = \ + $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%-build.o,$(x))) generator-objects = \ - $(call cpp-objects,$(generator-sources),$(src),$(build)) + $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) generator = $(build)/generator converter-objects = \ @@ -467,9 +459,9 @@ test-extra-dep = $(test-build)-extra.dep class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) -flags = -cp $(test-build) +test-flags = -cp $(build)/test -args = $(flags) $(input) +test-args = $(test-flags) $(input) .PHONY: build build: $(static-library) $(executable) $(dynamic-library) \ @@ -481,20 +473,20 @@ $(test-extra-dep): $(classpath-dep) .PHONY: run run: build - $(executable) $(args) + LD_LIBRARY_PATH=$(build) $(test-executable) $(test-args) .PHONY: debug debug: build - gdb --args $(executable) $(args) + LD_LIBRARY_PATH=$(build) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build - $(vg) $(executable) $(args) + LD_LIBRARY_PATH=$(build) $(vg) $(test-executable) $(test-args) .PHONY: test test: build /bin/sh $(test)/test.sh 2>/dev/null \ - $(test-library-path) $(test-executable) $(mode) "$(flags)" \ + $(build) $(test-executable) $(mode) "$(test-flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: tarball @@ -523,24 +515,15 @@ gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) - $(generator) $(classpath-build) $(call gen-arg,$(@)) < $(<) > $(@) - -$(build)/type-generator.o: \ - $(generator-headers) + $(generator) $(generator-classpath) $(<) $(@) $(call gen-arg,$(@)) $(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) $(classpath-jar) +$(classpath-dep): $(classpath-sources) @echo "compiling classpath classes" @mkdir -p $(classpath-build) -ifneq ($(classpath),avian) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) xf $(classpath-jar)) -endif - $(javac) -d $(classpath-build) \ - -bootclasspath $(classpath-build) \ + $(javac) -d $(classpath-build) -bootclasspath $(boot-classpath) \ $(shell $(MAKE) -s --no-print-directory build=$(build) \ $(classpath-classes)) @touch $(@) @@ -553,7 +536,7 @@ $(test-dep): $(test-sources) @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ - $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ test/Subroutine.java @@ -564,7 +547,7 @@ $(test-extra-dep): $(test-extra-sources) @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ if test -n "$${files}"; then \ - $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi @touch $(@) @@ -635,7 +618,8 @@ $(classpath-object): $(build)/classpath.jar $(converter) $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) -$(generator-objects): $(build)/%.o: $(src)/%.cpp +$(generator-objects): $(generator-depends) +$(generator-objects): $(build)/%-build.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 9ee25aa8cc..e3bbd602fe 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -92,6 +92,12 @@ class MyClasspath : public Classpath { // ignore } + virtual const char* + bootClasspath() + { + return ""; + } + virtual void dispose() { @@ -473,7 +479,7 @@ Avian_java_lang_Runtime_load RUNTIME_ARRAY(char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - loadLibrary(t, RUNTIME_ARRAY_BODY(n), mapName, true); + loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true); } extern "C" JNIEXPORT void JNICALL diff --git a/src/classpath-common.h b/src/classpath-common.h index b9f1ef69b0..3c65301de4 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -11,9 +11,11 @@ #ifndef CLASSPATH_COMMON_H #define CLASSPATH_COMMON_H +#include "tokenizer.h" + namespace vm { -inline object +object getCaller(Thread* t, unsigned target) { class Visitor: public Processor::StackVisitor { @@ -43,7 +45,7 @@ getCaller(Thread* t, unsigned target) return v.method; } -inline object +object getTrace(Thread* t, unsigned skipCount) { class Visitor: public Processor::StackVisitor { @@ -84,7 +86,7 @@ getTrace(Thread* t, unsigned skipCount) return v.trace; } -inline bool +bool compatibleArrayTypes(Thread* t, object a, object b) { return classArrayElementSize(t, a) @@ -94,7 +96,7 @@ compatibleArrayTypes(Thread* t, object a, object b) or (classVmFlags(t, b) & PrimitiveFlag)))); } -inline void +void arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, int32_t dstOffset, int32_t length) { @@ -160,37 +162,13 @@ runOnLoadIfFound(Thread* t, System::Library* library) } System::Library* -loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) +loadLibrary(Thread* t, const char* name) { ACQUIRE(t, t->m->classLock); - const char* builtins = findProperty(t, "avian.builtins"); - if (mapName and builtins) { - const char* s = builtins; - while (*s) { - unsigned length = strlen(name); - if (::strncmp(s, name, length) == 0 - and (s[length] == ',' or s[length] == 0)) - { - // library is built in to this executable - if (runOnLoad and not t->m->triedBuiltinOnLoad) { - t->m->triedBuiltinOnLoad = true; - runOnLoadIfFound(t, t->m->libraries); - } - return t->m->libraries; - } else { - while (*s and *s != ',') ++ s; - if (*s) ++ s; - } - } - } - System::Library* last = t->m->libraries; for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { - if (lib->name() - and ::strcmp(lib->name(), name) == 0 - and lib->mapName() == mapName) - { + if (lib->name() and ::strcmp(lib->name(), name) == 0) { // already loaded return lib; } @@ -198,18 +176,91 @@ loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) } System::Library* lib; - if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) { + if (LIKELY(t->m->system->success(t->m->system->load(&lib, name)))) { last->setNext(lib); + return lib; + } else { + return 0; + } +} + +System::Library* +loadLibrary(Thread* t, const char* path, const char* name, bool mapName, + bool runOnLoad) +{ + ACQUIRE(t, t->m->classLock); + + unsigned nameLength = strlen(name); + if (mapName) { + const char* builtins = findProperty(t, "avian.builtins"); + if (builtins) { + const char* s = builtins; + while (*s) { + if (::strncmp(s, name, nameLength) == 0 + and (s[nameLength] == ',' or s[nameLength] == 0)) + { + // library is built in to this executable + if (runOnLoad and not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + runOnLoadIfFound(t, t->m->libraries); + } + return t->m->libraries; + } else { + while (*s and *s != ',') ++ s; + if (*s) ++ s; + } + } + } + + const char* prefix = t->m->system->libraryPrefix(); + const char* suffix = t->m->system->librarySuffix(); + unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix); + + char* mappedName = static_cast + (t->m->heap->allocate(mappedNameLength + 1)); + + snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix); + + name = mappedName; + nameLength = mappedNameLength; + } + + System::Library* lib = 0; + for (Tokenizer tokenizer(path, t->m->system->pathSeparator()); + tokenizer.hasMore();) + { + Tokenizer::Token token(tokenizer.next()); + + unsigned fullNameLength = token.length + 1 + nameLength; + RUNTIME_ARRAY(char, fullName, fullNameLength + 1); + + snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, + "%*s%c%s", token.length, token.s, t->m->system->fileSeparator(), + name); + + lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName)); + if (lib) break; + } + + if (lib == 0) { + lib = loadLibrary(t, name); + } + + if (lib) { if (runOnLoad) { runOnLoadIfFound(t, lib); } - return lib; - } else { + } else { object message = makeString(t, "library not found: %s", name); t->exception = t->m->classpath->makeThrowable (t, Machine::UnsatisfiedLinkErrorType, message); - return 0; } + + if (mapName) { + t->m->heap->free(name, nameLength + 1); + } + + return lib; } object diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c762209189..13eed26e33 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -139,9 +139,73 @@ makeClassNameString(Thread* t, object name) class MyClasspath : public Classpath { public: - MyClasspath(Allocator* allocator): + static const unsigned BufferSize = 256; + + MyClasspath(System* s, Allocator* allocator): allocator(allocator) - { } + { + const char* javaHome = getenv("JAVA_HOME"); + if (javaHome == 0) { + javaHome = AVIAN_OPENJDK_JAVA_HOME; + } + + class StringBuilder { + public: + StringBuilder(System* s, char* pointer, unsigned remaining): + s(s), pointer(pointer), remaining(remaining) + { } + + void append(const char* append) { + unsigned length = strlen(append); + assert(s, remaining > length); + + strncpy(pointer, append, remaining); + + remaining -= length; + pointer += length; + } + + void append(char c) { + assert(s, remaining > 1); + + pointer[0] = c; + pointer[1] = 0; + + -- remaining; + ++ pointer; + } + + System* s; + char* pointer; + unsigned remaining; + } sb(s, buffer, BufferSize); + + this->javaHome = sb.pointer; + sb.append(javaHome); + sb.append('\0'); + + this->classpath = sb.pointer; + sb.append(javaHome); + sb.append("/jre/lib/rt.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/jsse.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/jce.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/resources.jar"); + sb.append('\0'); + + this->libraryPath = sb.pointer; + sb.append(javaHome); +#ifdef ARCH_x86_64 + sb.append("/jre/lib/amd64"); +#else + sb.append("/jre/lib"); +#endif + } virtual object makeJclass(Thread* t, object class_) @@ -232,7 +296,7 @@ class MyClasspath : public Classpath { { globalMachine = t->m; - if (loadLibrary(t, "java", true, true) == 0) { + if (loadLibrary(t, libraryPath, "java", true, true) == 0) { abort(t); } @@ -271,6 +335,12 @@ class MyClasspath : public Classpath { fieldOffset(t, sclSet)) = true; } + virtual const char* + bootClasspath() + { + return classpath; + } + virtual void dispose() { @@ -278,6 +348,10 @@ class MyClasspath : public Classpath { } Allocator* allocator; + const char* javaHome; + const char* classpath; + const char* libraryPath; + char buffer[BufferSize]; }; struct JVM_ExceptionTableEntryType{ @@ -560,10 +634,10 @@ interruptLock(Thread* t, object thread) namespace vm { Classpath* -makeClasspath(System*, Allocator* allocator) +makeClasspath(System* s, Allocator* allocator) { return new (allocator->allocate(sizeof(local::MyClasspath))) - local::MyClasspath(allocator); + local::MyClasspath(s, allocator); } } // namespace vm @@ -1028,18 +1102,20 @@ JVM_InitProperties(Thread* t, jobject properties) local::setProperty(t, method, *properties, "os.name", "Linux"); # endif local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); - local::setProperty(t, method, *properties, "java.home", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); - - // todo: set this to something sane: - local::setProperty(t, method, *properties, "sun.boot.library.path", - getenv("LD_LIBRARY_PATH")); - local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); #endif + local::setProperty + (t, method, *properties, "java.home", + static_cast(t->m->classpath)->javaHome); + + local::setProperty + (t, method, *properties, "sun.boot.library.path", + static_cast(t->m->classpath)->libraryPath); + local::setProperty(t, method, *properties, "file.encoding", "ASCII"); #ifdef ARCH_x86_32 local::setProperty(t, method, *properties, "os.arch", "x86"); @@ -1132,7 +1208,9 @@ JVM_LoadLibrary(const char* name) ENTER(t, Thread::ActiveState); - return loadLibrary(t, name, false, false); + return loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, name, + false, false); } extern "C" JNIEXPORT void JNICALL diff --git a/src/finder.cpp b/src/finder.cpp index 7ad3245c7a..4e0fa64166 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -10,6 +10,7 @@ #include "zlib-custom.h" #include "system.h" +#include "tokenizer.h" #include "finder.h" using namespace vm; @@ -19,8 +20,7 @@ namespace { const bool DebugFind = false; const char* -append(System* s, const char* a, const char* b, - const char* c) +append(System* s, const char* a, const char* b, const char* c) { unsigned al = strlen(a); unsigned bl = strlen(b); @@ -148,6 +148,9 @@ class DirectoryElement: public Element { } return region; } else { + if (DebugFind) { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } return 0; } } @@ -493,8 +496,12 @@ class JarElement: public Element { while (*name == '/') name++; System::Region* r = (index ? index->find(name, region->start()) : 0); - if (DebugFind and r) { - fprintf(stderr, "found %s in %s\n", name, this->name); + if (DebugFind) { + if (r) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } else { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } } return r; } @@ -533,7 +540,7 @@ class BuiltinElement: public JarElement { virtual void init() { if (index == 0) { - if (s->success(s->load(&library, libraryName, false))) { + if (s->success(s->load(&library, libraryName))) { void* p = library->resolve(name); if (p) { uint8_t* (*function)(unsigned*); @@ -564,33 +571,6 @@ class BuiltinElement: public JarElement { Element* parsePath(System* s, const char* path, const char* bootLibrary) { - class Tokenizer { - public: - class Token { - public: - Token(const char* s, unsigned length): s(s), length(length) { } - - const char* s; - unsigned length; - }; - - Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } - - bool hasMore() { - while (*s == delimiter) ++s; - return *s; - } - - Token next() { - const char* p = s; - while (*s and *s != delimiter) ++s; - return Token(p, s - p); - } - - const char* s; - char delimiter; - }; - Element* first = 0; Element* prev = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index b09c0815c8..549bdc92f4 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2306,26 +2306,31 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) if (classpath == 0) classpath = "."; + System* s = makeSystem(crashDumpDirectory); + Heap* h = makeHeap(s, heapLimit); + Classpath* c = makeClasspath(s, h); + const char* classpathBootClasspath = c->bootClasspath(); + unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); + unsigned cbcpl = strlen(classpathBootClasspath); unsigned bcpal = strlen(bootClasspathAppend); - unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; + unsigned bootClasspathBufferSize = bcppl + bcpl + cbcpl + bcpal + 3; RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); - local::append - (&bootClasspathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); + local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl, + bcpl + cbcpl + bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspath, bcpl, + cbcpl + bcpal ? PATH_SEPARATOR : 0); + local::append(&bootClasspathPointer, classpathBootClasspath, cbcpl, bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); - System* s = makeSystem(crashDumpDirectory); - Heap* h = makeHeap(s, heapLimit); Finder* bf = makeFinder (s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); Finder* af = makeFinder(s, classpath, bootLibrary); Processor* p = makeProcessor(s, h, true); - Classpath* c = makeClasspath(s, h); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); diff --git a/src/machine.cpp b/src/machine.cpp index 0542a5c216..d23c5ee1dd 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2166,7 +2166,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, not system->success(system->make(&referenceLock)) or not system->success(system->make(&shutdownLock)) or not system->success - (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) + (system->load(&libraries, findProperty(this, "avian.bootstrap")))) { system->abort(); } diff --git a/src/machine.h b/src/machine.h index b7b154ffa2..17348e8e88 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1432,6 +1432,9 @@ class Classpath { virtual void boot(Thread* t) = 0; + virtual const char* + bootClasspath() = 0; + virtual void dispose() = 0; }; diff --git a/src/posix.cpp b/src/posix.cpp index 0a96f70f29..7507beb28e 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -469,13 +469,12 @@ class MySystem: public System { class Library: public System::Library { public: Library(System* s, void* p, const char* name, unsigned nameLength, - bool mapName, bool isMain): + bool isMain): s(s), p(p), mainExecutable(isMain), name_(name), nameLength(nameLength), - mapName_(mapName), next_(0) { } @@ -487,10 +486,6 @@ class MySystem: public System { return name_; } - virtual bool mapName() { - return mapName_; - } - virtual System::Library* next() { return next_; } @@ -504,7 +499,7 @@ class MySystem: public System { fprintf(stderr, "close %p\n", p); } - if (!mainExecutable) dlclose(p); + if (not mainExecutable) dlclose(p); if (next_) { next_->disposeAll(); @@ -522,7 +517,6 @@ class MySystem: public System { bool mainExecutable; const char* name_; unsigned nameLength; - bool mapName_; System::Library* next_; }; @@ -716,27 +710,23 @@ class MySystem: public System { } } + virtual const char* libraryPrefix() { + return "lib"; + } + + virtual const char* librarySuffix() { + return SO_SUFFIX; + } + virtual Status load(System::Library** lib, - const char* name, - bool mapName) + const char* name) { - void* p; - bool alreadyAllocated = false; - bool isMain = false; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName and name) { - unsigned size = nameLength + 3 + sizeof(SO_SUFFIX); - char buffer[size]; - vm::snprintf(buffer, size, "lib%s" SO_SUFFIX, name); - p = dlopen(buffer, RTLD_LAZY | RTLD_LOCAL); - } else { - if (!name) { - pathOfExecutable(this, &name, &nameLength); - alreadyAllocated = true; - isMain = true; - } - p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); + bool isMain = name == 0; + if (isMain) { + pathOfExecutable(this, &name, &nameLength); } + void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); if (p) { if (Verbose) { @@ -747,7 +737,7 @@ class MySystem: public System { if (name) { n = static_cast(allocate(this, nameLength + 1)); memcpy(n, name, nameLength + 1); - if (alreadyAllocated) { + if (isMain) { free(name); } } else { @@ -755,11 +745,13 @@ class MySystem: public System { } *lib = new (allocate(this, sizeof(Library))) - Library(this, p, n, nameLength, mapName, isMain); + Library(this, p, n, nameLength, isMain); return 0; } else { - fprintf(stderr, "dlerror: %s\n", dlerror()); + if (Verbose) { + fprintf(stderr, "dlerror: %s\n", dlerror()); + } return 1; } } @@ -768,6 +760,10 @@ class MySystem: public System { return ':'; } + virtual char fileSeparator() { + return '/'; + } + virtual int64_t now() { timeval tv = { 0, 0 }; gettimeofday(&tv, 0); diff --git a/src/system.h b/src/system.h index a58d3bba73..1cdddb3afe 100644 --- a/src/system.h +++ b/src/system.h @@ -89,7 +89,6 @@ class System { public: virtual void* resolve(const char* symbol) = 0; virtual const char* name() = 0; - virtual bool mapName() = 0; virtual Library* next() = 0; virtual void setNext(Library* lib) = 0; virtual void disposeAll() = 0; @@ -135,8 +134,11 @@ class System { virtual Status map(Region**, const char* name) = 0; virtual FileType identify(const char* name) = 0; virtual Status open(Directory**, const char* name) = 0; - virtual Status load(Library**, const char* name, bool mapName) = 0; + virtual const char* libraryPrefix() = 0; + virtual const char* librarySuffix() = 0; + virtual Status load(Library**, const char* name) = 0; virtual char pathSeparator() = 0; + virtual char fileSeparator() = 0; virtual int64_t now() = 0; virtual void exit(int code) = 0; virtual void abort() = 0; diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000000..4036e7d197 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,45 @@ +/* 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 TOKENIZER_H +#define TOKENIZER_H + +namespace vm { + +class Tokenizer { + public: + class Token { + public: + Token(const char* s, unsigned length): s(s), length(length) { } + + const char* s; + unsigned length; + }; + + Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } + + bool hasMore() { + while (*s == delimiter) ++s; + return *s != 0; + } + + Token next() { + const char* p = s; + while (*s and *s != delimiter) ++s; + return Token(p, s - p); + } + + const char* s; + char delimiter; +}; + +} // namespace + +#endif//TOKENIZER_H diff --git a/src/type-generator.cpp b/src/type-generator.cpp index bec29c7e69..b8d63a9572 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -12,9 +12,13 @@ #include "stdio.h" #include "stdint.h" #include "string.h" -#include "assert.h" +#include "errno.h" #include "constants.h" +#include "finder.h" +#include "stream.h" + +#include "assert.h" #define UNREACHABLE abort() @@ -28,6 +32,8 @@ using namespace vm; namespace { +namespace local { + #ifndef POINTER_SIZE # define POINTER_SIZE sizeof(void*) #endif @@ -177,7 +183,7 @@ class Output { void write(int i) { static const int Size = 32; char s[Size]; - int c UNUSED = snprintf(s, Size, "%d", i); + int c UNUSED = ::snprintf(s, Size, "%d", i); assert(c > 0 and c < Size); write(s); } @@ -213,63 +219,6 @@ class FileOutput : public Output { } }; -class Stream { - public: - Stream(FILE* stream, bool close): - stream(stream), close(close) - { - assert(stream); - } - - ~Stream() { - if (close) fclose(stream); - } - - void skip(unsigned size) { - fseek(stream, size, SEEK_CUR); - } - - void read(uint8_t* data, unsigned size) { - fread(data, 1, size, stream); - } - - uint8_t read1() { - uint8_t v; - read(&v, 1); - return v; - } - - uint16_t read2() { - uint16_t a = read1(); - uint16_t b = read1(); - return (a << 8) | b; - } - - uint32_t read4() { - uint32_t a = read2(); - uint32_t b = read2(); - return (a << 16) | b; - } - - uint64_t read8() { - uint64_t a = read4(); - uint64_t b = read4(); - return (a << 32) | b; - } - - uint32_t readFloat() { - return read4(); - } - - uint64_t readDouble() { - return read8(); - } - - private: - FILE* stream; - bool close; -}; - class Object { public: typedef enum { @@ -1384,8 +1333,8 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) } Object* -parseType(Object::ObjectType type, Object* p, Object* declarations, - const char* javaClassDirectory) +parseType(Finder* finder, Object::ObjectType type, Object* p, + Object* declarations) { const char* name = string(car(p)); @@ -1400,9 +1349,16 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, bool isJavaType = javaName and *javaName != '['; if (isJavaType) { - const char* file = append(javaClassDirectory, "/", javaName, ".class"); - Stream s(fopen(file, "rb"), true); + class Client: public Stream::Client { + public: + virtual void NO_RETURN handleError() { + abort(); + } + } client; + System::Region* region = finder->find(append(javaName, ".class")); + Stream s(&client, region->start(), region->length()); parseJavaClass(t, &s, declarations); + region->dispose(); } for (p = cdr(p); p; p = cdr(p)) { @@ -1429,14 +1385,13 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, } Object* -parseDeclaration(Object* p, Object* declarations, - const char* javaClassDirectory) +parseDeclaration(Finder* finder, Object* p, Object* declarations) { const char* spec = string(car(p)); if (equal(spec, "type")) { - return parseType(Object::Type, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Type, cdr(p), declarations); } else if (equal(spec, "pod")) { - return parseType(Object::Pod, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Pod, cdr(p), declarations); } else { fprintf(stderr, "unexpected declaration spec: %s\n", spec); abort(); @@ -1444,7 +1399,7 @@ parseDeclaration(Object* p, Object* declarations, } Object* -parse(Input* in, const char* javaClassDirectory) +parse(Finder* finder, Input* in) { Object* eos = Singleton::make(Object::Eos); List declarations; @@ -1452,7 +1407,7 @@ parse(Input* in, const char* javaClassDirectory) Object* o; while ((o = read(in, eos, 0)) != eos) { declarations.append - (parseDeclaration(o, declarations.first, javaClassDirectory)); + (parseDeclaration(finder, o, declarations.first)); } return declarations.first; @@ -1522,7 +1477,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) if (not unsafe) { out->write("const unsigned "); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); out->write(" = "); writeOffset(out, offset); @@ -1547,7 +1502,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) writeAccessorName(out, member, unsafe); if (memberOwner(member)->type == Object::Pod) { out->write("("); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("*"); } else { out->write("(Thread* t UNUSED, object"); @@ -1563,13 +1518,13 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write(" assert(t, t->m->unsafe or "); out->write("instanceOf(t, arrayBodyUnsafe"); out->write("(t, t->m->types, Machine::"); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("Type)"); out->write(", o));\n"); if (member->type != Object::Scalar) { out->write(" assert(t, i < "); - out->write(::typeName(memberOwner(member))); + out->write(local::typeName(memberOwner(member))); out->write("Length(t, o));\n"); } } @@ -1599,7 +1554,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write("["); } - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); if (member->type != Object::Scalar) { @@ -2221,62 +2176,83 @@ void usageAndExit(const char* command) { fprintf(stderr, - "usage: %s " + "usage: %s " "{enums,declarations,constructors,initializations," "java-initializations}\n", command); exit(-1); } +} // namespace local + } // namespace +extern "C" uint64_t +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); +} + +extern "C" void +vmJump(void*, void*, void*, void*, uintptr_t, uintptr_t) +{ + abort(); +} + int main(int ac, char** av) { - if ((ac != 2 and ac != 3) - or (ac == 3 - and not equal(av[2], "enums") - and not equal(av[2], "declarations") - and not equal(av[2], "constructors") - and not equal(av[2], "initializations") - and not equal(av[2], "java-initializations"))) + if (ac != 5 + or not (local::equal(av[4], "enums") + or local::equal(av[4], "declarations") + or local::equal(av[4], "constructors") + or local::equal(av[4], "initializations") + or local::equal(av[4], "java-initializations"))) { - usageAndExit(av[0]); + local::usageAndExit(av[0]); } - FileInput in(0, stdin, false); + System* system = makeSystem(0); + Finder* finder = makeFinder(system, av[1], 0); - Object* declarations = parse(&in, av[1]); - - FileOutput out(0, stdout, false); - - if (ac == 2 or equal(av[2], "enums")) { - writeEnums(&out, declarations); + FILE* inStream = ::fopen(av[2], "rb"); + if (inStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[2], strerror(errno)); + return -1; } + local::FileInput in(0, inStream, false); - if (ac == 2 or equal(av[2], "declarations")) { + local::Object* declarations = local::parse(finder, &in); + + finder->dispose(); + system->dispose(); + + FILE* outStream = ::fopen(av[3], "wb"); + if (outStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[3], strerror(errno)); + return -1; + } + local::FileOutput out(0, outStream, false); + + if (local::equal(av[4], "enums")) { + local::writeEnums(&out, declarations); + } else if (local::equal(av[4], "declarations")) { out.write("const unsigned TypeCount = "); - out.Output::write(typeCount(declarations)); + out.Output::write(local::typeCount(declarations)); out.write(";\n\n"); - writePods(&out, declarations); - writeAccessors(&out, declarations); - writeSizes(&out, declarations); - writeInitializerDeclarations(&out, declarations); - writeConstructorDeclarations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "constructors")) { - writeInitializers(&out, declarations); - writeConstructors(&out, declarations); - } - - if (ac == 2 or equal(av[2], "initializations")) { - writeInitializations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "java-initializations")) { - writeJavaInitializations(&out, declarations); + local::writePods(&out, declarations); + local::writeAccessors(&out, declarations); + local::writeSizes(&out, declarations); + local::writeInitializerDeclarations(&out, declarations); + local::writeConstructorDeclarations(&out, declarations); + } else if (local::equal(av[4], "constructors")) { + local::writeInitializers(&out, declarations); + local::writeConstructors(&out, declarations); + } else if (local::equal(av[4], "initializations")) { + local::writeInitializations(&out, declarations); + } else if (local::equal(av[4], "java-initializations")) { + local::writeJavaInitializations(&out, declarations); } return 0;