blob: a349a5198da6d7e0079d1132f2f7e58d62eeb2d1 [file] [log] [blame]
//===--- JavaConstantPool.cpp - Java constant pool definition ---------------===//
//
// JnJVM
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <alloca.h>
#include <stdio.h>
#include <stdlib.h>
#include "llvm/GlobalValue.h"
#include "debug.h"
#include "JavaAccess.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaJIT.h"
#include "Jnjvm.h"
#include "JnjvmModuleProvider.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "Reader.h"
using namespace jnjvm;
const uint32 JavaCtpInfo::ConstantUTF8 = 1;
const uint32 JavaCtpInfo::ConstantInteger = 3;
const uint32 JavaCtpInfo::ConstantFloat = 4;
const uint32 JavaCtpInfo::ConstantLong = 5;
const uint32 JavaCtpInfo::ConstantDouble = 6;
const uint32 JavaCtpInfo::ConstantClass = 7;
const uint32 JavaCtpInfo::ConstantString = 8;
const uint32 JavaCtpInfo::ConstantFieldref = 9;
const uint32 JavaCtpInfo::ConstantMethodref = 10;
const uint32 JavaCtpInfo::ConstantInterfaceMethodref = 11;
const uint32 JavaCtpInfo::ConstantNameAndType = 12;
void JavaCtpInfo::print(mvm::PrintBuffer* buf) {
buf->write("CtpInfoOf<");
classDef->print(buf);
buf->write(">");
}
static uint32 unimplemented(Jnjvm* vm, uint32 type, uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes, uint8* ctpType) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"unknown constant pool type %d",
type);
return 1;
}
uint32 JavaCtpInfo::CtpReaderClass(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef,
void** ctpRes, uint8* ctpType) {
uint16 entry = reader->readU2();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <class>\t\tutf8 is at %d\n", e,
entry);
return 1;
}
uint32 JavaCtpInfo::CtpReaderInteger(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef,
void** ctpRes, uint8* ctpType) {
uint32 val = reader->readU4();
ctpDef[e] = val;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <class>\tinteger: %d\n", e,
val);
return 1;
}
uint32 JavaCtpInfo::CtpReaderFloat(Jnjvm* vm, uint32 type, uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes, uint8* ctpType) {
uint32 val = reader->readU4();
ctpDef[e] = val;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <class>\tfloat: %p\n", e,
val);
return 1;
}
uint32 JavaCtpInfo::CtpReaderUTF8(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
uint16 len = reader->readU2();
uint16* buf = (uint16*)alloca(len * sizeof(uint16));
uint32 n = 0;
uint32 i = 0;
while (i < len) {
uint32 cur = reader->readU1();
if (cur & 0x80) {
uint32 y = reader->readU1();
if (cur & 0x20) {
uint32 z = reader->readU1();
cur = ((cur & 0x0F) << 12) +
((y & 0x3F) << 6) +
(z & 0x3F);
i += 3;
} else {
cur = ((cur & 0x1F) << 6) +
(y & 0x3F);
i += 2;
}
} else {
++i;
}
buf[n] = ((uint16)cur);
++n;
}
const UTF8* utf8 = UTF8::readerConstruct(vm, buf, n);
ctpRes[e] = (UTF8*)utf8;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <utf8>\t\t\"%s\"\n", e,
utf8->printString());
return 1;
}
uint32 JavaCtpInfo::CtpReaderNameAndType(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef,
void** ctpRes, uint8* ctpType) {
uint32 entry = reader->readU4();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL,
"; [%5d] <name/type>\tname is at %d, type is at %d\n", e,
(entry >> 16), (entry & 0xffff));
return 1;
}
uint32 JavaCtpInfo::CtpReaderFieldref(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef,
void** ctpRes, uint8* ctpType) {
uint32 entry = reader->readU4();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL,
"; [%5d] <fieldref>\tclass is at %d, name/type is at %d\n", e,
(entry >> 16), (entry & 0xffff));
return 1;
}
uint32 JavaCtpInfo::CtpReaderString(Jnjvm* vm, uint32 type, uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
uint16 entry = reader->readU2();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <string>\tutf8 is at %d\n",
e, entry);
return 1;
}
uint32 JavaCtpInfo::CtpReaderMethodref(Jnjvm* vm, uint32 type, uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
uint32 entry = reader->readU4();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL,
"; [%5d] <methodref>\tclass is at %d, name/type is at %d\n", e,
(entry >> 16), (entry & 0xffff));
return 1;
}
uint32 JavaCtpInfo::CtpReaderInterfaceMethodref(Jnjvm* vm, uint32 type,
uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
uint32 entry = reader->readU4();
ctpDef[e] = entry;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL,
"; [%5d] <Interface xmethodref>\tclass is at %d, name/type is at %d\n",
e, (entry >> 16), (entry & 0xffff));
return 1;
}
uint32 JavaCtpInfo::CtpReaderLong(Jnjvm* vm, uint32 type, uint32 e,
Reader* reader, sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
ctpDef[e + 1] = reader->readU4();
ctpDef[e] = reader->readU4();
ctpType[e] = ConstantLong;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <long>\%d %d\n", e,
ctpDef[e], ctpDef[e + 1]);
return 2;
}
uint32 JavaCtpInfo::CtpReaderDouble(Jnjvm* vm, uint32 type, uint32 e, Reader* reader,
sint32* ctpDef, void** ctpRes,
uint8* ctpType) {
ctpDef[e + 1] = reader->readU4();
ctpDef[e] = reader->readU4();
ctpType[e] = ConstantDouble;
PRINT_DEBUG(JNJVM_LOAD, 3, COLOR_NORMAL, "; [%5d] <double>\%d %d\n", e,
ctpDef[e], ctpDef[e + 1]);
return 2;
}
void JavaCtpInfo::read(Jnjvm *vm, Class* cl, Reader* reader) {
uint32 nbCtp = reader->readU2();
JavaCtpInfo* res = gc_new(JavaCtpInfo)();
res->ctpRes = (void**)malloc(sizeof(void*)*nbCtp);
res->ctpDef = (sint32*)malloc(sizeof(sint32)*nbCtp);
res->ctpType = (uint8*)malloc(sizeof(uint8)*nbCtp);
memset(res->ctpRes, 0, sizeof(void**)*nbCtp);
memset(res->ctpDef, 0, sizeof(sint32)*nbCtp);
memset(res->ctpType, 0, sizeof(uint8)*nbCtp);
res->ctpSize = nbCtp;
res->classDef = cl;
cl->ctpInfo = res;
uint32 cur = 1;
while (cur < nbCtp) {
uint8 curType = reader->readU1();
res->ctpType[cur] = curType;
cur += ((funcsReader[curType])(vm, curType, cur, reader, res->ctpDef,
res->ctpRes, res->ctpType));
}
}
bool JavaCtpInfo::isAStaticCall(uint32 index) {
return (ctpType[index] & 0x80) != 0;
}
void JavaCtpInfo::markAsStaticCall(uint32 index) {
ctpType[index] |= 0x80;
}
uint8 JavaCtpInfo::typeAt(uint32 index) {
return ctpType[index] & 0x7F;
}
const UTF8* JavaCtpInfo::UTF8At(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantUTF8) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for utf8 at entry %d", entry);
}
return (const UTF8*)ctpRes[entry];
}
float JavaCtpInfo::FloatAt(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantFloat) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for float at entry %d", entry);
}
return ((float*)ctpDef)[entry];
}
sint32 JavaCtpInfo::IntegerAt(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantInteger) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for integer at entry %d", entry);
}
return ((sint32*)ctpDef)[entry];
}
sint64 JavaCtpInfo::LongAt(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantLong) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for long at entry %d", entry);
}
return Reader::readLong(ctpDef[entry], ctpDef[entry + 1]);
}
double JavaCtpInfo::DoubleAt(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantDouble) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for double at entry %d", entry);
}
return Reader::readDouble(ctpDef[entry], ctpDef[entry + 1]);
}
CommonClass* JavaCtpInfo::isLoadedClassOrClassName(uint32 entry) {
if (! (entry > 0) && (entry < ctpSize) &&
typeAt(entry) == ConstantClass) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for class at entry %d", entry);
}
return (CommonClass*)ctpRes[entry];
}
const UTF8* JavaCtpInfo::resolveClassName(uint32 index) {
CommonClass* cl = isLoadedClassOrClassName(index);
if (cl) return cl->name;
else return UTF8At(ctpDef[index]);
}
CommonClass* JavaCtpInfo::loadClass(uint32 index) {
CommonClass* temp = isLoadedClassOrClassName(index);
if (!temp) {
JavaObject* loader = classDef->classLoader;
const UTF8* name = UTF8At(ctpDef[index]);
if (name->at(0) == AssessorDesc::I_TAB) {
// Don't put into ctpRes because the class can be isolate specific
temp = JavaThread::get()->isolate->constructArray(name, loader);
} else {
// Put into ctpRes because there is only one representation of the class
ctpRes[index] = temp = classDef->isolate->loadName(name, loader, false,
false, false);
}
}
return temp;
}
CommonClass* JavaCtpInfo::getMethodClassIfLoaded(uint32 index) {
CommonClass* temp = isLoadedClassOrClassName(index);
if (!temp) {
JavaObject* loader = classDef->classLoader;
const UTF8* name = UTF8At(ctpDef[index]);
temp = JavaThread::get()->isolate->lookupClass(name, loader);
if (!temp) temp = Jnjvm::bootstrapVM->lookupClass(name, CommonClass::jnjvmClassLoader);
}
return temp;
}
void JavaCtpInfo::checkInfoOfClass(uint32 index) {
if (typeAt(index) != ConstantClass)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for class at entry %d", index);
/*if (!(ctpRes[index]))
ctpRes[index] = JavaJIT::newLookupLLVM;*/
}
Typedef* JavaCtpInfo::resolveNameAndType(uint32 index) {
void* res = ctpRes[index];
if (!res) {
if (typeAt(index) != ConstantNameAndType) {
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for name/type at entry %d", index);
}
sint32 entry = ctpDef[index];
const UTF8* type = UTF8At(entry & 0xFFFF);
Typedef* sign = JavaThread::get()->isolate->constructType(type);
ctpRes[index] = sign;
return sign;
}
return (Typedef*)res;
}
Typedef* JavaCtpInfo::infoOfField(uint32 index) {
if (typeAt(index) != ConstantFieldref)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for field at entry %d", index);
return resolveNameAndType(ctpDef[index] & 0xFFFF);
}
void JavaCtpInfo::infoOfMethod(uint32 index, uint32 access,
CommonClass*& cl, JavaMethod*& meth) {
uint8 id = typeAt(index);
if (id != ConstantMethodref && id != ConstantInterfaceMethodref)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for method at entry %d", index);
Signdef* sign = (Signdef*)resolveNameAndType(ctpDef[index] & 0xFFFF);
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
const UTF8* utf8 = UTF8At(ctpDef[ntIndex] >> 16);
cl = getMethodClassIfLoaded(entry >> 16);
if (cl && cl->status >= readed) {
// lookup the method
meth = cl->lookupMethodDontThrow(utf8, sign->keyName, isStatic(access), false);
}
}
void JavaCtpInfo::nameOfStaticOrSpecialMethod(uint32 index,
const UTF8*& cl,
const UTF8*& name,
Signdef*& sign) {
uint8 id = typeAt(index);
if (id != ConstantMethodref && id != ConstantInterfaceMethodref)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for method at entry %d", index);
sign = (Signdef*)resolveNameAndType(ctpDef[index] & 0xFFFF);
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
name = UTF8At(ctpDef[ntIndex] >> 16);
cl = resolveClassName(entry >> 16);
}
llvm::Function* JavaCtpInfo::infoOfStaticOrSpecialMethod(
uint32 index,
uint32 access,
Signdef*& sign,
JavaMethod*& meth) {
uint8 id = typeAt(index);
if (id != ConstantMethodref && id != ConstantInterfaceMethodref)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for method at entry %d", index);
sign = (Signdef*)resolveNameAndType(ctpDef[index] & 0xFFFF);
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
const UTF8* utf8 = UTF8At(ctpDef[ntIndex] >> 16);
CommonClass* cl = getMethodClassIfLoaded(entry >> 16);
if (cl && cl->status >= readed) {
// lookup the method
meth = cl->lookupMethodDontThrow(utf8, sign->keyName, isStatic(access), false);
if (meth) { // don't throw if no meth, the exception will be thrown just in time
if (meth->methPtr) {
ctpRes[index] = (void*)meth->methPtr;
return (llvm::Function*)ctpRes[index];
}
}
}
// Must be a callback
if (ctpRes[index]) {
return (llvm::Function*)ctpRes[index];
} else {
// Create the callback
const llvm::FunctionType* type = 0;
if (isStatic(access)) {
type = sign->staticType;
} else {
type = sign->virtualType;
}
llvm::Function* func = new llvm::Function(type,
llvm::GlobalValue::GhostLinkage,
"callback", classDef->isolate->module);
classDef->isolate->TheModuleProvider->functions->hash(func,
new std::pair<Class*, uint32>(classDef, index));
ctpRes[index] = func;
return func;
}
}
Signdef* JavaCtpInfo::infoOfInterfaceOrVirtualMethod(uint32 index) {
uint8 id = typeAt(index);
if (id != ConstantMethodref && id != ConstantInterfaceMethodref)
JavaThread::get()->isolate->error(Jnjvm::ClassFormatError,
"bad constant pool number for method at entry %d", index);
Signdef* sign = (Signdef*)resolveNameAndType(ctpDef[index] & 0xFFFF);
return sign;
}
void JavaCtpInfo::resolveInterfaceOrMethod(uint32 index,
CommonClass*& cl, const UTF8*& utf8,
Signdef*& sign) {
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
sign = (Signdef*)ctpRes[ntIndex];
utf8 = UTF8At(ctpDef[ntIndex] >> 16);
cl = loadClass(entry >> 16);
cl->resolveClass(true);
}
void JavaCtpInfo::resolveField(uint32 index, CommonClass*& cl,
const UTF8*& utf8, Typedef*& sign) {
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
sign = (Typedef*)ctpRes[ntIndex];
utf8 = UTF8At(ctpDef[ntIndex] >> 16);
cl = loadClass(entry >> 16);
cl->resolveClass(true);
}
JavaField* JavaCtpInfo::lookupField(uint32 index, bool stat) {
if (!(ctpRes[index])) {
sint32 entry = ctpDef[index];
sint32 ntIndex = entry & 0xFFFF;
Typedef* sign = (Typedef*)ctpRes[ntIndex];
const UTF8* utf8 = UTF8At(ctpDef[ntIndex] >> 16);
CommonClass* cl = getMethodClassIfLoaded(entry >> 16);
if (cl && cl->status >= resolved) {
JavaField* field = cl->lookupFieldDontThrow(utf8, sign->keyName, stat,
true);
// don't throw if no field, the exception will be thrown just in time
if (field) {
ctpRes[index] = field;
return field;
}
} else {
return 0;
}
}
return (JavaField*)ctpRes[index];
}
JavaString* JavaCtpInfo::resolveString(const UTF8* utf8, uint16 index) {
JavaString* str = JavaThread::get()->isolate->UTF8ToStr(utf8);
return str;
}
ctpReader JavaCtpInfo::funcsReader[16] = {
unimplemented,
CtpReaderUTF8,
unimplemented,
CtpReaderInteger,
CtpReaderFloat,
CtpReaderLong,
CtpReaderDouble,
CtpReaderClass,
CtpReaderString,
CtpReaderFieldref,
CtpReaderMethodref,
CtpReaderInterfaceMethodref,
CtpReaderNameAndType,
unimplemented,
unimplemented,
unimplemented
};