//===-- VMClass.cpp - Compiler representation of a Java class ---*- 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 declaration of the Class class that represents a
// compile time representation of a Java class (java.lang.Class). This unlike
// a classfile representation, it resolves the constant pool, creates global
// variables for the static members of this class and also creates the class
// record (vtable) of this class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "javaclass"

#include "VMClass.h"
#include "Resolver.h"
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/Java/ClassFile.h>
#include <llvm/Support/Debug.h>
#include <iostream>

using namespace llvm;
using namespace llvm::Java;

// On initialization we create a placeholder global for the class
// record that will be patched later when the class record is
// computed.
void VMClass::init()
{
  classRecord_ = new GlobalVariable(
    OpaqueType::get(),
    false,
    GlobalVariable::ExternalLinkage,
    NULL,
    getName() + "<class_record>",
    resolver_->getModule());
}

VMClass::VMClass(Resolver* resolver, const std::string& className)
  : name_(className),
    descriptor_(Resolver::canonicalizeClassName(className)),
    resolver_(resolver),
    classFile_(ClassFile::get(className)),
    componentClass_(NULL),
    layoutType_(OpaqueType::get()),
    type_(PointerType::get(layoutType_)),
    interfaceIndex_(INVALID_INTERFACE_INDEX),
    resolvedConstantPool_(classFile_->getNumConstants())
{
  init();
}

VMClass::VMClass(Resolver* resolver, const VMClass* componentClass)
  : name_('[' + componentClass->getDescriptor()),
    descriptor_(name_),
    resolver_(resolver),
    classFile_(NULL),
    componentClass_(componentClass),
    layoutType_(OpaqueType::get()),
    type_(PointerType::get(layoutType_)),
    interfaceIndex_(INVALID_INTERFACE_INDEX)
{
  init();
}

VMClass::VMClass(Resolver* resolver, const Type* type)
  : name_(type == Type::SByteTy  ? "byte" :
          type == Type::UShortTy ? "char" :
          type == Type::DoubleTy ? "double" :
          type == Type::FloatTy  ? "float" :
          type == Type::IntTy    ? "int" :
          type == Type::LongTy   ? "long" :
          type == Type::ShortTy  ? "short" :
          type == Type::BoolTy   ? "boolean" : "void"),
    descriptor_(type == Type::SByteTy  ? "B" :
                type == Type::UShortTy ? "C" :
                type == Type::DoubleTy ? "D" :
                type == Type::FloatTy  ? "F" :
                type == Type::IntTy    ? "I" :
                type == Type::LongTy   ? "J" :
                type == Type::ShortTy  ? "S" :
                type == Type::BoolTy   ? "Z" : "V"),
    resolver_(resolver),
    classFile_(NULL),
    componentClass_(NULL),
    layoutType_(const_cast<Type*>(type)),
    type_(type),
    interfaceIndex_(INVALID_INTERFACE_INDEX)
{
  init();
}

const VMField* VMClass::lookupField(const std::string& name) const
{
  if (const VMField* field = getField(name))
    return field;

  for (unsigned i = 0, e = getNumInterfaces(); i != e; ++i) {
    const VMClass* interface = getInterface(i);
    if (const VMField* field = interface->getField(name))
      return field;
  }

  for (unsigned i = 0, e = getNumSuperClasses(); i != e; ++i) {
    const VMClass* superClass = getSuperClass(i);
    if (const VMField* field = superClass->getField(name))
      return field;
  }

  return NULL;
}

const VMMethod* VMClass::lookupMethod(const std::string& nameAndType) const
{
  if (const VMMethod* method = getMethod(nameAndType))
    return method;

  if (isInterface())
    for (unsigned i = 0, e = getNumInterfaces(); i != e; ++i) {
      const VMClass* interface = getInterface(i);
      if (const VMMethod* method = interface->getMethod(nameAndType))
        return method;
    }
  else
    for (unsigned i = 0, e = getNumSuperClasses(); i != e; ++i) {
      const VMClass* superClass = getSuperClass(i);
      if (const VMMethod* method = superClass->getMethod(nameAndType))
        return method;
    }

  return NULL;
}

