blob: 55774bc6ddb97da5b82e93c9717c85776e47a01b [file] [log] [blame]
//===------------- VMObject.cpp - VM object definition --------------------===//
//
// N3
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include "mvm/Threads/Locks.h"
#include "VMClass.h"
#include "VMObject.h"
#include "VMThread.h"
#include "N3.h"
using namespace n3;
N3VirtualTable LockObj::_VT((uintptr_t)LockObj::_destroy,
(uintptr_t)0,
(uintptr_t)mvm::Object::default_tracer,
(uintptr_t)LockObj::_print,
(uintptr_t)mvm::Object::default_hashCode);
void *N3VirtualTable::operator new(size_t size, mvm::BumpPtrAllocator &allocator, size_t totalVtSize) {
//printf("Allocate N3VirtualTable with %d elements\n", totalVtSize);
return allocator.Allocate(totalVtSize * sizeof(uintptr_t), "N3VirtualTable");
}
N3VirtualTable::N3VirtualTable() {
}
N3VirtualTable::N3VirtualTable(N3VirtualTable *baseVt, uint32 baseVtSize, uint32 totalSize) {
memcpy(this, baseVt, baseVtSize * sizeof(uintptr_t));
}
N3VirtualTable::N3VirtualTable(uintptr_t d, uintptr_t o, uintptr_t t, uintptr_t p, uintptr_t h) : VirtualTable(d, o, t) {
print = p;
hashCode = h;
}
uint32 N3VirtualTable::baseVtSize() {
return sizeof(N3VirtualTable) / sizeof(uintptr_t);
}
LockObj* LockObj::allocate() {
declare_gcroot(LockObj*, res) = new(&_VT) LockObj();
res->threads = new std::vector<VMThread*>();
res->lock = new mvm::LockRecursive();
return res;
}
void LockObj::_print(const LockObj *self, mvm::PrintBuffer* buf) {
llvm_gcroot(self, 0);
buf->write("Lock<>");
}
void LockObj::_destroy(LockObj *self) {
llvm_gcroot(self, 0);
delete self->threads;
delete self->lock;
}
void LockObj::notify(LockObj *self) {
llvm_gcroot(self, 0);
for (std::vector<VMThread*>::iterator i = self->threads->begin(),
e = self->threads->end(); i!= e; ++i) {
VMThread* cur = *i;
cur->lock->lock();
if (cur->interruptFlag != 0) {
cur->lock->unlock();
continue;
} else {
declare_gcroot(VMObject *, th) = cur->ooo_appThread;
if (th != 0) {
cur->varcond->signal();
cur->lock->unlock();
self->threads->erase(i);
break;
} else { // dead thread
self->threads->erase(i);
}
}
}
}
void LockObj::notifyAll(LockObj *self) {
llvm_gcroot(self, 0);
for (std::vector<VMThread*>::iterator i = self->threads->begin(),
e = self->threads->end(); i!= e; ++i) {
VMThread* cur = *i;
cur->lock->lock();
cur->varcond->signal();
cur->lock->unlock();
self->threads->erase(i);
}
}
void LockObj::wait(LockObj *self, VMThread* th) {
llvm_gcroot(self, 0);
self->threads->push_back(th);
}
void LockObj::remove(LockObj *self, VMThread* th) {
llvm_gcroot(self, 0);
for (std::vector<VMThread*>::iterator i = self->threads->begin(),
e = self->threads->end(); i!= e; ++i) {
if (*i == th) {
self->threads->erase(i);
break;
}
}
}
void LockObj::aquire(LockObj *self) {
llvm_gcroot(self, 0);
self->lock->lock();
}
void LockObj::release(LockObj *self) {
llvm_gcroot(self, 0);
self->lock->unlock();
}
bool LockObj::owner(LockObj *self) {
llvm_gcroot(self, 0);
return self->lock->selfOwner();
}
static LockObj* myLock(VMObject* obj) {
llvm_gcroot(obj, 0);
verifyNull(obj);
declare_gcroot(LockObj*, lock) = obj->lockObj;
if (lock == 0) {
VMObject::globalLock->lock();
lock = obj->lockObj;
if (lock == 0) {
lock = LockObj::allocate();
obj->lockObj = lock;
}
VMObject::globalLock->unlock();
}
return lock;
}
void VMObject::initialise(VMObject* self, VMCommonClass* cl) {
llvm_gcroot(self, 0);
self->classOf = cl;
self->lockObj = 0;
}
void VMObject::_print(const VMObject *self, mvm::PrintBuffer* buf) {
llvm_gcroot(self, 0);
buf->write("VMObject<");
self->classOf->print(buf);
buf->write("@0x");
buf->writePtr((void*)self->hashCode());
buf->write(">");
}
void VMObject::aquire(VMObject* self) {
llvm_gcroot(self, 0);
declare_gcroot(LockObj*, lock) = myLock(self);
LockObj::aquire(lock);
}
void VMObject::unlock(VMObject* self) {
llvm_gcroot(self, 0);
verifyNull(self);
declare_gcroot(LockObj*, lock) = myLock(self);
LockObj::release(lock);
}
void VMObject::waitIntern(VMObject* self, struct timeval* info, bool timed) {
llvm_gcroot(self, 0);
declare_gcroot(LockObj *, l) = myLock(self);
bool owner = LockObj::owner(l);
if (owner) {
VMThread* thread = VMThread::get();
mvm::Lock* mutexThread = thread->lock;
mvm::Cond* varcondThread = thread->varcond;
mutexThread->lock();
if (thread->interruptFlag != 0) {
mutexThread->unlock();
thread->interruptFlag = 0;
thread->getVM()->interruptedException(self);
} else {
unsigned int recur = l->lock->recursionCount();
bool timeout = false;
l->lock->unlockAll();
LockObj::wait(l, thread);
thread->state = VMThread::StateWaiting;
if (timed) {
timeout = varcondThread->timedWait(mutexThread, info);
} else {
varcondThread->wait(mutexThread);
}
bool interrupted = (thread->interruptFlag != 0);
mutexThread->unlock();
l->lock->lockAll(recur);
if (interrupted || timeout) {
LockObj::remove(l, thread);
}
thread->state = VMThread::StateRunning;
if (interrupted) {
thread->interruptFlag = 0;
thread->getVM()->interruptedException(self);
}
}
} else {
VMThread::get()->getVM()->illegalMonitorStateException(self);
}
}
void VMObject::wait(VMObject* self) {
llvm_gcroot(self, 0);
waitIntern(self, 0, false);
}
void VMObject::timedWait(VMObject* self, struct timeval& info) {
llvm_gcroot(self, 0);
waitIntern(self, &info, false);
}
void VMObject::notify(VMObject* self) {
llvm_gcroot(self, 0);
declare_gcroot(LockObj*, l) = myLock(self);
if (LockObj::owner(l)) {
LockObj::notify(l);
} else {
VMThread::get()->getVM()->illegalMonitorStateException(self);
}
}
void VMObject::notifyAll(VMObject* self) {
llvm_gcroot(self, 0);
declare_gcroot(LockObj*, l) = myLock(self);
if (LockObj::owner(l)) {
LockObj::notifyAll(l);
} else {
VMThread::get()->getVM()->illegalMonitorStateException(self);
}
}
bool VMObject::instanceOf(VMObject* self, VMCommonClass* cl) {
llvm_gcroot(self, 0);
if (!self) return false;
else return self->classOf->isAssignableFrom(cl);
}