blob: 206251170605201b483713805fdfcf26c8104617 [file] [log] [blame]
//===--------- Object.cc - Common objects for vmlets ----------------------===//
//
// The Micro Virtual Machine
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <cstdio>
#include <cstdlib>
#include "MvmGC.h"
#include "mvm/Allocator.h"
#include "mvm/Object.h"
#include "mvm/PrintBuffer.h"
#include "mvm/VirtualMachine.h"
#include "mvm/Threads/Thread.h"
using namespace mvm;
VirtualTable NativeString::VT(0, 0, (uintptr_t)VirtualTable::emptyTracer);
VirtualTable PrintBuffer::VT(0, 0, (uintptr_t)PrintBuffer::staticTracer);
extern "C" void printFloat(float f) {
fprintf(stderr, "%f\n", f);
}
extern "C" void printDouble(double d) {
fprintf(stderr, "%f\n", d);
}
extern "C" void printLong(sint64 l) {
fprintf(stderr, "%lld\n", (long long int)l);
}
extern "C" void printInt(sint32 i) {
fprintf(stderr, "%d\n", i);
}
extern "C" void printObject(mvm::Object* obj) {
fprintf(stderr, "%s\n", obj->printString());
}
PrintBuffer *PrintBuffer::writeObj(const Object *obj) {
Object *beg = (Object*)Collector::begOf(obj);
if(beg) {
if(beg == obj) {
obj->print((mvm::PrintBuffer*)this);
} else {
write("<In Object [");
beg->print(this);
write("] -- offset ");
writeS4((intptr_t)obj - (intptr_t)beg);
write(">");
}
} else {
write("<DirectValue: ");
writeS4((intptr_t)obj);
write(">");
}
return this;
}
extern "C" void write_ptr(PrintBuffer* buf, void* obj) {
buf->writePtr(obj);
}
extern "C" void write_int(PrintBuffer* buf, int a) {
buf->writeS4(a);
}
extern "C" void write_str(PrintBuffer* buf, char* a) {
buf->write(a);
}
char *Object::printString(void) const {
PrintBuffer *buf= PrintBuffer::alloc();
buf->writeObj(this);
return buf->contents()->cString();
}
void Object::print(PrintBuffer *buf) const {
buf->write("<Object@");
buf->writePtr((void*)this);
buf->write(">");
}
void NativeString::print(PrintBuffer *buf) const {
NativeString *const self= (NativeString *)this;
buf->write("\"");
for (size_t i= 0; i < strlen(self->cString()); ++i) {
int c= self->cString()[i];
switch (c) {
case '\b': buf->write("\\b"); break;
case '\f': buf->write("\\f"); break;
case '\n': buf->write("\\n"); break;
case '\r': buf->write("\\r"); break;
case '\t': buf->write("\\t"); break;
case '"': buf->write("\\\""); break;
default: {
char esc[32];
if (c < 32)
sprintf(esc, "\\x%02x", c);
else
sprintf(esc, "%c", c);
buf->write(esc);
}
}
}
buf->write("\"");
}
typedef void (*destructor_t)(void*);
void VirtualMachine::finalizerStart(mvm::Thread* th) {
VirtualMachine* vm = th->MyVM;
gc* res = 0;
llvm_gcroot(res, 0);
while (true) {
vm->FinalizationLock.lock();
while (vm->CurrentFinalizedIndex == 0) {
vm->FinalizationCond.wait(&vm->FinalizationLock);
}
vm->FinalizationLock.unlock();
while (true) {
vm->FinalizationQueueLock.acquire();
if (vm->CurrentFinalizedIndex != 0) {
res = vm->ToBeFinalized[--vm->CurrentFinalizedIndex];
}
vm->FinalizationQueueLock.release();
if (!res) break;
try {
VirtualTable* VT = res->getVirtualTable();
if (VT->operatorDelete) {
destructor_t dest = (destructor_t)VT->destructor;
dest(res);
} else {
vm->invokeFinalizer(res);
}
} catch(...) {
}
res = 0;
th->clearException();
}
}
}
void VirtualMachine::enqueueStart(mvm::Thread* th) {
VirtualMachine* vm = th->MyVM;
gc* res = 0;
llvm_gcroot(res, 0);
while (true) {
vm->EnqueueLock.lock();
while (vm->ToEnqueueIndex == 0) {
vm->EnqueueCond.wait(&vm->EnqueueLock);
}
vm->EnqueueLock.unlock();
while (true) {
vm->ToEnqueueLock.acquire();
if (vm->ToEnqueueIndex != 0) {
res = vm->ToEnqueue[--vm->ToEnqueueIndex];
}
vm->ToEnqueueLock.release();
if (!res) break;
try {
vm->enqueueReference(res);
} catch(...) {
}
res = 0;
th->clearException();
}
}
}
void VirtualMachine::growFinalizationQueue() {
if (CurrentIndex >= QueueLength) {
uint32 newLength = QueueLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle finalizer overflows yet!\n");
abort();
}
for (uint32 i = 0; i < QueueLength; ++i) newQueue[i] = FinalizationQueue[i];
delete[] FinalizationQueue;
FinalizationQueue = newQueue;
QueueLength = newLength;
}
}
void VirtualMachine::growToBeFinalizedQueue() {
if (CurrentFinalizedIndex >= ToBeFinalizedLength) {
uint32 newLength = ToBeFinalizedLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle finalizer overflows yet!\n");
abort();
}
for (uint32 i = 0; i < ToBeFinalizedLength; ++i) newQueue[i] = ToBeFinalized[i];
delete[] ToBeFinalized;
ToBeFinalized = newQueue;
ToBeFinalizedLength = newLength;
}
}
void VirtualMachine::addFinalizationCandidate(gc* obj) {
FinalizationQueueLock.acquire();
if (CurrentIndex >= QueueLength) {
growFinalizationQueue();
}
FinalizationQueue[CurrentIndex++] = obj;
FinalizationQueueLock.release();
}
void VirtualMachine::scanFinalizationQueue() {
uint32 NewIndex = 0;
for (uint32 i = 0; i < CurrentIndex; ++i) {
gc* obj = FinalizationQueue[i];
if (!Collector::isLive(obj)) {
obj->markAndTrace();
if (CurrentFinalizedIndex >= ToBeFinalizedLength)
growToBeFinalizedQueue();
/* Add to object table */
ToBeFinalized[CurrentFinalizedIndex++] = obj;
} else {
FinalizationQueue[NewIndex++] = obj;
}
}
CurrentIndex = NewIndex;
for (uint32 i = 0; i < CurrentFinalizedIndex; ++i) {
gc* obj = ToBeFinalized[i];
obj->markAndTrace();
}
}
gc* ReferenceQueue::processReference(gc* reference, VirtualMachine* vm) {
if (!Collector::isLive(reference)) {
vm->clearReferent(reference);
return 0;
}
gc* referent = vm->getReferent(reference);
if (!referent) return 0;
if (semantics == SOFT) {
// TODO: are we are out of memory? Consider that we always are for now.
if (false) {
referent->markAndTrace();
}
} else if (semantics == PHANTOM) {
// Nothing to do.
}
if (Collector::isLive(referent)) {
return reference;
} else {
vm->clearReferent(reference);
vm->addToEnqueue(reference);
return 0;
}
}
void ReferenceQueue::scan(VirtualMachine* vm) {
uint32 NewIndex = 0;
for (uint32 i = 0; i < CurrentIndex; ++i) {
gc* obj = References[i];
gc* res = processReference(obj, vm);
if (res) References[NewIndex++] = res;
}
CurrentIndex = NewIndex;
}
void* Allocator::allocateManagedObject(unsigned int sz, VirtualTable* VT) {
return gc::operator new(sz, VT);
}
void* Allocator::allocatePermanentMemory(unsigned int sz) {
return malloc(sz);
}
void Allocator::freePermanentMemory(void* obj) {
return free(obj);
}
void* Allocator::allocateTemporaryMemory(unsigned int sz) {
return malloc(sz);
}
void Allocator::freeTemporaryMemory(void* obj) {
return free(obj);
}