void VMClass::computeLayout()
{
  DEBUG(std::cerr << "Computing layout for: " << getName() << '\n');
  // The layout of primitive classes is already computed.
  if (isPrimitive()) {
    DEBUG(std::cerr << "Computed layout for: " << getName() << '\n');
    return;
  }

  std::vector<const Type*> layout;
  if (isArray()) {
    layout.reserve(3);
    layout.push_back(resolver_->getClass("java/lang/Object")->getLayoutType());
    layout.push_back(Type::UIntTy);
    layout.push_back(ArrayType::get(componentClass_->getType(), 0));
  }
  else {
    if (const VMClass* superClass = getSuperClass())
      layout.push_back(superClass->getLayoutType());
    else // This is java/lang/Object
      layout.push_back(resolver_->getObjectBaseLayoutType());
    // Now add the fields.
    const Fields& fields = classFile_->getFields();
    for (unsigned i = 0, e = fields.size(); i != e; ++i) {
      Field* field = fields[i];
      const std::string& name = field->getName()->str();
      if (field->isStatic()) {
        FieldMap::iterator i = fieldMap_.insert(
          std::make_pair(name, VMField(this, field))).first;
        staticFields_.push_back(&i->second);
      }
      else {
        unsigned index = memberFields_.size() + 1;
        FieldMap::iterator i = fieldMap_.insert(
          std::make_pair(name, VMField(this, field, index))).first;
        const VMField* vmf = &i->second;
        memberFields_.push_back(vmf);
        layout.push_back(vmf->getClass()->getType());
      }
    }
  }

  PATypeHolder holder = layoutType_;
  Type* resolvedType = StructType::get(layout);
  cast<OpaqueType>(layoutType_)->refineAbstractTypeTo(resolvedType);
  layoutType_ = holder.get();
  type_ = PointerType::get(layoutType_);

  DEBUG(std::cerr << "Computed layout for: " << getName() << '\n');
}

llvm::Constant* VMClass::buildSuperClassRecords() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(getNumSuperClasses());
  for (unsigned i = getNumSuperClasses(); i--; )
    init.push_back(ConstantExpr::getCast(
                     getSuperClass(i)->getClassRecord(),
                     resolver_->getClassRecordPtrType()));

  const ArrayType* superClassRecordsType =
    ArrayType::get(resolver_->getClassRecordPtrType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      superClassRecordsType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(superClassRecordsType, init),
      getName() + "<super_class_records>",
      resolver_->getModule()));
}

llvm::Constant*
VMClass::buildInterfaceClassRecord(const VMClass* interface) const
{
  assert(interface->isInterface() && "Must be passed an interface!");

  std::vector<llvm::Constant*> init;
  init.reserve(interface->getNumDynamicMethods() + 1);
  // Insert a null type info for this interface.
  init.push_back(llvm::Constant::getNullValue(resolver_->getTypeInfoType()));
  // For each method this interface declares, find the corresponding
  // method in this class and put it in its slot.
  for (unsigned i = 0, e = interface->getNumDynamicMethods(); i != e; ++i) {
    assert(init.size() == i+1 && "Interface method not found in class!");
    const VMMethod* interfaceMethod = interface->getDynamicMethod(i);
    for (unsigned j = 0, f = getNumDynamicMethods(); j != f; ++j) {
      const VMMethod* method = getDynamicMethod(j);
      if (method->getName() == interfaceMethod->getName() &&
          method->getDescriptor() == interfaceMethod->getDescriptor()) {
        init.push_back(method->getFunction());
        break;
      }
    }
  }

  llvm::Constant* classRecordInit = ConstantStruct::get(init);

  return ConstantExpr::getCast(
    new GlobalVariable(
      classRecordInit->getType(),
      true,
      GlobalVariable::ExternalLinkage,
      classRecordInit,
      getName() + '+' + interface->getName() + "<class_record>",
      resolver_->getModule()),
    resolver_->getClassRecordPtrType());
}

