blob: b5b33e284d92dc4dfc6bb8bc994615502c688229 [file] [log] [blame]
//===-------- JavaClass.cpp - Java class representation -------------------===//
//
// JnJVM
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include <string.h>
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "mvm/JIT.h"
#include "mvm/GC/GC.h"
#include "types.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaJIT.h"
#include "JavaObject.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "Jnjvm.h"
#include "JnjvmModuleProvider.h"
#include "Reader.h"
using namespace jnjvm;
const int CommonClass::MaxDisplay = 6;
void Attribut::print(mvm::PrintBuffer* buf) const {
buf->write("Attribut<");
buf->writeObj(name);
buf->write(">");
}
Attribut* Attribut::derive(const UTF8* name, unsigned int length, const Reader*
reader) {
Attribut* attr = gc_new(Attribut)();
attr->start = reader->cursor;
attr->nbb = length;
attr->name = name;
return attr;
}
// TODO: Optimize
Attribut* Attribut::lookup(const std::vector<Attribut*>* vec,
const UTF8* key ) {
for (uint32 i = 0; i < vec->size(); i++) {
Attribut* cur = vec->at(i);
if (cur->name == key) return cur;
}
return 0;
}
Reader* Attribut::toReader(ArrayUInt8* array, Attribut* attr) {
return Reader::allocateReader(array, attr->start, attr->nbb);
}
static void printClassNameIntern(const UTF8* name, unsigned int start,
unsigned int end, mvm::PrintBuffer* buf) {
uint16 first = name->at(start);
if (first == AssessorDesc::I_TAB) {
unsigned int stepsEnd = start;
while (name->at(stepsEnd) == AssessorDesc::I_TAB) stepsEnd++;
if (name->at(stepsEnd) == AssessorDesc::I_REF) {
printClassNameIntern(name, (stepsEnd + 1),(end - 1), buf);
} else {
AssessorDesc * funcs = 0;
uint32 next = 0;
AssessorDesc::analyseIntern(name, stepsEnd, 0, funcs, next);
buf->write(funcs->asciizName);
}
buf->write(" ");
for (uint32 i = start; i < stepsEnd; i++)
buf->write("[]");
} else {
char* tmp = (char*)(alloca(1 + (end - start)));
for (uint32 i = start; i < end; i++) {
short int cur = name->at(i);
tmp[i - start] = (cur == '/' ? '.' : cur);
}
tmp[end - start] = 0;
buf->write(tmp);
}
}
void CommonClass::printClassName(const UTF8* name, mvm::PrintBuffer* buf) {
printClassNameIntern(name, 0, name->size, buf);
}
void CommonClass::print(mvm::PrintBuffer* buf) const {
buf->write("CommonClass<");
printClassName(name, buf);
buf->write(">");
}
void CommonClass::initialise(Jnjvm* isolate, bool isArray) {
this->lockVar = mvm::Lock::allocRecursive();
this->condVar = mvm::Cond::allocCond();
this->status = hashed;
this->isolate = isolate;
this->dim = -1;
this->isArray = isArray;
this->_llvmVar = 0;
#ifdef SINGLE_VM
this->_llvmDelegatee = 0;
this->delegatee = 0;
#endif
}
void CommonClass::aquire() {
lockVar->lock();
}
void CommonClass::release() {
lockVar->unlock();
}
void CommonClass::waitClass() {
condVar->wait(lockVar);
}
void CommonClass::broadcastClass() {
condVar->broadcast();
}
bool CommonClass::ownerClass() {
return mvm::Lock::selfOwner(lockVar);
}
void Class::print(mvm::PrintBuffer* buf) const {
buf->write("Class<");
printClassName(name, buf);
buf->write(">");
}
void ClassArray::print(mvm::PrintBuffer* buf) const {
buf->write("ClassArray<");
printClassName(name, buf);
buf->write(">");
}
void ClassArray::resolveComponent() {
AssessorDesc::introspectArray(isolate, classLoader, name, 0, _funcs,
_baseClass);
}
CommonClass* ClassArray::baseClass() {
if (_baseClass == 0) {
this->resolveComponent();
}
return _baseClass;
}
AssessorDesc* ClassArray::funcs() {
if (_funcs == 0) {
this->resolveComponent();
}
return _funcs;
}
JavaObject* ClassArray::arrayLoader(Jnjvm* isolate, const UTF8* name,
JavaObject* loader,
unsigned int start, unsigned int len) {
if (name->at(start) == AssessorDesc::I_TAB) {
return arrayLoader(isolate, name, loader, start + 1, len - 1);
} else if (name->at(start) == AssessorDesc::I_REF) {
const UTF8* componentName = name->javaToInternal(isolate, start + 1,
len - 2);
CommonClass* cl = isolate->loadName(componentName, loader, false, false,
true);
return cl->classLoader;
} else {
return 0;
}
}
void* JavaMethod::compiledPtr() {
if (code != 0) return code;
else {
classDef->aquire();
if (code == 0) {
if (isStatic(access)) {
llvmType = signature->staticType;
} else {
llvmType = signature->virtualType;
}
if (!methPtr) {
JavaJIT* jit = gc_new(JavaJIT)();
jit->compilingClass = classDef;
jit->compilingMethod = this;
if (isNative(access)) {
methPtr = jit->nativeCompile();
} else {
methPtr = jit->javaCompile();
}
}
// We can compile it, since if we're here, it's for a good reason
void* val = mvm::jit::executionEngine->getPointerToGlobal(methPtr);
if (gc::isObject(val)) {
mvm::Code* temp = (mvm::Code*)((unsigned*)val - 1);
temp->method()->definition(this);
}
code = (mvm::Code*)val;
classDef->release();
} else {
classDef->release();
}
return code;
}
}
void JavaMethod::print(mvm::PrintBuffer* buf) const {
buf->write("JavaMethod<");
signature->printWithSign(classDef, name, buf);
buf->write(">");
}
void JavaField::print(mvm::PrintBuffer* buf) const {
buf->write("JavaField<");
if (isStatic(access))
buf->write("static ");
else
buf->write("virtual ");
signature->tPrintBuf(buf);
buf->write(" ");
classDef->print(buf);
buf->write("::");
name->print(buf);
buf->write(">");
}
JavaMethod* CommonClass::lookupMethodDontThrow(const UTF8* name,
const UTF8* type, bool isStatic,
bool recurse) {
#ifndef SINGLE_VM
if (isolate == Jnjvm::bootstrapVM) {
name = Jnjvm::bootstrapVM->readerConstructUTF8(name->elements,
name->size);
type = Jnjvm::bootstrapVM->readerConstructUTF8(type->elements,
type->size);
}
#endif
std::vector<JavaMethod*>* meths = (isStatic? &staticMethods :
&virtualMethods);
JavaMethod *cur, *res = 0;
int i = 0;
int nbm = meths->size();
while (!res && i < nbm) {
cur = meths->at(i);
if (cur->name == name && cur->type == type) {
return cur;
}
++i;
}
if (recurse) {
if (super) res = super->lookupMethodDontThrow(name, type, isStatic,
recurse);
if (!res && isStatic) {
int nbi = interfaces.size();
i = 0;
while (res == 0 && i < nbi) {
res = interfaces[i]->lookupMethodDontThrow(name, type, isStatic,
recurse);
++i;
}
}
}
return res;
}
JavaMethod* CommonClass::lookupMethod(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse) {
JavaMethod* res = lookupMethodDontThrow(name, type, isStatic, recurse);
if (!res) {
JavaThread::get()->isolate->error(Jnjvm::NoSuchMethodError,
"unable to find %s in %s",
name->printString(), this->printString());
}
return res;
}
JavaField* CommonClass::lookupFieldDontThrow(const UTF8* name,
const UTF8* type, bool isStatic,
bool recurse) {
#ifndef SINGLE_VM
if (isolate == Jnjvm::bootstrapVM) {
name = Jnjvm::bootstrapVM->readerConstructUTF8(name->elements,
name->size);
type = Jnjvm::bootstrapVM->readerConstructUTF8(type->elements,
type->size);
}
#endif
std::vector<JavaField*>* fields = (isStatic? &staticFields : &virtualFields);
JavaField *cur, *res = 0;
int i = 0;
int nbm = fields->size();
while (!res && i < nbm) {
cur = fields->at(i);
if (cur->name == name && cur->type == type) {
return cur;
}
++i;
}
if (recurse) {
if (super) res = super->lookupFieldDontThrow(name, type, isStatic,
recurse);
if (!res && isStatic) {
int nbi = interfaces.size();
i = 0;
while (res == 0 && i < nbi) {
res = interfaces[i]->lookupFieldDontThrow(name, type, isStatic,
recurse);
++i;
}
}
}
return res;
}
JavaField* CommonClass::lookupField(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse) {
JavaField* res = lookupFieldDontThrow(name, type, isStatic, recurse);
if (!res) {
JavaThread::get()->isolate->error(Jnjvm::NoSuchFieldError,
"unable to find %s in %s",
name->printString(), this->printString());
}
return res;
}
JavaObject* Class::doNew() {
JavaObject* res = (JavaObject*)gc::operator new(virtualSize, virtualVT);
memcpy(res, virtualInstance, virtualSize);
return res;
}
// Copy doNew because LLVM wants two different pointers (for simplicity)
JavaObject* Class::doNewUnknown() {
JavaObject* res = (JavaObject*)gc::operator new(virtualSize, virtualVT);
memcpy(res, virtualInstance, virtualSize);
return res;
}
JavaObject* Class::initialiseObject(JavaObject* res) {
memcpy(res, virtualInstance, virtualSize);
return res;
}
#ifndef SINGLE_VM
JavaObject* Class::doNewIsolate() {
if (!isReady())
initialiseClass();
JavaObject* res = (JavaObject*)gc::operator new(virtualSize, virtualVT);
memcpy(res, virtualInstance, virtualSize);
return res;
}
#endif
bool CommonClass::inheritName(const UTF8* Tname) {
if (name == Tname) {
return true;
} else if (AssessorDesc::bogusClassToPrimitive(this)) {
return true;
} else if (super) {
if (super->inheritName(Tname)) return true;
}
for (uint32 i = 0; i < interfaces.size(); ++i) {
if (interfaces[i]->inheritName(Tname)) return true;
}
return false;
}
bool CommonClass::isOfTypeName(const UTF8* Tname) {
if (inheritName(Tname)) {
return true;
} else if (isArray) {
CommonClass* curS = this;
uint32 prof = 0;
uint32 len = Tname->size;
bool res = true;
while (res && Tname->at(prof) == AssessorDesc::I_TAB) {
CommonClass* cl = ((ClassArray*)curS)->baseClass();
Jnjvm *vm = cl->isolate;
++prof;
vm->resolveClass(cl, false);
res = curS->isArray && cl && (prof < len);
curS = cl;
}
Jnjvm *vm = this->isolate;
return (Tname->at(prof) == AssessorDesc::I_REF) &&
(res && curS->inheritName(Tname->extract(vm, prof + 1, len - 1)));
} else {
return false;
}
}
bool CommonClass::implements(CommonClass* cl) {
if (this == cl) return true;
else {
for (uint32 i = 0; i < interfaces.size(); i++) {
CommonClass* cur = interfaces[i];
if (cur == cl) return true;
else if (cur->implements(cl)) return true;
}
if (super) {
return super->implements(cl);
}
}
return false;
}
bool CommonClass::instantiationOfArray(CommonClass* cl) {
if (this == cl) return true;
else {
if (isArray && cl->isArray) {
CommonClass* baseThis = ((ClassArray*)this)->baseClass();
CommonClass* baseCl = ((ClassArray*)cl)->baseClass();
if (isInterface(baseThis->access) && isInterface(baseCl->access)) {
return baseThis->implements(baseCl);
} else {
return baseThis->isAssignableFrom(baseCl);
}
}
}
return false;
}
bool CommonClass::subclassOf(CommonClass* cl) {
if (cl->depth < display.size()) {
return display[cl->depth] == cl;
} else {
return false;
}
}
bool CommonClass::isAssignableFrom(CommonClass* cl) {
if (this == cl) {
return true;
} else if (isInterface(cl->access)) {
return this->implements(cl);
} else if (cl->isArray) {
return this->instantiationOfArray(cl);
} else {
return this->subclassOf(cl);
}
}
void JavaField::initField(JavaObject* obj) {
const AssessorDesc* funcs = signature->funcs;
Attribut* attribut = Attribut::lookup(&attributs,
Attribut::constantAttribut);
if (!attribut) {
JavaJIT::initField(this, obj);
} else {
Reader* reader = attribut->toReader(classDef->bytes, attribut);
JavaCtpInfo * ctpInfo = classDef->ctpInfo;
uint16 idx = reader->readU2();
if (funcs == AssessorDesc::dLong) {
JavaJIT::initField(this, obj, (uint64)ctpInfo->LongAt(idx));
} else if (funcs == AssessorDesc::dDouble) {
JavaJIT::initField(this, obj, ctpInfo->DoubleAt(idx));
} else if (funcs == AssessorDesc::dFloat) {
JavaJIT::initField(this, obj, ctpInfo->FloatAt(idx));
} else if (funcs == AssessorDesc::dRef) {
const UTF8* utf8 = ctpInfo->UTF8At(ctpInfo->ctpDef[idx]);
JavaJIT::initField(this, obj,
(JavaObject*)ctpInfo->resolveString(utf8, idx));
} else if (funcs == AssessorDesc::dInt || funcs == AssessorDesc::dChar ||
funcs == AssessorDesc::dShort || funcs == AssessorDesc::dByte ||
funcs == AssessorDesc::dBool) {
JavaJIT::initField(this, obj, (uint64)ctpInfo->IntegerAt(idx));
} else {
JavaThread::get()->isolate->
unknownError("unknown constant %c", funcs->byteId);
}
}
}
static void resolveStaticFields(Class* cl) {
std::vector<const llvm::Type*> fields;
fields.push_back(JavaObject::llvmType->getContainedType(0));
uint64 offset = 0;
mvm::jit::protectConstants();//->lock();
for (std::vector<JavaField*>::iterator i = cl->staticFields.begin(),
e = cl->staticFields.end(); i!= e; ++i) {
// preincrement because 0 is JavaObject
(*i)->offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, ++offset);
fields.push_back((*i)->signature->funcs->llvmType);
}
mvm::jit::unprotectConstants();//->unlock();
mvm::jit::protectTypes();//->lock();
cl->staticType = llvm::PointerType::getUnqual(llvm::StructType::get(fields, false));
mvm::jit::unprotectTypes();//->unlock();
VirtualTable* VT = JavaJIT::makeVT(cl, true);
uint64 size = mvm::jit::getTypeSize(cl->staticType->getContainedType(0));
#ifndef SINGLE_VM
cl->staticSize = size;
cl->staticVT = VT;
if (cl->isolate != Jnjvm::bootstrapVM) {
#endif
JavaObject* val = (JavaObject*)mvm::Object::gcmalloc(size, VT);
cl->setStaticInstance(val);
val->initialise(cl);
for (std::vector<JavaField*>::iterator i = cl->staticFields.begin(),
e = cl->staticFields.end(); i!= e; ++i) {
(*i)->initField(val);
}
#ifndef SINGLE_VM
}
#endif
}
static void resolveVirtualFields(Class* cl) {
std::vector<const llvm::Type*> fields;
if (cl->super) {
fields.push_back(cl->super->virtualType->getContainedType(0));
} else {
fields.push_back(JavaObject::llvmType->getContainedType(0));
}
uint64 offset = 0;
mvm::jit::protectConstants();//->lock();
for (std::vector<JavaField*>::iterator i = cl->virtualFields.begin(),
e = cl->virtualFields.end(); i!= e; ++i) {
// preincrement because 0 is JavaObject
(*i)->offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, ++offset);
fields.push_back((*i)->signature->funcs->llvmType);
}
mvm::jit::unprotectConstants();//->unlock();
mvm::jit::protectTypes();//->lock();
cl->virtualType = llvm::PointerType::getUnqual(llvm::StructType::get(fields, false));
mvm::jit::unprotectTypes();//->unlock();
VirtualTable* VT = JavaJIT::makeVT(cl, false);
uint64 size = mvm::jit::getTypeSize(cl->virtualType->getContainedType(0));
cl->virtualSize = size;
cl->virtualVT = VT;
cl->virtualInstance = (JavaObject*)mvm::Object::gcmalloc(size, VT);
cl->virtualInstance->initialise(cl);
for (std::vector<JavaField*>::iterator i = cl->virtualFields.begin(),
e = cl->virtualFields.end(); i!= e; ++i) {
// Virtual fields apparenty do not have inititizalizers, which is good
// for isolates. I should not have to do this, but just to make sure.
(*i)->initField(cl->virtualInstance);
}
}
void Class::resolveFields() {
resolveStaticFields(this);
resolveVirtualFields(this);
}
JavaObject* CommonClass::getClassDelegatee() {
return JavaThread::get()->isolate->getClassDelegatee(this);
}
void CommonClass::resolveClass(bool doClinit) {
isolate->resolveClass(this, doClinit);
}
void CommonClass::initialiseClass() {
return isolate->initialiseClass(this);
}
#ifndef SINGLE_VM
void Class::setStaticInstance(JavaObject* val) {
_staticInstance = val;
}
JavaObject* Class::staticInstance() {
if (isolate == Jnjvm::bootstrapVM) {
Class* cl = this;
std::pair<uint8, JavaObject*>* val = JavaThread::get()->isolate->statics->lookup(cl);
assert(val);
return val->second;
} else {
return _staticInstance;
}
}
JavaObject* Class::createStaticInstance() {
JavaObject* val = (JavaObject*)mvm::Object::gcmalloc(staticSize, staticVT);
val->initialise(this);
for (std::vector<JavaField*>::iterator i = this->staticFields.begin(),
e = this->staticFields.end(); i!= e; ++i) {
(*i)->initField(val);
}
return val;
}
bool CommonClass::isReady() {
if (isolate == Jnjvm::bootstrapVM) {
Class* cl = this;
std::pair<uint8, JavaObject*>* val = JavaThread::get()->isolate->statics->lookup(cl);
return val && val->first;
} else {
return status == ready;
}
}
#endif