diff --git a/makefile b/makefile index e85eef1e39..1fbd4b5920 100644 --- a/makefile +++ b/makefile @@ -47,7 +47,8 @@ interpreter-depends = \ $(src)/vm.h interpreter-sources = \ $(src)/vm.cpp \ - $(src)/heap.cpp + $(src)/heap.cpp \ + $(src)/main.cpp interpreter-objects = $(call cpp-objects,$(interpreter-sources),$(src)) interpreter-cflags = $(slow) $(cflags) diff --git a/src/class_finder.h b/src/class_finder.h index 1c52ee0f23..d46061ab73 100644 --- a/src/class_finder.h +++ b/src/class_finder.h @@ -7,9 +7,16 @@ namespace vm { class ClassFinder { public: + class Data { + public: + virtual ~Data() { } + virtual const uint8_t* start() = 0; + virtual size_t length() = 0; + virtual void dispose() = 0; + }; + virtual ~ClassFinder() { } - virtual const uint8_t* find(const char* className, unsigned* size) = 0; - virtual void free(const uint8_t* class_) = 0; + virtual Data* find(const char* className) = 0; }; } // namespace vm diff --git a/src/heap.cpp b/src/heap.cpp index 28492d930e..c88b0dbb06 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -238,12 +238,8 @@ class Segment { map(map) { if (capacity) { - unsigned count = footprint(capacity) * BytesPerWord; - data = static_cast<uintptr_t*>(system(context)->allocate(&count)); - - if (count != footprint(capacity) * BytesPerWord) { - abort(context); - } + data = static_cast<uintptr_t*> + (system(context)->allocate(footprint(capacity) * BytesPerWord)); if (map) { map->setSegment(this); @@ -998,6 +994,8 @@ collect(Context* c) } // namespace +namespace vm { + Heap* makeHeap(System* system) { @@ -1047,11 +1045,7 @@ makeHeap(System* system) Context c; }; - unsigned count = sizeof(Heap); - void* p = system->allocate(&count); - if (count != sizeof(Heap)) { - system->abort(); - } - - return new (p) Heap(system); + return new (system->allocate(sizeof(Heap))) Heap(system); } + +} // namespace vm diff --git a/src/heap.h b/src/heap.h index f618435268..3203ea4e1a 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1,6 +1,8 @@ #ifndef HEAP_H #define HEAP_H +#include "system.h" + namespace vm { class Heap { @@ -38,6 +40,8 @@ class Heap { virtual void dispose() = 0; }; +Heap* makeHeap(System* system); + } // namespace vm #endif//HEAP_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000000..8723e0f865 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,244 @@ +#include "sys/mman.h" +#include "sys/types.h" +#include "sys/stat.h" +#include "fcntl.h" +#include "system.h" +#include "heap.h" +#include "vm.h" + +using namespace vm; + +namespace { + +class System: public vm::System { + public: + System(unsigned limit): limit(limit), count(0) { } + + virtual bool success(Status s) { + return s == 0; + } + + virtual void* allocate(unsigned* size) { + if (count + *size > limit) { + *size = limit - count; + } + + uintptr_t* up = static_cast<uintptr_t*>(malloc(*size + sizeof(uintptr_t))); + if (up == 0) abort(); + + *up = *size; + return up + 1; + } + + virtual void free(const void* p) { + if (p) { + const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1; + count -= *up; + ::free(const_cast<uintptr_t*>(up)); + } + } + + virtual Status start(Thread*) { + return 1; + } + + virtual Status make(Monitor**) { + return 1; + } + + virtual void abort() { + ::abort(); + } + + unsigned limit; + unsigned count; +}; + +const char* +append(vm::System* s, const char* a, const char* b, const char* c) +{ + unsigned al = strlen(a); + unsigned bl = strlen(b); + unsigned cl = strlen(c); + char* p = static_cast<char*>(s->allocate(al + bl + cl + 1)); + memcpy(p, a, al); + memcpy(p + al, b, bl); + memcpy(p + al + bl, c, cl + 1); + return p; +} + +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(uint8_t* start, size_t length): + 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_); + } + } + + uint8_t* start_; + size_t length_; + }; + + virtual Data* find(const char* className) { + Data* d = new (system->allocate(sizeof(Data))) Data(0, 0); + + for (const char** p = path; *p; ++p) { + const char* file = append(system, *p, "/", className); + int fd = open(file, O_RDONLY); + 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<uint8_t*>(data); + d->length_ = s.st_size; + return d; + } + } + } + system->free(file); + } + + 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();) ++ count; + + const char** v = static_cast<const char**> + (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<char*>(s->allocate(token.length)); + memcpy(p, token.s, token.length); + p[token.length] = 0; + v[i] = p; + } + + v[i] = 0; + + return v; +} + +void +run(unsigned heapSize, const char* path, const char* class_, int argc, + const char** argv) +{ + System s(heapSize); + + const char** pathv = parsePath(&s, path); + ClassFinder cf(&s, pathv); + + Heap* heap = makeHeap(&s); + + run(&s, heap, &cf, class_, argc, argv); + + heap->dispose(); + + for (const char** p = pathv; *p; ++p) { + s.free(*p); + } + + s.free(pathv); +} + +void +usageAndExit(const char* name) +{ + fprintf(stderr, "usage: %s [-cp <classpath>] [-hs <maximum heap size>] " + "<class name> [<argument> ...]", name); + exit(-1); +} + +} // namespace + +int +main(int ac, const char** av) +{ + unsigned heapSize = 4 * 1024 * 1024; + const char* path = "."; + const char* class_ = 0; + int argc = 0; + const char** argv = 0; + + for (int i = 1; i < ac; ++i) { + if (strcmp(av[i], "-cp") == 0) { + path = av[++i]; + } else if (strcmp(av[i], "-hs") == 0) { + heapSize = atoi(av[++i]); + } else { + class_ = av[i++]; + if (i < ac) { + argc = ac - i; + argv = av + i; + i = ac; + } + } + } + + if (class_ == 0) { + usageAndExit(av[0]); + } + + run(heapSize, path, class_, argc, argv); + + return 0; +} diff --git a/src/system.h b/src/system.h index d8214ed493..0ab5258952 100644 --- a/src/system.h +++ b/src/system.h @@ -27,39 +27,23 @@ class System { virtual void dispose() = 0; }; - class File { - public: - virtual ~File() { } - virtual Status read(uint8_t* data, unsigned* size) = 0; - virtual Status write(const uint8_t* data, unsigned size) = 0; - virtual Status close() = 0; - }; - - static const int ReadOnly = 00; - static const int WriteOnly = 01; - static const int ReadWrite = 02; - static const int Append = 02000; - static const int Create = 0100; - - static const int UserRead = 0400; - static const int UserWrite = 0200; - static const int UserExecute = 0100; - static const int GroupRead = 040; - static const int GroupWrite = 020; - static const int GroupExecute = 010; - static const int OtherRead = 04; - static const int OtherWrite = 02; - static const int OtherExecute = 01; - virtual ~System() { } virtual bool success(Status) = 0; virtual void* allocate(unsigned* size) = 0; - virtual void free(void*) = 0; + virtual void free(const void*) = 0; virtual Status start(Thread*) = 0; virtual Status make(Monitor**) = 0; - virtual Status open(File**, const char* path, int flags, int mode) = 0; virtual void abort() = 0; + + void* allocate(unsigned size) { + unsigned requested = size; + void* p = allocate(&size); + if (size != requested) { + abort(); + } + return p; + } }; } // namespace vm diff --git a/src/vm.cpp b/src/vm.cpp index 97caa24799..3785d7e897 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1429,15 +1429,13 @@ resolveClass(Thread* t, object spec) object class_ = hashMapFind (t, t->vm->classMap, spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { - unsigned size; - const uint8_t* data = t->vm->classFinder->find - (reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)), &size); + ClassFinder::Data* data = t->vm->classFinder->find + (reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0))); if (data) { // parse class file - class_ = parseClass(t, data, size); - - t->vm->classFinder->free(data); + class_ = parseClass(t, data->start(), data->length()); + data->dispose(); PROTECT(t, class_);