llvm::Constant* VMClass::buildInterfaceClassRecords() const
{
  // This is an interface or primitive class record so it doesn't
  // implement any interfaces. Thus the pointer to the array of
  // implemented interfaces is null.
  if (isInterface() || isPrimitive()) {
    const Type* classRecordPtrPtrType =
      PointerType::get(resolver_->getClassRecordPtrType());

    return llvm::Constant::getNullValue(classRecordPtrPtrType);
  }

  // Otherwise this is a class or array class record so we have to
  // fill in the array of implemented interfaces up the max interface
  // index and build each individual interface class record for this
  // class.
  llvm::Constant* nullClassRecord =
    llvm::Constant::getNullValue(resolver_->getClassRecordPtrType());
  std::vector<llvm::Constant*> init(getInterfaceIndex()+1, nullClassRecord);

  for (unsigned i = 0, e = getNumInterfaces(); i != e; ++i) {
    const VMClass* interface = getInterface(i);
    init[interface->getInterfaceIndex()] = buildInterfaceClassRecord(interface);
  }

  const ArrayType* interfaceClassRecordsType =
    ArrayType::get(resolver_->getClassRecordPtrType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      interfaceClassRecordsType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(interfaceClassRecordsType, init),
      getName() + "<interface_class_records>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildClassName() const
{
  llvm::Constant* name = ConstantArray::get(getName());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      name->getType(),
      true,
      GlobalVariable::ExternalLinkage,
      name,
      getName() + "<classname>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildFieldDescriptors() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(memberFields_.size()+1);

  for (unsigned i = 0, e = memberFields_.size(); i != e; ++i) {
    const VMField* field = memberFields_[i];
    init.push_back(field->buildFieldDescriptor());
  }
  // Null terminate.
  init.push_back(llvm::Constant::getNullValue(PointerType::get(Type::SByteTy)));

  const ArrayType* arrayType =
    ArrayType::get(init.back()->getType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<field_descriptors>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildFieldOffsets() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(memberFields_.size());

  for (unsigned i = 0, e = memberFields_.size(); i != e; ++i) {
    const VMField* field = memberFields_[i];
    init.push_back(field->buildFieldOffset());
  }

  const ArrayType* arrayType = ArrayType::get(Type::UIntTy, init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<field_offsets>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildStaticFieldDescriptors() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(staticFields_.size()+1);

  for (unsigned i = 0, e = staticFields_.size(); i != e; ++i) {
    const VMField* field = staticFields_[i];
    init.push_back(field->buildFieldDescriptor());
  }
  // Null terminate.
  init.push_back(llvm::Constant::getNullValue(PointerType::get(Type::SByteTy)));

  const ArrayType* arrayType =
    ArrayType::get(init.back()->getType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<static_field_descriptors>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildStaticFieldPointers() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(staticFields_.size());

  const Type* pointerType = PointerType::get(Type::SByteTy);
  for (unsigned i = 0, e = staticFields_.size(); i != e; ++i) {
    const VMField* field = staticFields_[i];
    init.push_back(ConstantExpr::getCast(field->getGlobal(), pointerType));
  }

  const ArrayType* arrayType = ArrayType::get(pointerType, init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<static_field_pointers>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildMethodDescriptors() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(getNumStaticMethods() + 1);

  for (unsigned i = 0, e = getNumDynamicMethods(); i != e; ++i) {
    const VMMethod* method = getDynamicMethod(i);
    init.push_back(method->buildMethodDescriptor());
  }
  // Null terminate.
  init.push_back(llvm::Constant::getNullValue(PointerType::get(Type::SByteTy)));

  const ArrayType* arrayType =
    ArrayType::get(init.back()->getType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<method_descriptors>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildMethodPointers() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(getNumStaticMethods());

  const Type* pointerType = PointerType::get(Type::SByteTy);
  for (unsigned i = 0, e = getNumDynamicMethods(); i != e; ++i) {
    const VMMethod* method = getDynamicMethod(i);
    init.push_back(ConstantExpr::getCast(method->getBridgeFunction(),
                                         pointerType));
  }

  const ArrayType* arrayType = ArrayType::get(pointerType, init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<method_pointers>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildStaticMethodDescriptors() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(getNumStaticMethods() + 1);

  for (unsigned i = 0, e = getNumStaticMethods(); i != e; ++i) {
    const VMMethod* method = getStaticMethod(i);
    init.push_back(method->buildMethodDescriptor());
  }
  // Null terminate.
  init.push_back(llvm::Constant::getNullValue(PointerType::get(Type::SByteTy)));

  const ArrayType* arrayType =
    ArrayType::get(init.back()->getType(), init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<static_method_descriptors>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildStaticMethodPointers() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(getNumStaticMethods());

  const Type* pointerType = PointerType::get(Type::SByteTy);
  for (unsigned i = 0, e = getNumStaticMethods(); i != e; ++i) {
    const VMMethod* method = getStaticMethod(i);
    init.push_back(ConstantExpr::getCast(method->getBridgeFunction(),
                                         pointerType));
  }

  const ArrayType* arrayType = ArrayType::get(pointerType, init.size());

  return ConstantExpr::getPtrPtrFromArrayPtr(
    new GlobalVariable(
      arrayType,
      true,
      GlobalVariable::ExternalLinkage,
      ConstantArray::get(arrayType, init),
      getName() + "<static_method_pointers>",
      resolver_->getModule()));
}

llvm::Constant* VMClass::buildClassTypeInfo() const
{
  std::vector<llvm::Constant*> init;
  init.reserve(5);

  init.push_back(buildClassName());
  init.push_back(ConstantSInt::get(Type::IntTy, getNumSuperClasses()));
  init.push_back(buildSuperClassRecords());
  init.push_back(ConstantSInt::get(Type::IntTy, getInterfaceIndex()));
  init.push_back(buildInterfaceClassRecords());
  if (isArray())
    init.push_back(ConstantExpr::getCast(getComponentClass()->getClassRecord(),
                                         resolver_->getClassRecordPtrType()));
  else
    init.push_back(
      llvm::Constant::getNullValue(resolver_->getClassRecordPtrType()));
  if (isArray())
    init.push_back(
      ConstantExpr::getCast(
        ConstantExpr::getSizeOf(getComponentClass()->getType()), Type::IntTy));
  else if (isPrimitive())
    init.push_back(ConstantSInt::get(Type::IntTy, -2));
  else if (isInterface())
    init.push_back(ConstantSInt::get(Type::IntTy, -1));
  else // A class.
    init.push_back(ConstantSInt::get(Type::IntTy, 0));

  init.push_back(buildFieldDescriptors());
  init.push_back(buildFieldOffsets());
  init.push_back(buildStaticFieldDescriptors());
  init.push_back(buildStaticFieldPointers());
  init.push_back(buildMethodDescriptors());
  init.push_back(buildMethodPointers());
  init.push_back(buildStaticMethodDescriptors());
  init.push_back(buildStaticMethodPointers());

  return ConstantStruct::get(init);
}

void VMClass::computeClassRecord()
{
  DEBUG(std::cerr << "Computing class record for: " << getName() << '\n');
  // Find dynamically bound methods.
  if (!isPrimitive()) {
    if (const VMClass* superClass = getSuperClass())
      dynamicMethods_ = superClass->dynamicMethods_;

    if (getClassFile()) {
      const Methods& methods = classFile_->getMethods();
      for (unsigned i = 0, e = methods.size(); i != e; ++i) {
        Method* method = methods[i];
        const std::string& name = method->getName()->str();
        const std::string& descriptor = method->getDescriptor()->str();

        // If method is statically bound just create it.
        if (method->isPrivate() || method->isStatic() || name[0] == '<') {
          MethodMap::iterator i =
            methodMap_.insert(
              std::make_pair(name + descriptor, VMMethod(this, method))).first;
          staticMethods_.push_back(&i->second);
        }
        // Otherwise we need to assign an index for it and update the
        // dynamicMethods_ vector.
        else {
          const VMMethod* overridenMethod = NULL;
          for (unsigned i = 0, e = getNumDynamicMethods(); i != e; ++i) {
            const VMMethod* m = getDynamicMethod(i);
            if (m->getName() == name && m->getDescriptor() == descriptor)
              overridenMethod = m;
          }

          // If this is an overriden method reuse the method index
          // with the overriding one.
          if (overridenMethod) {
            int index = overridenMethod->getMethodIndex();
            MethodMap::iterator i = methodMap_.insert(
              std::make_pair(name + descriptor,
                             VMMethod(this, method, index))).first;
            dynamicMethods_[index] = &i->second;
          }
          // Otherwise assign it a new index.
          else {
            int index = dynamicMethods_.size();
            MethodMap::iterator i = methodMap_.insert(
              std::make_pair(
                name + descriptor, VMMethod(this, method, index))).first;
            dynamicMethods_.push_back(&i->second);
          }
        }
      }
    }
  }

  std::vector<llvm::Constant*> init;
  init.reserve(1 + getNumDynamicMethods());
  init.push_back(buildClassTypeInfo());
  for (unsigned i = 0, e = getNumDynamicMethods(); i != e; ++i) {
    const VMMethod* method = getDynamicMethod(i);
    init.push_back(
      method->isAbstract() ?
      llvm::Constant::getNullValue(method->getFunction()->getType()) :
      method->getFunction());
  }

  llvm::Constant* classRecordInit = ConstantStruct::get(init);
  resolver_->getModule()->addTypeName("classRecord." + getName(),
                                      classRecordInit->getType());

  // Now resolve the opaque type of the placeholder class record.
  const Type* classRecordType =
    cast<PointerType>(classRecord_->getType())->getElementType();
  OpaqueType* opaqueType = cast<OpaqueType>(const_cast<Type*>(classRecordType));
  opaqueType->refineAbstractTypeTo(classRecordInit->getType());
  // Set the initializer of the class record.
  classRecord_->setInitializer(classRecordInit);
  // Mark the class record as constant.
  classRecord_->setConstant(true);

  DEBUG(std::cerr << "Computed class record for: " << getName() << '\n');
}

void VMClass::link()
{
  // Primitive classes require no linking.
  if (isPrimitive())
    ;
  else if (isArray()) {
    superClasses_.reserve(1);
    superClasses_.push_back(resolver_->getClass("java/lang/Object"));

    interfaces_.reserve(2);
    interfaces_.push_back(resolver_->getClass("java/lang/Cloneable"));
    interfaces_.push_back(resolver_->getClass("java/io/Serializable"));
  }
  else {
    // This is any class but java/lang/Object.
    if (classFile_->getSuperClass()) {
      // Our direct super class.
      const VMClass* superClass = getClass(classFile_->getSuperClassIndex());

      // Add the interfaces of our direct superclass.
      for (unsigned i = 0, e = superClass->getNumInterfaces(); i != e; ++i)
        interfaces_.push_back(superClass->getInterface(i));

      // The first class is the direct super class of this class.
      superClasses_.reserve(superClass->getNumSuperClasses() + 1);
      superClasses_.push_back(superClass);
      for (unsigned i = 0, e = superClass->getNumSuperClasses(); i != e; ++i)
        superClasses_.push_back(superClass->getSuperClass(i));
    }

    // For each of the interfaces we implement, load it and add that
    // interface and all the interfaces it inherits from.
    for (unsigned i = 0, e = classFile_->getNumInterfaces(); i != e; ++i) {
      const VMClass* interface = getClass(classFile_->getInterfaceIndex(i));
      interfaces_.push_back(interface);
      for (unsigned j = 0, f = interface->getNumInterfaces(); j != f; ++j)
        interfaces_.push_back(interface->getInterface(j));
    }

    // Sort the interfaces array and remove duplicates.
    std::sort(interfaces_.begin(), interfaces_.end());
    interfaces_.erase(std::unique(interfaces_.begin(), interfaces_.end()),
                      interfaces_.end());
  }

  // The interface index for an interface is a unique number generated
  // from the resolver.
  if (isInterface())
    interfaceIndex_ = resolver_->getNextInterfaceIndex();
  // For a class it is the max index of all the interfaces it implements.
  else {
    for (unsigned i = 0, e = getNumInterfaces(); i != e; ++i)
      interfaceIndex_ =
        std::max(interfaceIndex_, getInterface(i)->getInterfaceIndex());
  }

  computeLayout();
  computeClassRecord();

  assert(!isa<OpaqueType>(getLayoutType()) &&"Class not initialized properly!");
}

llvm::Constant* VMClass::getConstant(unsigned index) const
{
  assert(classFile_ && "No constant pool!");
  assert((dynamic_cast<ConstantString*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantInteger*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantFloat*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantLong*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantDouble*>(classFile_->getConstant(index))) &&
         "Not an index to a constant!");

  // If we haven't resolved this constant already, do so now.
  if (!resolvedConstantPool_[index]) {
    Constant* jc = classFile_->getConstant(index);
    if (ConstantString* s = dynamic_cast<ConstantString*>(jc)) {
      const VMClass* stringClass = resolver_->getClass("java/lang/String");
      const Type* stringType = stringClass->getLayoutType();
      resolvedConstantPool_[index] =
        new GlobalVariable(stringType,
                           false,
                           GlobalVariable::LinkOnceLinkage,
                           llvm::Constant::getNullValue(stringType),
                           s->getValue()->str() + ".java/lang/String",
                           resolver_->getModule());
    }
    else if (ConstantInteger* i = dynamic_cast<ConstantInteger*>(jc))
      resolvedConstantPool_[index] =
        ConstantSInt::get(Type::IntTy, i->getValue());
    else if (ConstantFloat* f = dynamic_cast<ConstantFloat*>(jc))
      resolvedConstantPool_[index] =
        ConstantFP::get(Type::FloatTy, f->getValue());
    else if (ConstantLong* l = dynamic_cast<ConstantLong*>(jc))
      resolvedConstantPool_[index] =
        ConstantSInt::get(Type::LongTy, l->getValue());
    else if (ConstantDouble* d = dynamic_cast<ConstantDouble*>(jc))
      resolvedConstantPool_[index] =
        ConstantFP::get(Type::DoubleTy, d->getValue());
    else
      assert(0 && "Not a constant!");
  }

  return static_cast<llvm::Constant*>(resolvedConstantPool_[index]);
}

const VMClass* VMClass::getClass(unsigned index) const
{
  assert(classFile_ && "No constant pool!");
  assert((dynamic_cast<ConstantClass*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantUtf8*>(classFile_->getConstant(index))) &&
         "Not an index to a class or descriptor reference!");

  // If we haven't resolved this constant already, do so now.
  if (!resolvedConstantPool_[index]) {
    Constant* jc = classFile_->getConstant(index);
    if (ConstantClass* c = dynamic_cast<ConstantClass*>(jc))
      resolvedConstantPool_[index] =
        const_cast<VMClass*>(resolver_->getClass(c->getName()->str()));
    else if (ConstantUtf8* d = dynamic_cast<ConstantUtf8*>(jc))
      resolvedConstantPool_[index] =
        const_cast<VMClass*>(resolver_->getClassForDesc(d->str()));
    else
      assert(0 && "Not a class!");
  }

  return static_cast<const VMClass*>(resolvedConstantPool_[index]);
}

const VMField* VMClass::getField(unsigned index) const
{
  assert(classFile_ && "No constant pool!");
  assert(dynamic_cast<ConstantFieldRef*>(classFile_->getConstant(index)) &&
         "Not an index to a field reference!");

  // If we haven't resolved this constant already, do so now.
  if (!resolvedConstantPool_[index]) {
    ConstantFieldRef* jc = classFile_->getConstantFieldRef(index);
    const VMClass* clazz = getClass(jc->getClassIndex());
    const std::string& name = jc->getNameAndType()->getName()->str();
    resolvedConstantPool_[index] =
      const_cast<VMField*>(clazz->lookupField(name));
  }

  return static_cast<const VMField*>(resolvedConstantPool_[index]);
}

const VMMethod* VMClass::getMethod(unsigned index) const
{
  assert(classFile_ && "No constant pool!");
  assert((dynamic_cast<ConstantMethodRef*>(classFile_->getConstant(index)) ||
          dynamic_cast<ConstantInterfaceMethodRef*>(classFile_->getConstant(index))) &&
         "Not an index to a method reference!");

  // If we haven't resolved this constant already, do so now.
  if (!resolvedConstantPool_[index]) {
    ConstantMemberRef* jc = classFile_->getConstantMemberRef(index);
    const VMClass* clazz = getClass(jc->getClassIndex());
    ConstantNameAndType* ntc = jc->getNameAndType();
    const std::string& name = ntc->getName()->str();
    const std::string& descriptor = ntc->getDescriptor()->str();
    resolvedConstantPool_[index] =
      const_cast<VMMethod*>(clazz->lookupMethod(name + descriptor));
  }

  return static_cast<const VMMethod*>(resolvedConstantPool_[index]);
}
