blob: 7e61cf1669fd7e5067fe3c12c0dcc5b6823a7f9e [file] [log] [blame]
//===--------- VirtualMachine.h - Registering a VM ------------------------===//
//
// The VMKit project
//
// This file is distributed under the University of Pierre et Marie Curie
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Ultimately, this would be like a generic way of defining a VM. But we're not
// quite there yet.
//
//===----------------------------------------------------------------------===//
#ifndef MVM_VIRTUALMACHINE_H
#define MVM_VIRTUALMACHINE_H
#include "mvm/Allocator.h"
#include "mvm/Threads/Cond.h"
#include "mvm/Threads/Locks.h"
#include <cassert>
#include <map>
namespace jnjvm {
class JavaCompiler;
class JnjvmClassLoader;
}
class gc;
namespace mvm {
// Same values than JikesRVM
#define INITIAL_QUEUE_SIZE 256
#define GROW_FACTOR 2
class CompilationUnit;
class VirtualMachine;
class ReferenceQueue {
private:
gc** References;
uint32 QueueLength;
uint32 CurrentIndex;
mvm::SpinLock QueueLock;
uint8_t semantics;
gc* processReference(gc*, VirtualMachine*);
public:
static const uint8_t WEAK = 1;
static const uint8_t SOFT = 2;
static const uint8_t PHANTOM = 3;
ReferenceQueue(uint8_t s) {
References = new gc*[INITIAL_QUEUE_SIZE];
QueueLength = INITIAL_QUEUE_SIZE;
CurrentIndex = 0;
semantics = s;
}
void addReference(gc* ref) {
QueueLock.acquire();
if (CurrentIndex >= QueueLength) {
uint32 newLength = QueueLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle reference overflow yet!\n");
abort();
}
for (uint32 i = 0; i < QueueLength; ++i) newQueue[i] = References[i];
delete[] References;
References = newQueue;
QueueLength = newLength;
}
References[CurrentIndex++] = ref;
QueueLock.release();
}
void acquire() {
QueueLock.acquire();
}
void release() {
QueueLock.release();
}
void scan(VirtualMachine* vm);
};
/// VirtualMachine - This class is the root of virtual machine classes. It
/// defines what a VM should be.
///
class VirtualMachine : public mvm::PermanentObject {
friend class ReferenceQueue;
protected:
VirtualMachine() :
WeakReferencesQueue(ReferenceQueue::WEAK),
SoftReferencesQueue(ReferenceQueue::SOFT),
PhantomReferencesQueue(ReferenceQueue::PHANTOM) {
#ifdef SERVICE
memoryLimit = ~0;
executionLimit = ~0;
GCLimit = ~0;
threadLimit = ~0;
parent = this;
status = 1;
_since_last_collection = 4*1024*1024;
#endif
FinalizationQueue = new gc*[INITIAL_QUEUE_SIZE];
QueueLength = INITIAL_QUEUE_SIZE;
CurrentIndex = 0;
ToBeFinalized = new gc*[INITIAL_QUEUE_SIZE];
ToBeFinalizedLength = INITIAL_QUEUE_SIZE;
CurrentFinalizedIndex = 0;
ToEnqueue = new gc*[INITIAL_QUEUE_SIZE];
ToEnqueueLength = INITIAL_QUEUE_SIZE;
ToEnqueueIndex = 0;
}
public:
virtual void tracer() {}
virtual ~VirtualMachine() {}
/// runApplication - Run an application. The application name is in
/// the arguments, hence it is the virtual machine's job to parse them.
virtual void runApplication(int argc, char** argv) = 0;
/// waitForExit - Wait until the virtual machine stops its execution.
virtual void waitForExit() = 0;
static jnjvm::JnjvmClassLoader* initialiseJVM(jnjvm::JavaCompiler* C,
bool dlLoad = true);
static VirtualMachine* createJVM(jnjvm::JnjvmClassLoader* C = 0);
static CompilationUnit* initialiseCLIVM();
static VirtualMachine* createCLIVM(CompilationUnit* C = 0);
private:
/// WeakReferencesQueue - The queue of weak references.
///
ReferenceQueue WeakReferencesQueue;
/// SoftReferencesQueue - The queue of soft references.
///
ReferenceQueue SoftReferencesQueue;
/// PhantomReferencesQueue - The queue of phantom references.
///
ReferenceQueue PhantomReferencesQueue;
/// FinalizationQueueLock - A lock to protect access to the queue.
///
mvm::SpinLock FinalizationQueueLock;
/// finalizationQueue - A list of allocated objets that contain a finalize
/// method.
///
gc** FinalizationQueue;
/// CurrentIndex - Current index in the queue of finalizable objects.
///
uint32 CurrentIndex;
/// QueueLength - Current length of the queue of finalizable objects.
///
uint32 QueueLength;
/// growFinalizationQueue - Grow the queue of finalizable objects.
///
void growFinalizationQueue();
/// ToBeFinalized - List of objects that are scheduled to be finalized.
///
gc** ToBeFinalized;
/// ToBeFinalizedLength - Current length of the queue of objects scheduled
/// for finalization.
///
uint32 ToBeFinalizedLength;
/// CurrentFinalizedIndex - The current index in the ToBeFinalized queue
/// that will be sceduled for finalization.
///
uint32 CurrentFinalizedIndex;
/// growToBeFinalizedQueue - Grow the queue of the to-be finalized objects.
///
void growToBeFinalizedQueue();
/// finalizationCond - Condition variable to wake up finalization threads.
///
mvm::Cond FinalizationCond;
/// finalizationLock - Lock for the condition variable.
///
mvm::LockNormal FinalizationLock;
gc** ToEnqueue;
uint32 ToEnqueueLength;
uint32 ToEnqueueIndex;
/// ToEnqueueLock - A lock to protect access to the queue.
///
mvm::LockNormal EnqueueLock;
mvm::Cond EnqueueCond;
mvm::SpinLock ToEnqueueLock;
void addToEnqueue(gc* obj) {
if (ToEnqueueIndex >= ToEnqueueLength) {
uint32 newLength = ToEnqueueLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle reference overflow yet!\n");
abort();
}
for (uint32 i = 0; i < QueueLength; ++i) newQueue[i] = ToEnqueue[i];
delete[] ToEnqueue;
ToEnqueue = newQueue;
ToEnqueueLength = newLength;
}
ToEnqueue[ToEnqueueIndex++] = obj;
}
protected:
/// invokeFinalizer - Invoke the finalizer of the object. This may involve
/// changing the environment, e.g. going to native to Java.
///
virtual void invokeFinalizer(gc*) {}
public:
/// finalizerStart - The start function of a finalizer. Will poll the
/// finalizationQueue.
///
static void finalizerStart(mvm::Thread*);
/// enqueueStart - The start function of a thread for references. Will poll
/// ToEnqueue.
///
static void enqueueStart(mvm::Thread*);
/// addFinalizationCandidate - Add an object to the queue of objects with
/// a finalization method.
///
void addFinalizationCandidate(gc*);
/// scanFinalizationQueue - Scan objets with a finalized method and schedule
/// them for finalization if they are not live.
///
void scanFinalizationQueue();
/// wakeUpFinalizers - Wake the finalizers.
///
void wakeUpFinalizers() { FinalizationCond.broadcast(); }
/// wakeUpEnqueue - Wake the threads for enqueueing.
///
void wakeUpEnqueue() { EnqueueCond.broadcast(); }
virtual void startCollection() {
FinalizationQueueLock.acquire();
ToEnqueueLock.acquire();
SoftReferencesQueue.acquire();
WeakReferencesQueue.acquire();
PhantomReferencesQueue.acquire();
}
virtual void endCollection() {
FinalizationQueueLock.release();
ToEnqueueLock.release();
SoftReferencesQueue.release();
WeakReferencesQueue.release();
PhantomReferencesQueue.release();
}
/// scanWeakReferencesQueue - Scan all weak references. Called by the GC
/// before scanning the finalization queue.
///
void scanWeakReferencesQueue() {
WeakReferencesQueue.scan(this);
}
/// scanSoftReferencesQueue - Scan all soft references. Called by the GC
/// before scanning the finalization queue.
///
void scanSoftReferencesQueue() {
SoftReferencesQueue.scan(this);
}
/// scanPhantomReferencesQueue - Scan all phantom references. Called by the GC
/// after the finalization queue.
///
void scanPhantomReferencesQueue() {
PhantomReferencesQueue.scan(this);
}
/// addWeakReference - Add a weak reference to the queue.
///
void addWeakReference(gc* ref) {
WeakReferencesQueue.addReference(ref);
}
/// addSoftReference - Add a weak reference to the queue.
///
void addSoftReference(gc* ref) {
SoftReferencesQueue.addReference(ref);
}
/// addPhantomReference - Add a weak reference to the queue.
///
void addPhantomReference(gc* ref) {
PhantomReferencesQueue.addReference(ref);
}
/// clearReferent - Clear the referent in a reference. Should be overriden
/// by the VM.
///
virtual void clearReferent(gc*) {}
/// getReferent - Get the referent of the reference. Should be overriden
/// by the VM.
//
virtual gc* getReferent(gc*) { return 0; }
/// enqueueReference - Calls the enqueue method. Should be overriden
/// by the VM.
///
virtual bool enqueueReference(gc*) { return false; }
protected:
/// JavaFunctionMap - Map of Java method to function pointers. This map is
/// used when walking the stack so that VMKit knows which Java method is
/// executing on the stack.
///
std::map<void*, void*> Functions;
/// FunctionMapLock - Spin lock to protect the JavaFunctionMap.
///
mvm::SpinLock FunctionMapLock;
public:
/// addMethodInFunctionMap - A new method pointer in the function map.
///
template <typename T>
void addMethodInFunctionMap(T* meth, void* addr) {
FunctionMapLock.acquire();
Functions.insert(std::make_pair((void*)addr, meth));
FunctionMapLock.release();
}
/// IPToJavaMethod - Map an instruction pointer to the Java method.
///
template <typename T> T* IPToMethod(void* ip) {
FunctionMapLock.acquire();
std::map<void*, void*>::iterator I = Functions.upper_bound(ip);
assert(I != Functions.begin() && "Wrong value in function map");
FunctionMapLock.release();
// Decrement because we had the "greater than" value.
I--;
return (T*)I->second;
}
#ifdef ISOLATE
size_t IsolateID;
#endif
#ifdef SERVICE
uint64_t memoryUsed;
uint64_t gcTriggered;
uint64_t executionTime;
uint64_t numThreads;
CompilationUnit* CU;
virtual void stopService() {}
uint64_t memoryLimit;
uint64_t executionLimit;
uint64_t threadLimit;
uint64_t GCLimit;
int _since_last_collection;
VirtualMachine* parent;
uint32 status;
#endif
mvm::Allocator gcAllocator;
};
} // end namespace mvm
#endif // MVM_VIRTUALMACHINE_H