2010-12-06 03:21:09 +00:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-06-03 01:57:37 +00:00
|
|
|
#ifndef SYSTEM_H
|
|
|
|
#define SYSTEM_H
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
2007-06-18 19:23:44 +00:00
|
|
|
namespace vm {
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
class System {
|
2007-06-03 01:57:37 +00:00
|
|
|
public:
|
2007-06-20 21:27:22 +00:00
|
|
|
typedef intptr_t Status;
|
2007-06-03 01:57:37 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
enum FileType {
|
2008-11-21 23:20:35 +00:00
|
|
|
TypeUnknown,
|
|
|
|
TypeDoesNotExist,
|
|
|
|
TypeFile,
|
|
|
|
TypeDirectory
|
2007-09-17 00:13:36 +00:00
|
|
|
};
|
|
|
|
|
2007-06-03 01:57:37 +00:00
|
|
|
class Thread {
|
|
|
|
public:
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual void interrupt() = 0;
|
2007-07-07 18:09:16 +00:00
|
|
|
virtual void join() = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
class ThreadVisitor {
|
|
|
|
public:
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
virtual void visit(void* ip, void* stack) = 0;
|
2008-04-09 19:08:13 +00:00
|
|
|
};
|
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
class Runnable {
|
|
|
|
public:
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual void attach(Thread*) = 0;
|
|
|
|
virtual void run() = 0;
|
|
|
|
virtual bool interrupted() = 0;
|
|
|
|
virtual void setInterrupted(bool v) = 0;
|
2007-06-03 01:57:37 +00:00
|
|
|
};
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
class Mutex {
|
|
|
|
public:
|
|
|
|
virtual void acquire() = 0;
|
|
|
|
virtual void release() = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2007-06-03 01:57:37 +00:00
|
|
|
class Monitor {
|
|
|
|
public:
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual bool tryAcquire(Thread* context) = 0;
|
|
|
|
virtual void acquire(Thread* context) = 0;
|
|
|
|
virtual void release(Thread* context) = 0;
|
|
|
|
virtual bool wait(Thread* context, int64_t time) = 0;
|
|
|
|
virtual void notify(Thread* context) = 0;
|
|
|
|
virtual void notifyAll(Thread* context) = 0;
|
|
|
|
virtual Thread* owner() = 0;
|
2007-06-03 01:57:37 +00:00
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
class Local {
|
|
|
|
public:
|
|
|
|
virtual void* get() = 0;
|
|
|
|
virtual void set(void* p) = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
class Region {
|
|
|
|
public:
|
|
|
|
virtual const uint8_t* start() = 0;
|
|
|
|
virtual size_t length() = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
class Directory {
|
|
|
|
public:
|
|
|
|
virtual const char* next() = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
class Library {
|
|
|
|
public:
|
2010-09-10 21:05:29 +00:00
|
|
|
virtual void* resolve(const char* symbol) = 0;
|
2007-09-18 23:30:09 +00:00
|
|
|
virtual const char* name() = 0;
|
2007-06-24 01:39:49 +00:00
|
|
|
virtual Library* next() = 0;
|
2008-01-25 23:38:26 +00:00
|
|
|
virtual void setNext(Library* lib) = 0;
|
|
|
|
virtual void disposeAll() = 0;
|
2007-06-24 01:39:49 +00:00
|
|
|
};
|
|
|
|
|
2007-12-30 22:24:48 +00:00
|
|
|
class SignalHandler {
|
|
|
|
public:
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
virtual bool handleSignal(void** ip, void** stack, void** thread) = 0;
|
2007-12-30 22:24:48 +00:00
|
|
|
};
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
class MonitorResource {
|
|
|
|
public:
|
|
|
|
MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) {
|
|
|
|
m->acquire(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
~MonitorResource() {
|
|
|
|
m->release(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
System::Thread* t;
|
|
|
|
System::Monitor* m;
|
|
|
|
};
|
|
|
|
|
2007-06-03 01:57:37 +00:00
|
|
|
virtual bool success(Status) = 0;
|
2008-04-13 18:15:04 +00:00
|
|
|
virtual void* tryAllocate(unsigned sizeInBytes) = 0;
|
|
|
|
virtual void free(const void* p) = 0;
|
|
|
|
virtual void* tryAllocateExecutable(unsigned sizeInBytes) = 0;
|
|
|
|
virtual void freeExecutable(const void* p, unsigned sizeInBytes) = 0;
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual Status attach(Runnable*) = 0;
|
2007-07-07 18:09:16 +00:00
|
|
|
virtual Status start(Runnable*) = 0;
|
2008-01-13 22:05:08 +00:00
|
|
|
virtual Status make(Mutex**) = 0;
|
2007-06-03 01:57:37 +00:00
|
|
|
virtual Status make(Monitor**) = 0;
|
2007-09-10 23:33:58 +00:00
|
|
|
virtual Status make(Local**) = 0;
|
2007-12-30 22:24:48 +00:00
|
|
|
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
2010-12-20 00:47:21 +00:00
|
|
|
virtual Status handleDivideByZero(SignalHandler* handler) = 0;
|
2008-04-09 19:08:13 +00:00
|
|
|
virtual Status visit(Thread* thread, Thread* target,
|
|
|
|
ThreadVisitor* visitor) = 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) = 0;
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual Status map(Region**, const char* name) = 0;
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual FileType stat(const char* name, unsigned* length) = 0;
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Status open(Directory**, const char* name) = 0;
|
2010-09-20 23:31:23 +00:00
|
|
|
virtual const char* libraryPrefix() = 0;
|
|
|
|
virtual const char* librarySuffix() = 0;
|
|
|
|
virtual Status load(Library**, const char* name) = 0;
|
2007-10-24 15:46:09 +00:00
|
|
|
virtual char pathSeparator() = 0;
|
2010-09-20 23:31:23 +00:00
|
|
|
virtual char fileSeparator() = 0;
|
2007-08-18 22:35:22 +00:00
|
|
|
virtual int64_t now() = 0;
|
2007-10-24 15:46:09 +00:00
|
|
|
virtual void exit(int code) = 0;
|
2007-06-18 04:25:42 +00:00
|
|
|
virtual void abort() = 0;
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual void dispose() = 0;
|
2007-06-03 01:57:37 +00:00
|
|
|
};
|
|
|
|
|
2008-08-19 23:38:37 +00:00
|
|
|
inline void*
|
|
|
|
allocate(System* s, unsigned size)
|
|
|
|
{
|
|
|
|
void* p = s->tryAllocate(size);
|
|
|
|
if (p == 0) s->abort();
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
#define ACQUIRE_MONITOR(t, m) \
|
|
|
|
System::MonitorResource MAKE_NAME(monitorResource_) (t, m)
|
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
inline void NO_RETURN
|
|
|
|
abort(System* s)
|
|
|
|
{
|
|
|
|
s->abort(); // this should not return
|
|
|
|
::abort();
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
inline void NO_RETURN
|
|
|
|
sysAbort(System* s)
|
|
|
|
{
|
|
|
|
abort(s);
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
inline void
|
|
|
|
expect(System* s, bool v)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(not v)) abort(s);
|
|
|
|
}
|
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
#ifdef NDEBUG
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2007-08-19 19:45:51 +00:00
|
|
|
# define assert(a, b)
|
2009-08-27 00:26:44 +00:00
|
|
|
# define vm_assert(a, b)
|
2007-07-28 21:28:25 +00:00
|
|
|
|
|
|
|
#else // not NDEBUG
|
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
inline void
|
|
|
|
assert(System* s, bool v)
|
|
|
|
{
|
2007-06-24 19:57:00 +00:00
|
|
|
expect(s, v);
|
2007-06-22 23:17:13 +00:00
|
|
|
}
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
# define vm_assert(a, b) vm::assert(a, b)
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
#endif // not NDEBUG
|
2007-06-22 23:17:13 +00:00
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
System*
|
2008-11-11 15:20:49 +00:00
|
|
|
makeSystem(const char* crashDumpDirectory);
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2007-06-18 19:23:44 +00:00
|
|
|
} // namespace vm
|
|
|
|
|
2007-06-03 01:57:37 +00:00
|
|
|
#endif//SYSTEM_H
|