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
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) \

View File

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

View File

@ -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<char*>
(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

View File

@ -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<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");
#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<local::MyClasspath*>(t->m->classpath)->libraryPath, name,
false, false);
}
extern "C" JNIEXPORT void JNICALL

View File

@ -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();) {

View File

@ -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<const char**>
(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(&shutdownLock)) or
not system->success
(system->load(&libraries, findProperty(this, "avian.bootstrap"), false)))
(system->load(&libraries, findProperty(this, "avian.bootstrap"))))
{
system->abort();
}

View File

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

View File

@ -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<char*>(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);

View File

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

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 "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 <java class directory> "
"usage: %s <classpath> <input file> <output file> "
"{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;