blob: 17287328357c0a4315ecbaf9e9185c39ed5f9a10 [file] [log] [blame]
//===-------- JavaClass.cpp - Java class representation -------------------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define JNJVM_LOAD 1
#include "debug.h"
#include "types.h"
#include "vmkit/System.h"
#include "ClasspathReflect.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "j3/JavaCompiler.h"
#include "JavaString.h"
#include "JavaConstantPool.h"
#include "JavaObject.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
#include "LockedMap.h"
#include "Reader.h"
#include <cstring>
#include <cstdlib>
#include <algorithm>
#if 0
using namespace vmkit;
#define dprintf(...) do { printf("JavaClass: "); printf(__VA_ARGS__); } while(0)
#define ddprintf(...) do { printf(__VA_ARGS__); } while(0)
#else
#define dprintf(...)
#define ddprintf(...)
#endif
using namespace j3;
using namespace std;
const UTF8* JavaAttribute::annotationsAttribute = 0;
const UTF8* JavaAttribute::codeAttribute = 0;
const UTF8* JavaAttribute::exceptionsAttribute = 0;
const UTF8* JavaAttribute::constantAttribute = 0;
const UTF8* JavaAttribute::lineNumberTableAttribute = 0;
const UTF8* JavaAttribute::innerClassesAttribute = 0;
const UTF8* JavaAttribute::sourceFileAttribute = 0;
const UTF8* JavaAttribute::signatureAttribute = 0;
const UTF8* JavaAttribute::enclosingMethodAttribute = 0;
const UTF8* JavaAttribute::paramAnnotationsAttribute = 0;
const UTF8* JavaAttribute::annotationDefaultAttribute = 0;
Class* ClassArray::SuperArray;
Class** ClassArray::InterfacesArray;
extern "C" void JavaObjectTracer(JavaObject*);
extern "C" void ArrayObjectTracer(JavaObject*);
extern "C" void RegularObjectTracer(JavaObject*);
extern "C" void ReferenceObjectTracer(JavaObject*);
extern "C" bool CheckIfObjectIsAssignableToArrayPosition(JavaObject * obj, JavaObject* array) {
llvm_gcroot(obj, 0);
llvm_gcroot(array, 0);
if (obj == 0)
return true;
bool b = obj->getVirtualTable()->isSubtypeOf(array->getVirtualTable()->baseClassVT);
if (!b) {
BEGIN_NATIVE_EXCEPTION(0)
Jnjvm* vm = JavaThread::get()->getJVM();
vm->CreateArrayStoreException(obj->getVirtualTable());
END_NATIVE_EXCEPTION
}
return b;
}
extern "C" bool IsSubtypeIntrinsic(JavaVirtualTable* obj, JavaVirtualTable* clazz){
//printf("2 + 1 \n");
return obj->isSubtypeOf(clazz);
}
static bool LessThanPtrVirtualTable (JavaVirtualTable * elem1, JavaVirtualTable * elem2) {
return elem1 < elem2;
}
static bool equalsPtrVirtualTable (JavaVirtualTable * elem1, JavaVirtualTable * elem2) {
return elem1 == elem2;
}
JavaAttribute::JavaAttribute(const UTF8* name, uint32 length,
uint32 offset) {
this->start = offset;
this->nbb = length;
this->name = name;
}
JavaAttribute* Class::lookupAttribute(const UTF8* key) {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
JavaAttribute* JavaField::lookupAttribute(const UTF8* key) {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
JavaAttribute* JavaMethod::lookupAttribute(const UTF8* key) {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
CommonClass::~CommonClass() {
}
Class::~Class() {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
cur->~JavaAttribute();
classLoader->allocator.Deallocate(cur);
}
for (uint32 i = 0; i < nbStaticFields; ++i) {
JavaField* cur = &(staticFields[i]);
cur->~JavaField();
classLoader->allocator.Deallocate(cur);
}
for (uint32 i = 0; i < nbVirtualFields; ++i) {
JavaField* cur = &(virtualFields[i]);
cur->~JavaField();
classLoader->allocator.Deallocate(cur);
}
for (uint32 i = 0; i < nbVirtualMethods; ++i) {
JavaMethod* cur = &(virtualMethods[i]);
cur->~JavaMethod();
classLoader->allocator.Deallocate(cur);
}
for (uint32 i = 0; i < nbStaticMethods; ++i) {
JavaMethod* cur = &(staticMethods[i]);
cur->~JavaMethod();
classLoader->allocator.Deallocate(cur);
}
if (ctpInfo) {
ctpInfo->~JavaConstantPool();
classLoader->allocator.Deallocate(ctpInfo);
}
classLoader->allocator.Deallocate(IsolateInfo);
// Currently, only regular classes have a heap allocated virtualVT.
// Array classes have a C++ allocated virtualVT and primitive classes
// do not have a virtualVT.
classLoader->allocator.Deallocate(virtualVT);
}
JavaField::~JavaField() {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
cur->~JavaAttribute();
classDef->classLoader->allocator.Deallocate(cur);
}
}
JavaMethod::~JavaMethod() {
for (uint32 i = 0; i < nbAttributes; ++i) {
JavaAttribute* cur = &(attributes[i]);
cur->~JavaAttribute();
classDef->classLoader->allocator.Deallocate(cur);
}
}
UserClassPrimitive* CommonClass::toPrimitive(Jnjvm* vm) const {
if (this == vm->upcalls->voidClass) {
return vm->upcalls->OfVoid;
} else if (this == vm->upcalls->intClass) {
return vm->upcalls->OfInt;
} else if (this == vm->upcalls->shortClass) {
return vm->upcalls->OfShort;
} else if (this == vm->upcalls->charClass) {
return vm->upcalls->OfChar;
} else if (this == vm->upcalls->doubleClass) {
return vm->upcalls->OfDouble;
} else if (this == vm->upcalls->byteClass) {
return vm->upcalls->OfByte;
} else if (this == vm->upcalls->boolClass) {
return vm->upcalls->OfBool;
} else if (this == vm->upcalls->longClass) {
return vm->upcalls->OfLong;
} else if (this == vm->upcalls->floatClass) {
return vm->upcalls->OfFloat;
} else {
return 0;
}
}
UserClassPrimitive*
ClassPrimitive::byteIdToPrimitive(char id, Classpath* upcalls) {
switch (id) {
case I_FLOAT :
return upcalls->OfFloat;
case I_INT :
return upcalls->OfInt;
case I_SHORT :
return upcalls->OfShort;
case I_CHAR :
return upcalls->OfChar;
case I_DOUBLE :
return upcalls->OfDouble;
case I_BYTE :
return upcalls->OfByte;
case I_BOOL :
return upcalls->OfBool;
case I_LONG :
return upcalls->OfLong;
case I_VOID :
return upcalls->OfVoid;
default :
return 0;
}
}
CommonClass::CommonClass(JnjvmClassLoader* loader, const UTF8* n) {
name = n;
classLoader = loader;
nbInterfaces = 0;
interfaces = 0;
access = 0;
super = 0;
memset(delegatee, 0, sizeof(JavaObject*) * NR_ISOLATES);
}
ClassPrimitive::ClassPrimitive(JnjvmClassLoader* loader, const UTF8* n,
uint32 nb) :
CommonClass(loader, n) {
uint32 size = JavaVirtualTable::getBaseSize();
virtualVT = new(loader->allocator, size) JavaVirtualTable(this);
access = ACC_ABSTRACT | ACC_FINAL | ACC_PUBLIC | JNJVM_PRIMITIVE;
logSize = nb;
}
Class::Class(JnjvmClassLoader* loader, const UTF8* n, ClassBytes* B) :
CommonClass(loader, n) {
virtualVT = 0;
bytes = B;
super = 0;
ctpInfo = 0;
outerClass = 0;
innerOuterResolved = false;
nbInnerClasses = 0;
nbVirtualMethods = 0;
nbStaticMethods = 0;
nbStaticFields = 0;
nbVirtualFields = 0;
virtualMethods = 0;
staticMethods = 0;
virtualFields = 0;
staticFields = 0;
ownerClass = 0;
innerAccess = 0;
access = JNJVM_CLASS;
memset(IsolateInfo, 0, sizeof(TaskClassMirror) * NR_ISOLATES);
}
ClassArray::ClassArray(JnjvmClassLoader* loader, const UTF8* n,
UserCommonClass* base) : CommonClass(loader, n) {
_baseClass = base;
super = ClassArray::SuperArray;
interfaces = ClassArray::InterfacesArray;
nbInterfaces = 2;
uint32 size = JavaVirtualTable::getBaseSize();
virtualVT = new(loader->allocator, size) JavaVirtualTable(this);
access = ACC_FINAL | ACC_ABSTRACT | JNJVM_ARRAY | base->getAccess();
access &= ~ACC_INTERFACE;
}
JavaObject* UserClassArray::doNew(sint32 n, Jnjvm* vm) {
JavaObject* res = NULL;
llvm_gcroot(res, 0);
if (n < 0) {
vm->negativeArraySizeException(n);
} else if (n > JavaArray::MaxArraySize) {
vm->outOfMemoryError();
}
UserCommonClass* cl = baseClass();
uint32 logSize = cl->isPrimitive() ?
cl->asPrimitiveClass()->logSize : (sizeof(JavaObject*) == 8 ? 3 : 2);
VirtualTable* VT = virtualVT;
uint32 size = sizeof(JavaObject) + sizeof(ssize_t) + (n << logSize);
res = (JavaObject*)JavaObject::operator new(size, VT);
JavaArray::setSize(res, n);
return res;
}
void* JavaMethod::compiledPtr(Class* customizeFor) {
if ((isCustomizable && customizeFor != NULL) || code == 0) {
return classDef->classLoader->getCompiler()->materializeFunction(this, customizeFor);
}
return code;
}
void JavaMethod::setNative() {
access |= ACC_NATIVE;
}
void JavaVirtualTable::setNativeTracer(word_t ptr, const char* name) {
tracer = ptr;
}
void JavaVirtualTable::setNativeDestructor(word_t ptr, const char* name) {
if (!cl->classLoader->getCompiler()->isStaticCompiling()) {
destructor = ptr;
operatorDelete = ptr;
}
}
JavaMethod* Class::lookupInterfaceMethodDontThrow(const UTF8* name,
const UTF8* type) {
JavaMethod* cur = lookupMethodDontThrow(name, type, false, false, 0);
if (cur == NULL) {
for (uint16 i = 0; i < nbInterfaces; ++i) {
Class* I = interfaces[i];
cur = I->lookupInterfaceMethodDontThrow(name, type);
if (cur) return cur;
}
}
if (cur == NULL && super != NULL) {
cur = super->lookupInterfaceMethodDontThrow(name, type);
}
return cur;
}
JavaMethod* Class::lookupSpecialMethodDontThrow(const UTF8* name,
const UTF8* type,
Class* current) {
JavaMethod* meth = lookupMethodDontThrow(name, type, false, true, NULL);
if (meth &&
isSuper(current->access) &&
current != meth->classDef &&
meth->classDef->isSubclassOf(current) &&
!name->equals(classLoader->bootstrapLoader->initName)) {
meth = current->super->lookupMethodDontThrow(name, type, false, true, NULL);
}
return meth;
}
JavaMethod* Class::lookupMethodDontThrow(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse,
Class** methodCl) {
// This is a dirty hack because of a dirty usage pattern. See UPCALL_METHOD macro...
if (this == NULL) return NULL;
JavaMethod* methods = 0;
uint32 nb = 0;
if (isStatic) {
methods = getStaticMethods();
nb = nbStaticMethods;
} else {
methods = getVirtualMethods();
nb = nbVirtualMethods;
}
for (uint32 i = 0; i < nb; ++i) {
JavaMethod& res = methods[i];
if (res.name->equals(name) && res.type->equals(type)) {
if (methodCl) *methodCl = (Class*)this;
return &res;
}
}
JavaMethod *cur = 0;
if (recurse) {
if (super) cur = super->lookupMethodDontThrow(name, type, isStatic,
recurse, methodCl);
if (cur) return cur;
if (isStatic) {
for (uint16 i = 0; i < nbInterfaces; ++i) {
Class* I = interfaces[i];
cur = I->lookupMethodDontThrow(name, type, isStatic, recurse,
methodCl);
if (cur) return cur;
}
}
}
return 0;
}
JavaMethod* Class::lookupMethod(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse,
Class** methodCl) {
JavaMethod* res = lookupMethodDontThrow(name, type, isStatic, recurse,
methodCl);
if (!res) {
JavaThread::get()->getJVM()->noSuchMethodError(this, name);
}
return res;
}
JavaMethod* Class::lookupInterfaceMethod(const UTF8* name, const UTF8* type) {
JavaMethod* res = lookupInterfaceMethodDontThrow(name, type);
if (!res) {
JavaThread::get()->getJVM()->noSuchMethodError(this, name);
}
return res;
}
JavaField*
Class::lookupFieldDontThrow(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse,
Class** definingClass) {
JavaField* fields = 0;
uint32 nb = 0;
if (isStatic) {
fields = getStaticFields();
nb = nbStaticFields;
} else {
fields = getVirtualFields();
nb = nbVirtualFields;
}
for (uint32 i = 0; i < nb; ++i) {
JavaField& res = fields[i];
if (res.name->equals(name) && res.type->equals(type)) {
if (definingClass) *definingClass = this;
return &res;
}
}
JavaField *cur = 0;
if (recurse) {
if (super) cur = super->lookupFieldDontThrow(name, type, isStatic,
recurse, definingClass);
if (cur) return cur;
if (isStatic) {
for (uint16 i = 0; i < nbInterfaces; ++i) {
Class* I = interfaces[i];
cur = I->lookupFieldDontThrow(name, type, isStatic, recurse,
definingClass);
if (cur) return cur;
}
}
}
return 0;
}
JavaField* Class::lookupField(const UTF8* name, const UTF8* type,
bool isStatic, bool recurse,
Class** definingClass) {
JavaField* res = lookupFieldDontThrow(name, type, isStatic, recurse,
definingClass);
if (!res) {
JavaThread::get()->getJVM()->noSuchFieldError(this, name);
}
return res;
}
JavaObject* UserClass::doNew(Jnjvm* vm) {
JavaObject* res = NULL;
llvm_gcroot(res, 0);
assert(this && "No class when allocating.");
assert((this->isInitializing() ||
classLoader->getCompiler()->isStaticCompiling() ||
this == classLoader->bootstrapLoader->upcalls->newClass)
&& "Uninitialized class when allocating.");
assert(getVirtualVT() && "No VT\n");
res = (JavaObject*)JavaObject::operator new(getVirtualSize(), getVirtualVT());
return res;
}
bool UserCommonClass::inheritName(const uint16* buf, uint32 len) {
if (getName()->equals(buf, len)) {
return true;
} else if (isPrimitive()) {
return false;
} else if (super) {
if (getSuper()->inheritName(buf, len)) return true;
}
for (uint32 i = 0; i < nbInterfaces; ++i) {
if (interfaces[i]->inheritName(buf, len)) return true;
}
return false;
}
bool UserCommonClass::isOfTypeName(const UTF8* Tname) {
if (inheritName(Tname->elements, Tname->size)) {
return true;
} else if (isArray()) {
UserCommonClass* curS = this;
uint32 prof = 0;
uint32 len = Tname->size;
bool res = true;
while (res && Tname->elements[prof] == I_TAB) {
UserCommonClass* cl = ((UserClassArray*)curS)->baseClass();
++prof;
if (cl->isClass()) cl->asClass()->resolveClass();
res = curS->isArray() && cl && (prof < len);
curS = cl;
}
return (Tname->elements[prof] == I_REF) &&
(res && curS->inheritName(&(Tname->elements[prof + 1]), len - 1));
} else {
return false;
}
}
bool UserCommonClass::isSubclassOf(UserCommonClass* cl) {
assert(virtualVT && cl->virtualVT);
return virtualVT->isSubtypeOf(cl->virtualVT);
}
bool JavaVirtualTable::isSubtypeOf(JavaVirtualTable* otherVT) {
assert(this);
assert(otherVT);
if (otherVT == ((JavaVirtualTable**)this)[otherVT->offset]) return true;
else if (otherVT->offset != getCacheIndex()) return false;
else if (this == otherVT) return true;
else {
for (uint32 i = 0; i < nbSecondaryTypes; ++i) {
if (secondaryTypes[i] == otherVT) {
cache = otherVT;
return true;
}
}
if (cl->isArray() && otherVT->cl->isArray()) {
return baseClassVT->isSubtypeOf(otherVT->baseClassVT);
}
}
return false;
}
void JavaField::InitNullStaticField() {
Typedef* type = getSignature();
void* obj = classDef->getStaticInstance();
if (!type->isPrimitive()) {
((JavaObject**)((uint64)obj + ptrOffset))[0] = NULL;
return;
}
PrimitiveTypedef* prim = (PrimitiveTypedef*)type;
if (prim->isLong()) {
((sint64*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isInt()) {
((sint32*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isChar()) {
((uint16*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isShort()) {
((sint16*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isByte()) {
((sint8*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isBool()) {
((uint8*)((uint64)obj + ptrOffset))[0] = 0;
} else if (prim->isDouble()) {
((double*)((uint64)obj + ptrOffset))[0] = 0.0;
} else if (prim->isFloat()) {
((float*)((uint64)obj + ptrOffset))[0] = 0.0;
} else {
abort();
}
}
void JavaField::InitStaticField(uint64 val) {
Typedef* type = getSignature();
void* obj = classDef->getStaticInstance();
assert(type->isPrimitive() && "Non primitive field");
PrimitiveTypedef* prim = (PrimitiveTypedef*)type;
if (prim->isLong()) {
((sint64*)((uint64)obj + ptrOffset))[0] = val;
} else if (prim->isInt()) {
((sint32*)((uint64)obj + ptrOffset))[0] = (sint32)val;
} else if (prim->isChar()) {
((uint16*)((uint64)obj + ptrOffset))[0] = (uint16)val;
} else if (prim->isShort()) {
((sint16*)((uint64)obj + ptrOffset))[0] = (sint16)val;
} else if (prim->isByte()) {
((sint8*)((uint64)obj + ptrOffset))[0] = (sint8)val;
} else if (prim->isBool()) {
((uint8*)((uint64)obj + ptrOffset))[0] = (uint8)val;
} else {
// Should never be here.
abort();
}
}
void JavaField::InitStaticField(JavaObject* val) {
llvm_gcroot(val, 0);
void* obj = classDef->getStaticInstance();
assert(isReference());
JavaObject** ptr = (JavaObject**)((uint64)obj + ptrOffset);
vmkit::Collector::objectReferenceNonHeapWriteBarrier((gc**)ptr, (gc*)val);
}
void JavaField::InitStaticField(double val) {
void* obj = classDef->getStaticInstance();
((double*)((uint64)obj + ptrOffset))[0] = val;
}
void JavaField::InitStaticField(float val) {
void* obj = classDef->getStaticInstance();
((float*)((uint64)obj + ptrOffset))[0] = val;
}
void JavaField::InitStaticField(Jnjvm* vm) {
JavaString* obj = 0;
llvm_gcroot(obj, 0);
const Typedef* type = getSignature();
JavaAttribute* attribute = lookupAttribute(JavaAttribute::constantAttribute);
if (!attribute) {
InitNullStaticField();
} else {
Reader reader(attribute, classDef->bytes);
JavaConstantPool * ctpInfo = classDef->ctpInfo;
uint16 idx = reader.readU2();
if (type->isPrimitive()) {
UserCommonClass* cl = type->assocClass(vm->bootstrapLoader);
if (cl == vm->upcalls->OfLong) {
InitStaticField((uint64)ctpInfo->LongAt(idx));
} else if (cl == vm->upcalls->OfDouble) {
InitStaticField(ctpInfo->DoubleAt(idx));
} else if (cl == vm->upcalls->OfFloat) {
InitStaticField(ctpInfo->FloatAt(idx));
} else {
InitStaticField((uint64)ctpInfo->IntegerAt(idx));
}
} else if (type->isReference()) {
const UTF8* utf8 = ctpInfo->UTF8At(ctpInfo->ctpDef[idx]);
obj = ctpInfo->resolveString(utf8, idx);
InitStaticField(obj);
} else {
fprintf(stderr, "I haven't verified your class file and it's malformed:"
" unknown constant %s!\n",
UTF8Buffer(type->keyName).cString());
abort();
}
}
}
void* UserClass::allocateStaticInstance(Jnjvm* vm) {
void* val = classLoader->allocator.Allocate(getStaticSize(),
"Static instance");
setStaticInstance(val);
return val;
}
void JavaMethod::initialise(Class* cl, const UTF8* N, const UTF8* T, uint16 A) {
name = N;
type = T;
classDef = cl;
_signature = 0;
code = 0;
access = A;
isCustomizable = false;
offset = 0;
}
void JavaField::initialise(Class* cl, const UTF8* N, const UTF8* T, uint16 A) {
name = N;
type = T;
classDef = cl;
_signature = 0;
ptrOffset = 0;
access = A;
}
void Class::readParents(Reader& reader) {
uint16 superEntry = reader.readU2();
if (superEntry) {
const UTF8* superUTF8 = ctpInfo->resolveClassName(superEntry);
super = classLoader->loadName(superUTF8, false, true, NULL);
}
uint16 nbI = reader.readU2();
interfaces = (Class**)
classLoader->allocator.Allocate(nbI * sizeof(Class*), "Interfaces");
// Do not set nbInterfaces yet, we may be interrupted by the GC
// in anon-cooperative environment.
for (int i = 0; i < nbI; i++) {
const UTF8* name = ctpInfo->resolveClassName(reader.readU2());
interfaces[i] = classLoader->loadName(name, false, true, NULL);
}
nbInterfaces = nbI;
}
void internalLoadExceptions(JavaMethod& meth) {
JavaAttribute* codeAtt = meth.lookupAttribute(JavaAttribute::codeAttribute);
if (codeAtt) {
Reader reader(codeAtt, meth.classDef->bytes);
//uint16 maxStack =
reader.readU2();
//uint16 maxLocals =
reader.readU2();
uint16 codeLen = reader.readU4();
reader.seek(codeLen, Reader::SeekCur);
uint16 nbe = reader.readU2();
for (uint16 i = 0; i < nbe; ++i) {
//startpc =
reader.readU2();
//endpc=
reader.readU2();
//handlerpc =
reader.readU2();
uint16 catche = reader.readU2();
if (catche) meth.classDef->ctpInfo->loadClass(catche, false);
}
}
}
void UserClass::loadExceptions() {
for (uint32 i = 0; i < nbVirtualMethods; ++i)
internalLoadExceptions(virtualMethods[i]);
for (uint32 i = 0; i < nbStaticMethods; ++i)
internalLoadExceptions(staticMethods[i]);
}
JavaAttribute* Class::readAttributes(Reader& reader, uint16& size) {
uint16 nba = reader.readU2();
JavaAttribute* attributes = new(classLoader->allocator, "Attributes") JavaAttribute[nba];
for (int i = 0; i < nba; i++) {
const UTF8* attName = ctpInfo->UTF8At(reader.readU2());
uint32 attLen = reader.readU4();
JavaAttribute& att = attributes[i];
att.start = reader.cursor;
att.nbb = attLen;
att.name = attName;
reader.seek(attLen, Reader::SeekCur);
}
size = nba;
return attributes;
}
void Class::readFields(Reader& reader) {
uint16 nbFields = reader.readU2();
virtualFields = new (classLoader->allocator, "Fields") JavaField[nbFields];
staticFields = virtualFields + nbFields;
for (int i = 0; i < nbFields; i++) {
uint16 access = reader.readU2();
const UTF8* name = ctpInfo->UTF8At(reader.readU2());
const UTF8* type = ctpInfo->UTF8At(reader.readU2());
JavaField* field = 0;
if (isStatic(access)) {
--staticFields;
field = &(staticFields[0]);
field->initialise(this, name, type, access);
++nbStaticFields;
} else {
field = &(virtualFields[nbVirtualFields]);
field->initialise(this, name, type, access);
++nbVirtualFields;
}
field->attributes = readAttributes(reader, field->nbAttributes);
}
}
void Class::fillIMT(std::set<JavaMethod*>* meths) {
for (uint32 i = 0; i < nbInterfaces; ++i) {
interfaces[i]->fillIMT(meths);
}
if (super != NULL) {
super->fillIMT(meths);
}
// Specification says that an invokeinterface also looks at j.l.Object.
if (isInterface() || (super == NULL)) {
for (uint32 i = 0; i < nbVirtualMethods; ++i) {
JavaMethod& meth = virtualMethods[i];
uint32_t index = InterfaceMethodTable::getIndex(meth.name, meth.type);
meths[index].insert(&meth);
}
}
}
void Class::makeVT() {
if (super == NULL) {
virtualTableSize = JavaVirtualTable::getFirstJavaMethodIndex();
} else {
virtualTableSize = super->virtualTableSize;
}
for (uint32 i = 0; i < nbVirtualMethods; ++i) {
JavaMethod& meth = virtualMethods[i];
if (meth.name->equals(classLoader->bootstrapLoader->finalize) &&
meth.type->equals(classLoader->bootstrapLoader->clinitType)) {
meth.offset = 0;
} else {
JavaMethod* parent = super?
super->lookupMethodDontThrow(meth.name, meth.type, false, true, 0) :
0;
uint64_t offset = 0;
if (!parent) {
offset = virtualTableSize++;
meth.offset = offset;
} else {
offset = parent->offset;
meth.offset = parent->offset;
}
}
}
vmkit::BumpPtrAllocator& allocator = classLoader->allocator;
virtualVT = new(allocator, virtualTableSize) JavaVirtualTable(this);
}
static void computeMirandaMethods(Class* current,
Class* baseClass, std::vector<JavaMethod*>& mirandaMethods) {
for (uint32 i = 0; i < current->nbInterfaces; i++) {
Class* I = current->interfaces[i];
// TODO: At this point, the interface may have not been read, so there
// is no methods yet.
for (uint32 j = 0; j < I->nbVirtualMethods; j++) {
JavaMethod& orig = I->virtualMethods[j];
JavaMethod* meth = baseClass->lookupMethodDontThrow(orig.name, orig.type,
false, true, 0);
if (meth == NULL) {
mirandaMethods.push_back(&orig);
}
}
computeMirandaMethods(I, baseClass, mirandaMethods);
}
}
static bool lessThanJavaMethods (JavaMethod* a,JavaMethod* b) {
bool flag = a->name->lessThan(b->name);
if (!flag) {
flag = a->name->equals(b->name);
if (flag) {
flag = a->type->lessThan(b->type);
}
}
return flag;
}
static bool cmpJavaMethods (JavaMethod* a,JavaMethod* b) {
bool flag = a->name->equals(b->name) && a->type->equals(b->type);
return flag;
}
static void cleanMirandaMethods(std::vector<JavaMethod*>& mirandaMethods) {
std::sort(mirandaMethods.begin(), mirandaMethods.end(), lessThanJavaMethods);
// using predicate comparison:
std::vector<JavaMethod*>::iterator it;
it = std::unique (mirandaMethods.begin(), mirandaMethods.end(), cmpJavaMethods); // (no changes)
mirandaMethods.resize( std::distance(mirandaMethods.begin(),it) ); // 10 20 30 20 10
}
void Class::readMethods(Reader& reader) {
uint32 nbMethods = reader.readU2();
vmkit::ThreadAllocator allocator;
if (isAbstract(access)) {
virtualMethods = (JavaMethod*)
allocator.Allocate(nbMethods * sizeof(JavaMethod));
} else {
virtualMethods =
new(classLoader->allocator, "Methods") JavaMethod[nbMethods];
}
staticMethods = virtualMethods + nbMethods;
for (uint32 i = 0; i < nbMethods; i++) {
uint16 access = reader.readU2();
const UTF8* name = ctpInfo->UTF8At(reader.readU2());
const UTF8* type = ctpInfo->UTF8At(reader.readU2());
JavaMethod* meth = 0;
if (isStatic(access)) {
--staticMethods;
meth = &(staticMethods[0]);
meth->initialise(this, name, type, access);
++nbStaticMethods;
} else {
meth = &(virtualMethods[nbVirtualMethods]);
meth->initialise(this, name, type, access);
++nbVirtualMethods;
}
meth->attributes = readAttributes(reader, meth->nbAttributes);
}
if (isAbstract(access)) {
std::vector<JavaMethod*> mirandaMethods;
computeMirandaMethods(this, this, mirandaMethods);
uint32 size = mirandaMethods.size();
if (size > 100) {
cleanMirandaMethods(mirandaMethods);
size = mirandaMethods.size();
}
nbMethods += size;
JavaMethod* realMethods =
new(classLoader->allocator, "Methods") JavaMethod[nbMethods];
memcpy(realMethods + size, virtualMethods,
sizeof(JavaMethod) * (nbMethods - size));
nbVirtualMethods += size;
staticMethods = realMethods + nbVirtualMethods;
if (size != 0) {
int j = 0;
for (std::vector<JavaMethod*>::iterator i = mirandaMethods.begin(),
e = mirandaMethods.end(); i != e; i++) {
JavaMethod* cur = *i;
realMethods[j++].initialise(this, cur->name, cur->type, cur->access);
}
}
virtualMethods = realMethods;
}
}
void Class::readClass() {
PRINT_DEBUG(JNJVM_LOAD, 0, LIGHT_GREEN, "readClass \t");
PRINT_DEBUG(JNJVM_LOAD, 0, DARK_MAGENTA, "%s\n", UTF8Buffer(this->name).cString());
assert(getInitializationState() == loaded && "Wrong init state");
Reader reader(bytes);
uint32 magic;
magic = reader.readU4();
assert(magic == Jnjvm::Magic && "I've created a class but magic is no good!");
uint16 minor = reader.readU2();
uint16 major = reader.readU2();
this->isClassVersionSupported(major, minor);
uint32 ctpSize = reader.readU2();
ctpInfo = new(classLoader->allocator, ctpSize) JavaConstantPool(this, reader,
ctpSize);
access |= reader.readU2();
if (!isPublic(access)) access |= ACC_PRIVATE;
const UTF8* thisClassName =
ctpInfo->resolveClassName(reader.readU2());
if (!(thisClassName->equals(name))) {
JavaThread::get()->getJVM()->noClassDefFoundError(this, thisClassName);
}
readParents(reader);
readFields(reader);
readMethods(reader);
attributes = readAttributes(reader, nbAttributes);
}
void Class::getMinimalJDKVersion(uint16_t major, uint16_t minor, uint16_t& JDKMajor, uint16_t& JDKMinor, uint16_t& JDKBuild)
{
JDKMajor = 1;
JDKBuild = 0;
if (major == 45 && minor <= 3) { // Supported by Java 1.0.2
JDKMinor = 0;
JDKBuild = 2;
} else if (major == 45 && minor <= 65535) { // Supported by Java 1.1
JDKMinor = 1;
} else { // Supported by Java 1.x (x >= 2)
JDKMinor = major - 43;
if (minor == 0) --JDKMinor;
}
}
bool Class::isClassVersionSupported(uint16_t major, uint16_t minor)
{
const uint16_t supportedJavaMinorVersion = 6; // Java 1.6
Class::getMinimalJDKVersion(major, minor, minJDKVersionMajor, minJDKVersionMinor, minJDKVersionBuild);
bool res = (minJDKVersionMajor <= 1) && (minJDKVersionMinor <= supportedJavaMinorVersion);
if (!res) {
cerr << "WARNING: Class file '" << *name << "' requires Java version " << minJDKVersionMajor << '.' << minJDKVersionMinor <<
". This JVM only supports Java versions up to 1." << supportedJavaMinorVersion << '.' << endl;
}
return res;
}
void UserClass::resolveParents() {
if (super != NULL) {
super->resolveClass();
}
for (unsigned i = 0; i < nbInterfaces; i++)
interfaces[i]->resolveClass();
}
void Class::resolveClass() {
if (isResolved() || isErroneous()) return;
resolveParents();
loadExceptions();
// Do a compare and swap in case another thread initialized the class.
__sync_val_compare_and_swap(
&(getCurrentTaskClassMirror().status), loaded, resolved);
assert(isResolved() || isErroneous());
}
void UserClass::resolveInnerOuterClasses() {
if (!innerOuterResolved) {
JavaAttribute* attribute = lookupAttribute(JavaAttribute::innerClassesAttribute);
if (attribute != 0) {
Reader reader(attribute, bytes);
uint16 nbi = reader.readU2();
for (uint16 i = 0; i < nbi; ++i) {
uint16 inner = reader.readU2();
uint16 outer = reader.readU2();
uint16 innerName = reader.readU2();
uint16 accessFlags = reader.readU2();
UserClass* clInner = 0;
UserClass* clOuter = 0;
if (inner) clInner = (UserClass*)ctpInfo->loadClass(inner);
if (outer) clOuter = (UserClass*)ctpInfo->loadClass(outer);
if (clInner == this) {
outerClass = clOuter;
if (!innerName) isAnonymous = true;
} else if (clOuter == this) {
if (!innerClasses) {
innerClasses = (Class**)
classLoader->allocator.Allocate(nbi * sizeof(Class*),
"Inner classes");
}
clInner->setInnerAccess(accessFlags);
if (!innerName) clInner->isAnonymous = true;
innerClasses[nbInnerClasses++] = clInner;
}
}
}
innerOuterResolved = true;
}
}
static JavaObject* getClassType(Jnjvm* vm, JnjvmClassLoader* loader,
Typedef* type) {
UserCommonClass* res = type->assocClass(loader);
assert(res && "No associated class");
return res->getClassDelegatee(vm);
}
ArrayObject* JavaMethod::getParameterTypes(JnjvmClassLoader* loader) {
ArrayObject* res = NULL;
JavaObject* delegatee = NULL;
llvm_gcroot(res, 0);
llvm_gcroot(delegatee, 0);
Jnjvm* vm = JavaThread::get()->getJVM();
Signdef* sign = getSignature();
Typedef* const* arguments = sign->getArgumentsType();
res = (ArrayObject*)vm->upcalls->classArrayClass->doNew(sign->nbArguments,vm);
for (uint32 index = 0; index < sign->nbArguments; ++index) {
delegatee = getClassType(vm, loader, arguments[index]);
ArrayObject::setElement(res, delegatee, index);
}
return res;
}
JavaObject* JavaMethod::getReturnType(JnjvmClassLoader* loader) {
JavaObject* obj = 0;
llvm_gcroot(obj, 0);
Jnjvm* vm = JavaThread::get()->getJVM();
Typedef* ret = getSignature()->getReturnType();
obj = getClassType(vm, loader, ret);
return obj;
}
ArrayObject* JavaMethod::getExceptionTypes(JnjvmClassLoader* loader) {
ArrayObject* res = NULL;
JavaObject* delegatee = NULL;
llvm_gcroot(res, 0);
llvm_gcroot(delegatee, 0);
JavaAttribute* exceptionAtt = lookupAttribute(JavaAttribute::exceptionsAttribute);
Jnjvm* vm = JavaThread::get()->getJVM();
if (exceptionAtt == 0) {
return (ArrayObject*)vm->upcalls->classArrayClass->doNew(0, vm);
} else {
UserConstantPool* ctp = classDef->getConstantPool();
Reader reader(exceptionAtt, classDef->bytes);
uint16 nbe = reader.readU2();
res = (ArrayObject*)vm->upcalls->classArrayClass->doNew(nbe, vm);
for (uint16 i = 0; i < nbe; ++i) {
uint16 idx = reader.readU2();
UserCommonClass* cl = ctp->loadClass(idx);
assert(cl->asClass() && "Wrong exception type");
cl->asClass()->resolveClass();
delegatee = cl->getClassDelegatee(vm);
ArrayObject::setElement(res, delegatee, i);
}
return res;
}
}
JavaObject* CommonClass::setDelegatee(JavaObject* val) {
llvm_gcroot(val, 0);
JavaObject** obj = &(delegatee[0]);
if (*obj == NULL) {
vmkit::Collector::objectReferenceNonHeapWriteBarrier((gc**)obj, (gc*)val);
}
return getDelegatee();
}
UserCommonClass* UserCommonClass::resolvedImplClass(Jnjvm* vm,
JavaObject* clazz,
bool doClinit) {
JavaObjectClass* jcl = 0;
llvm_gcroot(clazz, 0);
llvm_gcroot(jcl, 0);
UserCommonClass* cl = JavaObjectClass::getClass(jcl = (JavaObjectClass*)clazz);
assert(cl && "No class in Class object");
if (cl->isClass()) {
cl->asClass()->resolveClass();
if (doClinit) cl->asClass()->initialiseClass(vm);
}
return cl;
}
void JavaMethod::jniConsFromMeth(char* buf, const UTF8* jniConsClName,
const UTF8* jniConsName,
const UTF8* jniConsType,
bool synthetic) {
sint32 clen = jniConsClName->size;
sint32 mnlen = jniConsName->size;
uint32 cur = 0;
char* ptr = &(buf[JNI_NAME_PRE_LEN]);
memcpy(buf, JNI_NAME_PRE, JNI_NAME_PRE_LEN);
for (sint32 i = 0; i < clen; ++i) {
cur = jniConsClName->elements[i];
if (cur == '/') {
ptr[0] = '_';
ptr++;
} else if (cur == '_') {
ptr[0] = '_';
ptr[1] = '1';
ptr += 2;
} else if (cur == '$') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '2';
ptr[5] = '4';
ptr += 6;
} else {
ptr[0] = (uint8)cur;
ptr++;
}
}
ptr[0] = '_';
++ptr;
for (sint32 i = 0; i < mnlen; ++i) {
cur = jniConsName->elements[i];
if (cur == '/') {
ptr[0] = '_';
++ptr;
} else if (cur == '_') {
ptr[0] = '_';
ptr[1] = '1';
ptr += 2;
} else if (cur == '<') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '3';
ptr[5] = 'C';
ptr += 6;
} else if (cur == '>') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '3';
ptr[5] = 'E';
ptr += 6;
} else {
ptr[0] = (uint8)cur;
++ptr;
}
}
ptr[0] = 0;
}
void JavaMethod::jniConsFromMethOverloaded(char* buf, const UTF8* jniConsClName,
const UTF8* jniConsName,
const UTF8* jniConsType,
bool synthetic) {
sint32 clen = jniConsClName->size;
sint32 mnlen = jniConsName->size;
uint32 cur = 0;
char* ptr = &(buf[JNI_NAME_PRE_LEN]);
memcpy(buf, JNI_NAME_PRE, JNI_NAME_PRE_LEN);
for (sint32 i = 0; i < clen; ++i) {
cur = jniConsClName->elements[i];
if (cur == '/') {
ptr[0] = '_';
++ptr;
} else if (cur == '_') {
ptr[0] = '_';
ptr[1] = '1';
ptr += 2;
} else if (cur == '$') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '2';
ptr[5] = '4';
ptr += 6;
} else {
ptr[0] = (uint8)cur;
++ptr;
}
}
ptr[0] = '_';
++ptr;
for (sint32 i = 0; i < mnlen; ++i) {
cur = jniConsName->elements[i];
if (cur == '/') ptr[0] = '_';
else if (cur == '_') {
ptr[0] = '_';
ptr[1] = '1';
ptr += 2;
} else if (cur == '<') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '3';
ptr[5] = 'C';
ptr += 6;
} else if (cur == '>') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '3';
ptr[5] = 'E';
ptr += 6;
} else {
ptr[0] = (uint8)cur;
++ptr;
}
}
sint32 i = 0;
while (i < jniConsType->size) {
char c = jniConsType->elements[i++];
if (c == I_PARG) {
ptr[0] = '_';
ptr[1] = '_';
ptr += 2;
} else if (c == '/') {
ptr[0] = '_';
++ptr;
} else if (c == '_') {
ptr[0] = '_';
ptr[1] = '1';
ptr += 2;
} else if (c == '$') {
ptr[0] = '_';
ptr[1] = '0';
ptr[2] = '0';
ptr[3] = '0';
ptr[4] = '2';
ptr[5] = '4';
ptr += 6;
} else if (c == I_END_REF) {
ptr[0] = '_';
ptr[1] = '2';
ptr += 2;
} else if (c == I_TAB) {
ptr[0] = '_';
ptr[1] = '3';
ptr += 2;
} else if (c == I_PARD) {
break;
} else {
ptr[0] = c;
++ptr;
}
}
if (synthetic) {
ptr[0] = 'S';
++ptr;
}
ptr[0] = 0;
}
bool UserClass::isNativeOverloaded(JavaMethod* meth) {
for (uint32 i = 0; i < nbVirtualMethods; ++i) {
JavaMethod& cur = virtualMethods[i];
if (&cur != meth && isNative(cur.access) && cur.name->equals(meth->name))
return true;
}
for (uint32 i = 0; i < nbStaticMethods; ++i) {
JavaMethod& cur = staticMethods[i];
if (&cur != meth && isNative(cur.access) && cur.name->equals(meth->name))
return true;
}
return false;
}
ArrayUInt16* JavaMethod::toString() const {
Jnjvm* vm = JavaThread::get()->getJVM();
uint32 size = classDef->name->size + name->size + type->size + 1;
ArrayUInt16* res = (ArrayUInt16*)vm->upcalls->ArrayOfChar->doNew(size, vm);
llvm_gcroot(res, 0);
uint32 i = 0;
for (sint32 j = 0; j < classDef->name->size; ++j) {
if (classDef->name->elements[j] == '/') {
ArrayUInt16::setElement(res, '.', i);
} else {
ArrayUInt16::setElement(res, classDef->name->elements[j], i);
}
i++;
}
ArrayUInt16::setElement(res, '.', i);
i++;
for (sint32 j = 0; j < name->size; ++j) {
ArrayUInt16::setElement(res, name->elements[j], i);
i++;
}
for (sint32 j = 0; j < type->size; ++j) {
ArrayUInt16::setElement(res, type->elements[j], i);
i++;
}
return res;
}
bool UserClass::needsInitialisationCheck() {
if (isReady()) return false;
if (super && super->needsInitialisationCheck())
return true;
if (nbStaticFields > 0) return true;
JavaMethod* meth =
lookupMethodDontThrow(classLoader->bootstrapLoader->clinitName,
classLoader->bootstrapLoader->clinitType,
true, false, 0);
if (meth) return true;
setInitializationState(ready);
return false;
}
void ClassArray::initialiseVT(Class* javaLangObject) {
ClassArray::SuperArray = javaLangObject;
JnjvmClassLoader* JCL = javaLangObject->classLoader;
Classpath* upcalls = JCL->bootstrapLoader->upcalls;
assert(javaLangObject->virtualVT->init &&
"Initializing array VT before JavaObjectVT");
// Load and resolve interfaces of array classes. We resolve them now
// so that the secondary type list of array VTs can reference them.
ClassArray::InterfacesArray[0] =
JCL->loadName(JCL->asciizConstructUTF8("java/lang/Cloneable"),
true, false, NULL);
ClassArray::InterfacesArray[1] =
JCL->loadName(JCL->asciizConstructUTF8("java/io/Serializable"),
true, false, NULL);
// Load base array classes that JnJVM internally uses. Now that the interfaces
// have been loaded, the secondary type can be safely created.
upcalls->ArrayOfObject =
JCL->constructArray(JCL->asciizConstructUTF8("[Ljava/lang/Object;"));
upcalls->ArrayOfString =
JCL->constructArray(JCL->asciizConstructUTF8("[Ljava/lang/String;"));
// Update native array classes. A few things have not been set properly
// when loading these classes because java.lang.Object and java.lang.Object[]
// were not loaded yet. Correct that now by updating these classes.
#define COPY(CLASS) \
memcpy(CLASS->virtualVT->getFirstJavaMethod(), \
javaLangObject->virtualVT->getFirstJavaMethod(), \
sizeof(word_t) * JavaVirtualTable::getNumJavaMethods()); \
CLASS->super = javaLangObject; \
CLASS->virtualVT->display[0] = javaLangObject->virtualVT; \
CLASS->virtualVT->secondaryTypes = \
upcalls->ArrayOfObject->virtualVT->secondaryTypes; \
COPY(upcalls->ArrayOfBool)
COPY(upcalls->ArrayOfByte)
COPY(upcalls->ArrayOfChar)
COPY(upcalls->ArrayOfShort)
COPY(upcalls->ArrayOfInt)
COPY(upcalls->ArrayOfFloat)
COPY(upcalls->ArrayOfDouble)
COPY(upcalls->ArrayOfLong)
#undef COPY
}
JavaVirtualTable::JavaVirtualTable(Class* C) {
if (C->super) {
Class* referenceClass =
C->classLoader->bootstrapLoader->upcalls->newReference;
if (referenceClass != NULL && C->super->isSubclassOf(referenceClass)) {
tracer = (word_t)ReferenceObjectTracer;
} else {
tracer = (word_t)RegularObjectTracer;
}
operatorDelete = 0;
// Set IMT.
if (!isAbstract(C->access)) {
IMT = new (C->classLoader->allocator, "IMT") InterfaceMethodTable();
}
// Set the class of this VT.
cl = C;
// Set depth and display for fast dynamic type checking.
JavaVirtualTable* superVT = C->super->virtualVT;
assert(superVT && "Super has no VT");
depth = superVT->depth + 1;
nbSecondaryTypes = superVT->nbSecondaryTypes + cl->nbInterfaces;
for (uint32 i = 0; i < cl->nbInterfaces; ++i) {
nbSecondaryTypes += cl->interfaces[i]->virtualVT->nbSecondaryTypes;
}
uint32 length = getDisplayLength() < depth ? getDisplayLength() : depth;
memcpy(display, superVT->display, length * sizeof(JavaVirtualTable*));
uint32 outOfDepth = 0;
if (C->isInterface()) {
offset = getCacheIndex();
} else if (depth < getDisplayLength()) {
display[depth] = this;
offset = getCacheIndex() + depth + 1;
} else {
offset = getCacheIndex();
++nbSecondaryTypes;
outOfDepth = 1;
}
vmkit::BumpPtrAllocator& allocator = C->classLoader->allocator;
secondaryTypes = (JavaVirtualTable**)
allocator.Allocate(sizeof(JavaVirtualTable*) * nbSecondaryTypes,
"Secondary types");
if (outOfDepth) {
secondaryTypes[0] = this;
}
if (superVT->nbSecondaryTypes) {
memcpy(secondaryTypes + outOfDepth, superVT->secondaryTypes,
sizeof(JavaVirtualTable*) * superVT->nbSecondaryTypes);
}
for (uint32 i = 0; i < cl->nbInterfaces; ++i) {
JavaVirtualTable* cur = cl->interfaces[i]->virtualVT;
assert(cur && "Interface not resolved!\n");
uint32 index = superVT->nbSecondaryTypes + outOfDepth + i;
secondaryTypes[index] = cur;
}
uint32 lastIndex = superVT->nbSecondaryTypes + cl->nbInterfaces +
outOfDepth;
for (uint32 i = 0; i < cl->nbInterfaces; ++i) {
JavaVirtualTable* cur = cl->interfaces[i]->virtualVT;
memcpy(secondaryTypes + lastIndex, cur->secondaryTypes,
sizeof(JavaVirtualTable*) * cur->nbSecondaryTypes);
lastIndex += cur->nbSecondaryTypes;
}
if (nbSecondaryTypes) {
std::sort(secondaryTypes, &secondaryTypes[nbSecondaryTypes],LessThanPtrVirtualTable);
JavaVirtualTable** it = std::unique (secondaryTypes, &secondaryTypes[nbSecondaryTypes], equalsPtrVirtualTable); // (no changes)
nbSecondaryTypes = std::distance(secondaryTypes,it);
//isSortedSecondaryTypes = true;
}
} else {
// Set the tracer, destructor and delete.
tracer = (word_t)JavaObjectTracer;
operatorDelete = 0;
// Set the class of this VT.
cl = C;
// Set depth and display for fast dynamic type checking.
// java.lang.Object does not have any secondary types.
offset = getCacheIndex() + 1;
depth = 0;
display[0] = this;
nbSecondaryTypes = 0;
}
}
JavaVirtualTable::JavaVirtualTable(ClassArray* C) {
if (C->baseClass()->isClass())
C->baseClass()->asClass()->resolveClass();
if (!C->baseClass()->isPrimitive()) {
baseClassVT = C->baseClass()->virtualVT;
// Copy the super VT into the current VT.
uint32 size = (getBaseSize() - getFirstJavaMethodIndex());
memcpy(this->getFirstJavaMethod(),
C->super->virtualVT->getFirstJavaMethod(),
size * sizeof(word_t));
tracer = (word_t)ArrayObjectTracer;
// Set the class of this VT.
cl = C;
// Set depth and display for fast dynamic type checking.
JnjvmClassLoader* JCL = cl->classLoader;
Classpath* upcalls = JCL->bootstrapLoader->upcalls;
if (upcalls->ArrayOfObject) {
UserCommonClass* base = C->baseClass();
uint32 dim = 1;
while (base->isArray()) {
base = base->asArrayClass()->baseClass();
++dim;
}
bool newSecondaryTypes = false;
bool intf = base->isInterface();
ClassArray* super = 0;
if (base->isPrimitive()) {
// If the base class is primitive, then the super is one
// dimension below, e.g. the super of int[][] is Object[].
--dim;
const UTF8* superName = JCL->constructArrayName(dim, C->super->name);
super = JCL->constructArray(superName);
} else if (base == C->super) {
// If the base class is java.lang.Object, then the super is one
// dimension below, e.g. the super of Object[][] is Object[].
// Also, the class is the first class in the dimension hierarchy,
// so it must create a new secondary type list.
--dim;
newSecondaryTypes = true;
super = C->baseClass()->asArrayClass();
} else {
// If the base class is any other class, interface or not,
// the super is of the dimension of the current array class,
// and whose base class is the super of this base class.
const UTF8* superName = JCL->constructArrayName(dim, base->super->name);
JnjvmClassLoader* superLoader = base->super->classLoader;
super = superLoader->constructArray(superName);
}
assert(super && "No super found");
JavaVirtualTable* superVT = super->virtualVT;
depth = superVT->depth + 1;
// Record if we need to add the super in the list of secondary types.
uint32 addSuper = 0;
uint32 length = getDisplayLength() < depth ? getDisplayLength() : depth;
memcpy(display, superVT->display, length * sizeof(JavaVirtualTable*));
if (depth < getDisplayLength() && !intf) {
display[depth] = this;
offset = getCacheIndex() + depth + 1;
} else {
offset = getCacheIndex();
// We add the super if the current class is an interface or if the super
// class is out of depth.
if (intf || depth != getDisplayLength()) addSuper = 1;
}
vmkit::BumpPtrAllocator& allocator = JCL->allocator;
if (!newSecondaryTypes) {
if (base->nbInterfaces || addSuper) {
// If the base class implements interfaces, we must also add the
// arrays of these interfaces, of the same dimension than this array
// class and add them to the secondary types list.
// Finally, we must add the list of array of secondary classes from base
nbSecondaryTypes = base->nbInterfaces + superVT->nbSecondaryTypes +
addSuper
// + base->virtualVT->nbSecondaryTypes
;
secondaryTypes = (JavaVirtualTable**)
allocator.Allocate(sizeof(JavaVirtualTable*) * nbSecondaryTypes,
"Secondary types");
// Put the super in the list of secondary types.
if (addSuper) secondaryTypes[0] = superVT;
// Copy the list of secondary types of the super.
memcpy(secondaryTypes + addSuper, superVT->secondaryTypes,
superVT->nbSecondaryTypes * sizeof(JavaVirtualTable*));
// Add our own secondary types: the interfaces of the base class put
// in the dimension of the current array class.
for (uint32 i = 0; i < base->nbInterfaces; ++i) {
const UTF8* name =
JCL->constructArrayName(dim, base->interfaces[i]->name);
ClassArray* interface = JCL->constructArray(name);
JavaVirtualTable* CurVT = interface->virtualVT;
secondaryTypes[i + superVT->nbSecondaryTypes + addSuper] = CurVT;
}
// int index = superVT->nbSecondaryTypes + addSuper + base->nbInterfaces;
// for (uint32 i = 0; i < base->virtualVT->nbSecondaryTypes; ++i) {
// if (base->virtualVT == base->virtualVT->secondaryTypes[i]) continue;
//
// const UTF8* name =
// JCL->constructArrayName(dim, base->virtualVT->secondaryTypes[i]->cl->name);
// ClassArray* interface = JCL->constructArray(name);
// JavaVirtualTable* CurVT = interface->virtualVT;
// secondaryTypes[index++] = CurVT;
// }
//
// nbSecondaryTypes = index;
} else {
// If the super is not a secondary type and the base class does not
// implement any interface, we can reuse the list of secondary types
// of super. If the base class is a primitive, the array class shares
// the same secondary types than the super of the current superVT
// (eg Object[][] for int[][]).
if (base->isPrimitive()) {
const UTF8* superName = JCL->constructArrayName(dim + 1, C->super->name);
super = JCL->constructArray(superName);
superVT = super->virtualVT;
}
nbSecondaryTypes = superVT->nbSecondaryTypes;
secondaryTypes = superVT->secondaryTypes;
}
} else {
// This is an Object[....] array class. It will create the list of
// secondary types and all array classes of the same dimension whose
// base class does not have interfaces point to this array.
// If we're superior than the display limit, we must make room for one
// slot that will contain the current VT.
uint32 outOfDepth = 0;
if (depth >= getDisplayLength()) outOfDepth = 1;
assert(cl->nbInterfaces == 2 && "Arrays have more than 2 interface?");
// The list of secondary types is composed of:
// (1) The list of secondary types of super array.
// (2) The array of inherited interfaces with the same dimensions.
// (3) This VT, if its depth is superior than the display size.
nbSecondaryTypes = superVT->nbSecondaryTypes + 2 + outOfDepth;
secondaryTypes = (JavaVirtualTable**)
allocator.Allocate(sizeof(JavaVirtualTable*) * nbSecondaryTypes,
"Secondary types");
// First, copy the list of secondary types from super array.
memcpy(secondaryTypes + outOfDepth, superVT->secondaryTypes,
superVT->nbSecondaryTypes * sizeof(JavaVirtualTable*));
// If the depth is superior than the display size, put the current VT
// at the beginning of the list.
if (outOfDepth) secondaryTypes[0] = this;
// Load Cloneable[...] and Serializable[...]
const UTF8* name = JCL->constructArrayName(dim, cl->interfaces[0]->name);
ClassArray* firstInterface = JCL->constructArray(name);
name = JCL->constructArrayName(dim, cl->interfaces[1]->name);
ClassArray* secondInterface = JCL->constructArray(name);
uint32 index = superVT->nbSecondaryTypes + outOfDepth;
// Put Cloneable[...] and Serializable[...] at the end of the list.
secondaryTypes[index] = firstInterface->virtualVT;
secondaryTypes[index + 1] = secondInterface->virtualVT;
}
} else {
// This is java.lang.Object[].
depth = 1;
display[0] = C->super->virtualVT;
display[1] = this;
offset = getCacheIndex() + 2;
nbSecondaryTypes = 2;
vmkit::BumpPtrAllocator& allocator = JCL->allocator;
secondaryTypes = (JavaVirtualTable**)
allocator.Allocate(sizeof(JavaVirtualTable*) * nbSecondaryTypes,
"Secondary types");
// The interfaces have already been resolved.
secondaryTypes[0] = cl->interfaces[0]->virtualVT;
secondaryTypes[1] = cl->interfaces[1]->virtualVT;
}
} else {
// Set the tracer, destructor and delete
tracer = (word_t)JavaObjectTracer;
operatorDelete = 0;
// Set the class of this VT.
cl = C;
// Set depth and display for fast dynamic type checking. Since
// JavaObject has not been loaded yet, don't use super.
depth = 1;
display[0] = 0;
display[1] = this;
nbSecondaryTypes = 2;
offset = getCacheIndex() + 2;
// The list of secondary types has not been allocated yet by
// java.lang.Object[]. The initialiseVT function will update the current
// array to point to java.lang.Object[]'s secondary list.
}
if (offset == getCacheIndex() && nbSecondaryTypes) {
std::sort(secondaryTypes, &secondaryTypes[nbSecondaryTypes],LessThanPtrVirtualTable);
JavaVirtualTable** it = std::unique (secondaryTypes, &secondaryTypes[nbSecondaryTypes], equalsPtrVirtualTable); // (no changes)
nbSecondaryTypes = std::distance(secondaryTypes,it);
//isSortedSecondaryTypes = true;
}
}
JavaVirtualTable::JavaVirtualTable(ClassPrimitive* C) {
// Only used for subtype checking
cl = C;
depth = 0;
display[0] = this;
nbSecondaryTypes = 0;
offset = getCacheIndex() + 1;
}
void AnnotationReader::readAnnotation() {
uint16 typeIndex = reader.readU2();
uint16 numPairs = reader.readU2();
for (uint16 j = 0; j < numPairs; ++j) {
/* uint16 nameIndex = */ reader.readU2();
readElementValue();
}
AnnotationNameIndex = typeIndex;
}
void AnnotationReader::readAnnotationElementValues() {
uint16 numPairs = reader.readU2();
for (uint16 j = 0; j < numPairs; ++j) {
reader.readU2();
readElementValue();
}
}
void AnnotationReader::readElementValue() {
uint8 tag = reader.readU1();
if ((tag == 'B') || (tag == 'C') || (tag == 'D') || (tag == 'F') ||
(tag == 'J') || (tag == 'S') || (tag == 'I') || (tag == 'Z') ||
(tag == 's')) {
/* uint16 constValue = */ reader.readU2();
} else if (tag == 'e') {
/* uint16 typeName = */ reader.readU2();
/* uint16 constName = */ reader.readU2();
} else if (tag == 'c') {
/* uint16 classInfoIndex = */ reader.readU2();
} else if (tag == '@') {
readAnnotation();
} else if (tag == '[') {
uint16 numValues = reader.readU2();
for (uint32 i = 0; i < numValues; ++i) {
readElementValue();
}
}
}
JavaObject* AnnotationReader::createElementValue(bool nextParameterIsTypeOfMethod, JavaObject* type, const UTF8* lastKey) {
JavaObject* res = 0;
JavaObject* tmp = 0;
JavaString* str = 0;
JavaObject* field = 0;
JavaObject* clazzLoaded = 0;
JavaObject* classOfCurrentAnnotationProperty = 0;
JavaObject* newHashMap = 0;
JavaObject* annotationClass = 0;
llvm_gcroot(res, 0);
llvm_gcroot(tmp, 0);
llvm_gcroot(str, 0);
llvm_gcroot(clazzLoaded, 0);
llvm_gcroot(field, 0);
llvm_gcroot(type, 0);
llvm_gcroot(classOfCurrentAnnotationProperty, 0);
llvm_gcroot(newHashMap, 0);
llvm_gcroot(annotationClass, 0);
uint8 tag = reader.readU1();
Jnjvm* vm = JavaThread::get()->getJVM();
Classpath* upcalls = vm->upcalls;
ddprintf("value:");
if (tag == 'B') {
sint32 val = cl->ctpInfo->IntegerAt(reader.readU2());
ddprintf("B=%d", val);
res = upcalls->byteClass->doNew(vm);
upcalls->byteValue->setInstanceInt8Field(res, val);
} else if (tag == 'C') {
uint32 val = cl->ctpInfo->IntegerAt(reader.readU2());
ddprintf("C=%c", val);
res = upcalls->charClass->doNew(vm);
upcalls->charValue->setInstanceInt16Field(res, val);
} else if (tag == 'D') {
double val = cl->ctpInfo->DoubleAt(reader.readU2());
ddprintf("D=%f", val);
res = upcalls->doubleClass->doNew(vm);
upcalls->doubleValue->setInstanceDoubleField(res, val);
} else if (tag == 'F') {
float val = cl->ctpInfo->FloatAt(reader.readU2());
ddprintf("F=%f", val);
res = upcalls->floatClass->doNew(vm);
upcalls->floatValue->setInstanceFloatField(res, val);
} else if (tag == 'J') {
sint64 val = cl->ctpInfo->LongAt(reader.readU2());
ddprintf("J=%lld", val);
res = upcalls->longClass->doNew(vm);
upcalls->longValue->setInstanceLongField(res, val);
} else if (tag == 'S') {
uint32 val = cl->ctpInfo->IntegerAt(reader.readU2());
ddprintf("S=%d", val);
res = upcalls->shortClass->doNew(vm);
upcalls->shortValue->setInstanceInt16Field(res, val);
} else if (tag == 'I') {
sint32 val = cl->ctpInfo->IntegerAt(reader.readU2());
ddprintf("I=%d", val);
res = upcalls->intClass->doNew(vm);
upcalls->intValue->setInstanceInt32Field(res, val);
} else if (tag == 'Z') {
bool val = cl->ctpInfo->IntegerAt(reader.readU2());
ddprintf("Z=%d", val);
res = upcalls->boolClass->doNew(vm);
upcalls->boolValue->setInstanceInt8Field(res, val);
} else if (tag == 's') {
const UTF8* s = cl->ctpInfo->UTF8At(reader.readU2());
ddprintf("s=%s", PrintBuffer(s).cString());
res = JavaString::internalToJava(s, vm);
} else if (tag == 'e') {
const UTF8* n = cl->ctpInfo->UTF8At(reader.readU2());
const UTF8* m = cl->ctpInfo->UTF8At(reader.readU2());
JnjvmClassLoader* JCL = this->cl->classLoader;
n = n->extract(JCL->hashUTF8, 1,n->size-1);
UserCommonClass* cl = JCL->loadClassFromUserUTF8(n,true,false, NULL);
if (cl != NULL && !cl->isPrimitive()) {
if (cl->asClass())
cl->asClass()->initialiseClass(vm);
clazzLoaded = cl->getClassDelegatee(vm);
str = JavaString::internalToJava(m, vm);
assert(clazzLoaded && "Class not found");
assert(str && "Null string");
field = upcalls->getFieldInClass->invokeJavaObjectVirtual(vm, upcalls->newClass, clazzLoaded, &str);
assert(field && "Field not found");
JavaObject* obj = 0;
res = upcalls->getInField->invokeJavaObjectVirtual(vm, upcalls->newField, field, &obj);
} else {
str = JavaString::internalToJava(n, vm);
vm->classNotFoundException(str);
}
} else if (tag == 'c') {
ddprintf("class=");
const UTF8* m = cl->ctpInfo->UTF8At(reader.readU2());
JnjvmClassLoader* JCL = this->cl->classLoader;
m = m->extract(JCL->hashUTF8, 1,m->size-1);
UserCommonClass* cl = JCL->loadClassFromUserUTF8(m,true,false, NULL);
if (cl != NULL && !cl->isPrimitive()) {
if (cl->asClass())
cl->asClass()->initialiseClass(vm);
res = cl->getClassDelegatee(vm);
} else {
str = JavaString::internalToJava(m, vm);
vm->classNotFoundException(str);
}
} else if (tag == '[') {
uint16 numValues = reader.readU2();
classOfCurrentAnnotationProperty = type;
if (!nextParameterIsTypeOfMethod) {
UserCommonClass* uss = UserCommonClass::resolvedImplClass(vm, type, false);
//printf("Class name : %s\n", UTF8Buffer(uss->name).cString());
UserClass* clazzOfAnnotation = uss->asClass();
uint16 i = 0;
while ( i < clazzOfAnnotation->nbVirtualMethods && !(lastKey->equals(clazzOfAnnotation->virtualMethods[i].name))) i++;
assert((i < clazzOfAnnotation->nbVirtualMethods) && "Incorrect property for annotation");
classOfCurrentAnnotationProperty = clazzOfAnnotation->virtualMethods[i].getReturnType(this->cl->classLoader);
}
UserClassArray* clazzOfProperty = UserCommonClass::resolvedImplClass(vm, classOfCurrentAnnotationProperty, false)->asArrayClass();
//printf("Class name is : %s\n", UTF8Buffer(clazzOfProperty->name).cString());
res = clazzOfProperty->doNew(numValues, vm);
assert(res && "Error creating array of that type");
fillArray(res, numValues, clazzOfProperty);
} else if (tag == '@') {
uint16 typeIndex = reader.readU2();
annotationClass = type;
if (!nextParameterIsTypeOfMethod) {
UserCommonClass* uss = UserCommonClass::resolvedImplClass(vm, type, false);
//printf("Class name : %s\n", UTF8Buffer(uss->name).cString());
UserClass* clazzOfAnnotation = uss->asClass();
uint16 i = 0;
while ( i < clazzOfAnnotation->nbVirtualMethods && !(lastKey->equals(clazzOfAnnotation->virtualMethods[i].name))) i++;
assert((i < clazzOfAnnotation->nbVirtualMethods) && "Incorrect property for annotation");
annotationClass = clazzOfAnnotation->virtualMethods[i].getReturnType(this->cl->classLoader);
}
newHashMap = createAnnotationMapValues(annotationClass);
res = upcalls->createAnnotation->invokeJavaObjectStatic(vm, upcalls->newAnnotationHandler, &annotationClass, &newHashMap);
} else {
fprintf(stderr, "Wrong classfile format\n");
abort();
}
ddprintf("\n");
return res;
}
void AnnotationReader::fillArray(JavaObject* res, int numValues, UserClassArray* classArray) {
llvm_gcroot(res, 0);
JavaString* str = 0;
JavaObject* clazzObject = 0;
JavaObject* field = 0;
JavaObject* clazzLoaded = 0;
JavaObject* myEnum = 0;
JavaObject* annotationClass = 0;
JavaObject* newHashMap = 0;
// for cast
ArraySInt8* aSInt8 = 0;
ArrayUInt8* aUInt8 = 0;
ArraySInt16* aSInt16 = 0;
ArraySInt32* aSInt32 = 0;
ArrayLong* aSLong = 0;
ArrayDouble* aDouble = 0;
ArrayFloat* aFloat = 0;
ArrayObject* aObject = 0;
llvm_gcroot(str, 0);
llvm_gcroot(clazzObject, 0);
llvm_gcroot(clazzLoaded, 0);
llvm_gcroot(field, 0);
llvm_gcroot(myEnum, 0);
llvm_gcroot(annotationClass, 0);
llvm_gcroot(newHashMap, 0);
llvm_gcroot(aSInt8, 0);
llvm_gcroot(aUInt8, 0);
llvm_gcroot(aSInt16, 0);
llvm_gcroot(aSInt32, 0);
llvm_gcroot(aSLong, 0);
llvm_gcroot(aDouble, 0);
llvm_gcroot(aFloat, 0);
llvm_gcroot(aObject, 0);
sint32 valS;
uint32 valU;
sint64 val64S;
double valD;
float valF;
const UTF8* s = 0, *n = 0, * m = 0;
JnjvmClassLoader* JCL;
UserCommonClass* clLoaded;
UserCommonClass* aaa;
Jnjvm* vm = JavaThread::get()->getJVM();
Classpath* upcalls = vm->upcalls;
for (int i = 0 ; i < numValues ; i++) {
uint8 tag = reader.readU1();
switch (tag) {
case 'B':
valS = cl->ctpInfo->IntegerAt(reader.readU2());
aSInt8 = (ArraySInt8*)res;
ArraySInt8::setElement(aSInt8, valS, i);
break;
case 'C':
valS = cl->ctpInfo->IntegerAt(reader.readU2());
aSInt16 = (ArraySInt16*)res;
ArraySInt16::setElement(aSInt16, valS, i);
break;
case 'D':
valD = cl->ctpInfo->DoubleAt(reader.readU2());
aDouble = (ArrayDouble*)res;
ArrayDouble::setElement(aDouble, valD, i);
break;
case 'F':
valF = cl->ctpInfo->FloatAt(reader.readU2());
aFloat = (ArrayFloat*)res;
ArrayFloat::setElement(aFloat, valF, i);
break;
case 'J':
val64S = cl->ctpInfo->LongAt(reader.readU2());
aSLong = (ArrayLong*)res;
ArrayLong::setElement(aSLong, val64S, i);
break;
case 'S':
valS = cl->ctpInfo->IntegerAt(reader.readU2());
aSInt16 = (ArraySInt16*)res;
ArraySInt16::setElement(aSInt16, valS, i);
break;
case 'I':
valS = cl->ctpInfo->IntegerAt(reader.readU2());
aSInt32 = (ArraySInt32*)res;
ArraySInt32::setElement(aSInt32, valS,i);
break;
case 'Z':
valU = cl->ctpInfo->IntegerAt(reader.readU2());
aUInt8 = (ArrayUInt8*)res;
ArrayUInt8::setElement(aUInt8, valU, i);
break;
case 's':
s = cl->ctpInfo->UTF8At(reader.readU2());
str = JavaString::internalToJava(s, JavaThread::get()->getJVM());
aObject = (ArrayObject *)res;
ArrayObject::setElement(aObject, str, i);
break;
case 'e':
n = cl->ctpInfo->UTF8At(reader.readU2());
m = cl->ctpInfo->UTF8At(reader.readU2());
JCL = this->cl->classLoader;
n = n->extract(JCL->hashUTF8, 1,n->size-1);
clLoaded = JCL->loadClassFromUserUTF8(n,true,false, NULL);
if (clLoaded != NULL && !clLoaded->isPrimitive()) {
if (clLoaded->asClass())
clLoaded->asClass()->initialiseClass(vm);
clazzLoaded = clLoaded->getClassDelegatee(vm);
str = JavaString::internalToJava(m, vm);
assert(clazzLoaded && "Class not found");
assert(str && "Null string");
field = upcalls->getFieldInClass->invokeJavaObjectVirtual(vm, upcalls->newClass, clazzLoaded, &str);
assert(field && "Field not found");
JavaObject* obj = 0;
myEnum = upcalls->getInField->invokeJavaObjectVirtual(vm, upcalls->newField, field, &obj);
aObject = (ArrayObject *)res;
ArrayObject::setElement(aObject, str, i);
} else {
str = JavaString::internalToJava(n, vm);
vm->classNotFoundException(str);
}
break;
case 'c':
s = cl->ctpInfo->UTF8At(reader.readU2());
JCL = this->cl->classLoader;
s = s->extract(JCL->hashUTF8, 1,s->size-1);
clLoaded = JCL->loadClassFromUserUTF8(s,true,false, NULL);
if (clLoaded != NULL && !clLoaded->isPrimitive()) {
if (clLoaded->asClass())
clLoaded->asClass()->initialiseClass(vm);
clazzObject = clLoaded->getClassDelegatee(vm);
} else {
str = JavaString::internalToJava(s, vm);
vm->classNotFoundException(str);
}
aObject = (ArrayObject *)res;
ArrayObject::setElement(aObject, clazzObject, i);
break;
case '@':
reader.readU2();
aaa = classArray->_baseClass;
annotationClass = aaa->getDelegatee();
newHashMap = createAnnotationMapValues(annotationClass);
clazzObject = upcalls->createAnnotation->invokeJavaObjectStatic(vm, upcalls->newAnnotationHandler, &annotationClass, &newHashMap);
aObject = (ArrayObject *)res;
ArrayObject::setElement(aObject, clazzObject, i);
break;
default:
fprintf(stderr, "Wrong class file\n");
abort();
break;
}
}
}
JavaObject* AnnotationReader::createAnnotationMapValues(JavaObject* type) {
std::pair<JavaObject*, JavaObject*> pair;
JavaObject* tmp = 0;
JavaString* str = 0;
JavaObject* newHashMap = 0;
llvm_gcroot(type, 0);
llvm_gcroot(tmp, 0);
llvm_gcroot(str, 0);
llvm_gcroot(newHashMap, 0);
const UTF8* key = 0;
Jnjvm * vm = JavaThread::get()->getJVM();
Classpath* upcalls = vm->upcalls;
UserClass* HashMap = upcalls->newHashMap;
newHashMap = HashMap->doNew(vm);
upcalls->initHashMap->invokeIntSpecial(vm, HashMap, newHashMap);
uint16 numPairs = reader.readU2();
dprintf("numPairs:%d\n", numPairs);
for (uint16 j = 0; j < numPairs; ++j) {
uint16 nameIndex = reader.readU2();
key = cl->ctpInfo->UTF8At(nameIndex);
dprintf("keyAn:%s|", PrintBuffer(key).cString());
tmp = createElementValue(false, type, key);
str = JavaString::internalToJava(key, vm);
upcalls->putHashMap->invokeJavaObjectVirtual(vm, HashMap, newHashMap, &str, &tmp);
}
// annotationType
str = vm->asciizToStr("annotationType");
upcalls->putHashMap->invokeJavaObjectVirtual(vm, HashMap, newHashMap, &str, &type);
return newHashMap;
}
uint16 JavaMethod::lookupLineNumber(vmkit::FrameInfo* info) {
JavaAttribute* codeAtt = lookupAttribute(JavaAttribute::codeAttribute);
if (codeAtt == NULL) return 0;
Reader reader(codeAtt, classDef->bytes);
reader.readU2(); // max_stack
reader.readU2(); // max_locals;
uint32_t codeLength = reader.readU4();
reader.seek(codeLength, Reader::SeekCur);
uint16_t exceptionTableLength = reader.readU2();
reader.seek(8 * exceptionTableLength, Reader::SeekCur);
uint16_t nba = reader.readU2();
for (uint16 att = 0; att < nba; ++att) {
const UTF8* attName = classDef->ctpInfo->UTF8At(reader.readU2());
uint32 attLen = reader.readU4();
if (attName->equals(JavaAttribute::lineNumberTableAttribute)) {
uint16_t lineLength = reader.readU2();
uint16_t currentLine = 0;
for (uint16 j = 0; j < lineLength; ++j) {
uint16 pc = reader.readU2();
if (pc > info->SourceIndex) return currentLine;
currentLine = reader.readU2();
}
return currentLine;
} else {
reader.seek(attLen, Reader::SeekCur);
}
}
return 0;
}
uint16 JavaMethod::lookupCtpIndex(vmkit::FrameInfo* FI) {
JavaAttribute* codeAtt = lookupAttribute(JavaAttribute::codeAttribute);
Reader reader(codeAtt, classDef->bytes);
reader.cursor = reader.cursor + 2 + 2 + 4 + FI->SourceIndex + 1;
return reader.readU2();
}
void Class::acquire() {
JavaObject* delegatee = NULL;
llvm_gcroot(delegatee, 0);
delegatee = getClassDelegatee(JavaThread::get()->getJVM());
JavaObject::acquire(delegatee);
}
void Class::release() {
JavaObject* delegatee = NULL;
llvm_gcroot(delegatee, 0);
delegatee = getClassDelegatee(JavaThread::get()->getJVM());
JavaObject::release(delegatee);
}
void Class::waitClass() {
JavaObject* delegatee = NULL;
llvm_gcroot(delegatee, 0);
delegatee = getClassDelegatee(JavaThread::get()->getJVM());
JavaObject::wait(delegatee);
}
void Class::broadcastClass() {
JavaObject* delegatee = NULL;
llvm_gcroot(delegatee, 0);
delegatee = getClassDelegatee(JavaThread::get()->getJVM());
JavaObject::notifyAll(delegatee);
}
std::string& CommonClass::getName(std::string& nameBuffer, bool linkageName) const
{
name->toString(nameBuffer);
for (int32_t i=0; i < name->size; ++i) {
if (name->elements[i] == '/')
nameBuffer[i] = linkageName ? '_' : '.';
}
return nameBuffer;
}
std::string& JavaMethod::getName(std::string& nameBuffer, bool linkageName) const
{
classDef->getName(nameBuffer, linkageName);
nameBuffer += linkageName ? '_' : '.';
string methName;
return nameBuffer += name->toString(methName);
}
std::ostream& j3::operator << (std::ostream& os, const JavaMethod& m)
{
return os << *m.classDef->name << '.' << *m.name << " (" << *m.type << ')';
}
void JavaMethod::dump() const
{
cerr << *this << endl;
}
JavaField_IMPL_ASSESSORS(float, Float)
JavaField_IMPL_ASSESSORS(double, Double)
JavaField_IMPL_ASSESSORS(uint8, Int8)
JavaField_IMPL_ASSESSORS(uint16, Int16)
JavaField_IMPL_ASSESSORS(uint32, Int32)
JavaField_IMPL_ASSESSORS(sint64, Long)
// JavaField_IMPL_ASSESSORS(JavaObject*, Object)
JavaObject* JavaField::getStaticObjectField()
{
return getStaticField<JavaObject*>();
}
void JavaField::setStaticObjectField(JavaObject* val)
{
llvm_gcroot(val, 0);
return setStaticField<JavaObject*>(val);
}
JavaObject* JavaField::getInstanceObjectField(JavaObject* obj)
{
llvm_gcroot(obj, 0);
return this->getInstanceField<JavaObject*>(obj);
}
void JavaField::setInstanceObjectField(JavaObject* obj, JavaObject* val)
{
llvm_gcroot(obj, 0);
llvm_gcroot(val, 0);
return this->setInstanceField<JavaObject*>(obj, val);
}
template<>
void JavaField::setInstanceField(JavaObject* obj, JavaObject* val)
{
llvm_gcroot(obj, 0);
llvm_gcroot(val, 0);
FieldSetter<JavaObject*>::setInstanceField(this, obj, val);
}
template <>
void JavaField::setStaticField(JavaObject* val)
{
llvm_gcroot(val, 0);
FieldSetter<JavaObject*>::setStaticField(this, val);
}
std::ostream& j3::operator << (std::ostream& os, const CommonClass& ccl)
{
return os << *ccl.name << ';';
// return (!ccl.super) ? (os << ';') : (os << ':' << *ccl.super);
}
void CommonClass::dump() const
{
cerr << *this << endl;
}