blob: 0ec75d380782b4bdff5323f5ecd0a32f6c0618d9 [file] [log] [blame]
#ifdef SERVICE
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Target/TargetJITInfo.h"
#include "../lib/ExecutionEngine/JIT/JIT.h"
#include "JavaThread.h"
#include "JavaJIT.h"
#include "Jnjvm.h"
#include "mvm/VirtualMachine.h"
#include "mvm/Threads/Cond.h"
#include "mvm/Threads/Locks.h"
#include "mvm/JIT.h"
#include "signal.h"
using namespace jnjvm;
#if defined(__MACH__) && !defined(__i386__)
#define FRAME_IP(fp) (fp[2])
#else
#define FRAME_IP(fp) (fp[1])
#endif
static void throwInlineStoppedBundleException() {
void** addr = (void**)__builtin_frame_address(0);
JavaThread* th = JavaThread::get();
FRAME_IP(addr) = (void**)th->replacedEIPs[--th->eipIndex];
th->throwException(th->ServiceException);
}
static void throwStoppedBundleException() {
JavaThread* th = JavaThread::get();
th->throwException(th->ServiceException);
}
static mvm::LockNormal lock;
static mvm::Cond cond;
static mvm::Thread* initiator = 0;
static bool Finished = true;
void terminationHandler(int) {
void** addr = (void**)__builtin_frame_address(0);
mvm::Thread* th = mvm::Thread::get();
JnjvmClassLoader* stoppedBundle =
(JnjvmClassLoader*)(th->stoppingService->CU);
void* baseSP = th->baseSP;
bool inStack = false;
while (addr && addr < baseSP && addr < addr[0]) {
addr = (void**)addr[0];
void** ptr = (void**)FRAME_IP(addr);
JavaMethod* meth = JavaJIT::IPToJavaMethod(ptr);
if (meth) {
if (meth->classDef->classLoader == stoppedBundle) {
inStack = true;
JavaThread* th = JavaThread::get();
th->replacedEIPs[th->eipIndex++] = FRAME_IP(addr);
FRAME_IP(addr) = (void**)(uintptr_t)throwInlineStoppedBundleException;
}
}
}
// If the malicious bundle is in the stack, interrupt the thread.
if (inStack) {
JavaThread* th = JavaThread::get();
th->lock.lock();
th->interruptFlag = 1;
// here we could also raise a signal for interrupting I/O
if (th->state == JavaThread::StateWaiting) {
th->state = JavaThread::StateInterrupted;
th->varcond.signal();
}
th->lock.unlock();
}
if (mvm::Thread::get() != initiator) {
lock.lock();
while (!Finished)
cond.wait(&lock);
lock.unlock();
}
}
void Jnjvm::stopService() {
lock.lock();
while (!Finished)
cond.wait(&lock);
Finished = false;
lock.unlock();
JnjvmClassLoader* bundle = (JnjvmClassLoader*)CU;
bundle->getIsolate()->status = 1;
mvm::Thread* th = mvm::Thread::get();
th->stoppingService = this;
initiator = th;
for(mvm::Thread* cur = (mvm::Thread*)th->next(); cur != th;
cur = (mvm::Thread*)cur->next()) {
mvm::VirtualMachine* executingVM = cur->MyVM;
assert(executingVM && "Thread with no VM!");
cur->stoppingService = this;
uint32 res = cur->kill(SIGUSR1);
assert(res == 0);
}
// I have to do it too!
terminationHandler(0);
llvm::TargetJITInfo& TJI =
((llvm::JIT*)mvm::MvmModule::executionEngine)->getJITInfo();
for (ClassMap::iterator i = bundle->getClasses()->map.begin(),
e = bundle->getClasses()->map.end(); i!= e; ++i) {
Class* cl = i->second->asClass();
if (cl) {
for (uint32 i = 0; i < cl->nbVirtualMethods; ++i) {
if (cl->virtualMethods[i].code) {
TJI.replaceMachineCodeForFunction(cl->virtualMethods[i].code,
(void*)(uintptr_t)throwStoppedBundleException);
}
}
for (uint32 i = 0; i < cl->nbStaticMethods; ++i) {
if (cl->staticMethods[i].code) {
TJI.replaceMachineCodeForFunction(cl->staticMethods[i].code,
(void*)(uintptr_t)throwStoppedBundleException);
}
}
}
}
lock.lock();
Finished = true;
cond.broadcast();
lock.unlock();
}
#endif