| //===--------- 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/MethodInfo.h" |
| #include "mvm/Threads/CollectionRV.h" |
| #include "mvm/Threads/Cond.h" |
| #include "mvm/Threads/Locks.h" |
| #include "mvm/GC/GC.h" |
| |
| #include <cassert> |
| #include <map> |
| |
| namespace j3 { |
| class JavaCompiler; |
| class JnjvmClassLoader; |
| } |
| |
| class gc; |
| |
| namespace mvm { |
| |
| class FunctionMap { |
| public: |
| /// Functions - Map of applicative methods to function pointers. This map is |
| /// used when walking the stack so that VMKit knows which applicative method |
| /// is executing on the stack. |
| /// |
| std::map<void*, MethodInfo*> Functions; |
| |
| /// FunctionMapLock - Spin lock to protect the Functions map. |
| /// |
| mvm::SpinLock FunctionMapLock; |
| }; |
| |
| /// StartEndFunctionMap - This map is for functions for which we have |
| /// a start and end address. |
| /// |
| class StartEndFunctionMap : public FunctionMap { |
| public: |
| /// addMethodInFunctionMap - A new method pointer in the function map. |
| /// |
| void addMethodInfo(MethodInfo* meth, void* start, void* end) { |
| FunctionMapLock.acquire(); |
| Functions.insert(std::make_pair(start, meth)); |
| Functions.insert(std::make_pair(end, meth)); |
| FunctionMapLock.release(); |
| } |
| |
| /// IPToMethodInfo - Map an instruction pointer to the MethodInfo. |
| /// |
| MethodInfo* IPToMethodInfo(void* ip) { |
| FunctionMapLock.acquire(); |
| std::map<void*, MethodInfo*>::iterator I = Functions.upper_bound(ip); |
| MethodInfo* res = 0; |
| if (I != Functions.end() && I != Functions.begin()) { |
| res = I->second; |
| if ((--I)->second != res) res = 0; |
| } |
| FunctionMapLock.release(); |
| return res; |
| } |
| }; |
| |
| /// StartFunctionMap - This map is for static functions where getting an end |
| /// address is cumbersome. |
| /// |
| class StartFunctionMap : public FunctionMap { |
| public: |
| /// addMethodInFunctionMap - A new method pointer in the function map. |
| /// |
| void addMethodInfo(MethodInfo* meth, void* addr) { |
| FunctionMapLock.acquire(); |
| Functions.insert(std::make_pair((void*)addr, meth)); |
| FunctionMapLock.release(); |
| } |
| |
| /// IPToMethodInfo - Map an instruction pointer to the MethodInfo. |
| /// |
| MethodInfo* IPToMethodInfo(void* ip); |
| |
| }; |
| |
| class SharedStartFunctionMap : public StartFunctionMap { |
| public: |
| BumpPtrAllocator* StaticAllocator; |
| bool initialized; |
| SharedStartFunctionMap() { |
| initialized = false; |
| } |
| |
| void initialize(); |
| }; |
| |
| |
| |
| // 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; |
| } |
| |
| ~ReferenceQueue() { |
| delete[] References; |
| } |
| |
| 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(mvm::BumpPtrAllocator &Alloc) : |
| allocator(Alloc), |
| 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; |
| |
| mainThread = 0; |
| NumberOfThreads = 0; |
| if (!SharedStaticFunctions.initialized) SharedStaticFunctions.initialize(); |
| } |
| public: |
| |
| /// allocator - Bump pointer allocator to allocate permanent memory |
| /// related to this VM. |
| /// |
| mvm::BumpPtrAllocator& allocator; |
| |
| /// mainThread - The main thread of this VM. |
| /// |
| mvm::Thread* mainThread; |
| |
| /// NumberOfThreads - The number of threads that currently run under this VM. |
| /// |
| uint32_t NumberOfThreads; |
| |
| /// ThreadLock - Lock to create or destroy a new thread. |
| /// |
| mvm::SpinLock ThreadLock; |
| |
| /// setMainThread - Set the main thread of this VM. |
| /// |
| void setMainThread(mvm::Thread* th) { mainThread = th; } |
| |
| /// getMainThread - Get the main thread of this VM. |
| /// |
| mvm::Thread* getMainThread() const { return mainThread; } |
| |
| /// addThread - Add a new thread to the list of threads. |
| /// |
| void addThread(mvm::Thread* th) { |
| ThreadLock.lock(); |
| NumberOfThreads++; |
| if (th != mainThread) { |
| if (mainThread) th->append(mainThread); |
| else mainThread = th; |
| } |
| ThreadLock.unlock(); |
| } |
| |
| /// removeThread - Remove the thread from the list of threads. |
| /// |
| void removeThread(mvm::Thread* th) { |
| ThreadLock.lock(); |
| NumberOfThreads--; |
| if (mainThread == th) mainThread = (Thread*)th->next(); |
| th->remove(); |
| if (!NumberOfThreads) mainThread = 0; |
| ThreadLock.unlock(); |
| } |
| |
| |
| virtual void tracer(); |
| |
| virtual ~VirtualMachine() { |
| if (scanner) delete scanner; |
| delete[] FinalizationQueue; |
| delete[] ToBeFinalized; |
| delete[] ToEnqueue; |
| } |
| |
| /// 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 j3::JnjvmClassLoader* initialiseJVM(j3::JavaCompiler* C, |
| bool dlLoad = true); |
| static VirtualMachine* createJVM(j3::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** getReferentPtr(gc*) { return 0; } |
| |
| /// setReferent - Set the referent of the reference. Should be overriden |
| /// by the VM. |
| virtual void setReferent(gc* reference, gc* referent) { } |
| |
| /// enqueueReference - Calls the enqueue method. Should be overriden |
| /// by the VM. |
| /// |
| virtual bool enqueueReference(gc*) { return false; } |
| |
| |
| public: |
| |
| /// scanner - Scanner of threads' stacks. |
| /// |
| mvm::StackScanner* scanner; |
| |
| mvm::StackScanner* getScanner() { |
| return scanner; |
| } |
| |
| /// rendezvous - The rendezvous implementation for garbage collection. |
| /// |
| CollectionRV rendezvous; |
| |
| |
| StartEndFunctionMap RuntimeFunctions; |
| static StartEndFunctionMap SharedRuntimeFunctions; |
| StartFunctionMap StaticFunctions; |
| static SharedStartFunctionMap SharedStaticFunctions; |
| |
| MethodInfo* IPToMethodInfo(void* ip); |
| |
| #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 |
| |
| }; |
| |
| |
| } // end namespace mvm |
| #endif // MVM_VIRTUALMACHINE_H |