blob: caadc686142e0e4d8b33bd585e5c7ef01b99fefc [file] [log] [blame]
//===------------- JavaTypes.cpp - Java primitives ------------------------===//
//
// JnJVM
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "mvm/JIT.h"
#include "JavaAccess.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaConstantPool.h"
#include "JavaJIT.h"
#include "JavaThread.h"
#include "JavaTypes.h"
#include "Jnjvm.h"
using namespace jnjvm;
const char AssessorDesc::I_TAB = '[';
const char AssessorDesc::I_END_REF = ';';
const char AssessorDesc::I_PARG = '(';
const char AssessorDesc::I_PARD = ')';
const char AssessorDesc::I_BYTE = 'B';
const char AssessorDesc::I_CHAR = 'C';
const char AssessorDesc::I_DOUBLE = 'D';
const char AssessorDesc::I_FLOAT = 'F';
const char AssessorDesc::I_INT = 'I';
const char AssessorDesc::I_LONG = 'J';
const char AssessorDesc::I_REF = 'L';
const char AssessorDesc::I_SHORT = 'S';
const char AssessorDesc::I_VOID = 'V';
const char AssessorDesc::I_BOOL = 'Z';
const char AssessorDesc::I_SEP = '/';
AssessorDesc* AssessorDesc::dParg = 0;
AssessorDesc* AssessorDesc::dPard = 0;
AssessorDesc* AssessorDesc::dVoid = 0;
AssessorDesc* AssessorDesc::dBool = 0;
AssessorDesc* AssessorDesc::dByte = 0;
AssessorDesc* AssessorDesc::dChar = 0;
AssessorDesc* AssessorDesc::dShort = 0;
AssessorDesc* AssessorDesc::dInt = 0;
AssessorDesc* AssessorDesc::dFloat = 0;
AssessorDesc* AssessorDesc::dLong = 0;
AssessorDesc* AssessorDesc::dDouble = 0;
AssessorDesc* AssessorDesc::dTab = 0;
AssessorDesc* AssessorDesc::dRef = 0;
AssessorDesc* AssessorDesc::allocate(bool dt, char bid, uint32 nb, uint32 nw,
const char* name, Jnjvm* vm,
const llvm::Type* t,
const char* assocName, arrayCtor_t ctor) {
AssessorDesc* res = gc_new(AssessorDesc)();
res->doTrace = dt;
res->byteId = bid;
res->nbb = nb;
res->nbw = nw;
res->asciizName = name;
res->llvmType = t;
if (t && t != llvm::Type::VoidTy) {
res->llvmTypePtr = llvm::PointerType::getUnqual(t);
res->llvmNullConstant = llvm::Constant::getNullValue(t);
}
res->arrayCtor = ctor;
if (assocName)
res->assocClassName = vm->asciizConstructUTF8(assocName);
else
res->assocClassName = 0;
if (bid != I_PARG && bid != I_PARD && bid != I_REF && bid != I_TAB) {
res->classType = vm->constructClass(vm->asciizConstructUTF8(name),
CommonClass::jnjvmClassLoader);
res->classType->status = ready;
res->classType->access = ACC_ABSTRACT | ACC_FINAL | ACC_PUBLIC;
} else {
res->classType = 0;
}
return res;
}
void AssessorDesc::initialise(Jnjvm* vm) {
dParg = AssessorDesc::allocate(false, I_PARG, 0, 0, "(", vm, 0, 0, 0);
dPard = AssessorDesc::allocate(false, I_PARD, 0, 0, ")", vm, 0, 0, 0);
dVoid = AssessorDesc::allocate(false, I_VOID, 0, 0, "void", vm,
llvm::Type::VoidTy, "java/lang/Void", 0);
dBool = AssessorDesc::allocate(false, I_BOOL, 1, 1, "boolean", vm,
llvm::Type::Int8Ty, "java/lang/Boolean",
(arrayCtor_t)ArrayUInt8::acons);
dByte = AssessorDesc::allocate(false, I_BYTE, 1, 1, "byte", vm,
llvm::Type::Int8Ty, "java/lang/Byte",
(arrayCtor_t)ArraySInt8::acons);
dChar = AssessorDesc::allocate(false, I_CHAR, 2, 1, "char", vm,
llvm::Type::Int16Ty, "java/lang/Character",
(arrayCtor_t)ArrayUInt16::acons);
dShort = AssessorDesc::allocate(false, I_SHORT, 2, 1, "short", vm,
llvm::Type::Int16Ty, "java/lang/Short",
(arrayCtor_t)ArraySInt16::acons);
dInt = AssessorDesc::allocate(false, I_INT, 4, 1, "int", vm,
llvm::Type::Int32Ty, "java/lang/Integer",
(arrayCtor_t)ArraySInt32::acons);
dFloat = AssessorDesc::allocate(false, I_FLOAT, 4, 1, "float", vm,
llvm::Type::FloatTy, "java/lang/Float",
(arrayCtor_t)ArrayFloat::acons);
dLong = AssessorDesc::allocate(false, I_LONG, 8, 2, "long", vm,
llvm::Type::Int64Ty, "java/lang/Long",
(arrayCtor_t)ArrayLong::acons);
dDouble = AssessorDesc::allocate(false, I_DOUBLE, 8, 2, "double", vm,
llvm::Type::DoubleTy, "java/lang/Double",
(arrayCtor_t)ArrayDouble::acons);
dTab = AssessorDesc::allocate(true, I_TAB, 4, 1, "array", vm,
JavaObject::llvmType, 0,
(arrayCtor_t)ArrayObject::acons);
dRef = AssessorDesc::allocate(true, I_REF, 4, 1, "reference", vm,
JavaObject::llvmType, 0,
(arrayCtor_t)ArrayObject::acons);
mvm::Object::pushRoot((mvm::Object*)dParg);
mvm::Object::pushRoot((mvm::Object*)dPard);
mvm::Object::pushRoot((mvm::Object*)dVoid);
mvm::Object::pushRoot((mvm::Object*)dBool);
mvm::Object::pushRoot((mvm::Object*)dByte);
mvm::Object::pushRoot((mvm::Object*)dChar);
mvm::Object::pushRoot((mvm::Object*)dShort);
mvm::Object::pushRoot((mvm::Object*)dInt);
mvm::Object::pushRoot((mvm::Object*)dFloat);
mvm::Object::pushRoot((mvm::Object*)dLong);
mvm::Object::pushRoot((mvm::Object*)dDouble);
mvm::Object::pushRoot((mvm::Object*)dTab);
mvm::Object::pushRoot((mvm::Object*)dRef);
}
void AssessorDesc::print(mvm::PrintBuffer* buf) const {
buf->write("AssessorDescriptor<");
buf->write(asciizName);
buf->write(">");
}
static void typeError(const UTF8* name, short int l) {
if (l != 0) {
JavaThread::get()->isolate->
unknownError("wrong type %d in %s", l, name->printString());
} else {
JavaThread::get()->isolate->
unknownError("wrong type %s", name->printString());
}
}
void AssessorDesc::analyseIntern(const UTF8* name, uint32 pos,
uint32 meth, AssessorDesc*& ass,
uint32& ret) {
short int cur = name->at(pos);
if (cur == I_PARG) {
ass = dParg;
ret = pos + 1;
} else if (cur == I_PARD) {
ass = dPard;
ret = pos + 1;
} else if (cur == I_BOOL) {
ass = dBool;
ret = pos + 1;
} else if (cur == I_BYTE) {
ass = dByte;
ret = pos + 1;
} else if (cur == I_CHAR) {
ass = dChar;
ret = pos + 1;
} else if (cur == I_SHORT) {
ass = dShort;
ret = pos + 1;
} else if (cur == I_INT) {
ass = dInt;
ret = pos + 1;
} else if (cur == I_FLOAT) {
ass = dFloat;
ret = pos + 1;
} else if (cur == I_DOUBLE) {
ass = dDouble;
ret = pos + 1;
} else if (cur == I_LONG) {
ass = dLong;
ret = pos + 1;
} else if (cur == I_VOID) {
ass = dVoid;
ret = pos + 1;
} else if (cur == I_TAB) {
if (meth == 1) {
pos++;
} else {
AssessorDesc * typeIntern = dTab;
while (name->at(++pos) == I_TAB);
analyseIntern(name, pos, 1, typeIntern, pos);
}
ass = dTab;
ret = pos;
} else if (cur == I_REF) {
if (meth != 2) {
while (name->at(++pos) != I_END_REF);
}
ass = dRef;
ret = pos + 1;
} else {
typeError(name, cur);
}
}
const UTF8* AssessorDesc::constructArrayName(Jnjvm *vm, AssessorDesc* ass,
uint32 steps,
const UTF8* className) {
if (ass) {
uint16* buf = (uint16*)alloca((steps + 1) * sizeof(uint16));
for (uint32 i = 0; i < steps; i++) {
buf[i] = I_TAB;
}
buf[steps] = ass->byteId;
return UTF8::readerConstruct(vm, buf, steps + 1);
} else {
uint32 len = className->size;
uint32 pos = steps;
AssessorDesc * funcs = (className->at(0) == I_TAB ? dTab : dRef);
uint32 n = steps + len + (funcs == dRef ? 2 : 0);
uint16* buf = (uint16*)alloca(n * sizeof(uint16));
for (uint32 i = 0; i < steps; i++) {
buf[i] = I_TAB;
}
if (funcs == dRef) {
++pos;
buf[steps] = funcs->byteId;
}
for (uint32 i = 0; i < len; i++) {
buf[pos + i] = className->at(i);
}
if (funcs == dRef) {
buf[n - 1] = I_END_REF;
}
return UTF8::readerConstruct(vm, buf, n);
}
}
void AssessorDesc::introspectArrayName(Jnjvm *vm, const UTF8* utf8,
uint32 start, AssessorDesc*& ass,
const UTF8*& res) {
uint32 pos = 0;
uint32 intern = 0;
AssessorDesc* funcs = 0;
analyseIntern(utf8, start, 1, funcs, intern);
if (funcs != dTab) {
vm->unknownError("%s isn't an array", utf8->printString());
}
analyseIntern(utf8, intern, 0, funcs, pos);
if (funcs == dRef) {
ass = dRef;
res = utf8->extract(vm, intern + 1, pos - 1);
} else if (funcs == dTab) {
ass = dTab;
res = utf8->extract(vm, intern, pos);
} else {
ass = funcs;
res = 0;
}
}
void AssessorDesc::introspectArray(Jnjvm *vm, JavaObject* loader,
const UTF8* utf8, uint32 start,
AssessorDesc*& ass, CommonClass*& res) {
uint32 pos = 0;
uint32 intern = 0;
AssessorDesc* funcs = 0;
analyseIntern(utf8, start, 1, funcs, intern);
if (funcs != dTab) {
vm->unknownError("%s isn't an array", utf8->printString());
}
analyseIntern(utf8, intern, 0, funcs, pos);
if (funcs == dRef) {
ass = dRef;
res = vm->loadName(utf8->extract(vm, intern + 1, pos - 1), loader, false,
false, true);
} else if (funcs == dTab) {
ass = dTab;
res = vm->constructArray(utf8->extract(vm, intern, pos), loader);
} else {
ass = funcs;
res = funcs->classType;
}
}
static void _arrayType(Jnjvm *vm, unsigned int t, AssessorDesc*& funcs,
llvm::Function*& ctor) {
if (t == JavaArray::T_CHAR) {
funcs = AssessorDesc::dChar;
ctor = JavaJIT::UTF8AconsLLVM;
} else if (t == JavaArray::T_BOOLEAN) {
funcs = AssessorDesc::dBool;
ctor = JavaJIT::Int8AconsLLVM;
} else if (t == JavaArray::T_INT) {
funcs = AssessorDesc::dInt;
ctor = JavaJIT::Int32AconsLLVM;
} else if (t == JavaArray::T_SHORT) {
funcs = AssessorDesc::dShort;
ctor = JavaJIT::Int16AconsLLVM;
} else if (t == JavaArray::T_BYTE) {
funcs = AssessorDesc::dByte;
ctor = JavaJIT::Int8AconsLLVM;
} else if (t == JavaArray::T_FLOAT) {
funcs = AssessorDesc::dFloat;
ctor = JavaJIT::FloatAconsLLVM;
} else if (t == JavaArray::T_LONG) {
funcs = AssessorDesc::dLong;
ctor = JavaJIT::LongAconsLLVM;
} else if (t == JavaArray::T_DOUBLE) {
funcs = AssessorDesc::dDouble;
ctor = JavaJIT::DoubleAconsLLVM;
} else {
vm->unknownError("unknown array type %d\n", t);
}
}
void AssessorDesc::arrayType(Jnjvm *vm, JavaObject* loader, unsigned int t,
ClassArray*& cl, AssessorDesc*& ass,
llvm::Function*& ctr) {
_arrayType(vm, t, ass, ctr);
cl = vm->constructArray(constructArrayName(vm, ass, 1, 0), loader);
assert(cl);
}
void Typedef::tPrintBuf(mvm::PrintBuffer* buf) const {
if (pseudoAssocClassName == 0)
buf->write(funcs->asciizName);
else
CommonClass::printClassName(pseudoAssocClassName, buf);
}
AssessorDesc* AssessorDesc::byteIdToPrimitive(char id) {
if (id == I_FLOAT) {
return dFloat;
} else if (id == I_INT) {
return dInt;
} else if (id == I_SHORT) {
return dShort;
} else if (id == I_CHAR) {
return dChar;
} else if (id == I_DOUBLE) {
return dDouble;
} else if (id == I_BYTE) {
return dByte;
} else if (id == I_BOOL) {
return dBool;
} else if (id == I_LONG) {
return dLong;
} else if (id == I_VOID) {
return dVoid;
} else {
return 0;
}
}
AssessorDesc* AssessorDesc::classToPrimitive(CommonClass* cl) {
const UTF8* name = cl->name;
if (name == dFloat->assocClassName) {
return dFloat;
} else if (name == dInt->assocClassName) {
return dInt;
} else if (name == dShort->assocClassName) {
return dShort;
} else if (name == dChar->assocClassName) {
return dChar;
} else if (name == dDouble->assocClassName) {
return dDouble;
} else if (name == dByte->assocClassName) {
return dByte;
} else if (name == dBool->assocClassName) {
return dBool;
} else if (name == dLong->assocClassName) {
return dLong;
} else if (name == dVoid->assocClassName) {
return dVoid;
} else {
return 0;
}
}
AssessorDesc* AssessorDesc::bogusClassToPrimitive(CommonClass* cl) {
if (cl == dFloat->classType) {
return dFloat;
} else if (cl == dInt->classType) {
return dInt;
} else if (cl == dShort->classType) {
return dShort;
} else if (cl == dChar->classType) {
return dChar;
} else if (cl == dDouble->classType) {
return dDouble;
} else if (cl == dByte->classType) {
return dByte;
} else if (cl == dBool->classType) {
return dBool;
} else if (cl == dLong->classType) {
return dLong;
} else if (cl == dVoid->classType) {
return dVoid;
} else {
return 0;
}
}
void Typedef::print(mvm::PrintBuffer* buf) const {
buf->write("Type<");
tPrintBuf(buf);
buf->write(">");
}
CommonClass* Typedef::assocClass(JavaObject* loader) {
if (pseudoAssocClassName == 0) {
return funcs->classType;
} else if (funcs == AssessorDesc::dRef) {
return isolate->loadName(pseudoAssocClassName, loader, false, true, true);
} else {
return isolate->constructArray(pseudoAssocClassName, loader);
}
}
void Typedef::humanPrintArgs(const std::vector<Typedef*>* args,
mvm::PrintBuffer* buf) {
buf->write("(");
for (uint32 i = 0; i < args->size(); i++) {
args->at(i)->tPrintBuf(buf);
if (i != args->size() - 1) {
buf->write(", ");
}
}
buf->write(")");
}
void Signdef::print(mvm::PrintBuffer* buf) const {
buf->write("Signature<");
ret->tPrintBuf(buf);
buf->write("...");
Typedef::humanPrintArgs(&args, buf);
buf->write(">");
}
const llvm::FunctionType* Signdef::createVirtualType(
const std::vector<Typedef*>* args, Typedef* ret) {
std::vector<const llvm::Type*> llvmArgs;
unsigned int size = args->size();
llvmArgs.push_back(JavaObject::llvmType);
for (uint32 i = 0; i < size; ++i) {
llvmArgs.push_back(args->at(i)->funcs->llvmType);
}
mvm::jit::protectTypes();//->lock();
llvm::FunctionType* res = llvm::FunctionType::get(ret->funcs->llvmType,
llvmArgs, false);
mvm::jit::unprotectTypes();//->unlock();
return res;
}
const llvm::FunctionType* Signdef::createStaticType(
const std::vector<Typedef*>* args, Typedef* ret) {
std::vector<const llvm::Type*> llvmArgs;
unsigned int size = args->size();
for (uint32 i = 0; i < size; ++i) {
llvmArgs.push_back(args->at(i)->funcs->llvmType);
}
mvm::jit::protectTypes();//->lock();
llvm::FunctionType* res = llvm::FunctionType::get(ret->funcs->llvmType,
llvmArgs, false);
mvm::jit::unprotectTypes();//->unlock();
return res;
}
const llvm::FunctionType* Signdef::createNativeType(
const std::vector<Typedef*>* args, Typedef* ret) {
std::vector<const llvm::Type*> llvmArgs;
unsigned int size = args->size();
llvmArgs.push_back(mvm::jit::ptrType); // JNIEnv
llvmArgs.push_back(JavaObject::llvmType); // Class
for (uint32 i = 0; i < size; ++i) {
llvmArgs.push_back(args->at(i)->funcs->llvmType);
}
mvm::jit::protectTypes();//->lock();
llvm::FunctionType* res = llvm::FunctionType::get(ret->funcs->llvmType,
llvmArgs, false);
mvm::jit::unprotectTypes();//->unlock();
return res;
}
void Signdef::printWithSign(CommonClass* cl, const UTF8* name,
mvm::PrintBuffer* buf) {
ret->tPrintBuf(buf);
buf->write(" ");
CommonClass::printClassName(cl->name, buf);
buf->write("::");
name->print(buf);
humanPrintArgs(&args, buf);
}
unsigned int Signdef::nbInWithThis(unsigned int flag) {
return args.size() + (isStatic(flag) ? 0 : 1);
}
Signdef* Signdef::signDup(const UTF8* name, Jnjvm *vm) {
std::vector<Typedef*> buf;
uint32 len = (uint32)name->size;
uint32 pos = 1;
uint32 pred = 0;
AssessorDesc* funcs = 0;
while (pos < len) {
pred = pos;
AssessorDesc::analyseIntern(name, pos, 0, funcs, pos);
if (funcs == AssessorDesc::dPard) break;
else {
buf.push_back(vm->constructType(name->extract(vm, pred, pos)));
}
}
if (pos == len) {
typeError(name, 0);
}
AssessorDesc::analyseIntern(name, pos, 0, funcs, pred);
if (pred != len) {
typeError(name, 0);
}
Signdef* res = gc_new(Signdef)();
res->args = buf;
res->ret = vm->constructType(name->extract(vm, pos, pred));
res->isolate = vm;
res->keyName = name;
res->pseudoAssocClassName = name;
res->funcs = 0;
res->nbIn = buf.size();
res->_virtualCallBuf = 0;
res->_staticCallBuf = 0;
res->_virtualCallAP = 0;
res->_staticCallAP = 0;
res->staticType = Signdef::createStaticType(&buf, res->ret);
res->virtualType = Signdef::createVirtualType(&buf, res->ret);
res->nativeType = Signdef::createNativeType(&buf, res->ret);
mvm::jit::protectTypes();//->lock();
res->staticTypePtr = llvm::PointerType::getUnqual(res->staticType);
res->virtualTypePtr = llvm::PointerType::getUnqual(res->virtualType);
res->nativeTypePtr = llvm::PointerType::getUnqual(res->nativeType);
std::vector<const llvm::Type*> Args;
Args.push_back(res->staticTypePtr);
Args.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty));
res->staticBufType = llvm::FunctionType::get(res->ret->funcs->llvmType, Args, false);
std::vector<const llvm::Type*> Args2;
Args2.push_back(res->virtualTypePtr);
Args2.push_back(JavaObject::llvmType);
Args2.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty));
res->virtualBufType = llvm::FunctionType::get(res->ret->funcs->llvmType, Args2, false);
mvm::jit::unprotectTypes();//->unlock();
return res;
}
Typedef* Typedef::typeDup(const UTF8* name, Jnjvm *vm) {
AssessorDesc* funcs = 0;
uint32 next;
AssessorDesc::analyseIntern(name, 0, 0, funcs, next);
if (funcs == AssessorDesc::dParg) {
return Signdef::signDup(name, vm);
} else {
Typedef* res = gc_new(Typedef)();
res->isolate = vm;
res->keyName = name;
res->funcs = funcs;
if (funcs == AssessorDesc::dRef) {
res->pseudoAssocClassName = name->extract(vm, 1, next - 1);
} else if (funcs == AssessorDesc::dTab) {
res->pseudoAssocClassName = name;
}
return res;
}
}