diff --git a/makefile b/makefile index 1994bd5349..e875719e7a 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -MAKEFLAGS = -s +#MAKEFLAGS = -s arch = $(shell uname -m) ifeq ($(arch),i586) @@ -43,7 +43,7 @@ ifeq ($(mode),stress-major) cflags += -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR endif ifeq ($(mode),fast) -fast = -Os -DNDEBUG +cflags += -Os -DNDEBUG -DMONOLITHIC endif lflags = $(thread-lflags) -ldl @@ -81,11 +81,13 @@ interpreter-depends = \ $(src)/machine.h interpreter-sources = \ - $(src)/run.cpp \ + $(src)/system.cpp \ + $(src)/class-finder.cpp \ $(src)/machine.cpp \ - $(src)/jnienv.cpp \ - $(src)/builtin.cpp \ $(src)/heap.cpp \ + $(src)/run.cpp \ + $(src)/builtin.cpp \ + $(src)/jnienv.cpp \ $(src)/main.cpp ifeq ($(arch),i386) diff --git a/src/builtin.cpp b/src/builtin.cpp index 29358142a3..50d685dfdc 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -3,6 +3,7 @@ #include "run.h" namespace vm { + namespace builtin { jstring @@ -262,4 +263,5 @@ populate(Thread* t, object map) } } // namespace builtin + } // namespace vm diff --git a/src/builtin.h b/src/builtin.h index b8fee910e4..3c03ffba8c 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -4,12 +4,14 @@ #include "machine.h" namespace vm { + namespace builtin { void populate(Thread* t, object map); } // namespace builtin + } // namespace vm #endif//BUILTIN_H diff --git a/src/class-finder.cpp b/src/class-finder.cpp new file mode 100644 index 0000000000..4ff401a1ff --- /dev/null +++ b/src/class-finder.cpp @@ -0,0 +1,167 @@ + + +#include "sys/mman.h" +#include "sys/types.h" +#include "sys/stat.h" +#include "fcntl.h" + + + +#include "system.h" +#include "class-finder.h" + +using namespace vm; + +namespace { + +const char* +append(System* s, const char* a, const char* b, const char* c, + const char* d) +{ + unsigned al = strlen(a); + unsigned bl = strlen(b); + unsigned cl = strlen(c); + unsigned dl = strlen(d); + char* p = static_cast(s->allocate(al + bl + cl + dl + 1)); + memcpy(p, a, al); + memcpy(p + al, b, bl); + memcpy(p + al + bl, c, cl); + memcpy(p + al + bl + cl, d, dl + 1); + return p; +} + +const char** +parsePath(System* s, const char* path) +{ + 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; + }; + + unsigned count = 0; + for (Tokenizer t(path, ':'); t.hasMore(); t.next()) ++ count; + + const char** v = static_cast + (s->allocate((count + 1) * sizeof(const char*))); + + unsigned i = 0; + for (Tokenizer t(path, ':'); t.hasMore(); ++i) { + Tokenizer::Token token(t.next()); + char* p = static_cast(s->allocate(token.length + 1)); + memcpy(p, token.s, token.length); + p[token.length] = 0; + v[i] = p; + } + + v[i] = 0; + + return v; +} + +class MyClassFinder: public ClassFinder { + public: + MyClassFinder(System* system, const char* path): + system(system), + path(parsePath(system, path)) + { } + + class Data: public ClassFinder::Data { + public: + Data(System* system, uint8_t* start, size_t length): + system(system), + start_(start), + length_(length) + { } + + virtual const uint8_t* start() { + return start_; + } + + virtual size_t length() { + return length_; + } + + virtual void dispose() { + if (start_) { + munmap(start_, length_); + } + system->free(this); + } + + System* system; + uint8_t* start_; + size_t length_; + }; + + virtual Data* find(const char* className) { + Data* d = new (system->allocate(sizeof(Data))) Data(system, 0, 0); + + for (const char** p = path; *p; ++p) { + const char* file = append(system, *p, "/", className, ".class"); + int fd = open(file, O_RDONLY); + system->free(file); + + if (fd != -1) { + struct stat s; + int r = fstat(fd, &s); + if (r != -1) { + void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data) { + d->start_ = static_cast(data); + d->length_ = s.st_size; + return d; + } + } + } + } + + system->free(d); + return 0; + } + + virtual void dispose() { + for (const char** p = path; *p; ++p) { + system->free(*p); + } + system->free(path); + + system->free(this); + } + + System* system; + const char** path; +}; + +} // namespace + +namespace vm { + +ClassFinder* +makeClassFinder(System* s, const char* path) +{ + return new (s->allocate(sizeof(MyClassFinder))) MyClassFinder(s, path); +} + +} // namespace vm diff --git a/src/class-finder.h b/src/class-finder.h index d46061ab73..36f5d45eb9 100644 --- a/src/class-finder.h +++ b/src/class-finder.h @@ -2,6 +2,7 @@ #define CLASS_FINDER_H #include "common.h" +#include "system.h" namespace vm { @@ -17,8 +18,12 @@ class ClassFinder { virtual ~ClassFinder() { } virtual Data* find(const char* className) = 0; + virtual void dispose() = 0; }; +ClassFinder* +makeClassFinder(System* s, const char* path); + } // namespace vm #endif//CLASS_FINDER_H diff --git a/src/common.h b/src/common.h index bf1b26b388..76d6473a60 100644 --- a/src/common.h +++ b/src/common.h @@ -1,6 +1,8 @@ #ifndef COMMON_H #define COMMON_H + + #include "stdint.h" #include "stdlib.h" #include "stdarg.h" @@ -27,6 +29,8 @@ inline void* operator new(size_t, void* p) throw() { return p; } + + namespace vm { typedef void* object; @@ -127,6 +131,6 @@ mask(T* p) return reinterpret_cast(reinterpret_cast(p) & PointerMask); } -} +} // namespace vm #endif//COMMON_H diff --git a/src/constants.h b/src/constants.h index 799b931547..e381b2dc09 100644 --- a/src/constants.h +++ b/src/constants.h @@ -168,7 +168,7 @@ enum OpCode { ldc = 0x12, ldc_w = 0x13, ldc2_w = 0x14, - ldiv = 0x6d, + ldiv_ = 0x6d, lload = 0x16, lload_0 = 0x1e, lload_1 = 0x1f, diff --git a/src/heap.cpp b/src/heap.cpp index 0f055b65db..95b4c660a0 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1374,99 +1374,99 @@ collect(Context* c) } } +class MyHeap: public Heap { + public: + MyHeap(System* system): c(system) { } + + virtual void collect(CollectionType type, Client* client) { + switch (type) { + case MinorCollection: + c.mode = ::MinorCollection; + break; + + case MajorCollection: + c.mode = ::MajorCollection; + break; + + default: abort(&c); + } + + c.client = client; + + ::collect(&c); + } + + virtual bool needsMark(void** p) { + return *p and c.gen2.contains(p) and not c.gen2.contains(*p); + } + + virtual void mark(void** p) { + if (Debug) { + fprintf(stderr, "mark %p (%s) at %p (%s)\n", + *p, segment(&c, *p), p, segment(&c, p)); + } + + c.heapMap.set(p); + } + + virtual void dispose() { + c.dispose(); + c.system->free(this); + } + + virtual void* follow(void* p) { + if (wasCollected(&c, p)) { + if (Debug) { + fprintf(stderr, "follow %p (%s) to %p (%s)\n", + p, segment(&c, p), + ::follow(&c, p), segment(&c, ::follow(&c, p))); + } + + return ::follow(&c, p); + } else { + return p; + } + } + + virtual Status status(void* p) { + p = mask(p); + + if (p == 0) { + return Null; + } else if (c.nextGen1.contains(p)) { + return Reachable; + } else if (c.nextGen2.contains(p) + or (c.gen2.contains(p) + and (c.mode == ::MinorCollection + or c.gen2.indexOf(p) >= c.gen2Base))) + { + return Tenured; + } else if (wasCollected(&c, p)) { + return Reachable; + } else { + return Unreachable; + } + } + + virtual CollectionType collectionType() { + if (c.mode == ::MinorCollection) { + return MinorCollection; + } else { + return MajorCollection; + } + } + + Context c; +}; + } // namespace namespace vm { Heap* makeHeap(System* system) -{ - class Heap: public vm::Heap { - public: - Heap(System* system): c(system) { } - - virtual void collect(CollectionType type, Client* client) { - switch (type) { - case MinorCollection: - c.mode = ::MinorCollection; - break; - - case MajorCollection: - c.mode = ::MajorCollection; - break; - - default: abort(&c); - } - - c.client = client; - - ::collect(&c); - } - - virtual bool needsMark(void** p) { - return *p and c.gen2.contains(p) and not c.gen2.contains(*p); - } - - virtual void mark(void** p) { - if (Debug) { - fprintf(stderr, "mark %p (%s) at %p (%s)\n", - *p, segment(&c, *p), p, segment(&c, p)); - } - - c.heapMap.set(p); - } - - virtual void dispose() { - c.dispose(); - c.system->free(this); - } - - virtual void* follow(void* p) { - if (wasCollected(&c, p)) { - if (Debug) { - fprintf(stderr, "follow %p (%s) to %p (%s)\n", - p, segment(&c, p), - ::follow(&c, p), segment(&c, ::follow(&c, p))); - } - - return ::follow(&c, p); - } else { - return p; - } - } - - virtual Status status(void* p) { - p = mask(p); - - if (p == 0) { - return Null; - } else if (c.nextGen1.contains(p)) { - return Reachable; - } else if (c.nextGen2.contains(p) - or (c.gen2.contains(p) - and (c.mode == ::MinorCollection - or c.gen2.indexOf(p) >= c.gen2Base))) - { - return Tenured; - } else if (wasCollected(&c, p)) { - return Reachable; - } else { - return Unreachable; - } - } - - virtual CollectionType collectionType() { - if (c.mode == ::MinorCollection) { - return MinorCollection; - } else { - return MajorCollection; - } - } - - Context c; - }; - - return new (system->allocate(sizeof(Heap))) Heap(system); +{ + return new (system->allocate(sizeof(MyHeap))) MyHeap(system); } } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index f6d22189a3..c373b9b03f 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2,6 +2,7 @@ #include "machine.h" namespace vm { + namespace jni { jsize @@ -51,4 +52,5 @@ populate(JNIEnvVTable* table) } } // namespace jni + } // namespace vm diff --git a/src/jnienv.h b/src/jnienv.h index 6632b0510d..c9454e1598 100644 --- a/src/jnienv.h +++ b/src/jnienv.h @@ -4,12 +4,14 @@ #include "machine.h" namespace vm { + namespace jni { void populate(JNIEnvVTable* table); } // namespace jni + } // namespace vm #endif//JNIENV_H diff --git a/src/machine.h b/src/machine.h index cf2bf9d015..e6c0952ceb 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2008,6 +2008,12 @@ wait(Thread* t, object o, int64_t milliseconds) stress(t); } +inline void +vmWait(Thread* t, object o, int64_t milliseconds) +{ + wait(t, o, milliseconds); +} + inline void notify(Thread* t, object o) { @@ -2025,6 +2031,12 @@ notify(Thread* t, object o) } } +inline void +vmNotify(Thread* t, object o) +{ + notify(t, o); +} + inline void notifyAll(Thread* t, object o) { @@ -2042,6 +2054,12 @@ notifyAll(Thread* t, object o) } } +inline void +vmNotifyAll(Thread* t, object o) +{ + notifyAll(t, o); +} + void exit(Thread* t); diff --git a/src/main.cpp b/src/main.cpp index 120ad63106..8b2efc2168 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,3 @@ -#include "sys/mman.h" -#include "sys/types.h" -#include "sys/stat.h" -#include "sys/time.h" -#include "time.h" -#include "fcntl.h" -#include "dlfcn.h" -#include "errno.h" -#include "pthread.h" - #include "common.h" #include "system.h" #include "heap.h" @@ -16,534 +6,21 @@ using namespace vm; -#ifdef __i386__ - -extern "C" uint64_t -cdeclCall(void* function, void* stack, unsigned stackSize, - unsigned returnType); - namespace { -inline uint64_t -dynamicCall(void* function, uint32_t* arguments, uint8_t*, - unsigned, unsigned argumentsSize, unsigned returnType) -{ - return cdeclCall(function, arguments, argumentsSize, returnType); -} - -} // namespace - -#elif defined __x86_64__ - -extern "C" uint64_t -amd64Call(void* function, void* stack, unsigned stackSize, - void* gprTable, void* sseTable, unsigned returnType); - -namespace { - -uint64_t -dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes, - unsigned argumentCount, unsigned, unsigned returnType) -{ - const unsigned GprCount = 6; - uint64_t gprTable[GprCount]; - unsigned gprIndex = 0; - - const unsigned SseCount = 8; - uint64_t sseTable[SseCount]; - unsigned sseIndex = 0; - - uint64_t stack[argumentCount]; - unsigned stackIndex = 0; - - for (unsigned i = 0; i < argumentCount; ++i) { - switch (argumentTypes[i]) { - case FLOAT_TYPE: - case DOUBLE_TYPE: { - if (sseIndex < SseCount) { - sseTable[sseIndex++] = arguments[i]; - } else { - stack[stackIndex++] = arguments[i]; - } - } break; - - default: { - if (gprIndex < GprCount) { - gprTable[gprIndex++] = arguments[i]; - } else { - stack[stackIndex++] = arguments[i]; - } - } break; - } - } - - return amd64Call(function, stack, stackIndex * 8, (gprIndex ? gprTable : 0), - (sseIndex ? sseTable : 0), returnType); -} - -} // namespace - -#else -# error unsupported platform -#endif - -namespace { - -void* -run(void* t) -{ - static_cast(t)->run(); - return 0; -} - -int64_t -now() -{ - timeval tv = { 0, 0 }; - gettimeofday(&tv, 0); - return (static_cast(tv.tv_sec) * 1000) + - (static_cast(tv.tv_usec) / 1000); -} - -const char* -append(vm::System* s, const char* a, const char* b, const char* c, - const char* d) -{ - unsigned al = strlen(a); - unsigned bl = strlen(b); - unsigned cl = strlen(c); - unsigned dl = strlen(d); - char* p = static_cast(s->allocate(al + bl + cl + dl + 1)); - memcpy(p, a, al); - memcpy(p + al, b, bl); - memcpy(p + al + bl, c, cl); - memcpy(p + al + bl + cl, d, dl + 1); - return p; -} - -const bool Verbose = false; - -class System: public vm::System { - public: - class Thread: public vm::System::Thread { - public: - Thread(vm::System* s, vm::System::Runnable* r): s(s), r(r) { } - - virtual void run() { - r->run(this); - } - - virtual void join() { - int rv = pthread_join(thread, 0); - assert(s, rv == 0); - } - - virtual void dispose() { - if (r) { - r->dispose(); - } - s->free(this); - } - - vm::System* s; - vm::System::Runnable* r; - pthread_t thread; - }; - - class Monitor: public vm::System::Monitor { - public: - Monitor(vm::System* s): s(s), context(0), depth(0) { - pthread_mutex_init(&mutex, 0); - pthread_cond_init(&condition, 0); - } - - virtual bool tryAcquire(void* context) { - if (this->context == context) { - ++ depth; - return true; - } else { - switch (pthread_mutex_trylock(&mutex)) { - case EBUSY: - return false; - - case 0: - this->context = context; - ++ depth; - return true; - - default: - vm::abort(s); - } - } - } - - virtual void acquire(void* context) { - if (this->context != context) { - pthread_mutex_lock(&mutex); - this->context = context; - } - ++ depth; - } - - virtual void release(void* context) { - if (this->context == context) { - if (-- depth == 0) { - this->context = 0; - pthread_mutex_unlock(&mutex); - } - } else { - vm::abort(s); - } - } - - virtual void wait(void* context, int64_t time) { - if (this->context == context) { - unsigned depth = this->depth; - this->depth = 0; - this->context = 0; - if (time) { - int64_t then = now() + time; - timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 }; - int rv = pthread_cond_timedwait(&condition, &mutex, &ts); - assert(s, rv == 0); - } else { - int rv = pthread_cond_wait(&condition, &mutex); - assert(s, rv == 0); - } - this->context = context; - this->depth = depth; - } else { - vm::abort(s); - } - } - - virtual void notify(void* context) { - if (this->context == context) { - int rv = pthread_cond_signal(&condition); - assert(s, rv == 0); - } else { - vm::abort(s); - } - } - - virtual void notifyAll(void* context) { - if (this->context == context) { - int rv = pthread_cond_broadcast(&condition); - assert(s, rv == 0); - } else { - vm::abort(s); - } - } - - virtual void* owner() { - return context; - } - - virtual void dispose() { - assert(s, context == 0); - pthread_mutex_destroy(&mutex); - pthread_cond_destroy(&condition); - s->free(this); - } - - vm::System* s; - pthread_mutex_t mutex; - pthread_cond_t condition; - void* context; - unsigned depth; - }; - - class Library: public vm::System::Library { - public: - Library(vm::System* s, void* p, vm::System::Library* next): - s(s), - p(p), - next_(next) - { } - - virtual void* resolve(const char* function) { - return dlsym(p, function); - } - - virtual vm::System::Library* next() { - return next_; - } - - virtual void dispose() { - if (Verbose) { - fprintf(stderr, "close %p\n", p); - } - - dlclose(p); - - if (next_) { - next_->dispose(); - } - s->free(this); - } - - vm::System* s; - void* p; - vm::System::Library* next_; - }; - - System(unsigned limit): limit(limit), count(0) { - pthread_mutex_init(&mutex, 0); - } - - ~System() { - pthread_mutex_destroy(&mutex); - } - - virtual bool success(Status s) { - return s == 0; - } - - virtual void* tryAllocate(unsigned size) { - pthread_mutex_lock(&mutex); - - if (Verbose) { - fprintf(stderr, "try %d; count: %d; limit: %d\n", - size, count, limit); - } - - if (count + size > limit) { - pthread_mutex_unlock(&mutex); - return 0; - } else { - uintptr_t* up = static_cast - (malloc(size + sizeof(uintptr_t))); - if (up == 0) { - pthread_mutex_unlock(&mutex); - vm::abort(this); - } else { - *up = size; - count += *up; - - pthread_mutex_unlock(&mutex); - return up + 1; - } - } - } - - virtual void free(const void* p) { - pthread_mutex_lock(&mutex); - - if (p) { - const uintptr_t* up = static_cast(p) - 1; - if (count < *up) { - abort(); - } - count -= *up; - - if (Verbose) { - fprintf(stderr, "free " LD "; count: %d; limit: %d\n", - *up, count, limit); - } - - ::free(const_cast(up)); - } - - pthread_mutex_unlock(&mutex); - } - - virtual Status attach(vm::System::Thread** tp) { - Thread* t = new (vm::System::allocate(sizeof(Thread))) Thread(this, 0); - t->thread = pthread_self(); - *tp = t; - return 0; - } - - virtual Status start(Runnable* r) { - Thread* t = new (vm::System::allocate(sizeof(Thread))) Thread(this, r); - int rv = pthread_create(&(t->thread), 0, run, t); - assert(this, rv == 0); - return 0; - } - - virtual Status make(vm::System::Monitor** m) { - *m = new (vm::System::allocate(sizeof(Monitor))) Monitor(this); - return 0; - } - - virtual void sleep(int64_t milliseconds) { - timespec ts = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 }; - - nanosleep(&ts, 0); - } - - virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, - unsigned count, unsigned size, unsigned returnType) - { - return dynamicCall(function, arguments, types, count, size, returnType); - } - - virtual Status load(vm::System::Library** lib, - const char* name, - vm::System::Library* next) - { - unsigned size = strlen(name) + 7; - char buffer[size]; - snprintf(buffer, size, "lib%s.so", name); - - void* p = dlopen(buffer, RTLD_LAZY); - if (p) { - if (Verbose) { - fprintf(stderr, "open %s as %p\n", buffer, p); - } - - *lib = new (vm::System::allocate(sizeof(Library))) - Library(this, p, next); - return 0; - } else { - return 1; - } - } - - virtual void abort() { - ::abort(); - } - - pthread_mutex_t mutex; - unsigned limit; - unsigned count; -}; - -class ClassFinder: public vm::ClassFinder { - public: - ClassFinder(vm::System* system, const char** path): - system(system), - path(path) - { } - - class Data: public vm::ClassFinder::Data { - public: - Data(vm::System* system, uint8_t* start, size_t length): - system(system), - start_(start), - length_(length) - { } - - virtual const uint8_t* start() { - return start_; - } - - virtual size_t length() { - return length_; - } - - virtual void dispose() { - if (start_) { - munmap(start_, length_); - } - system->free(this); - } - - vm::System* system; - uint8_t* start_; - size_t length_; - }; - - virtual Data* find(const char* className) { - Data* d = new (system->allocate(sizeof(Data))) Data(system, 0, 0); - - for (const char** p = path; *p; ++p) { - const char* file = append(system, *p, "/", className, ".class"); - int fd = open(file, O_RDONLY); - system->free(file); - - if (fd != -1) { - struct stat s; - int r = fstat(fd, &s); - if (r != -1) { - void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (data) { - d->start_ = static_cast(data); - d->length_ = s.st_size; - return d; - } - } - } - } - - system->free(d); - return 0; - } - - vm::System* system; - const char** path; -}; - -const char** -parsePath(vm::System* s, const char* path) -{ - 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; - }; - - unsigned count = 0; - for (Tokenizer t(path, ':'); t.hasMore(); t.next()) ++ count; - - const char** v = static_cast - (s->allocate((count + 1) * sizeof(const char*))); - - unsigned i = 0; - for (Tokenizer t(path, ':'); t.hasMore(); ++i) { - Tokenizer::Token token(t.next()); - char* p = static_cast(s->allocate(token.length + 1)); - memcpy(p, token.s, token.length); - p[token.length] = 0; - v[i] = p; - } - - v[i] = 0; - - return v; -} - int run(unsigned heapSize, const char* path, const char* class_, int argc, const char** argv) { - System s(heapSize); + System* s = makeSystem(heapSize); + ClassFinder* cf = makeClassFinder(s, path); + Heap* heap = makeHeap(s); - const char** pathv = parsePath(&s, path); - ClassFinder cf(&s, pathv); - - Heap* heap = makeHeap(&s); - - int exitCode = run(&s, heap, &cf, class_, argc, argv); + int exitCode = run(s, heap, cf, class_, argc, argv); heap->dispose(); - - for (const char** p = pathv; *p; ++p) { - s.free(*p); - } - - s.free(pathv); + cf->dispose(); + s->dispose(); return exitCode; } diff --git a/src/run.cpp b/src/run.cpp index 11a685c55a..239373fac5 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -1656,7 +1656,7 @@ run(Thread* t) } } goto loop; - case vm::ldiv: { + case ldiv_: { int64_t b = popLong(t); int64_t a = popLong(t); @@ -2386,4 +2386,4 @@ run(System* system, Heap* heap, ClassFinder* classFinder, return exitCode; } -} +} // namespace vm diff --git a/src/run.h b/src/run.h index 1e721dbfc6..069b38c0a6 100644 --- a/src/run.h +++ b/src/run.h @@ -16,6 +16,6 @@ int run(System* sys, Heap* heap, ClassFinder* classFinder, const char* className, int argc, const char** argv); -} +} // namespace vm #endif//RUN_H diff --git a/src/system.cpp b/src/system.cpp new file mode 100644 index 0000000000..7cdde23232 --- /dev/null +++ b/src/system.cpp @@ -0,0 +1,403 @@ +#include "sys/mman.h" +#include "sys/types.h" +#include "sys/stat.h" +#include "sys/time.h" +#include "time.h" +#include "fcntl.h" +#include "dlfcn.h" +#include "errno.h" +#include "pthread.h" +#include "stdint.h" + +#ifdef __i386__ + +extern "C" uint64_t +cdeclCall(void* function, void* stack, unsigned stackSize, + unsigned returnType); + +namespace { + +inline uint64_t +dynamicCall(void* function, uint32_t* arguments, uint8_t*, + unsigned, unsigned argumentsSize, unsigned returnType) +{ + return cdeclCall(function, arguments, argumentsSize, returnType); +} + +} // namespace + +#elif defined __x86_64__ + +extern "C" uint64_t +amd64Call(void* function, void* stack, unsigned stackSize, + void* gprTable, void* sseTable, unsigned returnType); + +#include "system.h" + +namespace { + +uint64_t +dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes, + unsigned argumentCount, unsigned, unsigned returnType) +{ + const unsigned GprCount = 6; + uint64_t gprTable[GprCount]; + unsigned gprIndex = 0; + + const unsigned SseCount = 8; + uint64_t sseTable[SseCount]; + unsigned sseIndex = 0; + + uint64_t stack[argumentCount]; + unsigned stackIndex = 0; + + for (unsigned i = 0; i < argumentCount; ++i) { + switch (argumentTypes[i]) { + case FLOAT_TYPE: + case DOUBLE_TYPE: { + if (sseIndex < SseCount) { + sseTable[sseIndex++] = arguments[i]; + } else { + stack[stackIndex++] = arguments[i]; + } + } break; + + default: { + if (gprIndex < GprCount) { + gprTable[gprIndex++] = arguments[i]; + } else { + stack[stackIndex++] = arguments[i]; + } + } break; + } + } + + return amd64Call(function, stack, stackIndex * 8, (gprIndex ? gprTable : 0), + (sseIndex ? sseTable : 0), returnType); +} + +} // namespace + +#else +# error unsupported platform +#endif + +using namespace vm; + +namespace { + +void* +run(void* t) +{ + static_cast(t)->run(); + return 0; +} + +int64_t +now() +{ + timeval tv = { 0, 0 }; + gettimeofday(&tv, 0); + return (static_cast(tv.tv_sec) * 1000) + + (static_cast(tv.tv_usec) / 1000); +} + +const bool Verbose = false; + +class MySystem: public System { + public: + class Thread: public System::Thread { + public: + Thread(System* s, System::Runnable* r): s(s), r(r) { } + + virtual void run() { + r->run(this); + } + + virtual void join() { + int rv = pthread_join(thread, 0); + assert(s, rv == 0); + } + + virtual void dispose() { + if (r) { + r->dispose(); + } + s->free(this); + } + + System* s; + System::Runnable* r; + pthread_t thread; + }; + + class Monitor: public System::Monitor { + public: + Monitor(System* s): s(s), context(0), depth(0) { + pthread_mutex_init(&mutex, 0); + pthread_cond_init(&condition, 0); + } + + virtual bool tryAcquire(void* context) { + if (this->context == context) { + ++ depth; + return true; + } else { + switch (pthread_mutex_trylock(&mutex)) { + case EBUSY: + return false; + + case 0: + this->context = context; + ++ depth; + return true; + + default: + sysAbort(s); + } + } + } + + virtual void acquire(void* context) { + if (this->context != context) { + pthread_mutex_lock(&mutex); + this->context = context; + } + ++ depth; + } + + virtual void release(void* context) { + if (this->context == context) { + if (-- depth == 0) { + this->context = 0; + pthread_mutex_unlock(&mutex); + } + } else { + sysAbort(s); + } + } + + virtual void wait(void* context, int64_t time) { + if (this->context == context) { + unsigned depth = this->depth; + this->depth = 0; + this->context = 0; + if (time) { + int64_t then = now() + time; + timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 }; + int rv = pthread_cond_timedwait(&condition, &mutex, &ts); + assert(s, rv == 0); + } else { + int rv = pthread_cond_wait(&condition, &mutex); + assert(s, rv == 0); + } + this->context = context; + this->depth = depth; + } else { + sysAbort(s); + } + } + + virtual void notify(void* context) { + if (this->context == context) { + int rv = pthread_cond_signal(&condition); + assert(s, rv == 0); + } else { + sysAbort(s); + } + } + + virtual void notifyAll(void* context) { + if (this->context == context) { + int rv = pthread_cond_broadcast(&condition); + assert(s, rv == 0); + } else { + sysAbort(s); + } + } + + virtual void* owner() { + return context; + } + + virtual void dispose() { + assert(s, context == 0); + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&condition); + s->free(this); + } + + System* s; + pthread_mutex_t mutex; + pthread_cond_t condition; + void* context; + unsigned depth; + }; + + class Library: public System::Library { + public: + Library(System* s, void* p, System::Library* next): + s(s), + p(p), + next_(next) + { } + + virtual void* resolve(const char* function) { + return dlsym(p, function); + } + + virtual System::Library* next() { + return next_; + } + + virtual void dispose() { + if (Verbose) { + fprintf(stderr, "close %p\n", p); + } + + dlclose(p); + + if (next_) { + next_->dispose(); + } + s->free(this); + } + + System* s; + void* p; + System::Library* next_; + }; + + MySystem(unsigned limit): limit(limit), count(0) { + pthread_mutex_init(&mutex, 0); + } + + virtual bool success(Status s) { + return s == 0; + } + + virtual void* tryAllocate(unsigned size) { + pthread_mutex_lock(&mutex); + + if (Verbose) { + fprintf(stderr, "try %d; count: %d; limit: %d\n", + size, count, limit); + } + + if (count + size > limit) { + pthread_mutex_unlock(&mutex); + return 0; + } else { + uintptr_t* up = static_cast + (malloc(size + sizeof(uintptr_t))); + if (up == 0) { + pthread_mutex_unlock(&mutex); + sysAbort(this); + } else { + *up = size; + count += *up; + + pthread_mutex_unlock(&mutex); + return up + 1; + } + } + } + + virtual void free(const void* p) { + pthread_mutex_lock(&mutex); + + if (p) { + const uintptr_t* up = static_cast(p) - 1; + if (count < *up) { + abort(); + } + count -= *up; + + if (Verbose) { + fprintf(stderr, "free " LD "; count: %d; limit: %d\n", + *up, count, limit); + } + + ::free(const_cast(up)); + } + + pthread_mutex_unlock(&mutex); + } + + virtual Status attach(System::Thread** tp) { + Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, 0); + t->thread = pthread_self(); + *tp = t; + return 0; + } + + virtual Status start(Runnable* r) { + Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r); + int rv = pthread_create(&(t->thread), 0, run, t); + assert(this, rv == 0); + return 0; + } + + virtual Status make(System::Monitor** m) { + *m = new (System::allocate(sizeof(Monitor))) Monitor(this); + return 0; + } + + virtual void sleep(int64_t milliseconds) { + timespec ts = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 }; + + nanosleep(&ts, 0); + } + + virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, + unsigned count, unsigned size, unsigned returnType) + { + return dynamicCall(function, arguments, types, count, size, returnType); + } + + virtual Status load(System::Library** lib, + const char* name, + System::Library* next) + { + unsigned size = strlen(name) + 7; + char buffer[size]; + snprintf(buffer, size, "lib%s.so", name); + + void* p = dlopen(buffer, RTLD_LAZY); + if (p) { + if (Verbose) { + fprintf(stderr, "open %s as %p\n", buffer, p); + } + + *lib = new (System::allocate(sizeof(Library))) Library(this, p, next); + return 0; + } else { + return 1; + } + } + + virtual void abort() { + ::abort(); + } + + virtual void dispose() { + pthread_mutex_destroy(&mutex); + ::free(this); + } + + pthread_mutex_t mutex; + unsigned limit; + unsigned count; +}; + +} // namespace + +namespace vm { + +System* +makeSystem(unsigned heapSize) +{ + return new (malloc(sizeof(MySystem))) MySystem(heapSize); +} + +} // namespace vm diff --git a/src/system.h b/src/system.h index 789f615528..03a3d8275f 100644 --- a/src/system.h +++ b/src/system.h @@ -65,6 +65,7 @@ class System: public Allocator { unsigned returnType) = 0; virtual Status load(Library**, const char* name, Library* next) = 0; virtual void abort() = 0; + virtual void dispose() = 0; virtual void* allocate(unsigned size) { void* p = tryAllocate(size); @@ -82,6 +83,12 @@ abort(System* s) ::abort(); } +inline void NO_RETURN +sysAbort(System* s) +{ + abort(s); +} + inline void expect(System* s, bool v) { @@ -100,6 +107,9 @@ assert(System* s, bool v) } #endif +System* +makeSystem(unsigned heapSize); + } // namespace vm #endif//SYSTEM_H