// Copyright 2011 Google Inc. All Rights Reserved.

#ifndef ART_SRC_DEX_CACHE_H_
#define ART_SRC_DEX_CACHE_H_

#include "dex_file.h"
#include "globals.h"
#include "macros.h"
#include "object.h"

namespace art {

class Class;
class Field;
class ImageWriter;
class Method;
class String;
union JValue;

class MANAGED CodeAndDirectMethods : public IntArray {
 public:
  void* GetResolvedCode(uint32_t method_idx) const {
    return reinterpret_cast<byte*>(Get(CodeIndex(method_idx)));
  }
  Method* GetResolvedMethod(uint32_t method_idx) const {
    return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
  }

  void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array) {
    CHECK(code_array != NULL);
    int32_t code = reinterpret_cast<int32_t>(code_array->GetData());
    Set(CodeIndex(method_idx), code);
    Set(MethodIndex(method_idx), method_idx);
  }

  void SetResolvedDirectMethod(uint32_t method_idx, Method* method) {
    CHECK(method != NULL);
    CHECK(method->IsDirect()) << PrettyMethod(method);
    CHECK(method->GetCode() != NULL) << PrettyMethod(method);
    Set(CodeIndex(method_idx),   reinterpret_cast<int32_t>(method->GetCode()));
    Set(MethodIndex(method_idx), reinterpret_cast<int32_t>(method));
  }

  static size_t LengthAsArray(size_t elements) {
    return kMax * elements;
  }

  // Offset of resolved method entry from start of code_and_direct_methods_
  static size_t MethodOffsetInBytes(uint32_t method_idx) {
    return (MethodIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
  }

  // Offset of resolved method's code_ from start of code_and_direct_methods_
  static size_t CodeOffsetInBytes(uint32_t method_idx) {
    return (CodeIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
  }

  size_t NumCodeAndDirectMethods() const {
    return GetLength() / kMax;
  }

 private:
  enum TupleIndex {
    kCode   = 0,
    kMethod = 1,
    kMax    = 2,
  };

  static size_t CodeIndex(uint32_t method_idx) {
    return method_idx * kMax + kCode;
  }
  static size_t MethodIndex(uint32_t method_idx) {
    return method_idx * kMax + kMethod;
  }

  // grant friend status to ImageWriter fixup code that needs to know internal layout
  friend class ImageWriter;

  DISALLOW_IMPLICIT_CONSTRUCTORS(CodeAndDirectMethods);
};

class MANAGED DexCache : public ObjectArray<Object> {
 public:
  void Init(String* location,
            ObjectArray<String>* strings,
            ObjectArray<Class>* types,
            ObjectArray<Method>* methods,
            ObjectArray<Field>* fields,
            CodeAndDirectMethods* code_and_direct_methods,
            ObjectArray<StaticStorageBase>* initialized_static_storage);

  String* GetLocation() const {
    return Get(kLocation)->AsString();
  }

  static MemberOffset StringsOffset() {
    return MemberOffset(DataOffset().Int32Value() +
                        kStrings * sizeof(Object*));
  }

  static MemberOffset ResolvedFieldsOffset() {
    return MemberOffset(DataOffset().Int32Value() +
                        kResolvedFields * sizeof(Object*));
  }

  static MemberOffset ResolvedMethodsOffset() {
    return MemberOffset(DataOffset().Int32Value() +
                        kResolvedMethods * sizeof(Object*));
  }

  size_t NumStrings() const {
    return GetStrings()->GetLength();
  }

  size_t NumResolvedTypes() const {
    return GetResolvedTypes()->GetLength();
  }

  size_t NumResolvedMethods() const {
    return GetResolvedMethods()->GetLength();
  }

  size_t NumResolvedFields() const {
    return GetResolvedFields()->GetLength();
  }

  size_t NumCodeAndDirectMethods() const {
    return GetCodeAndDirectMethods()->NumCodeAndDirectMethods();
  }

  size_t NumInitializedStaticStorage() const {
    return GetInitializedStaticStorage()->GetLength();
  }

  String* GetResolvedString(uint32_t string_idx) const {
    return GetStrings()->Get(string_idx);
  }

  void SetResolvedString(uint32_t string_idx, String* resolved) {
    GetStrings()->Set(string_idx, resolved);
  }

  Class* GetResolvedType(uint32_t type_idx) const {
    return GetResolvedTypes()->Get(type_idx);
  }

  void SetResolvedType(uint32_t type_idx, Class* resolved) {
    GetResolvedTypes()->Set(type_idx, resolved);
  }

  Method* GetResolvedMethod(uint32_t method_idx) const {
    return GetResolvedMethods()->Get(method_idx);
  }

  void SetResolvedMethod(uint32_t method_idx, Method* resolved) {
    GetResolvedMethods()->Set(method_idx, resolved);
  }

  Field* GetResolvedField(uint32_t field_idx) const {
    return GetResolvedFields()->Get(field_idx);
  }

  void SetResolvedField(uint32_t field_idx, Field* resolved) {
    GetResolvedFields()->Set(field_idx, resolved);
  }

  ObjectArray<String>* GetStrings() const {
    return static_cast<ObjectArray<String>*>(GetNonNull(kStrings));
  }
  ObjectArray<Class>* GetResolvedTypes() const {
    return static_cast<ObjectArray<Class>*>(GetNonNull(kResolvedTypes));
  }
  ObjectArray<Method>* GetResolvedMethods() const {
    return static_cast<ObjectArray<Method>*>(GetNonNull(kResolvedMethods));
  }
  ObjectArray<Field>* GetResolvedFields() const {
    return static_cast<ObjectArray<Field>*>(GetNonNull(kResolvedFields));
  }
  CodeAndDirectMethods* GetCodeAndDirectMethods() const {
    return static_cast<CodeAndDirectMethods*>(GetNonNull(kCodeAndDirectMethods));
  }
  ObjectArray<StaticStorageBase>* GetInitializedStaticStorage() const {
    return static_cast<ObjectArray<StaticStorageBase>*>(GetNonNull(kInitializedStaticStorage));
  }

  static size_t LengthAsArray() {
    return kMax;
  }

 private:

  enum ArrayIndex {
    kLocation                 = 0,
    kStrings                  = 1,
    kResolvedTypes            = 2,
    kResolvedMethods          = 3,
    kResolvedFields           = 4,
    kCodeAndDirectMethods     = 5,
    kInitializedStaticStorage = 6,
    kMax                      = 7,
  };

  Object* GetNonNull(ArrayIndex array_index) const {
    Object* obj = Get(array_index);
    DCHECK(obj != NULL);
    return obj;
  }
  DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache);
};

}  // namespace art

#endif  // ART_SRC_DEX_CACHE_H_
