blob: d79640855b842d8b6a7c65f5534f1142dade778b [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 0
#include "debug.h"
#include "types.h"
#include "ClasspathReflect.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaCompiler.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>
using namespace j3;
const UTF8* Attribut::annotationsAttribut = 0;
const UTF8* Attribut::codeAttribut = 0;
const UTF8* Attribut::exceptionsAttribut = 0;
const UTF8* Attribut::constantAttribut = 0;
const UTF8* Attribut::lineNumberTableAttribut = 0;
const UTF8* Attribut::innerClassesAttribut = 0;
const UTF8* Attribut::sourceFileAttribut = 0;
Class* ClassArray::SuperArray;
Class** ClassArray::InterfacesArray;
extern "C" void JavaArrayTracer(JavaObject*);
extern "C" void JavaObjectTracer(JavaObject*);
extern "C" void ArrayObjectTracer(JavaObject*);
extern "C" void RegularObjectTracer(JavaObject*);
Attribut::Attribut(const UTF8* name, uint32 length,
uint32 offset) {
this->start = offset;
this->nbb = length;
this->name = name;
}
Attribut* Class::lookupAttribut(const UTF8* key ) {
for (uint32 i = 0; i < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
Attribut* JavaField::lookupAttribut(const UTF8* key ) {
for (uint32 i = 0; i < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
Attribut* JavaMethod::lookupAttribut(const UTF8* key ) {
for (uint32 i = 0; i < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
if (cur->name->equals(key)) return cur;
}
return 0;
}
CommonClass::~CommonClass() {
}
Class::~Class() {
for (uint32 i = 0; i < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
cur->~Attribut();
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 < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
cur->~Attribut();
classDef->classLoader->allocator.Deallocate(cur);
}
}
JavaMethod::~JavaMethod() {
for (uint32 i = 0; i < nbAttributs; ++i) {
Attribut* cur = &(attributs[i]);
cur->~Attribut();
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, ArrayUInt8* 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 | ACC_PUBLIC | JNJVM_ARRAY;
}
JavaArray* UserClassArray::doNew(sint32 n, Jnjvm* vm) {
if (n < 0)
vm->negativeArraySizeException(n);
else if (n > JavaArray::MaxArraySize)
vm->outOfMemoryError();
return doNew(n);
}
JavaArray* UserClassArray::doNew(sint32 n) {
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);
JavaArray* res = (JavaArray*)gc::operator new(size, VT);
res->size = n;
return res;
}
JavaArray* UserClassArray::doNew(sint32 n, mvm::BumpPtrAllocator& allocator,
bool temp) {
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);
JavaArray* res = 0;
// If the array is not temporary, use the allocator.
if (!temp) {
res = (JavaArray*)allocator.Allocate(size, "Array");
} else {
// Otherwise, allocate with the malloc
res = (JavaArray*)malloc(size);
}
((void**)res)[0] = VT;
res->size = n;
return res;
}
void* JavaMethod::compiledPtr() {
if (code != 0) return code;
else {
#ifdef SERVICE
Jnjvm *vm = classDef->classLoader->getIsolate();
if (vm && vm->status == 0) {
JavaThread* th = JavaThread::get();
th->throwException(th->ServiceException);
}
#endif
code = classDef->classLoader->getCompiler()->materializeFunction(this);
}
return code;
}
void JavaStaticMethodInfo::print(void* ip, void* addr) {
void* new_ip = NULL;
if (ip) new_ip = mvm::MethodInfo::isStub(ip, addr);
fprintf(stderr, "; %p in %s.%s", new_ip,
UTF8Buffer(meth->classDef->name).cString(),
UTF8Buffer(meth->name).cString());
if (ip != new_ip) fprintf(stderr, " (from stub)");
fprintf(stderr, "\n");
}
void JavaMethod::setCompiledPtr(void* ptr, const char* name) {
classDef->acquire();
if (code == 0) {
code = ptr;
Jnjvm* vm = JavaThread::get()->getJVM();
JavaStaticMethodInfo* MI =
new (classDef->classLoader->allocator, "JavaStaticMethodInfo")
JavaStaticMethodInfo(0, code, this);
vm->StaticFunctions.addMethodInfo(MI, code);
classDef->classLoader->getCompiler()->setMethod(this, ptr, name);
}
access |= ACC_NATIVE;
classDef->release();
}
void JavaVirtualTable::setNativeTracer(uintptr_t ptr, const char* name) {
tracer = ptr;
}
void JavaVirtualTable::setNativeDestructor(uintptr_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) {
for (uint16 i = 0; i < nbInterfaces; ++i) {
Class* I = interfaces[i];
cur = I->lookupInterfaceMethodDontThrow(name, type);
if (cur) return cur;
}
}
return cur;
}
JavaMethod* Class::lookupSpecialMethodDontThrow(const UTF8* name,
const UTF8* type,
Class* current) {
JavaMethod* meth = lookupMethodDontThrow(name, type, false, true, NULL);
if (isSuper(current->access) &&
current != meth->classDef &&
meth->classDef->isAssignableFrom(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) {
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;
}
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 = 0;
llvm_gcroot(res, 0);
assert(this && "No class when allocating.");
assert((this->isInitializing() ||
classLoader->getCompiler()->isStaticCompiling())
&& "Uninitialized class when allocating.");
assert(getVirtualVT() && "No VT\n");
res = (JavaObject*)gc::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::isAssignableFrom(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;
}
}
}
return false;
}
void JavaField::InitField(void* obj, uint64 val) {
Typedef* type = getSignature();
if (!type->isPrimitive()) {
((JavaObject**)((uint64)obj + ptrOffset))[0] = (JavaObject*)val;
return;
}
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 {
// 0 value for everything else
((sint32*)((uint64)obj + ptrOffset))[0] = (sint32)val;
}
}
void JavaField::InitField(void* obj, JavaObject* val) {
((JavaObject**)((uint64)obj + ptrOffset))[0] = val;
}
void JavaField::InitField(void* obj, double val) {
((double*)((uint64)obj + ptrOffset))[0] = val;
}
void JavaField::InitField(void* obj, float val) {
((float*)((uint64)obj + ptrOffset))[0] = val;
}
void JavaField::initField(void* obj, Jnjvm* vm) {
const Typedef* type = getSignature();
Attribut* attribut = lookupAttribut(Attribut::constantAttribut);
if (!attribut) {
InitField(obj);
} else {
Reader reader(attribut, &(classDef->bytes));
JavaConstantPool * ctpInfo = classDef->ctpInfo;
uint16 idx = reader.readU2();
if (type->isPrimitive()) {
UserCommonClass* cl = type->assocClass(vm->bootstrapLoader);
if (cl == vm->upcalls->OfLong) {
InitField(obj, (uint64)ctpInfo->LongAt(idx));
} else if (cl == vm->upcalls->OfDouble) {
InitField(obj, ctpInfo->DoubleAt(idx));
} else if (cl == vm->upcalls->OfFloat) {
InitField(obj, ctpInfo->FloatAt(idx));
} else {
InitField(obj, (uint64)ctpInfo->IntegerAt(idx));
}
} else if (type->isReference()){
const UTF8* utf8 = ctpInfo->UTF8At(ctpInfo->ctpDef[idx]);
InitField(obj, (JavaObject*)ctpInfo->resolveString(utf8, idx));
} 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) {
#ifdef USE_GC_BOEHM
void* val = GC_MALLOC(getStaticSize());
#else
void* val = classLoader->allocator.Allocate(getStaticSize(),
"Static instance");
#endif
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;
canBeInlined = 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);
}
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);
}
nbInterfaces = nbI;
}
void UserClass::loadParents() {
if (super == 0) {
virtualTableSize = JavaVirtualTable::getFirstJavaMethodIndex();
} else {
super->resolveClass();
virtualTableSize = super->virtualTableSize;
}
for (unsigned i = 0; i < nbInterfaces; i++)
interfaces[i]->resolveClass();
}
static void internalLoadExceptions(JavaMethod& meth) {
Attribut* codeAtt = meth.lookupAttribut(Attribut::codeAttribut);
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);
}
}
}
void UserClass::loadExceptions() {
for (uint32 i = 0; i < nbVirtualMethods; ++i)
internalLoadExceptions(virtualMethods[i]);
for (uint32 i = 0; i < nbStaticMethods; ++i)
internalLoadExceptions(staticMethods[i]);
}
Attribut* Class::readAttributs(Reader& reader, uint16& size) {
uint16 nba = reader.readU2();
Attribut* attributs = new(classLoader->allocator, "Attributs") Attribut[nba];
for (int i = 0; i < nba; i++) {
const UTF8* attName = ctpInfo->UTF8At(reader.readU2());
uint32 attLen = reader.readU4();
Attribut& att = attributs[i];
att.start = reader.cursor;
att.nbb = attLen;
att.name = attName;
reader.seek(attLen, Reader::SeekCur);
}
size = nba;
return attributs;
}
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->attributs = readAttributs(reader, field->nbAttributs);
}
}
void Class::fillIMT(std::set<JavaMethod*>* meths) {
for (uint32 i = 0; i < nbInterfaces; ++i) {
interfaces[i]->fillIMT(meths);
}
if (super) super->fillIMT(meths);
if (isInterface()) {
for (uint32 i = 0; i < nbVirtualMethods; ++i) {
JavaMethod& meth = virtualMethods[i];
uint32_t index = InterfaceMethodTable::getIndex(meth.name, meth.type);
if (meths[index].find(&meth) == meths[index].end())
meths[index].insert(&meth);
}
}
}
void Class::makeVT() {
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;
}
}
}
if (super) {
assert(virtualTableSize >= super->virtualTableSize &&
"Size of virtual table less than super!");
}
mvm::BumpPtrAllocator& allocator = classLoader->allocator;
virtualVT = new(allocator, virtualTableSize) JavaVirtualTable(this);
}
void Class::readMethods(Reader& reader) {
uint16 nbMethods = reader.readU2();
virtualMethods = new(classLoader->allocator, "Methods") JavaMethod[nbMethods];
staticMethods = virtualMethods + nbMethods;
for (int 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->attributs = readAttributs(reader, meth->nbAttributs);
}
}
void Class::readClass() {
assert(getInitializationState() == loaded && "Wrong init state");
PRINT_DEBUG(JNJVM_LOAD, 0, COLOR_NORMAL, "; ", 0);
PRINT_DEBUG(JNJVM_LOAD, 0, LIGHT_GREEN, "reading ", 0);
PRINT_DEBUG(JNJVM_LOAD, 0, COLOR_NORMAL, "%s\n", mvm::PrintBuffer(this).cString());
Reader reader(&bytes);
uint32 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();
uint32 ctpSize = reader.readU2();
ctpInfo = new(classLoader->allocator, ctpSize) JavaConstantPool(this, reader,
ctpSize);
access |= (reader.readU2() & 0x0FFF);
if (!isPublic(access)) access |= ACC_PRIVATE;
const UTF8* thisClassName =
ctpInfo->resolveClassName(reader.readU2());
if (!(thisClassName->equals(name))) {
JavaThread::get()->getJVM()->classFormatError(this, thisClassName);
}
readParents(reader);
readFields(reader);
readMethods(reader);
attributs = readAttributs(reader, nbAttributs);
setIsRead();
}
#ifndef ISOLATE_SHARING
void Class::resolveClass() {
if (!isResolved() && !isErroneous()) {
acquire();
if (isResolved() || isErroneous()) {
release();
} else if (!isResolving()) {
setOwnerClass(JavaThread::get());
JavaObject* exc = 0;
try {
readClass();
} catch (...) {
exc = JavaThread::get()->pendingException;
JavaThread::get()->clearException();
}
if (exc) {
setErroneous();
setOwnerClass(0);
broadcastClass();
release();
JavaThread::get()->throwException(exc);
}
release();
try {
loadParents();
} catch (...) {
setInitializationState(loaded);
exc = JavaThread::get()->pendingException;
JavaThread::get()->clearException();
}
if (exc) {
setErroneous();
setOwnerClass(0);
JavaThread::get()->throwException(exc);
}
makeVT();
JavaCompiler *Comp = classLoader->getCompiler();
Comp->resolveVirtualClass(this);
Comp->resolveStaticClass(this);
loadExceptions();
setResolved();
if (!needsInitialisationCheck()) {
setInitializationState(ready);
}
if (!super) ClassArray::initialiseVT(this);
bool needInit = needsInitialisationCheck();
acquire();
if (needInit) setResolved();
setOwnerClass(0);
broadcastClass();
release();
} else if (JavaThread::get() != getOwnerClass()) {
while (!isResolved()) {
waitClass();
if (isErroneous()) break;
}
release();
}
}
if (isErroneous()) {
JavaThread* th = JavaThread::get();
th->getJVM()->noClassDefFoundError(name);
}
assert(virtualVT && "No virtual VT after resolution");
}
#else
void Class::resolveClass() {
assert(status >= resolved &&
"Asking to resolve a not resolved-class in a isolate environment");
}
#endif
void UserClass::resolveInnerOuterClasses() {
if (!innerOuterResolved) {
Attribut* attribut = lookupAttribut(Attribut::innerClassesAttribut);
if (attribut != 0) {
Reader reader(attribut, getBytesPtr());
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;
} else if (clOuter == this) {
if (!innerClasses) {
innerClasses = (Class**)
classLoader->allocator.Allocate(nbi * sizeof(Class*),
"Inner classes");
}
clInner->setInnerAccess(accessFlags);
if (!innerName) 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 = 0;
llvm_gcroot(res, 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) {
res->elements[index] = getClassType(vm, loader, arguments[index]);
}
return res;
}
JavaObject* JavaMethod::getReturnType(JnjvmClassLoader* loader) {
Jnjvm* vm = JavaThread::get()->getJVM();
Typedef* ret = getSignature()->getReturnType();
return getClassType(vm, loader, ret);
}
ArrayObject* JavaMethod::getExceptionTypes(JnjvmClassLoader* loader) {
ArrayObject* res = 0;
llvm_gcroot(res, 0);
Attribut* exceptionAtt = lookupAttribut(Attribut::exceptionsAttribut);
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->getBytesPtr());
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();
res->elements[i] = cl->getClassDelegatee(vm);
}
return res;
}
}
#ifdef ISOLATE
TaskClassMirror& Class::getCurrentTaskClassMirror() {
return IsolateInfo[JavaThread::get()->getJVM()->IsolateID];
}
JavaObject* CommonClass::getDelegatee() {
return delegatee[JavaThread::get()->getJVM()->IsolateID];
}
JavaObject** CommonClass::getDelegateePtr() {
return &(delegatee[JavaThread::get()->getJVM()->IsolateID]);
}
JavaObject* CommonClass::setDelegatee(JavaObject* val) {
JavaObject** obj = &(delegatee[JavaThread::get()->getJVM()->IsolateID]);
JavaObject* prev = (JavaObject*)
__sync_val_compare_and_swap((uintptr_t)obj, NULL, val);
if (!prev) return val;
else return prev;
}
#else
JavaObject* CommonClass::setDelegatee(JavaObject* val) {
JavaObject* prev = (JavaObject*)
__sync_val_compare_and_swap(&(delegatee[0]), NULL, val);
if (!prev) return val;
else return prev;
}
#endif
UserCommonClass* UserCommonClass::resolvedImplClass(Jnjvm* vm,
JavaObject* clazz,
bool doClinit) {
llvm_gcroot(clazz, 0);
UserCommonClass* cl = ((JavaObjectClass*)clazz)->getClass();
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] = '_';
else if (cur == '_') {
ptr[0] = '_';
ptr[1] = '1';
++ptr;
}
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;
}
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] == '/') res->elements[i++] = '.';
else res->elements[i++] = classDef->name->elements[j];
}
res->elements[i++] = '.';
for (sint32 j = 0; j < name->size; ++j) {
res->elements[i++] = name->elements[j];
}
for (sint32 j = 0; j < type->size; ++j) {
res->elements[i++] = type->elements[j];
}
return res;
}
bool UserClass::needsInitialisationCheck() {
if (!isClassRead()) return true;
if (isReady()) return false;
if (super && super->needsInitialisationCheck())
return true;
if (nbStaticFields) 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);
ClassArray::InterfacesArray[1] =
JCL->loadName(JCL->asciizConstructUTF8("java/io/Serializable"),
true, false);
// 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(uintptr_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) {
assert(C->super->virtualVT && "Super has no VT");
// Set the regular object tracer, destructor and delete.
tracer = (uintptr_t)RegularObjectTracer;
destructor = 0;
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;
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();
// Add the super in the list of secondary types only if it is
// out of depth.
if (depth > getDisplayLength()) {
++nbSecondaryTypes;
outOfDepth = 1;
}
}
mvm::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;
}
} else {
// Set the tracer, destructor and delete.
tracer = (uintptr_t)JavaObjectTracer;
destructor = 0;
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;
destructor = 0;
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(uintptr_t));
tracer = (uintptr_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;
}
mvm::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.
nbSecondaryTypes = base->nbInterfaces + superVT->nbSecondaryTypes +
addSuper;
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;
}
} 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.
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;
// If the depth is greater than the display size,
// Cloneable[...] and Serializable[...] have their own list of
// secondary types, and we must therefore tell them that they
// implement themselves.
// If the depth is less than than the display size, there is nothing
// to do: the array of secondary types has been created before loading
// the interface arrays, so the interface arrays already reference
// the array.
if (outOfDepth) {
firstInterface->virtualVT->secondaryTypes[index] =
firstInterface->virtualVT;
firstInterface->virtualVT->secondaryTypes[index + 1] =
secondInterface->virtualVT;
secondInterface->virtualVT->secondaryTypes[index] =
firstInterface->virtualVT;
secondInterface->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;
mvm::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 = (uintptr_t)JavaArrayTracer;
destructor = 0;
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.
}
}
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::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();
}
}
}
uint16 JavaMethod::lookupLineNumber(uintptr_t ip) {
for(uint16 i = 0; i < codeInfoLength; ++i) {
if (codeInfo[i].address > ip) {
assert(i > 0 && "Wrong ip address for method");
return codeInfo[i - 1].lineNumber;
}
}
if (codeInfoLength) return codeInfo[codeInfoLength - 1].lineNumber;
return 0;
}
uint16 JavaMethod::lookupCtpIndex(uintptr_t ip) {
for(uint16 i = 0; i < codeInfoLength; ++i) {
if (codeInfo[i].address > ip) {
assert(i > 0 && "Wrong ip address for method");
return codeInfo[i - 1].ctpIndex;
}
}
if (codeInfoLength) return codeInfo[codeInfoLength - 1].ctpIndex;
return 0;
}