2007-06-20 19:20:25 +00:00
|
|
|
#include "sys/mman.h"
|
|
|
|
#include "sys/types.h"
|
|
|
|
#include "sys/stat.h"
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "sys/time.h"
|
|
|
|
#include "time.h"
|
2007-06-20 19:20:25 +00:00
|
|
|
#include "fcntl.h"
|
2007-06-24 21:49:04 +00:00
|
|
|
#include "dlfcn.h"
|
2007-07-01 21:34:22 +00:00
|
|
|
#include "errno.h"
|
|
|
|
#include "pthread.h"
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
#include "common.h"
|
2007-06-20 19:20:25 +00:00
|
|
|
#include "system.h"
|
|
|
|
#include "heap.h"
|
2007-06-25 02:02:24 +00:00
|
|
|
#include "class-finder.h"
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "run.h"
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
#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
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
void*
|
|
|
|
run(void* t)
|
|
|
|
{
|
|
|
|
static_cast<vm::System::Thread*>(t)->run();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t
|
|
|
|
now()
|
|
|
|
{
|
|
|
|
timeval tv = { 0, 0 };
|
|
|
|
gettimeofday(&tv, 0);
|
|
|
|
return (static_cast<int64_t>(tv.tv_sec) * 1000) +
|
|
|
|
(static_cast<int64_t>(tv.tv_usec) / 1000);
|
|
|
|
}
|
|
|
|
|
2007-06-29 16:42:39 +00:00
|
|
|
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<char*>(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;
|
|
|
|
}
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
const bool Verbose = false;
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
class System: public vm::System {
|
|
|
|
public:
|
2007-07-07 18:09:16 +00:00
|
|
|
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() {
|
2007-07-11 04:19:26 +00:00
|
|
|
if (r) {
|
|
|
|
r->dispose();
|
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm::System* s;
|
|
|
|
vm::System::Runnable* r;
|
|
|
|
pthread_t thread;
|
|
|
|
};
|
|
|
|
|
2007-06-20 21:27:22 +00:00
|
|
|
class Monitor: public vm::System::Monitor {
|
|
|
|
public:
|
2007-07-01 21:34:22 +00:00
|
|
|
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) {
|
2007-07-11 04:19:26 +00:00
|
|
|
unsigned depth = this->depth;
|
|
|
|
this->depth = 0;
|
|
|
|
this->context = 0;
|
2007-07-01 21:34:22 +00:00
|
|
|
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);
|
|
|
|
}
|
2007-07-11 04:19:26 +00:00
|
|
|
this->context = context;
|
|
|
|
this->depth = depth;
|
2007-07-01 21:34:22 +00:00
|
|
|
} else {
|
|
|
|
vm::abort(s);
|
|
|
|
}
|
|
|
|
}
|
2007-06-20 21:27:22 +00:00
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2007-07-07 23:47:35 +00:00
|
|
|
|
|
|
|
virtual void* owner() {
|
|
|
|
return context;
|
|
|
|
}
|
2007-07-01 21:34:22 +00:00
|
|
|
|
|
|
|
virtual void dispose() {
|
2007-07-11 04:19:26 +00:00
|
|
|
assert(s, context == 0);
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_destroy(&mutex);
|
|
|
|
pthread_cond_destroy(&condition);
|
|
|
|
s->free(this);
|
|
|
|
}
|
2007-06-20 21:27:22 +00:00
|
|
|
|
|
|
|
vm::System* s;
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_t mutex;
|
|
|
|
pthread_cond_t condition;
|
|
|
|
void* context;
|
|
|
|
unsigned depth;
|
2007-06-20 21:27:22 +00:00
|
|
|
};
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
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() {
|
2007-07-04 18:15:03 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "close %p\n", p);
|
|
|
|
}
|
|
|
|
|
|
|
|
dlclose(p);
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
if (next_) {
|
|
|
|
next_->dispose();
|
|
|
|
}
|
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm::System* s;
|
|
|
|
void* p;
|
|
|
|
vm::System::Library* next_;
|
|
|
|
};
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
System(unsigned limit): limit(limit), count(0) {
|
|
|
|
pthread_mutex_init(&mutex, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
~System() {
|
|
|
|
pthread_mutex_destroy(&mutex);
|
|
|
|
}
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
virtual bool success(Status s) {
|
|
|
|
return s == 0;
|
|
|
|
}
|
|
|
|
|
2007-06-22 02:13:17 +00:00
|
|
|
virtual void* tryAllocate(unsigned size) {
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_lock(&mutex);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "try %d; count: %d; limit: %d\n",
|
|
|
|
size, count, limit);
|
|
|
|
}
|
|
|
|
|
2007-06-22 02:13:17 +00:00
|
|
|
if (count + size > limit) {
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_unlock(&mutex);
|
2007-06-22 02:13:17 +00:00
|
|
|
return 0;
|
2007-07-01 21:34:22 +00:00
|
|
|
} else {
|
|
|
|
uintptr_t* up = static_cast<uintptr_t*>
|
|
|
|
(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;
|
|
|
|
}
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void free(const void* p) {
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_lock(&mutex);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
if (p) {
|
|
|
|
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
|
2007-06-21 01:38:02 +00:00
|
|
|
if (count < *up) {
|
|
|
|
abort();
|
|
|
|
}
|
2007-06-20 19:20:25 +00:00
|
|
|
count -= *up;
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
if (Verbose) {
|
2007-06-29 16:42:39 +00:00
|
|
|
fprintf(stderr, "free " LD "; count: %d; limit: %d\n",
|
2007-06-22 22:47:57 +00:00
|
|
|
*up, count, limit);
|
|
|
|
}
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
::free(const_cast<uintptr_t*>(up));
|
|
|
|
}
|
2007-07-01 21:34:22 +00:00
|
|
|
|
|
|
|
pthread_mutex_unlock(&mutex);
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
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);
|
2007-07-01 21:34:22 +00:00
|
|
|
assert(this, rv == 0);
|
|
|
|
return 0;
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 21:27:22 +00:00
|
|
|
virtual Status make(vm::System::Monitor** m) {
|
|
|
|
*m = new (vm::System::allocate(sizeof(Monitor))) Monitor(this);
|
|
|
|
return 0;
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
2007-07-11 01:38:06 +00:00
|
|
|
virtual void sleep(int64_t milliseconds) {
|
|
|
|
timespec ts = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 };
|
|
|
|
|
|
|
|
nanosleep(&ts, 0);
|
|
|
|
}
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
|
|
|
unsigned count, unsigned size, unsigned returnType)
|
2007-06-24 21:49:04 +00:00
|
|
|
{
|
2007-06-29 02:58:48 +00:00
|
|
|
return dynamicCall(function, arguments, types, count, size, returnType);
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
2007-06-25 01:34:07 +00:00
|
|
|
virtual Status load(vm::System::Library** lib,
|
|
|
|
const char* name,
|
|
|
|
vm::System::Library* next)
|
|
|
|
{
|
2007-06-29 16:42:39 +00:00
|
|
|
unsigned size = strlen(name) + 7;
|
|
|
|
char buffer[size];
|
|
|
|
snprintf(buffer, size, "lib%s.so", name);
|
|
|
|
|
|
|
|
void* p = dlopen(buffer, RTLD_LAZY);
|
2007-06-24 21:49:04 +00:00
|
|
|
if (p) {
|
2007-07-04 18:15:03 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "open %s as %p\n", buffer, p);
|
|
|
|
}
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
*lib = new (vm::System::allocate(sizeof(Library)))
|
|
|
|
Library(this, p, next);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
virtual void abort() {
|
|
|
|
::abort();
|
|
|
|
}
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
pthread_mutex_t mutex;
|
2007-06-20 19:20:25 +00:00
|
|
|
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:
|
2007-06-21 01:38:02 +00:00
|
|
|
Data(vm::System* system, uint8_t* start, size_t length):
|
|
|
|
system(system),
|
2007-06-20 19:20:25 +00:00
|
|
|
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_);
|
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
system->free(this);
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
vm::System* system;
|
2007-06-20 19:20:25 +00:00
|
|
|
uint8_t* start_;
|
|
|
|
size_t length_;
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual Data* find(const char* className) {
|
2007-06-21 01:38:02 +00:00
|
|
|
Data* d = new (system->allocate(sizeof(Data))) Data(system, 0, 0);
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
for (const char** p = path; *p; ++p) {
|
2007-06-21 01:38:02 +00:00
|
|
|
const char* file = append(system, *p, "/", className, ".class");
|
2007-06-20 19:20:25 +00:00
|
|
|
int fd = open(file, O_RDONLY);
|
2007-06-21 01:38:02 +00:00
|
|
|
system->free(file);
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
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(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;
|
2007-06-20 21:27:22 +00:00
|
|
|
for (Tokenizer t(path, ':'); t.hasMore(); t.next()) ++ count;
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
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());
|
2007-06-21 01:38:02 +00:00
|
|
|
char* p = static_cast<char*>(s->allocate(token.length + 1));
|
2007-06-20 19:20:25 +00:00
|
|
|
memcpy(p, token.s, token.length);
|
|
|
|
p[token.length] = 0;
|
|
|
|
v[i] = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
v[i] = 0;
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2007-07-16 01:03:02 +00:00
|
|
|
int
|
2007-06-20 19:20:25 +00:00
|
|
|
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);
|
|
|
|
|
2007-07-16 01:03:02 +00:00
|
|
|
int exitCode = run(&s, heap, &cf, class_, argc, argv);
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
heap->dispose();
|
|
|
|
|
|
|
|
for (const char** p = pathv; *p; ++p) {
|
|
|
|
s.free(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
s.free(pathv);
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
return exitCode;
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usageAndExit(const char* name)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "usage: %s [-cp <classpath>] [-hs <maximum heap size>] "
|
2007-06-20 21:27:22 +00:00
|
|
|
"<class name> [<argument> ...]\n", name);
|
2007-06-20 19:20:25 +00:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2007-07-16 01:03:02 +00:00
|
|
|
return run(heapSize, path, class_, argc, argv);
|
2007-06-20 19:20:25 +00:00
|
|
|
}
|