add support for accessing embedded JARs as if they were directories

This allows OpenJDK to access time zone data which is normally found
under java.home, but which we must embed in the executable itself to
create a self-contained build.  The VM intercepts various file
operations, looking for paths which start with a prefix specified by
the avian.embed.prefix property and redirecting those operations to an
embedded JAR.

For example, if avian.embed.prefix is "/avian-embedded", and code
calls File.exists() with a path of
"/avian-embedded/javahomeJar/foo.txt", the VM looks for a function
named javahomeJar via dlsym, calls the function to find the memory
region containing the embeded JAR, and finally consults the JAR to see
if the file "foo.txt" exists.
This commit is contained in:
Joel Dice 2010-11-05 13:18:28 -06:00
parent 4cb796d2fb
commit d0a6096eb0
18 changed files with 773 additions and 221 deletions

View File

@ -52,25 +52,29 @@ classpath = avian
test-executable = $(executable) test-executable = $(executable)
boot-classpath = $(classpath-build) boot-classpath = $(classpath-build)
java-home = /avian-embedded embed-prefix = /avian-embedded
ifdef openjdk ifdef openjdk
ifdef openjdk-src ifdef openjdk-src
include openjdk-src.mk include openjdk-src.mk
options := $(options)-openjdk-src options := $(options)-openjdk-src
classpath-objects = $(openjdk-objects) classpath-objects = $(openjdk-objects)
classpath-cflags = -DAVIAN_OPENJDK_SRC classpath-cflags = -DAVIAN_OPENJDK_SRC -DBOOT_JAVAHOME
openjdk-jar-dep = $(build)/openjdk-jar.dep openjdk-jar-dep = $(build)/openjdk-jar.dep
classpath-jar-dep = $(openjdk-jar-dep) classpath-jar-dep = $(openjdk-jar-dep)
javahome = $(embed-prefix)/javahomeJar
javahome-files = lib/zi
javahome-object = $(build)/javahome-jar.o
else else
options := $(options)-openjdk options := $(options)-openjdk
test-executable = $(executable-dynamic) test-executable = $(executable-dynamic)
library-path = LD_LIBRARY_PATH=$(build) library-path = LD_LIBRARY_PATH=$(build)
java-home = $(openjdk)/jre javahome = $(openjdk)/jre
endif endif
classpath = openjdk classpath = openjdk
boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar
build-javahome = $(openjdk)/jre
endif endif
ifeq ($(classpath),avian) ifeq ($(classpath),avian)
@ -120,7 +124,8 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(java-home)\" -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\"
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
@ -593,12 +598,6 @@ $(driver-dynamic-object): $(driver-source)
$(boot-object): $(boot-source) $(boot-object): $(boot-source)
$(compile-object) $(compile-object)
$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
@echo "creating $(@)"
(wd=$$(pwd) && \
cd $(classpath-build) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .)
$(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp
$(build-cxx) -c $(^) -o $(@) $(build-cxx) -c $(^) -o $(@)
@ -620,11 +619,28 @@ $(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp
$(converter): $(converter-objects) $(converter): $(converter-objects)
$(build-cxx) $(^) -o $(@) $(build-cxx) $(^) -o $(@)
$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
@echo "creating $(@)"
(wd=$$(pwd) && \
cd $(classpath-build) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .)
$(classpath-object): $(build)/classpath.jar $(converter) $(classpath-object): $(build)/classpath.jar $(converter)
@echo "creating $(@)" @echo "creating $(@)"
$(converter) $(<) $(@) _binary_classpath_jar_start \ $(converter) $(<) $(@) _binary_classpath_jar_start \
_binary_classpath_jar_end $(platform) $(arch) _binary_classpath_jar_end $(platform) $(arch)
$(build)/javahome.jar: $(foreach x,$(javahome-files),$(build-javahome)/$(x))
@echo "creating $(@)"
(wd=$$(pwd) && \
cd $(build-javahome) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $(javahome-files))
$(javahome-object): $(build)/javahome.jar $(converter)
@echo "creating $(@)"
$(converter) $(<) $(@) _binary_javahome_jar_start \
_binary_javahome_jar_end $(platform) $(arch)
$(generator-objects): $(generator-depends) $(generator-objects): $(generator-depends)
$(generator-objects): $(build)/%-build.o: $(src)/%.cpp $(generator-objects): $(build)/%-build.o: $(src)/%.cpp
@echo "compiling $(@)" @echo "compiling $(@)"
@ -651,7 +667,8 @@ $(bootimage-object): $(bootimage-bin) $(converter)
writable executable writable executable
executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \
$(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \
$(javahome-object)
$(executable): $(executable-objects) $(executable): $(executable-objects)
@echo "linking $(@)" @echo "linking $(@)"
@ -696,18 +713,16 @@ else
$(ld) $(^) $(rdynamic) $(lflags) -o $(@) $(ld) $(^) $(rdynamic) $(lflags) -o $(@)
endif endif
dynamic-library-objects = $(vm-objects) $(dynamic-object) \ $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \
$(classpath-objects) $(vm-heapwalk-objects) $(boot-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \
$(vm-classpath-object) $(classpath-libraries) $(classpath-libraries) $(javahome-object)
$(dynamic-library): $(dynamic-library-objects)
@echo "linking $(@)" @echo "linking $(@)"
ifdef msvc ifdef msvc
$(ld) $(shared) $(lflags) $(dynamic-library-objects) -out:$(@) \ $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \
-PDB:$(@).pdb -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest
$(mt) -manifest $(@).manifest -outputresource:"$(@);2" $(mt) -manifest $(@).manifest -outputresource:"$(@);2"
else else
$(ld) $(dynamic-library-objects) -Wl,--version-script=openjdk.ld \ $(ld) $(^) -Wl,--version-script=openjdk.ld \
$(shared) $(lflags) $(bootimage-lflags) -o $(@) $(shared) $(lflags) $(bootimage-lflags) -o $(@)
endif endif
$(strip) $(strip-all) $(@) $(strip) $(strip-all) $(@)

View File

@ -52,6 +52,8 @@ extern "C" {
} }
#undef SYMBOL
#endif//BOOT_IMAGE #endif//BOOT_IMAGE
#ifdef BOOT_CLASSPATH #ifdef BOOT_CLASSPATH
@ -76,4 +78,32 @@ extern "C" {
} }
#undef SYMBOL
#endif//BOOT_CLASSPATH #endif//BOOT_CLASSPATH
#ifdef BOOT_JAVAHOME
#if (defined __MINGW32__) || (defined _MSC_VER)
# define SYMBOL(x) binary_javahome_jar_##x
#else
# define SYMBOL(x) _binary_javahome_jar_##x
#endif
extern "C" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];
EXPORT const uint8_t*
javahomeJar(unsigned* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}
}
#undef SYMBOL
#endif//BOOT_JAVAHOME

View File

