blob: 823af53be31057b77e0ded499f83dda651de86a4 [file] [log] [blame]
//===--------- JavaThread.cpp - Java thread description -------------------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <sstream>
#include "vmkit/Locks.h"
#include "vmkit/Thread.h"
#include "JavaClass.h"
#include "JavaObject.h"
#include "JavaThread.h"
#include "JavaString.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
using namespace j3;
using namespace std;
JavaThread::JavaThread(vmkit::VirtualMachine* isolate) : MutatorThread() {
MyVM = isolate;
pendingException = NULL;
jniEnv = ((Jnjvm*)isolate)->jniEnv;
localJNIRefs = new JNILocalReferences();
currentAddedReferences = NULL;
javaThread = NULL;
vmThread = NULL;
state = vmkit::LockingThread::StateRunning;
}
void JavaThread::initialise(JavaObject* thread, JavaObject* vmth) {
llvm_gcroot(thread, 0);
llvm_gcroot(vmth, 0);
vmkit::Collector::objectReferenceNonHeapWriteBarrier((gc**)&javaThread, (gc*)thread);
vmkit::Collector::objectReferenceNonHeapWriteBarrier((gc**)&vmThread, (gc*)vmth);
}
JavaThread::~JavaThread() {
delete localJNIRefs;
}
void JavaThread::throwException(JavaObject* obj) {
llvm_gcroot(obj, 0);
JavaThread* th = JavaThread::get();
assert(th->pendingException == 0 && "pending exception already there?");
vmkit::Collector::objectReferenceNonHeapWriteBarrier((gc**)&(th->pendingException), (gc*)obj);
th->internalThrowException();
}
void JavaThread::throwPendingException() {
JavaThread* th = JavaThread::get();
assert(th->pendingException);
th->internalThrowException();
}
void JavaThread::startJNI() {
// Interesting, but no need to do anything.
}
void JavaThread::endJNI() {
localJNIRefs->removeJNIReferences(this, *currentAddedReferences);
endUnknownFrame();
// Go back to cooperative mode.
leaveUncooperativeCode();
}
uint32 JavaThread::getJavaFrameContext(void** buffer) {
vmkit::StackWalker Walker(this);
uint32 i = 0;
while (vmkit::FrameInfo* FI = Walker.get()) {
if (FI->Metadata != NULL) {
JavaMethod* M = (JavaMethod*)FI->Metadata;
buffer[i++] = M;
}
++Walker;
}
return i;
}
JavaMethod* JavaThread::getCallingMethodLevel(uint32 level) {
vmkit::StackWalker Walker(this);
uint32 index = 0;
while (vmkit::FrameInfo* FI = Walker.get()) {
if (FI->Metadata != NULL) {
if (index == level) {
return (JavaMethod*)FI->Metadata;
}
++index;
}
++Walker;
}
return 0;
}
UserClass* JavaThread::getCallingClassLevel(uint32 level) {
JavaMethod* meth = getCallingMethodLevel(level);
if (meth) return meth->classDef;
return 0;
}
JavaObject* JavaThread::getNonNullClassLoader() {
JavaObject* obj = 0;
llvm_gcroot(obj, 0);
vmkit::StackWalker Walker(this);
while (vmkit::FrameInfo* FI = Walker.get()) {
if (FI->Metadata != NULL) {
JavaMethod* meth = (JavaMethod*)FI->Metadata;
JnjvmClassLoader* loader = meth->classDef->classLoader;
obj = loader->getJavaClassLoader();
if (obj) return obj;
}
++Walker;
}
return 0;
}
void JavaThread::printJavaBacktrace() {
vmkit::StackWalker Walker(this);
while (vmkit::FrameInfo* FI = Walker.get()) {
if (FI->Metadata != NULL) {
MyVM->printMethod(FI, Walker.ip, Walker.addr);
}
++Walker;
}
}
JavaObject** JNILocalReferences::addJNIReference(JavaThread* th,
JavaObject* obj) {
llvm_gcroot(obj, 0);
if (length == MAXIMUM_REFERENCES) {
JNILocalReferences* next = new JNILocalReferences();
th->localJNIRefs = next;
next->prev = this;
return next->addJNIReference(th, obj);
} else {
vmkit::Collector::objectReferenceNonHeapWriteBarrier(
(gc**)&(localReferences[length]), (gc*)obj);
return &localReferences[length++];
}
}
/// TODO optimize this function with iterative impl.
///
void JNILocalReferences::removeJNIReferences(JavaThread* th, uint32_t num) {
if (th->localJNIRefs != this) {
delete th->localJNIRefs;
th->localJNIRefs = this;
}
if (num > length) {
assert(prev && "No prev and deleting too much local references");
prev->removeJNIReferences(th, num - length);
} else {
length -= num;
}
}
std::ostream& j3::operator << (std::ostream& os, const JavaThread& thread)
{
return os << *thread.currentThread();
}
void JavaThread::dump() const
{
cerr << *this << endl;
}
void JavaThread::throwNullPointerException(word_t methodIP)
{
if (!this->isVmkitThread())
return vmkit::Thread::throwNullPointerException(methodIP);
MyVM->nullPointerException();
UNREACHABLE();
}
ParkLock::ParkLock() {
permit = 0;
}
ParkLock::~ParkLock() {
}
inline void _OrderAccess_fence() {
// Always use locked addl since mfence is sometimes expensive
__sync_synchronize();
//__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
}
// Implementation of method park, see LockSupport.java
// time is in nanoseconds if !isAboslute, otherwise it is in milliseconds
void ParkLock::park(bool isAbsolute, int64_t time, JavaThread* thread) {
// Optional fast-path check:
// Return immediately if a permit is available.
if (permit) {
permit = false ;
//_OrderAccess_fence();//__sync_synchronize();//OrderAccess::fence();
return ;
}
// Optional optimization -- avoid state transitions if there's an interrupt pending.
// Check interrupt before trying to wait
if (thread->lockingThread.interruptFlag) {
return;
}
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
// Enter safepoint region
// Beware of deadlocks such as 6317397.
// The per-thread Parker:: mutex is a classic leaf-lock.
// In particular a thread must never block on the Threads_lock while
// holding the Parker:: mutex. If safepoints are pending both the
// the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
//ThreadBlockInVM tbivm(jt);
// Don't wait if cannot get lock since interference arises from
// unblocking. Also. check interrupt before trying wait
if (thread->lockingThread.interruptFlag || lock.tryLock() != 0) {
return;
}
int status ;
if (permit) { // no wait needed
permit = false;
lock.unlock(thread);
//_OrderAccess_fence();
return;
}
//OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
//jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
if (time == 0) {
//thread->setState(vmkit::LockingThread::StateWaiting);
thread->setState(vmkit::LockingThread::StateWaiting);
//_OrderAccess_fence();
//thread->doYield = true;
cond.wait(&lock);
//thread->doYield = false;
//cond.myTimeWait(&lock, false, 1000000000);
} else {
thread->setState(vmkit::LockingThread::StateTimeWaiting);
cond.myTimeWait(&lock, isAbsolute, time);
}
thread->setState(vmkit::LockingThread::StateRunning);
//thread->setState(vmkit::LockingThread::StateRunning);
permit = false ;
//_OrderAccess_fence();
lock.unlock(thread);
// If externally suspended while waiting, re-suspend
//if (jt->handle_special_suspend_equivalent_condition()) {
// jt->java_suspend_self();
//}
}
void ParkLock::unpark() {
JavaThread* thread = (JavaThread*)vmkit::Thread::get();
lock.lock();
permit = true;
//_OrderAccess_fence();
cond.signal();
lock.unlock(thread);
}
void ParkLock::interrupt() {
//
if (lock.tryLock() == 0) {
JavaThread* thread = (JavaThread*)vmkit::Thread::get();
cond.signal();
lock.unlock(thread);
}
//_OrderAccess_fence();
}