blob: 4e4cc9a35efa018f59edc1a18d6cc6c0955fad24 [file] [log] [blame]
//===-- Resolver.cpp - Class resolver for Java classes ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the Java class resolver.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "javaresolver"
#include "Resolver.h"
#include <llvm/Java/ClassFile.h>
#include <llvm/Constants.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Support/Debug.h>
using namespace llvm;
using namespace llvm::Java;
Resolver::Resolver(Module* module)
: module_(module),
nextInterfaceIndex_(0),
objectBaseLayoutType_(OpaqueType::get()),
objectBaseType_(PointerType::get(objectBaseLayoutType_)),
classRecordType_(OpaqueType::get()),
classRecordPtrType_(PointerType::get(classRecordType_))
{
module_->addTypeName("struct.llvm_java_object_base",
getObjectBaseLayoutType());
// Compute the class record type. A class record looks like:
//
// struct class_record {
// struct type_info;
// };
//
// struct type_info {
// char* name;
// int depth;
// struct class_record** superclasses;
// int interfaceIndex;
// struct class_record** interfaces;
// struct class_record* component;
// int elementSize;
// char** fieldDescriptors;
// unsigned* fieldOffsets;
// char** staticFieldDescriptors;
// void** staticFields;
// char** MethodDescriptors;
// void** Methods;
// char** staticMethodDescriptors;
// void** staticMethods;
// };
// Compute the type_info type.
std::vector<const Type*> elements;
elements.push_back(PointerType::get(Type::SByteTy));
elements.push_back(Type::IntTy);
elements.push_back(PointerType::get(PointerType::get(classRecordType_)));
elements.push_back(Type::IntTy);
elements.push_back(PointerType::get(PointerType::get(classRecordType_)));
elements.push_back(PointerType::get(classRecordType_));
elements.push_back(Type::IntTy);
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(Type::UIntTy));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
elements.push_back(PointerType::get(PointerType::get(Type::SByteTy)));
typeInfoType_ = StructType::get(elements);
module_->addTypeName("struct.llvm_java_typeinfo", getTypeInfoType());
// Compute the class_record type.
PATypeHolder holder = classRecordType_;
cast<OpaqueType>(const_cast<Type*>(classRecordType_))->refineAbstractTypeTo(
StructType::get(std::vector<const Type*>(1, getTypeInfoType())));
classRecordType_ = holder.get();
module_->addTypeName("struct.llvm_java_class_record", getClassRecordType());
classRecordPtrType_ = PointerType::get(classRecordType_);
}
const Type* Resolver::getType(const std::string& descriptor,
bool memberMethod) const
{
unsigned i = 0;
return getTypeHelper(descriptor, i, memberMethod);
}
const Type* Resolver::getTypeHelper(const std::string& descr,
unsigned& i,
bool memberMethod) const
{
assert(i < descr.size());
switch (descr[i++]) {
case 'B': return Type::SByteTy;
case 'C': return Type::UShortTy;
case 'D': return Type::DoubleTy;
case 'F': return Type::FloatTy;
case 'I': return Type::IntTy;
case 'J': return Type::LongTy;
case 'S': return Type::ShortTy;
case 'Z': return Type::BoolTy;
case 'V': return Type::VoidTy;
case 'L': {
unsigned e = descr.find(';', i);
i = e + 1;
return getObjectBaseType();
}
case '[':
// Skip '['s.
if (descr[i] == '[')
do { ++i; } while (descr[i] == '[');
// Consume the element type
getTypeHelper(descr, i);
return getObjectBaseType();
case '(': {
std::vector<const Type*> params;
if (memberMethod)
params.push_back(getObjectBaseType());
while (descr[i] != ')')
params.push_back(getTypeHelper(descr, i));
return FunctionType::get(getTypeHelper(descr, ++i), params, false);
}
// FIXME: Throw something
default: assert(0 && "Cannot parse type descriptor!");
}
return 0; // not reached
}
const VMClass* Resolver::getClassForDesc(const std::string& descriptor)
{
ClassMap::iterator it = classMap_.lower_bound(descriptor);
if (it == classMap_.end() || it->first != descriptor) {
switch (descriptor[0]) {
case 'B':
it = insertClass(it, VMClass(this, Type::SByteTy));
break;
case 'C':
it = insertClass(it, VMClass(this, Type::UShortTy));
break;
case 'D':
it = insertClass(it, VMClass(this, Type::DoubleTy));
break;
case 'F':
it = insertClass(it, VMClass(this, Type::FloatTy));
break;
case 'I':
it = insertClass(it, VMClass(this, Type::IntTy));
break;
case 'J':
it = insertClass(it, VMClass(this, Type::LongTy));
break;
case 'S':
it = insertClass(it, VMClass(this, Type::ShortTy));
break;
case 'Z':
it = insertClass(it, VMClass(this, Type::BoolTy));
break;
case 'V':
it = insertClass(it, VMClass(this, Type::VoidTy));
break;
case 'L': {
unsigned pos = descriptor.find(';', 1);
const std::string& className = descriptor.substr(1, pos - 1);
it = insertClass(it, VMClass(this, className));
break;
}
case '[': {
const std::string& componentDescriptor = descriptor.substr(1);
it = insertClass(it, VMClass(this, getClassForDesc(componentDescriptor)));
break;
}
default:
assert(0 && "Cannot parse type descriptor!");
abort();
}
it->second.link();
if (!it->second.isPrimitive() && !it->second.isInterface())
module_->addTypeName("struct." + descriptor, it->second.getLayoutType());
DEBUG(std::cerr << "Loaded class: " << it->second.getName());
DEBUG(std::cerr << " (" << it->second.getInterfaceIndex() << ")\n");
}
return &it->second;
}
const VMClass* Resolver::getClass(JType type)
{
switch (type) {
case BOOLEAN: return getClassForDesc("Z");
case CHAR: return getClassForDesc("C");
case FLOAT: return getClassForDesc("F");
case DOUBLE: return getClassForDesc("D");
case BYTE: return getClassForDesc("B");
case SHORT: return getClassForDesc("S");
case INT: return getClassForDesc("I");
case LONG: return getClassForDesc("J");
default: assert(0 && "Unhandled JType!"); abort();
}
}
const Type* Resolver::getStorageType(const Type* type) const
{
if (isa<PointerType>(type))
return getObjectBaseType();
else if (type == Type::BoolTy ||
type == Type::UByteTy ||
type == Type::SByteTy ||
type == Type::UShortTy ||
type == Type::ShortTy ||
type == Type::UIntTy)
return Type::IntTy;
else if (type == Type::ULongTy)
return Type::LongTy;
else
return type;
}
void Resolver::emitClassRecordsArray() const
{
std::vector<llvm::Constant*> init;
init.reserve(classMap_.size() + 1);
for (ClassMap::const_iterator i = classMap_.begin(), e = classMap_.end();
i != e; ++i)
init.push_back(ConstantExpr::getCast(i->second.getClassRecord(),
classRecordPtrType_));
// Null terminate the array.
init.push_back(llvm::Constant::getNullValue(classRecordPtrType_));
const ArrayType* arrayType = ArrayType::get(classRecordPtrType_, init.size());
new GlobalVariable(
arrayType,
true,
GlobalVariable::ExternalLinkage,
ConstantArray::get(arrayType, init),
"llvm_java_class_records",
module_);
}