@ -85,8 +85,9 @@ Avian_avian_SystemClassLoader_resourceExists
RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); RUNTIME_ARRAY(char, n, stringLength(t, name) + 1);
stringChars(t, name, RUNTIME_ARRAY_BODY(n)); stringChars(t, name, RUNTIME_ARRAY_BODY(n));
bool r = static_cast<Finder*>(systemClassLoaderFinder(t, loader))->exists unsigned length;
(RUNTIME_ARRAY_BODY(n)); bool r = static_cast<Finder*>(systemClassLoaderFinder(t, loader))->stat
(RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile;
// fprintf(stderr, "resource %s exists? %d\n", n, r); // fprintf(stderr, "resource %s exists? %d\n", n, r);

View File

@ -128,7 +128,7 @@ enumerateThreads(Thread* t, Thread* x, object array, unsigned* index,
namespace vm { namespace vm {
Classpath* Classpath*
makeClasspath(System*, Allocator* allocator, const char*) makeClasspath(System*, Allocator* allocator, const char*, const char*)
{ {
return new (allocator->allocate(sizeof(local::MyClasspath))) return new (allocator->allocate(sizeof(local::MyClasspath)))
local::MyClasspath(allocator); local::MyClasspath(allocator);

View File

@ -88,6 +88,7 @@ namespace local {
const unsigned InterfaceVersion = 4; const unsigned InterfaceVersion = 4;
const unsigned PageSize = 4 * 1024; const unsigned PageSize = 4 * 1024;
const int VirtualFileBase = 1000000000;
Machine* globalMachine; Machine* globalMachine;
@ -145,7 +146,6 @@ makeClassNameString(Thread* t, object name)
return makeString(t, "%s", s); return makeString(t, "%s", s);
} }
#ifdef AVIAN_OPENJDK_SRC
// only safe to call during bootstrap when there's only one thread // only safe to call during bootstrap when there's only one thread
// running: // running:
void void
@ -171,51 +171,20 @@ intercept(Thread* t, object c, const char* name, const char* spec,
} }
} }
const char*
zipLibrary(Thread*);
int64_t JNICALL int64_t JNICALL
getFileAttributes getFileAttributes
(Thread* t, object method, uintptr_t* arguments) (Thread* t, object method, uintptr_t* arguments);
{
const unsigned Exists = 1;
const unsigned Regular = 2;
object file = reinterpret_cast<object>(arguments[1]); int64_t JNICALL
getLength
object pathField = findFieldInClass2 (Thread* t, object method, uintptr_t* arguments);
(t, objectClass(t, file), "path", "Ljava/lang/String;");
if (pathField) {
object path = cast<object>(file, fieldOffset(t, pathField));
RUNTIME_ARRAY(char, p, stringLength(t, path) + 1);
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
if (strcmp(zipLibrary(t), p) == 0) {
return Exists | Regular;
} else {
object r = t->m->processor->invoke
(t, nativeInterceptOriginal(t, methodCode(t, method)),
reinterpret_cast<object>(arguments[0]), file);
return (r ? intValue(t, r) : 0);
}
} else {
object message = makeString
(t, "path Ljava/lang/String; not found in %s",
&byteArrayBody(t, className(t, objectClass(t, file)), 0));
t->exception = t->m->classpath->makeThrowable
(t, Machine::RuntimeExceptionType, message);
return 0;
}
}
#endif // AVIAN_OPENJDK_SRC
class MyClasspath : public Classpath { class MyClasspath : public Classpath {
public: public:
static const unsigned BufferSize = 1024; static const unsigned BufferSize = 1024;
MyClasspath(System* s, Allocator* allocator, const char* javaHome): MyClasspath(System* s, Allocator* allocator, const char* javaHome,
const char* embedPrefix):
allocator(allocator) allocator(allocator)
{ {
class StringBuilder { class StringBuilder {
@ -285,6 +254,11 @@ class MyClasspath : public Classpath {
sb.append(LIBRARY_PREFIX); sb.append(LIBRARY_PREFIX);
sb.append("zip"); sb.append("zip");
sb.append(LIBRARY_SUFFIX); sb.append(LIBRARY_SUFFIX);
sb.append('\0');
this->embedPrefix = sb.pointer;
sb.append(embedPrefix);
this->embedPrefixLength = sb.pointer - this->embedPrefix;
} }
virtual object virtual object
@ -377,13 +351,32 @@ class MyClasspath : public Classpath {
globalMachine = t->m; globalMachine = t->m;
#ifdef AVIAN_OPENJDK_SRC #ifdef AVIAN_OPENJDK_SRC
{ object c = resolveClass { object ufsClass = resolveClass
(t, root(t, Machine::BootLoader), "java/io/UnixFileSystem"); (t, root(t, Machine::BootLoader), "java/io/UnixFileSystem");
if (c) { if (ufsClass) {
intercept(t, c, "getBooleanAttributes0", "(Ljava/io/File;)I", PROTECT(t, ufsClass);
voidPointer(getFileAttributes));
object fileClass = resolveClass
(t, root(t, Machine::BootLoader), "java/io/File");
if (fileClass) {
object pathField = findFieldInClass2
(t, fileClass, "path", "Ljava/lang/String;");
if (pathField) {
this->pathField = fieldOffset(t, pathField);
intercept(t, ufsClass, "getBooleanAttributes0",
"(Ljava/io/File;)I", voidPointer(getFileAttributes));
intercept(t, ufsClass, "getLength", "(Ljava/io/File;)J",
voidPointer(getLength));
}
}
} }
if (UNLIKELY(t->exception)) return;
} }
#else // not AVIAN_OPENJDK_SRC #else // not AVIAN_OPENJDK_SRC
if (loadLibrary(t, libraryPath, "java", true, true) == 0) { if (loadLibrary(t, libraryPath, "java", true, true) == 0) {
@ -437,7 +430,7 @@ class MyClasspath : public Classpath {
virtual void virtual void
dispose() dispose()
{ {
allocator->free(this, sizeof(*this)); allocator->free(this, sizeof(*this));
} }
@ -446,33 +439,202 @@ class MyClasspath : public Classpath {
const char* classpath; const char* classpath;
const char* libraryPath; const char* libraryPath;
const char* zipLibrary; const char* zipLibrary;
const char* embedPrefix;
unsigned embedPrefixLength;
unsigned pathField;
char buffer[BufferSize]; char buffer[BufferSize];
}; };
struct JVM_ExceptionTableEntryType{ struct JVM_ExceptionTableEntryType {
jint start_pc; jint start_pc;
jint end_pc; jint end_pc;
jint handler_pc; jint handler_pc;
jint catchType; jint catchType;
}; };
struct jvm_version_info { struct jvm_version_info {
unsigned int jvm_version; unsigned jvm_version;
unsigned int update_version: 8; unsigned update_version: 8;
unsigned int special_update_version: 8; unsigned special_update_version: 8;
unsigned int reserved1: 16; unsigned reserved1: 16;
unsigned int reserved2; unsigned reserved2;
unsigned int is_attach_supported: 1; unsigned is_attach_supported: 1;
unsigned int is_kernel_jvm: 1; unsigned is_kernel_jvm: 1;
unsigned int: 30; unsigned: 30;
unsigned int: 32; unsigned: 32;
unsigned int: 32; unsigned: 32;
}; };
const char* Finder*
zipLibrary(Thread* t) getFinder(Thread* t, const char* name, unsigned nameLength)
{ {
return static_cast<MyClasspath*>(t->m->classpath)->zipLibrary; ACQUIRE(t, t->m->referenceLock);
for (object p = root(t, Machine::VirtualFileFinders);
p; p = finderNext(t, p))
{
if (byteArrayLength(t, finderName(t, p)) == nameLength
and strncmp(reinterpret_cast<const char*>
(&byteArrayBody(t, finderName(t, p), 0)),
name, nameLength))
{
return static_cast<Finder*>(finderFinder(t, p));
}
}
object n = makeByteArray(t, nameLength + 1);
memcpy(&byteArrayBody(t, n, 0), name, nameLength);
void* p = t->m->libraries->resolve
(reinterpret_cast<const char*>(&byteArrayBody(t, n, 0)));
if (p) {
uint8_t* (*function)(unsigned*);
memcpy(&function, &p, BytesPerWord);
unsigned size;
uint8_t* data = function(&size);
if (data) {
Finder* f = makeFinder(t->m->system, t->m->heap, data, size);
object finder = makeFinder
(t, f, n, root(t, Machine::VirtualFileFinders));
setRoot(t, Machine::VirtualFileFinders, finder);
return f;
}
}
return 0;
}
class EmbeddedFile {
public:
EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) {
if (strncmp(cp->embedPrefix, path, cp->embedPrefixLength) == 0) {
const char* p = path + cp->embedPrefixLength;
while (*p == '/') ++ p;
this->jar = p;
if (*p == 0) {
this->jarLength = 0;
this->path = 0;
this->pathLength = 0;
return;
}
while (*p and *p != '/') ++p;
this->jarLength = p - this->jar;
while (*p == '/') ++p;
this->path = p;
this->pathLength = pathLength - (p - path);
} else {
this->jar = 0;
this->jarLength =0;
this->path = 0;
this->pathLength = 0;
}
}
const char* jar;
const char* path;
unsigned jarLength;
unsigned pathLength;
};
int64_t JNICALL
getFileAttributes
(Thread* t, object method, uintptr_t* arguments)
{
const unsigned Exists = 1;
const unsigned Regular = 2;
const unsigned Directory = 4;
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
object file = reinterpret_cast<object>(arguments[1]);
object path = cast<object>(file, cp->pathField);
RUNTIME_ARRAY(char, p, stringLength(t, path) + 1);
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
if (strcmp(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) == 0) {
return Exists | Regular;
} else {
EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path));
if (ef.jar) {
if (ef.jarLength == 0) {
return Exists | Directory;
}
Finder* finder = getFinder(t, ef.jar, ef.jarLength);
if (finder) {
if (ef.pathLength == 0) {
return Exists | Directory;
}
unsigned length;
System::FileType type = finder->stat(ef.path, &length, true);
switch (type) {
case System::TypeUnknown: return Exists;
case System::TypeDoesNotExist: return 0;
case System::TypeFile: return Exists | Regular;
case System::TypeDirectory: return Exists | Directory;
default: abort(t);
}
} else {
return 0;
}
} else {
object r = t->m->processor->invoke
(t, nativeInterceptOriginal(t, methodCode(t, method)),
reinterpret_cast<object>(arguments[0]), file);
return (r ? intValue(t, r) : 0);
}
}
}
int64_t JNICALL
getLength
(Thread* t, object method, uintptr_t* arguments)
{
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
object file = reinterpret_cast<object>(arguments[1]);
object path = cast<object>(file, cp->pathField);
RUNTIME_ARRAY(char, p, stringLength(t, path) + 1);
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path));
if (ef.jar) {
if (ef.jarLength == 0) {
return 0;
}
Finder* finder = getFinder(t, ef.jar, ef.jarLength);
if (finder) {
if (ef.pathLength == 0) {
return 0;
}
unsigned fileLength;
finder->stat(ef.path, &fileLength);
return fileLength;
}
return 0;
} else {
object r = t->m->processor->invoke
(t, nativeInterceptOriginal(t, methodCode(t, method)),
reinterpret_cast<object>(arguments[0]), file);
return (r ? longValue(t, r) : 0);
}
} }
unsigned unsigned
@ -735,10 +897,11 @@ interruptLock(Thread* t, object thread)
namespace vm { namespace vm {
Classpath* Classpath*
makeClasspath(System* s, Allocator* allocator, const char* javaHome) makeClasspath(System* s, Allocator* allocator, const char* javaHome,
const char* embedPrefix)
{ {
return new (allocator->allocate(sizeof(local::MyClasspath))) return new (allocator->allocate(sizeof(local::MyClasspath)))
local::MyClasspath(s, allocator, javaHome); local::MyClasspath(s, allocator, javaHome, embedPrefix);
} }
} // namespace vm } // namespace vm
@ -1308,7 +1471,9 @@ JVM_LoadLibrary(const char* name)
Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get()); Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
#ifdef AVIAN_OPENJDK_SRC #ifdef AVIAN_OPENJDK_SRC
if (strcmp(local::zipLibrary(t), name) == 0) { if (strcmp(static_cast<local::MyClasspath*>(t->m->classpath)->zipLibrary,
name) == 0)
{
return t->m->libraries; return t->m->libraries;
} }
#endif // AVIAN_OPENJDK_SRC #endif // AVIAN_OPENJDK_SRC
@ -2475,21 +2640,126 @@ JVM_NativePath(char* path)
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
JVM_Open(const char* name, jint flags, jint mode) JVM_Open(const char* path, jint flags, jint mode)
{ {
return OPEN(name, flags, mode); Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
local::MyClasspath* cp = static_cast<local::MyClasspath*>(t->m->classpath);
local::EmbeddedFile ef(cp, path, strlen(path));
if (ef.jar) {
if (flags != O_RDONLY) {
errno = EACCES;
return -1;
}
if (ef.jarLength == 0 or ef.pathLength == 0) {
errno = ENOENT;
return -1;
}
Finder* finder = local::getFinder(t, ef.jar, ef.jarLength);
if (finder == 0) {
errno = ENOENT;
return -1;
}
System::Region* r = finder->find(ef.path);
if (r == 0) {
errno = ENOENT;
return -1;
}
ENTER(t, Thread::ActiveState);
ACQUIRE(t, t->m->referenceLock);
int index = -1;
unsigned oldLength = root(t, Machine::VirtualFiles)
? arrayLength(t, root(t, Machine::VirtualFiles)) : 0;
for (unsigned i = 0; i < oldLength; ++i) {
if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) {
index = i;
break;
}
}
if (index == -1) {
object newArray = growArray(t, root(t, Machine::VirtualFiles));
setRoot(t, Machine::VirtualFiles, newArray);
index = oldLength;
}
object region = makeRegion(t, r, 0);
set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord),
region);
return index + local::VirtualFileBase;
} else {
int r = OPEN(path, flags, mode);
expect(t, r < local::VirtualFileBase);
return r;
}
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
JVM_Close(jint fd) JVM_Close(jint fd)
{ {
return CLOSE(fd); if (fd >= local::VirtualFileBase) {
Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
unsigned index = fd - local::VirtualFileBase;
ENTER(t, Thread::ActiveState);
ACQUIRE(t, t->m->referenceLock);
object region = arrayBody(t, root(t, Machine::VirtualFiles), index);
if (region) {
static_cast<System::Region*>(regionRegion(t, region))->dispose();
}
set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord),
0);
return 0;
} else {
return CLOSE(fd);
}
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
JVM_Read(jint fd, char* dst, jint length) JVM_Read(jint fd, char* dst, jint length)
{ {
return READ(fd, dst, length); if (fd >= local::VirtualFileBase) {
Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
unsigned index = fd - local::VirtualFileBase;
ENTER(t, Thread::ActiveState);
ACQUIRE(t, t->m->referenceLock);
object region = arrayBody(t, root(t, Machine::VirtualFiles), index);
if (region) {
System::Region* r = static_cast<System::Region*>
(regionRegion(t, region));
int available = r->length() - regionPosition(t, region);
if (length > available) {
length = available;
}
memcpy(dst, r->start(), length);
regionPosition(t, region) += length;
return length;
} else {
errno = EINVAL;
return -1;
}
} else {
return READ(fd, dst, length);
}
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
@ -2501,34 +2771,94 @@ JVM_Write(jint fd, char* src, jint length)
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
JVM_Available(jint fd, jlong* result) JVM_Available(jint fd, jlong* result)
{ {
struct stat buffer; if (fd >= local::VirtualFileBase) {
int n; Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
if (FSTAT(fd, &buffer) >= 0 unsigned index = fd - local::VirtualFileBase;
and (S_ISCHR(buffer.st_mode)
or S_ISFIFO(buffer.st_mode) ENTER(t, Thread::ActiveState);
or S_ISSOCK(buffer.st_mode))
and ioctl(fd, FIONREAD, &n) >= 0) ACQUIRE(t, t->m->referenceLock);
{
*result = n; object region = arrayBody(t, root(t, Machine::VirtualFiles), index);
if (region) {
return static_cast<System::Region*>(regionRegion(t, region))->length()
- regionPosition(t, region);
} else {
return 0;
}
} else {
struct stat buffer;
int n;
if (FSTAT(fd, &buffer) >= 0
and (S_ISCHR(buffer.st_mode)
or S_ISFIFO(buffer.st_mode)
or S_ISSOCK(buffer.st_mode))
and ioctl(fd, FIONREAD, &n) >= 0)
{
*result = n;
return 1;
}
int current = LSEEK(fd, 0, SEEK_CUR);
if (current == -1) return 0;
int end = LSEEK(fd, 0, SEEK_END);
if (end == -1) return 0;
if (LSEEK(fd, current, SEEK_SET) == -1) return 0;
*result = end - current;
return 1; return 1;
} }
int current = LSEEK(fd, 0, SEEK_CUR);
if (current == -1) return 0;
int end = LSEEK(fd, 0, SEEK_END);
if (end == -1) return 0;
if (LSEEK(fd, current, SEEK_SET) == -1) return 0;
*result = end - current;
return 1;
} }
extern "C" JNIEXPORT jlong JNICALL extern "C" JNIEXPORT jlong JNICALL
JVM_Lseek(jint fd, jlong offset, jint start) JVM_Lseek(jint fd, jlong offset, jint seek)
{ {
return LSEEK(fd, offset, start); if (fd >= local::VirtualFileBase) {
Thread* t = static_cast<Thread*>(local::globalMachine->localThread->get());
unsigned index = fd - local::VirtualFileBase;
ENTER(t, Thread::ActiveState);
ACQUIRE(t, t->m->referenceLock);
object region = arrayBody(t, root(t, Machine::VirtualFiles), index);
if (region) {
System::Region* r = static_cast<System::Region*>
(regionRegion(t, region));
switch (seek) {
case SEEK_SET:
break;
case SEEK_CUR:
offset += regionPosition(t, region);
break;
case SEEK_END:
offset += r->length();
break;
default:
errno = EINVAL;
return -1;
}
if (offset >= 0 and offset <= static_cast<int>(r->length())) {
regionPosition(t, region) = offset;
return offset;
} else {
errno = EINVAL;
return -1;
}
} else {
errno = EINVAL;
return -1;
}
} else {
return LSEEK(fd, offset, seek);
}
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL

View File

@ -7156,7 +7156,7 @@ class SegFaultHandler: public System::SignalHandler {
t->exception = root(t, Machine::NullPointerException); t->exception = root(t, Machine::NullPointerException);
} }
// printTrace(t, t->exception); printTrace(t, t->exception);
object continuation; object continuation;
findUnwindTarget(t, ip, base, stack, &continuation); findUnwindTarget(t, ip, base, stack, &continuation);

View File

@ -20,12 +20,12 @@ namespace {
const bool DebugFind = false; const bool DebugFind = false;
const char* const char*
append(System* s, const char* a, const char* b, const char* c) append(Allocator* allocator, const char* a, const char* b, const char* c)
{ {
unsigned al = strlen(a); unsigned al = strlen(a);
unsigned bl = strlen(b); unsigned bl = strlen(b);
unsigned cl = strlen(c); unsigned cl = strlen(c);
char* p = static_cast<char*>(allocate(s, (al + bl + cl) + 1)); char* p = static_cast<char*>(allocator->allocate((al + bl + cl) + 1));
memcpy(p, a, al); memcpy(p, a, al);
memcpy(p + al, b, bl); memcpy(p + al, b, bl);
memcpy(p + al + bl, c, cl + 1); memcpy(p + al + bl, c, cl + 1);
@ -33,10 +33,10 @@ append(System* s, const char* a, const char* b, const char* c)
} }
const char* const char*
copy(System* s, const char* a) copy(Allocator* allocator, const char* a)
{ {
unsigned al = strlen(a); unsigned al = strlen(a);
char* p = static_cast<char*>(allocate(s, al + 1)); char* p = static_cast<char*>(allocator->allocate(al + 1));
memcpy(p, a, al + 1); memcpy(p, a, al + 1);
return p; return p;
} }
@ -63,7 +63,8 @@ class Element {
virtual Iterator* iterator() = 0; virtual Iterator* iterator() = 0;
virtual System::Region* find(const char* name) = 0; virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0; virtual System::FileType stat(const char* name, unsigned* length,
bool tryDirectory) = 0;
virtual void dispose() = 0; virtual void dispose() = 0;
Element* next; Element* next;
@ -73,8 +74,9 @@ class DirectoryElement: public Element {
public: public:
class Iterator: public Element::Iterator { class Iterator: public Element::Iterator {
public: public:
Iterator(System* s, const char* name, unsigned skip): Iterator(System* s, Allocator* allocator, const char* name, unsigned skip):
s(s), name(name), skip(skip), directory(0), last(0), it(0) s(s), allocator(allocator), name(name), skip(skip), directory(0),
last(0), it(0)
{ {
if (not s->success(s->open(&directory, name))) { if (not s->success(s->open(&directory, name))) {
directory = 0; directory = 0;
@ -93,15 +95,17 @@ class DirectoryElement: public Element {
} }
if (last) { if (last) {
s->free(last); allocator->free(last, strlen(last) + 1);
} }
if (directory) { if (directory) {
for (const char* v = directory->next(); v; v = directory->next()) { for (const char* v = directory->next(); v; v = directory->next()) {
if (v[0] != '.') { if (v[0] != '.') {
last = append(s, name, "/", v); last = append(allocator, name, "/", v);
if (s->identify(last) == System::TypeDirectory) { unsigned length;
it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip); if (s->stat(last, &length) == System::TypeDirectory) {
it = new (allocator->allocate(sizeof(Iterator)))
Iterator(s, allocator, last, skip);
it->name = last; it->name = last;
} }
const char* result = last + skip; const char* result = last + skip;
@ -116,10 +120,11 @@ class DirectoryElement: public Element {
virtual void dispose() { virtual void dispose() {
directory->dispose(); directory->dispose();
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
const char* name; const char* name;
unsigned skip; unsigned skip;
System::Directory* directory; System::Directory* directory;
@ -127,20 +132,20 @@ class DirectoryElement: public Element {
Iterator* it; Iterator* it;
}; };
DirectoryElement(System* s, const char* name): DirectoryElement(System* s, Allocator* allocator, const char* name):
s(s), name(name) s(s), allocator(allocator), name(name)
{ } { }
virtual Element::Iterator* iterator() { virtual Element::Iterator* iterator() {
return new (allocate(s, sizeof(Iterator))) return new (allocator->allocate(sizeof(Iterator)))
Iterator(s, name, strlen(name) + 1); Iterator(s, allocator, name, strlen(name) + 1);
} }
virtual System::Region* find(const char* name) { virtual System::Region* find(const char* name) {
const char* file = append(s, this->name, "/", name); const char* file = append(allocator, this->name, "/", name);
System::Region* region; System::Region* region;
System::Status status = s->map(&region, file); System::Status status = s->map(&region, file);
s->free(file); allocator->free(file, strlen(file) + 1);
if (s->success(status)) { if (s->success(status)) {
if (DebugFind) { if (DebugFind) {
@ -155,26 +160,29 @@ class DirectoryElement: public Element {
} }
} }
virtual bool exists(const char* name) { virtual System::FileType stat(const char* name, unsigned* length, bool) {
const char* file = append(s, this->name, "/", name); const char* file = append(allocator, this->name, "/", name);
System::FileType type = s->identify(file); System::FileType type = s->stat(file, length);
s->free(file); allocator->free(file, strlen(file) + 1);
return type != System::TypeDoesNotExist; return type;
} }
virtual void dispose() { virtual void dispose() {
s->free(name); allocator->free(name, strlen(name) + 1);
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
const char* name; const char* name;
}; };
class PointerRegion: public System::Region { class PointerRegion: public System::Region {
public: public:
PointerRegion(System* s, const uint8_t* start, size_t length): PointerRegion(System* s, Allocator* allocator, const uint8_t* start,
size_t length):
s(s), s(s),
allocator(allocator),
start_(start), start_(start),
length_(length) length_(length)
{ } { }
@ -188,18 +196,20 @@ class PointerRegion: public System::Region {
} }
virtual void dispose() { virtual void dispose() {
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
const uint8_t* start_; const uint8_t* start_;
size_t length_; size_t length_;
}; };
class DataRegion: public System::Region { class DataRegion: public System::Region {
public: public:
DataRegion(System* s, size_t length): DataRegion(System* s, Allocator* allocator, size_t length):
s(s), s(s),
allocator(allocator),
length_(length) length_(length)
{ } { }
@ -212,10 +222,11 @@ class DataRegion: public System::Region {
} }
virtual void dispose() { virtual void dispose() {
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
size_t length_; size_t length_;
uint8_t data[0]; uint8_t data[0];
}; };
@ -241,11 +252,12 @@ class JarIndex {
Node* next; Node* next;
}; };
JarIndex(System* s, unsigned capacity): JarIndex(System* s, Allocator* allocator, unsigned capacity):
s(s), s(s),
allocator(allocator),
capacity(capacity), capacity(capacity),
position(0), position(0),
nodes(static_cast<Node*>(allocate(s, sizeof(Node) * capacity))) nodes(static_cast<Node*>(allocator->allocate(sizeof(Node) * capacity)))
{ {
memset(table, 0, sizeof(Node*) * capacity); memset(table, 0, sizeof(Node*) * capacity);
} }
@ -322,14 +334,16 @@ class JarIndex {
commentFieldLength(p); commentFieldLength(p);
} }
static JarIndex* make(System* s, unsigned capacity) { static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) {
return new return new
(allocate(s, sizeof(JarIndex) + (sizeof(Node*) * capacity))) (allocator->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity)))
JarIndex(s, capacity); JarIndex(s, allocator, capacity);
} }
static JarIndex* open(System* s, System::Region* region) { static JarIndex* open(System* s, Allocator* allocator,
JarIndex* index = make(s, 32); System::Region* region)
{
JarIndex* index = make(s, allocator, 32);
const uint8_t* start = region->start(); const uint8_t* start = region->start();
const uint8_t* end = start + region->length(); const uint8_t* end = start + region->length();
@ -362,7 +376,7 @@ class JarIndex {
table[i] = new (nodes + (position++)) Node(hash, entry, table[i]); table[i] = new (nodes + (position++)) Node(hash, entry, table[i]);
return this; return this;
} else { } else {
JarIndex* index = make(s, capacity * 2); JarIndex* index = make(s, allocator, capacity * 2);
for (unsigned i = 0; i < capacity; ++i) { for (unsigned i = 0; i < capacity; ++i) {
index->add(nodes[i].hash, nodes[i].entry); index->add(nodes[i].hash, nodes[i].entry);
} }
@ -390,15 +404,15 @@ class JarIndex {
const uint8_t* p = n->entry; const uint8_t* p = n->entry;
switch (compressionMethod(p)) { switch (compressionMethod(p)) {
case Stored: { case Stored: {
return new (allocate(s, sizeof(PointerRegion))) return new (allocator->allocate(sizeof(PointerRegion)))
PointerRegion(s, fileData(start + localHeaderOffset(p)), PointerRegion(s, allocator, fileData(start + localHeaderOffset(p)),
compressedSize(p)); compressedSize(p));
} break; } break;
case Deflated: { case Deflated: {
DataRegion* region = new DataRegion* region = new
(allocate(s, sizeof(DataRegion) + uncompressedSize(p))) (allocator->allocate(sizeof(DataRegion) + uncompressedSize(p)))
DataRegion(s, uncompressedSize(p)); DataRegion(s, allocator, uncompressedSize(p));
z_stream zStream; memset(&zStream, 0, sizeof(z_stream)); z_stream zStream; memset(&zStream, 0, sizeof(z_stream));
@ -428,16 +442,41 @@ class JarIndex {
return 0; return 0;
} }
bool exists(const char* name) { System::FileType stat(const char* name, unsigned* length, bool tryDirectory)
return findNode(name) != 0; {
Node* node = findNode(name);
if (node) {
*length = uncompressedSize(node->entry);
return System::TypeFile;
} else if (tryDirectory) {
*length = 0;
// try again with '/' appended
unsigned length = strlen(name);
RUNTIME_ARRAY(char, n, length + 2);
memcpy(RUNTIME_ARRAY_BODY(n), name, length);
RUNTIME_ARRAY_BODY(n)[length] = '/';
RUNTIME_ARRAY_BODY(n)[length + 1] = 0;
node = findNode(n);
if (node) {
return System::TypeDirectory;
} else {
return System::TypeDoesNotExist;
}
} else {
*length = 0;
return System::TypeDoesNotExist;
}
} }
void dispose() { void dispose() {
s->free(nodes); allocator->free(nodes, sizeof(Node) * capacity);
s->free(this); allocator->free(this, sizeof(*this) + (sizeof(Node*) * capacity));
} }
System* s; System* s;
Allocator* allocator;
unsigned capacity; unsigned capacity;
unsigned position; unsigned position;
@ -449,7 +488,9 @@ class JarElement: public Element {
public: public:
class Iterator: public Element::Iterator { class Iterator: public Element::Iterator {
public: public:
Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { } Iterator(System* s, Allocator* allocator, JarIndex* index):
s(s), allocator(allocator), index(index), position(0)
{ }
virtual const char* next(unsigned* size) { virtual const char* next(unsigned* size) {
if (position < index->position) { if (position < index->position) {
@ -462,22 +503,34 @@ class JarElement: public Element {
} }
virtual void dispose() { virtual void dispose() {
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
JarIndex* index; JarIndex* index;
unsigned position; unsigned position;
}; };
JarElement(System* s, const char* name): JarElement(System* s, Allocator* allocator, const char* name):
s(s), name(name), region(0), index(0) s(s), allocator(allocator), name(name), region(0), index(0)
{ }
JarElement(System* s, Allocator* allocator, const uint8_t* jarData,
unsigned jarLength):
s(s),
allocator(allocator),
name(0),
region(new (allocator->allocate(sizeof(PointerRegion)))
PointerRegion(s, allocator, jarData, jarLength)),
index(JarIndex::open(s, allocator, region))
{ } { }
virtual Element::Iterator* iterator() { virtual Element::Iterator* iterator() {
init(); init();
return new (allocate(s, sizeof(Iterator))) Iterator(s, index); return new (allocator->allocate(sizeof(Iterator)))
Iterator(s, allocator, index);
} }
virtual void init() { virtual void init() {
@ -485,7 +538,7 @@ class JarElement: public Element {
System::Region* r; System::Region* r;
if (s->success(s->map(&r, name))) { if (s->success(s->map(&r, name))) {
region = r; region = r;
index = JarIndex::open(s, r); index = JarIndex::open(s, allocator, r);
} }
} }
} }
@ -506,26 +559,34 @@ class JarElement: public Element {
return r; return r;
} }
virtual bool exists(const char* name) { virtual System::FileType stat(const char* name, unsigned* length,
bool tryDirectory)
{
init(); init();
while (*name == '/') name++; while (*name == '/') name++;
return (index ? index->exists(name) : 0); return (index ? index->stat(name, length, tryDirectory)
: System::TypeDoesNotExist);
} }
virtual void dispose() { virtual void dispose() {
s->free(name); dispose(sizeof(*this));
}
virtual void dispose(unsigned size) {
allocator->free(name, strlen(name) + 1);
if (index) { if (index) {
index->dispose(); index->dispose();
} }
if (region) { if (region) {
region->dispose(); region->dispose();
} }
s->free(this); allocator->free(this, size);
} }
System* s; System* s;
Allocator* allocator;
const char* name; const char* name;
System::Region* region; System::Region* region;
JarIndex* index; JarIndex* index;
@ -533,9 +594,10 @@ class JarElement: public Element {
class BuiltinElement: public JarElement { class BuiltinElement: public JarElement {
public: public:
BuiltinElement(System* s, const char* name, const char* libraryName): BuiltinElement(System* s, Allocator* allocator, const char* name,
JarElement(s, name), const char* libraryName):
libraryName(libraryName ? copy(s, libraryName) : 0) JarElement(s, allocator, name),
libraryName(libraryName ? copy(allocator, libraryName) : 0)
{ } { }
virtual void init() { virtual void init() {
@ -549,9 +611,9 @@ class BuiltinElement: public JarElement {
unsigned size; unsigned size;
uint8_t* data = function(&size); uint8_t* data = function(&size);
if (data) { if (data) {
region = new (allocate(s, sizeof(PointerRegion))) region = new (allocator->allocate(sizeof(PointerRegion)))
PointerRegion(s, data, size); PointerRegion(s, allocator, data, size);
index = JarIndex::open(s, region); index = JarIndex::open(s, allocator, region);
} }
} }
} }
@ -560,8 +622,10 @@ class BuiltinElement: public JarElement {
virtual void dispose() { virtual void dispose() {
library->disposeAll(); library->disposeAll();
s->free(libraryName); if (libraryName) {
JarElement::dispose(); allocator->free(libraryName, strlen(libraryName) + 1);
}
JarElement::dispose(sizeof(*this));
} }
System::Library* library; System::Library* library;
@ -569,7 +633,8 @@ class BuiltinElement: public JarElement {
}; };
Element* Element*
parsePath(System* s, const char* path, const char* bootLibrary) parsePath(System* s, Allocator* allocator, const char* path,
const char* bootLibrary)
{ {
Element* first = 0; Element* first = 0;
Element* prev = 0; Element* prev = 0;
@ -578,29 +643,31 @@ parsePath(System* s, const char* path, const char* bootLibrary)
Element* e; Element* e;
if (*token.s == '[' and token.s[token.length - 1] == ']') { if (*token.s == '[' and token.s[token.length - 1] == ']') {
char* name = static_cast<char*>(allocate(s, token.length - 1)); char* name = static_cast<char*>(allocator->allocate(token.length - 1));
memcpy(name, token.s + 1, token.length - 1); memcpy(name, token.s + 1, token.length - 1);
name[token.length - 2] = 0; name[token.length - 2] = 0;
e = new (allocate(s, sizeof(BuiltinElement))) e = new (allocator->allocate(sizeof(BuiltinElement)))
BuiltinElement(s, name, bootLibrary); BuiltinElement(s, allocator, name, bootLibrary);
} else { } else {
char* name = static_cast<char*>(allocate(s, token.length + 1)); char* name = static_cast<char*>(allocator->allocate(token.length + 1));
memcpy(name, token.s, token.length); memcpy(name, token.s, token.length);
name[token.length] = 0; name[token.length] = 0;
switch (s->identify(name)) { unsigned length;
switch (s->stat(name, &length)) {
case System::TypeFile: { case System::TypeFile: {
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name); e = new (allocator->allocate(sizeof(JarElement)))
JarElement(s, allocator, name);
} break; } break;
case System::TypeDirectory: { case System::TypeDirectory: {
e = new (allocate(s, sizeof(DirectoryElement))) e = new (allocator->allocate(sizeof(DirectoryElement)))
DirectoryElement(s, name); DirectoryElement(s, allocator, name);
} break; } break;
default: { default: {
s->free(name); allocator->free(name, strlen(name) + 1);
e = 0; e = 0;
} break; } break;
} }
@ -621,8 +688,9 @@ parsePath(System* s, const char* path, const char* bootLibrary)
class MyIterator: public Finder::IteratorImp { class MyIterator: public Finder::IteratorImp {
public: public:
MyIterator(System* s, Element* path): MyIterator(System* s, Allocator* allocator, Element* path):
s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0) s(s), allocator(allocator), e(path ? path->next : 0),
it(path ? path->iterator() : 0)
{ } { }
virtual const char* next(unsigned* size) { virtual const char* next(unsigned* size) {
@ -645,25 +713,37 @@ class MyIterator: public Finder::IteratorImp {
virtual void dispose() { virtual void dispose() {
if (it) it->dispose(); if (it) it->dispose();
s->free(this); allocator->free(this, sizeof(*this));
} }
System* s; System* s;
Allocator* allocator;
Element* e; Element* e;
Element::Iterator* it; Element::Iterator* it;
}; };
class MyFinder: public Finder { class MyFinder: public Finder {
public: public:
MyFinder(System* system, const char* path, const char* bootLibrary): MyFinder(System* system, Allocator* allocator, const char* path,
const char* bootLibrary):
system(system), system(system),
path_(parsePath(system, path, bootLibrary)), allocator(allocator),
pathString(copy(system, path)) path_(parsePath(system, allocator, path, bootLibrary)),
pathString(copy(allocator, path))
{ }
MyFinder(System* system, Allocator* allocator, const uint8_t* jarData,
unsigned jarLength):
system(system),
allocator(allocator),
path_(new (allocator->allocate(sizeof(JarElement)))
JarElement(system, allocator, jarData, jarLength)),
pathString(0)
{ } { }
virtual IteratorImp* iterator() { virtual IteratorImp* iterator() {
return new (allocate(system, sizeof(MyIterator))) return new (allocator->allocate(sizeof(MyIterator)))
MyIterator(system, path_); MyIterator(system, allocator, path_);
} }
virtual System::Region* find(const char* name) { virtual System::Region* find(const char* name) {
@ -677,14 +757,17 @@ class MyFinder: public Finder {
return 0; return 0;
} }
virtual bool exists(const char* name) { virtual System::FileType stat(const char* name, unsigned* length,
bool tryDirectory)
{
for (Element* e = path_; e; e = e->next) { for (Element* e = path_; e; e = e->next) {
if (e->exists(name)) { System::FileType type = e->stat(name, length, tryDirectory);
return true; if (type != System::TypeDoesNotExist) {
return type;
} }
} }
return false; return System::TypeDoesNotExist;
} }
virtual const char* path() { virtual const char* path() {
@ -697,11 +780,12 @@ class MyFinder: public Finder {
e = e->next; e = e->next;
t->dispose(); t->dispose();
} }
system->free(pathString); allocator->free(pathString, strlen(pathString) + 1);
system->free(this); allocator->free(this, sizeof(*this));
} }
System* system; System* system;
Allocator* allocator;
Element* path_; Element* path_;
const char* pathString; const char* pathString;
}; };
@ -711,9 +795,16 @@ class MyFinder: public Finder {
namespace vm { namespace vm {
Finder* Finder*
makeFinder(System* s, const char* path, const char* bootLibrary) makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary)
{ {
return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary); return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary);
}
Finder*
makeFinder(System* s, Allocator* a, const uint8_t* jarData, unsigned jarLength)
{
return new (a->allocate(sizeof(MyFinder)))
MyFinder(s, a, jarData, jarLength);
} }
} // namespace vm } // namespace vm

View File

@ -60,13 +60,19 @@ class Finder {
virtual IteratorImp* iterator() = 0; virtual IteratorImp* iterator() = 0;
virtual System::Region* find(const char* name) = 0; virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0; virtual System::FileType stat(const char* name,
unsigned* length,
bool tryDirectory = false) = 0;
virtual const char* path() = 0; virtual const char* path() = 0;
virtual void dispose() = 0; virtual void dispose() = 0;
}; };
Finder* Finder*
makeFinder(System* s, const char* path, const char* bootLibrary); makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary);
Finder*
makeFinder(System* s, Allocator* a, const uint8_t* jarData,
unsigned jarLength);
} // namespace vm } // namespace vm

View File

@ -2228,6 +2228,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
#define BOOTSTRAP_PROPERTY "avian.bootstrap" #define BOOTSTRAP_PROPERTY "avian.bootstrap"
#define CRASHDIR_PROPERTY "avian.crash.dir" #define CRASHDIR_PROPERTY "avian.crash.dir"
#define EMBED_PREFIX_PROPERTY "avian.embed.prefix"
#define CLASSPATH_PROPERTY "java.class.path" #define CLASSPATH_PROPERTY "java.class.path"
#define JAVA_HOME_PROPERTY "java.home" #define JAVA_HOME_PROPERTY "java.home"
#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p"
@ -2250,6 +2251,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
const char* bootLibrary = 0; const char* bootLibrary = 0;
const char* classpath = 0; const char* classpath = 0;
const char* javaHome = AVIAN_JAVA_HOME; const char* javaHome = AVIAN_JAVA_HOME;
const char* embedPrefix = AVIAN_EMBED_PREFIX;
const char* bootClasspathPrepend = ""; const char* bootClasspathPrepend = "";
const char* bootClasspath = 0; const char* bootClasspath = 0;
const char* bootClasspathAppend = ""; const char* bootClasspathAppend = "";
@ -2293,6 +2295,10 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
sizeof(JAVA_HOME_PROPERTY)) == 0) sizeof(JAVA_HOME_PROPERTY)) == 0)
{ {
javaHome = p + sizeof(JAVA_HOME_PROPERTY); javaHome = p + sizeof(JAVA_HOME_PROPERTY);
} else if (strncmp(p, EMBED_PREFIX_PROPERTY "=",
sizeof(EMBED_PREFIX_PROPERTY)) == 0)
{
embedPrefix = p + sizeof(EMBED_PREFIX_PROPERTY);
} }
++ propertyCount; ++ propertyCount;
@ -2305,7 +2311,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
System* s = makeSystem(crashDumpDirectory); System* s = makeSystem(crashDumpDirectory);
Heap* h = makeHeap(s, heapLimit); Heap* h = makeHeap(s, heapLimit);
Classpath* c = makeClasspath(s, h, javaHome); Classpath* c = makeClasspath(s, h, javaHome, embedPrefix);
if (bootClasspath == 0) { if (bootClasspath == 0) {
bootClasspath = c->bootClasspath(); bootClasspath = c->bootClasspath();
@ -2325,8 +2331,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0);
Finder* bf = makeFinder Finder* bf = makeFinder
(s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); (s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary);
Finder* af = makeFinder(s, classpath, bootLibrary); Finder* af = makeFinder(s, h, classpath, bootLibrary);
Processor* p = makeProcessor(s, h, true); Processor* p = makeProcessor(s, h, true);
const char** properties = static_cast<const char**> const char** properties = static_cast<const char**>

View File

@ -193,6 +193,23 @@ turnOffTheLights(Thread* t)
} }
} }
if (root(t, Machine::VirtualFiles)) {
for (unsigned i = 0; i < arrayLength(t, root(t, Machine::VirtualFiles));
++i)
{
object region = arrayBody(t, root(t, Machine::VirtualFiles), i);
if (region) {
static_cast<System::Region*>(regionRegion(t, region))->dispose();
}
}
}
for (object p = root(t, Machine::VirtualFileFinders);
p; p = finderNext(t, p))
{
static_cast<Finder*>(finderFinder(t, p))->dispose();
}
Machine* m = t->m; Machine* m = t->m;
disposeAll(t, t->m->rootThread); disposeAll(t, t->m->rootThread);
@ -204,13 +221,13 @@ turnOffTheLights(Thread* t)
Finder* bf = m->bootFinder; Finder* bf = m->bootFinder;
Finder* af = m->appFinder; Finder* af = m->appFinder;
c->dispose();
m->dispose(); m->dispose();
h->disposeFixies(); h->disposeFixies();
c->dispose();
p->dispose(); p->dispose();
h->dispose();
bf->dispose(); bf->dispose();
af->dispose(); af->dispose();
h->dispose();
s->dispose(); s->dispose();
} }

View File

@ -1198,10 +1198,12 @@ class Machine {
ShutdownHooks, ShutdownHooks,
ObjectsToFinalize, ObjectsToFinalize,
NullPointerException, NullPointerException,
ArrayIndexOutOfBoundsException ArrayIndexOutOfBoundsException,
VirtualFileFinders,
VirtualFiles
}; };
static const unsigned RootCount = ArrayIndexOutOfBoundsException + 1; static const unsigned RootCount = VirtualFiles + 1;
Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder,
Processor* processor, Classpath* classpath, const char** properties, Processor* processor, Classpath* classpath, const char** properties,
@ -1446,7 +1448,8 @@ runJavaThread(Thread* t)
} }
Classpath* Classpath*
makeClasspath(System* system, Allocator* allocator, const char* javaHome); makeClasspath(System* system, Allocator* allocator, const char* javaHome,
const char* embedPrefix);
typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*);

View File

@ -698,18 +698,22 @@ class MySystem: public System {
return status; return status;
} }
virtual FileType identify(const char* name) { virtual FileType stat(const char* name, unsigned* length) {
struct stat s; struct stat s;
int r = stat(name, &s); int r = ::stat(name, &s);
if (r == 0) { if (r == 0) {
if (S_ISREG(s.st_mode)) { if (S_ISREG(s.st_mode)) {
*length = s.st_size;
return TypeFile; return TypeFile;
} else if (S_ISDIR(s.st_mode)) { } else if (S_ISDIR(s.st_mode)) {
*length = 0;
return TypeDirectory; return TypeDirectory;
} else { } else {
*length = 0;
return TypeUnknown; return TypeUnknown;
} }
} else { } else {
*length = 0;
return TypeDoesNotExist; return TypeDoesNotExist;
} }
} }

View File

@ -132,7 +132,7 @@ class System {
unsigned count, unsigned size, unsigned count, unsigned size,
unsigned returnType) = 0; unsigned returnType) = 0;
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 stat(const char* name, unsigned* length) = 0;
virtual Status open(Directory**, const char* name) = 0; virtual Status open(Directory**, const char* name) = 0;
virtual const char* libraryPrefix() = 0; virtual const char* libraryPrefix() = 0;
virtual const char* librarySuffix() = 0; virtual const char* librarySuffix() = 0;

View File

@ -2213,7 +2213,31 @@ main(int ac, char** av)
} }
System* system = makeSystem(0); System* system = makeSystem(0);
Finder* finder = makeFinder(system, av[1], 0);
class MyAllocator: public Allocator {
public:
MyAllocator(System* s): s(s) { }
virtual void* tryAllocate(unsigned size) {
return s->tryAllocate(size);
}
virtual void* allocate(unsigned size) {
void* p = tryAllocate(size);
if (p == 0) {
abort(s);
}
return p;
}
virtual void free(const void* p, unsigned) {
s->free(p);
}
System* s;
} allocator(system);
Finder* finder = makeFinder(system, &allocator, av[1], 0);
FILE* inStream = ::fopen(av[2], "rb"); FILE* inStream = ::fopen(av[2], "rb");
if (inStream == 0) { if (inStream == 0) {

View File

@ -48,6 +48,15 @@
(extends native) (extends native)
(object original)) (object original))
(type finder
(void* finder)
(object name)
(object next))
(type region
(void* region)
(unsigned position))
(pod exceptionHandler (pod exceptionHandler
(uint16_t start) (uint16_t start)
(uint16_t end) (uint16_t end)

View File

@ -529,11 +529,6 @@ vectorAppend(Thread* t, object vector, object value)
vectorSize(t, vector) * BytesPerWord); vectorSize(t, vector) * BytesPerWord);
} }
memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1),
0,
(vectorLength(t, newVector) - vectorSize(t, vector) - 1)
* BytesPerWord);
vector = newVector; vector = newVector;
} }
@ -542,6 +537,22 @@ vectorAppend(Thread* t, object vector, object value)
return vector; return vector;
} }
object
growArray(Thread* t, object array)
{
PROTECT(t, array);
object newArray = makeArray
(t, array == 0 ? 16 : (arrayLength(t, array) * 2));
if (array) {
memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0),
arrayLength(t, array));
}
return newArray;
}
object object
treeQuery(Thread* t, object tree, intptr_t key, object sentinal, treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b)) intptr_t (*compare)(Thread* t, intptr_t key, object b))

View File

@ -84,6 +84,9 @@ listAppend(Thread* t, object list, object value);
object object
vectorAppend(Thread* t, object vector, object value); vectorAppend(Thread* t, object vector, object value);
object
growArray(Thread* t, object array);
object object
treeQuery(Thread* t, object tree, intptr_t key, object sentinal, treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b)); intptr_t (*compare)(Thread* t, intptr_t key, object b));

View File

@ -204,5 +204,7 @@ public class Misc {
} while (x != 1); } while (x != 1);
} }
} }
System.out.println(java.util.Calendar.getInstance().toString());
} }
} }