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.
This commit is contained in:
Joel Dice 2010-09-20 17:31:23 -06:00
parent 88942a9672
commit 17f495eb27
12 changed files with 403 additions and 277 deletions

View File

@ -40,26 +40,20 @@ ifeq ($(continuations),true)
options := $(options)-continuations options := $(options)-continuations
endif 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 classpath = avian
test-library-path = .
test-executable = $(executable) 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 ifdef openjdk
classpath = openjdk classpath = openjdk
options := $(options)-openjdk options := $(options)-openjdk
@ -68,19 +62,12 @@ ifdef openjdk
else else
openjdk-lib-dir = $(openjdk)/jre/lib openjdk-lib-dir = $(openjdk)/jre/lib
endif endif
classpath-jar = $(openjdk)/jre/lib/rt.jar classpath-cflags = -DAVIAN_OPENJDK_JAVA_HOME=\"$(openjdk)\"
test-library-path = $(openjdk-lib-dir):$(build)
test-executable = $(executable-dynamic) test-executable = $(executable-dynamic)
generator-classpath := $(generator-classpath):$(openjdk)/jre/lib/rt.jar
boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar
endif 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) ifneq ($(classpath),avian)
classpath-object-dep = $(build)/classpath-object.dep classpath-object-dep = $(build)/classpath-object.dep
classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") classpath-objects = $(shell find $(build)/classpath-objects -name "*.o")
@ -138,7 +125,7 @@ cflags = $(build-cflags)
common-lflags = -lm -lz $(classpath-lflags) common-lflags = -lm -lz $(classpath-lflags)
build-lflags = build-lflags = -lz -lpthread -ldl
lflags = $(common-lflags) -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl
@ -401,10 +388,15 @@ driver-dynamic-object = $(build)/main-dynamic.o
boot-source = $(src)/boot.cpp boot-source = $(src)/boot.cpp
boot-object = $(build)/boot.o boot-object = $(build)/boot.o
generator-headers = $(src)/constants.h generator-depends := $(wildcard $(src)/*.h)
generator-sources = $(src)/type-generator.cpp 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 = \ generator-objects = \
$(call cpp-objects,$(generator-sources),$(src),$(build)) $(call generator-cpp-objects,$(generator-sources),$(src),$(build))
generator = $(build)/generator generator = $(build)/generator
converter-objects = \ converter-objects = \
@ -467,9 +459,9 @@ test-extra-dep = $(test-build)-extra.dep
class-name = $(patsubst $(1)/%.class,%,$(2)) class-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) 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 .PHONY: build
build: $(static-library) $(executable) $(dynamic-library) \ build: $(static-library) $(executable) $(dynamic-library) \
@ -481,20 +473,20 @@ $(test-extra-dep): $(classpath-dep)
.PHONY: run .PHONY: run
run: build run: build
$(executable) $(args) LD_LIBRARY_PATH=$(build) $(test-executable) $(test-args)
.PHONY: debug .PHONY: debug
debug: build debug: build
gdb --args $(executable) $(args) LD_LIBRARY_PATH=$(build) gdb --args $(test-executable) $(test-args)
.PHONY: vg .PHONY: vg
vg: build vg: build
$(vg) $(executable) $(args) LD_LIBRARY_PATH=$(build) $(vg) $(test-executable) $(test-args)
.PHONY: test .PHONY: test
test: build test: build
/bin/sh $(test)/test.sh 2>/dev/null \ /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)) $(call class-names,$(test-build),$(test-classes))
.PHONY: tarball .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) $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep)
@echo "generating $(@)" @echo "generating $(@)"
@mkdir -p $(dir $(@)) @mkdir -p $(dir $(@))
$(generator) $(classpath-build) $(call gen-arg,$(@)) < $(<) > $(@) $(generator) $(generator-classpath) $(<) $(@) $(call gen-arg,$(@))
$(build)/type-generator.o: \
$(generator-headers)
$(classpath-build)/%.class: $(classpath-src)/%.java $(classpath-build)/%.class: $(classpath-src)/%.java
@echo $(<) @echo $(<)
$(classpath-dep): $(classpath-sources) $(classpath-jar) $(classpath-dep): $(classpath-sources)
@echo "compiling classpath classes" @echo "compiling classpath classes"
@mkdir -p $(classpath-build) @mkdir -p $(classpath-build)
ifneq ($(classpath),avian) $(javac) -d $(classpath-build) -bootclasspath $(boot-classpath) \
(wd=$$(pwd) && \
cd $(classpath-build) && \
$(jar) xf $(classpath-jar))
endif
$(javac) -d $(classpath-build) \
-bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory build=$(build) \ $(shell $(MAKE) -s --no-print-directory build=$(build) \
$(classpath-classes)) $(classpath-classes))
@touch $(@) @touch $(@)
@ -553,7 +536,7 @@ $(test-dep): $(test-sources)
@mkdir -p $(test-build) @mkdir -p $(test-build)
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
if test -n "$${files}"; then \ if test -n "$${files}"; then \
$(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \
fi fi
$(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \
test/Subroutine.java test/Subroutine.java
@ -564,7 +547,7 @@ $(test-extra-dep): $(test-extra-sources)
@mkdir -p $(test-build) @mkdir -p $(test-build)
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \
if test -n "$${files}"; then \ if test -n "$${files}"; then \
$(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \
fi fi
@touch $(@) @touch $(@)
@ -635,7 +618,8 @@ $(classpath-object): $(build)/classpath.jar $(converter)
$(converter) $(<) $(@) _binary_classpath_jar_start \ $(converter) $(<) $(@) _binary_classpath_jar_start \
_binary_classpath_jar_end $(platform) $(arch) _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 $(@)" @echo "compiling $(@)"
@mkdir -p $(dir $(@)) @mkdir -p $(dir $(@))
$(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \

View File

@ -92,6 +92,12 @@ class MyClasspath : public Classpath {
// ignore // ignore
} }
virtual const char*
bootClasspath()
{
return "";
}
virtual void virtual void
dispose() dispose()
{ {
@ -473,7 +479,7 @@ Avian_java_lang_Runtime_load
RUNTIME_ARRAY(char, n, length + 1); RUNTIME_ARRAY(char, n, length + 1);
stringChars(t, name, RUNTIME_ARRAY_BODY(n)); 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 extern "C" JNIEXPORT void JNICALL

View File

@ -11,9 +11,11 @@
#ifndef CLASSPATH_COMMON_H #ifndef CLASSPATH_COMMON_H
#define CLASSPATH_COMMON_H #define CLASSPATH_COMMON_H
#include "tokenizer.h"
namespace vm { namespace vm {
inline object object
getCaller(Thread* t, unsigned target) getCaller(Thread* t, unsigned target)
{ {
class Visitor: public Processor::StackVisitor { class Visitor: public Processor::StackVisitor {
@ -43,7 +45,7 @@ getCaller(Thread* t, unsigned target)
return v.method; return v.method;
} }
inline object object
getTrace(Thread* t, unsigned skipCount) getTrace(Thread* t, unsigned skipCount)
{ {
class Visitor: public Processor::StackVisitor { class Visitor: public Processor::StackVisitor {
@ -84,7 +86,7 @@ getTrace(Thread* t, unsigned skipCount)
return v.trace; return v.trace;
} }
inline bool bool
compatibleArrayTypes(Thread* t, object a, object b) compatibleArrayTypes(Thread* t, object a, object b)
{ {
return classArrayElementSize(t, a) return classArrayElementSize(t, a)
@ -94,7 +96,7 @@ compatibleArrayTypes(Thread* t, object a, object b)
or (classVmFlags(t, b) & PrimitiveFlag)))); or (classVmFlags(t, b) & PrimitiveFlag))));
} }
inline void void
arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
int32_t dstOffset, int32_t length) int32_t dstOffset, int32_t length)
{ {
@ -160,17 +162,42 @@ runOnLoadIfFound(Thread* t, System::Library* library)
} }
System::Library* System::Library*
loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) loadLibrary(Thread* t, const char* name)
{ {
ACQUIRE(t, t->m->classLock); ACQUIRE(t, t->m->classLock);
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) {
// already loaded
return lib;
}
last = lib;
}
System::Library* lib;
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"); const char* builtins = findProperty(t, "avian.builtins");
if (mapName and builtins) { if (builtins) {
const char* s = builtins; const char* s = builtins;
while (*s) { while (*s) {
unsigned length = strlen(name); if (::strncmp(s, name, nameLength) == 0
if (::strncmp(s, name, length) == 0 and (s[nameLength] == ',' or s[nameLength] == 0))
and (s[length] == ',' or s[length] == 0))
{ {
// library is built in to this executable // library is built in to this executable
if (runOnLoad and not t->m->triedBuiltinOnLoad) { if (runOnLoad and not t->m->triedBuiltinOnLoad) {
@ -185,31 +212,55 @@ loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad)
} }
} }
System::Library* last = t->m->libraries; const char* prefix = t->m->system->libraryPrefix();
for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { const char* suffix = t->m->system->librarySuffix();
if (lib->name() unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix);
and ::strcmp(lib->name(), name) == 0
and lib->mapName() == mapName) char* mappedName = static_cast<char*>
{ (t->m->heap->allocate(mappedNameLength + 1));
// already loaded
return lib; snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix);
}
last = lib; name = mappedName;
nameLength = mappedNameLength;
} }
System::Library* lib; System::Library* lib = 0;
if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) { for (Tokenizer tokenizer(path, t->m->system->pathSeparator());
last->setNext(lib); 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) { if (runOnLoad) {
runOnLoadIfFound(t, lib); runOnLoadIfFound(t, lib);
} }
return lib;
} else { } else {
object message = makeString(t, "library not found: %s", name); object message = makeString(t, "library not found: %s", name);
t->exception = t->m->classpath->makeThrowable t->exception = t->m->classpath->makeThrowable
(t, Machine::UnsatisfiedLinkErrorType, message); (t, Machine::UnsatisfiedLinkErrorType, message);
return 0;
} }
if (mapName) {
t->m->heap->free(name, nameLength + 1);
}
return lib;
} }
object object

View File

@ -139,10 +139,74 @@ makeClassNameString(Thread* t, object name)
class MyClasspath : public Classpath { class MyClasspath : public Classpath {
public: public:
MyClasspath(Allocator* allocator): static const unsigned BufferSize = 256;
MyClasspath(System* s, Allocator* allocator):
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 virtual object
makeJclass(Thread* t, object class_) makeJclass(Thread* t, object class_)
{ {
@ -232,7 +296,7 @@ class MyClasspath : public Classpath {
{ {
globalMachine = t->m; globalMachine = t->m;
if (loadLibrary(t, "java", true, true) == 0) { if (loadLibrary(t, libraryPath, "java", true, true) == 0) {
abort(t); abort(t);
} }
@ -271,6 +335,12 @@ class MyClasspath : public Classpath {
fieldOffset(t, sclSet)) = true; fieldOffset(t, sclSet)) = true;
} }
virtual const char*
bootClasspath()
{
return classpath;
}
virtual void virtual void
dispose() dispose()
{ {
@ -278,6 +348,10 @@ class MyClasspath : public Classpath {
} }
Allocator* allocator; Allocator* allocator;
const char* javaHome;
const char* classpath;
const char* libraryPath;
char buffer[BufferSize];
}; };
struct JVM_ExceptionTableEntryType{ struct JVM_ExceptionTableEntryType{
@ -560,10 +634,10 @@ interruptLock(Thread* t, object thread)
namespace vm { namespace vm {
Classpath* Classpath*
makeClasspath(System*, Allocator* allocator) makeClasspath(System* s, Allocator* allocator)
{ {
return new (allocator->allocate(sizeof(local::MyClasspath))) return new (allocator->allocate(sizeof(local::MyClasspath)))
local::MyClasspath(allocator); local::MyClasspath(s, allocator);
} }
} // namespace vm } // namespace vm
@ -1028,18 +1102,20 @@ JVM_InitProperties(Thread* t, jobject properties)
local::setProperty(t, method, *properties, "os.name", "Linux"); local::setProperty(t, method, *properties, "os.name", "Linux");
# endif # endif
local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); 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.home", getenv("HOME"));
local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); 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", local::setProperty(t, method, *properties, "java.protocol.handler.pkgs",
"avian"); "avian");
#endif #endif
local::setProperty
(t, method, *properties, "java.home",
static_cast<local::MyClasspath*>(t->m->classpath)->javaHome);
local::setProperty
(t, method, *properties, "sun.boot.library.path",
static_cast<local::MyClasspath*>(t->m->classpath)->libraryPath);
local::setProperty(t, method, *properties, "file.encoding", "ASCII"); local::setProperty(t, method, *properties, "file.encoding", "ASCII");
#ifdef ARCH_x86_32 #ifdef ARCH_x86_32
local::setProperty(t, method, *properties, "os.arch", "x86"); local::setProperty(t, method, *properties, "os.arch", "x86");
@ -1132,7 +1208,9 @@ JVM_LoadLibrary(const char* name)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
return loadLibrary(t, name, false, false); return loadLibrary
(t, static_cast<local::MyClasspath*>(t->m->classpath)->libraryPath, name,
false, false);
} }
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL

View File

@ -10,6 +10,7 @@
#include "zlib-custom.h" #include "zlib-custom.h"
#include "system.h" #include "system.h"
#include "tokenizer.h"
#include "finder.h" #include "finder.h"
using namespace vm; using namespace vm;
@ -19,8 +20,7 @@ namespace {
const bool DebugFind = false; const bool DebugFind = false;
const char* const char*
append(System* s, const char* a, const char* b, append(System* s, const char* a, const char* b, const char* c)
const char* c)
{ {
unsigned al = strlen(a); unsigned al = strlen(a);
unsigned bl = strlen(b); unsigned bl = strlen(b);
@ -148,6 +148,9 @@ class DirectoryElement: public Element {
} }
return region; return region;
} else { } else {
if (DebugFind) {
fprintf(stderr, "%s not found in %s\n", name, this->name);
}
return 0; return 0;
} }
} }
@ -493,8 +496,12 @@ class JarElement: public Element {
while (*name == '/') name++; while (*name == '/') name++;
System::Region* r = (index ? index->find(name, region->start()) : 0); System::Region* r = (index ? index->find(name, region->start()) : 0);
if (DebugFind and r) { if (DebugFind) {
if (r) {
fprintf(stderr, "found %s in %s\n", name, this->name); fprintf(stderr, "found %s in %s\n", name, this->name);
} else {
fprintf(stderr, "%s not found in %s\n", name, this->name);
}
} }
return r; return r;
} }
@ -533,7 +540,7 @@ class BuiltinElement: public JarElement {
virtual void init() { virtual void init() {
if (index == 0) { if (index == 0) {
if (s->success(s->load(&library, libraryName, false))) { if (s->success(s->load(&library, libraryName))) {
void* p = library->resolve(name); void* p = library->resolve(name);
if (p) { if (p) {
uint8_t* (*function)(unsigned*); uint8_t* (*function)(unsigned*);
@ -564,33 +571,6 @@ class BuiltinElement: public JarElement {
Element* Element*
parsePath(System* s, const char* path, const char* bootLibrary) 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* first = 0;
Element* prev = 0; Element* prev = 0;
for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) {

View File

@ -2306,26 +2306,31 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
if (classpath == 0) classpath = "."; 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 bcppl = strlen(bootClasspathPrepend);
unsigned bcpl = strlen(bootClasspath); unsigned bcpl = strlen(bootClasspath);
unsigned cbcpl = strlen(classpathBootClasspath);
unsigned bcpal = strlen(bootClasspathAppend); unsigned bcpal = strlen(bootClasspathAppend);
unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; unsigned bootClasspathBufferSize = bcppl + bcpl + cbcpl + bcpal + 3;
RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize);
char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer);
local::append local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl,
(&bootClasspathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); bcpl + cbcpl + bcpal ? PATH_SEPARATOR : 0);
local::append(&bootClasspathPointer, bootClasspath, bcpl, local::append(&bootClasspathPointer, bootClasspath, bcpl,
cbcpl + bcpal ? PATH_SEPARATOR : 0);
local::append(&bootClasspathPointer, classpathBootClasspath, cbcpl,
bcpal ? PATH_SEPARATOR : 0); bcpal ? PATH_SEPARATOR : 0);
local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0);
System* s = makeSystem(crashDumpDirectory);
Heap* h = makeHeap(s, heapLimit);
Finder* bf = makeFinder Finder* bf = makeFinder
(s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); (s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary);
Finder* af = makeFinder(s, classpath, bootLibrary); Finder* af = makeFinder(s, classpath, bootLibrary);
Processor* p = makeProcessor(s, h, true); Processor* p = makeProcessor(s, h, true);
Classpath* c = makeClasspath(s, h);
const char** properties = static_cast<const char**> const char** properties = static_cast<const char**>
(h->allocate(sizeof(const char*) * propertyCount)); (h->allocate(sizeof(const char*) * propertyCount));

View File

@ -2166,7 +2166,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
not system->success(system->make(&referenceLock)) or not system->success(system->make(&referenceLock)) or
not system->success(system->make(&shutdownLock)) or not system->success(system->make(&shutdownLock)) or
not system->success not system->success
(system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) (system->load(&libraries, findProperty(this, "avian.bootstrap"))))
{ {
system->abort(); system->abort();
} }

View File

@ -1432,6 +1432,9 @@ class Classpath {
virtual void virtual void
boot(Thread* t) = 0; boot(Thread* t) = 0;
virtual const char*
bootClasspath() = 0;
virtual void virtual void
dispose() = 0; dispose() = 0;
}; };

View File

@ -469,13 +469,12 @@ class MySystem: public System {
class Library: public System::Library { class Library: public System::Library {
public: public:
Library(System* s, void* p, const char* name, unsigned nameLength, Library(System* s, void* p, const char* name, unsigned nameLength,
bool mapName, bool isMain): bool isMain):
s(s), s(s),
p(p), p(p),
mainExecutable(isMain), mainExecutable(isMain),
name_(name), name_(name),
nameLength(nameLength), nameLength(nameLength),
mapName_(mapName),
next_(0) next_(0)
{ } { }
@ -487,10 +486,6 @@ class MySystem: public System {
return name_; return name_;
} }
virtual bool mapName() {
return mapName_;
}
virtual System::Library* next() { virtual System::Library* next() {
return next_; return next_;
} }
@ -504,7 +499,7 @@ class MySystem: public System {
fprintf(stderr, "close %p\n", p); fprintf(stderr, "close %p\n", p);
} }
if (!mainExecutable) dlclose(p); if (not mainExecutable) dlclose(p);
if (next_) { if (next_) {
next_->disposeAll(); next_->disposeAll();
@ -522,7 +517,6 @@ class MySystem: public System {
bool mainExecutable; bool mainExecutable;
const char* name_; const char* name_;
unsigned nameLength; unsigned nameLength;
bool mapName_;
System::Library* next_; 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, virtual Status load(System::Library** lib,
const char* name, const char* name)
bool mapName)
{ {
void* p;
bool alreadyAllocated = false;
bool isMain = false;
unsigned nameLength = (name ? strlen(name) : 0); unsigned nameLength = (name ? strlen(name) : 0);
if (mapName and name) { bool isMain = name == 0;
unsigned size = nameLength + 3 + sizeof(SO_SUFFIX); if (isMain) {
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); pathOfExecutable(this, &name, &nameLength);
alreadyAllocated = true;
isMain = true;
}
p = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
} }
void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
if (p) { if (p) {
if (Verbose) { if (Verbose) {
@ -747,7 +737,7 @@ class MySystem: public System {
if (name) { if (name) {
n = static_cast<char*>(allocate(this, nameLength + 1)); n = static_cast<char*>(allocate(this, nameLength + 1));
memcpy(n, name, nameLength + 1); memcpy(n, name, nameLength + 1);
if (alreadyAllocated) { if (isMain) {
free(name); free(name);
} }
} else { } else {
@ -755,11 +745,13 @@ class MySystem: public System {
} }
*lib = new (allocate(this, sizeof(Library))) *lib = new (allocate(this, sizeof(Library)))
Library(this, p, n, nameLength, mapName, isMain); Library(this, p, n, nameLength, isMain);
return 0; return 0;
} else { } else {
if (Verbose) {
fprintf(stderr, "dlerror: %s\n", dlerror()); fprintf(stderr, "dlerror: %s\n", dlerror());
}
return 1; return 1;
} }
} }
@ -768,6 +760,10 @@ class MySystem: public System {
return ':'; return ':';
} }
virtual char fileSeparator() {
return '/';
}
virtual int64_t now() { virtual int64_t now() {
timeval tv = { 0, 0 }; timeval tv = { 0, 0 };
gettimeofday(&tv, 0); gettimeofday(&tv, 0);

View File

@ -89,7 +89,6 @@ class System {
public: public:
virtual void* resolve(const char* symbol) = 0; virtual void* resolve(const char* symbol) = 0;
virtual const char* name() = 0; virtual const char* name() = 0;
virtual bool mapName() = 0;
virtual Library* next() = 0; virtual Library* next() = 0;
virtual void setNext(Library* lib) = 0; virtual void setNext(Library* lib) = 0;
virtual void disposeAll() = 0; virtual void disposeAll() = 0;
@ -135,8 +134,11 @@ class System {
virtual Status map(Region**, const char* name) = 0; virtual Status map(Region**, const char* name) = 0;
virtual FileType identify(const char* name) = 0; virtual FileType identify(const char* name) = 0;
virtual Status open(Directory**, 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 pathSeparator() = 0;
virtual char fileSeparator() = 0;
virtual int64_t now() = 0; virtual int64_t now() = 0;
virtual void exit(int code) = 0; virtual void exit(int code) = 0;
virtual void abort() = 0; virtual void abort() = 0;

45
src/tokenizer.h Normal file
View File

@ -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

View File

@ -12,9 +12,13 @@
#include "stdio.h" #include "stdio.h"
#include "stdint.h" #include "stdint.h"
#include "string.h" #include "string.h"
#include "assert.h" #include "errno.h"
#include "constants.h" #include "constants.h"
#include "finder.h"
#include "stream.h"
#include "assert.h"
#define UNREACHABLE abort() #define UNREACHABLE abort()
@ -28,6 +32,8 @@ using namespace vm;
namespace { namespace {
namespace local {
#ifndef POINTER_SIZE #ifndef POINTER_SIZE
# define POINTER_SIZE sizeof(void*) # define POINTER_SIZE sizeof(void*)
#endif #endif
@ -177,7 +183,7 @@ class Output {
void write(int i) { void write(int i) {
static const int Size = 32; static const int Size = 32;
char s[Size]; 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); assert(c > 0 and c < Size);
write(s); 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 { class Object {
public: public:
typedef enum { typedef enum {
@ -1384,8 +1333,8 @@ parseJavaClass(Object* type, Stream* s, Object* declarations)
} }
Object* Object*
parseType(Object::ObjectType type, Object* p, Object* declarations, parseType(Finder* finder, Object::ObjectType type, Object* p,
const char* javaClassDirectory) Object* declarations)
{ {
const char* name = string(car(p)); const char* name = string(car(p));
@ -1400,9 +1349,16 @@ parseType(Object::ObjectType type, Object* p, Object* declarations,
bool isJavaType = javaName and *javaName != '['; bool isJavaType = javaName and *javaName != '[';
if (isJavaType) { if (isJavaType) {
const char* file = append(javaClassDirectory, "/", javaName, ".class"); class Client: public Stream::Client {
Stream s(fopen(file, "rb"), true); 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); parseJavaClass(t, &s, declarations);
region->dispose();
} }
for (p = cdr(p); p; p = cdr(p)) { for (p = cdr(p); p; p = cdr(p)) {
@ -1429,14 +1385,13 @@ parseType(Object::ObjectType type, Object* p, Object* declarations,
} }
Object* Object*
parseDeclaration(Object* p, Object* declarations, parseDeclaration(Finder* finder, Object* p, Object* declarations)
const char* javaClassDirectory)
{ {
const char* spec = string(car(p)); const char* spec = string(car(p));
if (equal(spec, "type")) { 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")) { } else if (equal(spec, "pod")) {
return parseType(Object::Pod, cdr(p), declarations, javaClassDirectory); return parseType(finder, Object::Pod, cdr(p), declarations);
} else { } else {
fprintf(stderr, "unexpected declaration spec: %s\n", spec); fprintf(stderr, "unexpected declaration spec: %s\n", spec);
abort(); abort();
@ -1444,7 +1399,7 @@ parseDeclaration(Object* p, Object* declarations,
} }
Object* Object*
parse(Input* in, const char* javaClassDirectory) parse(Finder* finder, Input* in)
{ {
Object* eos = Singleton::make(Object::Eos); Object* eos = Singleton::make(Object::Eos);
List declarations; List declarations;
@ -1452,7 +1407,7 @@ parse(Input* in, const char* javaClassDirectory)
Object* o; Object* o;
while ((o = read(in, eos, 0)) != eos) { while ((o = read(in, eos, 0)) != eos) {
declarations.append declarations.append
(parseDeclaration(o, declarations.first, javaClassDirectory)); (parseDeclaration(finder, o, declarations.first));
} }
return declarations.first; return declarations.first;
@ -1522,7 +1477,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false)
if (not unsafe) { if (not unsafe) {
out->write("const unsigned "); out->write("const unsigned ");
out->write(capitalize(::typeName(memberOwner(member)))); out->write(capitalize(local::typeName(memberOwner(member))));
out->write(capitalize(memberName(member))); out->write(capitalize(memberName(member)));
out->write(" = "); out->write(" = ");
writeOffset(out, offset); writeOffset(out, offset);
@ -1547,7 +1502,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false)
writeAccessorName(out, member, unsafe); writeAccessorName(out, member, unsafe);
if (memberOwner(member)->type == Object::Pod) { if (memberOwner(member)->type == Object::Pod) {
out->write("("); out->write("(");
out->write(capitalize(::typeName(memberOwner(member)))); out->write(capitalize(local::typeName(memberOwner(member))));
out->write("*"); out->write("*");
} else { } else {
out->write("(Thread* t UNUSED, object"); 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(" assert(t, t->m->unsafe or ");
out->write("instanceOf(t, arrayBodyUnsafe"); out->write("instanceOf(t, arrayBodyUnsafe");
out->write("(t, t->m->types, Machine::"); 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("Type)");
out->write(", o));\n"); out->write(", o));\n");
if (member->type != Object::Scalar) { if (member->type != Object::Scalar) {
out->write(" assert(t, i < "); out->write(" assert(t, i < ");
out->write(::typeName(memberOwner(member))); out->write(local::typeName(memberOwner(member)));
out->write("Length(t, o));\n"); out->write("Length(t, o));\n");
} }
} }
@ -1599,7 +1554,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false)
out->write("["); out->write("[");
} }
out->write(capitalize(::typeName(memberOwner(member)))); out->write(capitalize(local::typeName(memberOwner(member))));
out->write(capitalize(memberName(member))); out->write(capitalize(memberName(member)));
if (member->type != Object::Scalar) { if (member->type != Object::Scalar) {
@ -2221,62 +2176,83 @@ void
usageAndExit(const char* command) usageAndExit(const char* command)
{ {
fprintf(stderr, fprintf(stderr,
"usage: %s <java class directory> " "usage: %s <classpath> <input file> <output file> "
"{enums,declarations,constructors,initializations," "{enums,declarations,constructors,initializations,"
"java-initializations}\n", "java-initializations}\n",
command); command);
exit(-1); exit(-1);
} }
} // namespace local
} // namespace } // 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 int
main(int ac, char** av) main(int ac, char** av)
{ {
if ((ac != 2 and ac != 3) if (ac != 5
or (ac == 3 or not (local::equal(av[4], "enums")
and not equal(av[2], "enums") or local::equal(av[4], "declarations")
and not equal(av[2], "declarations") or local::equal(av[4], "constructors")
and not equal(av[2], "constructors") or local::equal(av[4], "initializations")
and not equal(av[2], "initializations") or local::equal(av[4], "java-initializations")))
and not equal(av[2], "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]); FILE* inStream = ::fopen(av[2], "rb");
if (inStream == 0) {
FileOutput out(0, stdout, false); fprintf(stderr, "unable to open %s: %s\n", av[2], strerror(errno));
return -1;
if (ac == 2 or equal(av[2], "enums")) {
writeEnums(&out, declarations);
} }
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.write("const unsigned TypeCount = ");
out.Output::write(typeCount(declarations)); out.Output::write(local::typeCount(declarations));
out.write(";\n\n"); out.write(";\n\n");
writePods(&out, declarations); local::writePods(&out, declarations);
writeAccessors(&out, declarations); local::writeAccessors(&out, declarations);
writeSizes(&out, declarations); local::writeSizes(&out, declarations);
writeInitializerDeclarations(&out, declarations); local::writeInitializerDeclarations(&out, declarations);
writeConstructorDeclarations(&out, declarations); local::writeConstructorDeclarations(&out, declarations);
} } else if (local::equal(av[4], "constructors")) {
local::writeInitializers(&out, declarations);
if (ac == 2 or equal(av[2], "constructors")) { local::writeConstructors(&out, declarations);
writeInitializers(&out, declarations); } else if (local::equal(av[4], "initializations")) {
writeConstructors(&out, declarations); local::writeInitializations(&out, declarations);
} } else if (local::equal(av[4], "java-initializations")) {
local::writeJavaInitializations(&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);
} }
return 0; return 0;