/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_SRC_OAT_FILE_H_
#define ART_SRC_OAT_FILE_H_

#include <vector>

#include "dex_file.h"
#include "mem_map.h"
#include "oat.h"
#include "object.h"

namespace art {

class OatFile {
 public:

  // Returns an OatFile name based on a DexFile location
  static std::string DexFilenameToOatFilename(const std::string& location);

  // Open an oat file. Returns NULL on failure.  Requested base can
  // optionally be used to request where the file should be loaded.
  static OatFile* Open(const std::string& filename,
                       const std::string& location,
                       byte* requested_base,
                       bool writable = false);

  // Open an oat file from an already opened File with the given location.
  static OatFile* Open(File& file,
                       const std::string& location,
                       byte* requested_base,
                       bool writable = false);

  ~OatFile();

  const std::string& GetLocation() const {
    return location_;
  }

  const OatHeader& GetOatHeader() const;

  class OatDexFile;

  class OatMethod {
   public:
    // Link Method for execution using the contents of this OatMethod
    void LinkMethodPointers(Method* method) const;

    // Link Method for image writing using the contents of this OatMethod
    void LinkMethodOffsets(Method* method) const;

    uint32_t GetCodeOffset() const {
      return code_offset_;
    }
    size_t GetFrameSizeInBytes() const {
      return frame_size_in_bytes_;
    }
    uint32_t GetCoreSpillMask() const {
      return core_spill_mask_;
    }
    uint32_t GetFpSpillMask() const {
      return fp_spill_mask_;
    }
    uint32_t GetMappingTableOffset() const {
      return mapping_table_offset_;
    }
    uint32_t GetVmapTableOffset() const {
      return vmap_table_offset_;
    }
    uint32_t GetGcMapOffset() const {
      return gc_map_offset_;
    }
    uint32_t GetInvokeStubOffset() const {
      return invoke_stub_offset_;
    }

    const void* GetCode() const {
      return GetOatPointer<const void*>(code_offset_);
    }
    uint32_t GetCodeSize() const {
      uintptr_t code = reinterpret_cast<uint32_t>(GetCode());
      if (code == 0) {
        return 0;
      }
      // TODO: make this Thumb2 specific
      code &= ~0x1;
      return reinterpret_cast<uint32_t*>(code)[-1];
    }
    const uint32_t* GetMappingTable() const {
      return GetOatPointer<const uint32_t*>(mapping_table_offset_);
    }
    const uint16_t* GetVmapTable() const {
      return GetOatPointer<const uint16_t*>(vmap_table_offset_);
    }
    const uint8_t* GetGcMap() const {
      return GetOatPointer<const uint8_t*>(gc_map_offset_);
    }
    const Method::InvokeStub* GetInvokeStub() const {
      return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
    }
    uint32_t GetInvokeStubSize() const {
      uintptr_t code = reinterpret_cast<uint32_t>(GetInvokeStub());
      if (code == 0) {
        return 0;
      }
      return reinterpret_cast<uint32_t*>(code)[-1];
    }

    ~OatMethod();

    // Create an OatMethod with offsets relative to the given base address
    OatMethod(const byte* base,
              const uint32_t code_offset,
              const size_t frame_size_in_bytes,
              const uint32_t core_spill_mask,
              const uint32_t fp_spill_mask,
              const uint32_t mapping_table_offset,
              const uint32_t vmap_table_offset,
              const uint32_t gc_map_offset,
              const uint32_t invoke_stub_offset);

   private:
    template<class T>
    T GetOatPointer(uint32_t offset) const {
      if (offset == 0) {
        return NULL;
      }
      return reinterpret_cast<T>(begin_ + offset);
    }

    const byte* begin_;

    uint32_t code_offset_;
    size_t frame_size_in_bytes_;
    uint32_t core_spill_mask_;
    uint32_t fp_spill_mask_;
    uint32_t mapping_table_offset_;
    uint32_t vmap_table_offset_;
    uint32_t gc_map_offset_;
    uint32_t invoke_stub_offset_;

    friend class OatClass;
  };

  class OatClass {
   public:
    Class::Status GetStatus() const;

    // get the OatMethod entry based on its index into the class
    // defintion. direct methods come first, followed by virtual
    // methods. note that runtime created methods such as miranda
    // methods are not included.
    const OatMethod GetOatMethod(uint32_t method_index) const;
    ~OatClass();

   private:
    OatClass(const OatFile* oat_file,
             Class::Status status,
             const OatMethodOffsets* methods_pointer);

    const OatFile* oat_file_;
    const Class::Status status_;
    const OatMethodOffsets* methods_pointer_;

    friend class OatDexFile;
  };

  class OatDexFile {
   public:
    const DexFile* OpenDexFile() const;
    const OatClass* GetOatClass(uint32_t class_def_index) const;

    const std::string& GetDexFileLocation() const {
      return dex_file_location_;
    }

    uint32_t GetDexFileLocationChecksum() const {
      return dex_file_location_checksum_;
    }

    ~OatDexFile();
   private:
    OatDexFile(const OatFile* oat_file,
               const std::string& dex_file_location,
               uint32_t dex_file_checksum,
               byte* dex_file_pointer,
               const uint32_t* oat_class_offsets_pointer);

    const OatFile* oat_file_;
    std::string dex_file_location_;
    uint32_t dex_file_location_checksum_;
    const byte* dex_file_pointer_;
    const uint32_t* oat_class_offsets_pointer_;

    friend class OatFile;
    DISALLOW_COPY_AND_ASSIGN(OatDexFile);
  };

  class OatElfImage {
   public:
    const byte* begin() const {
      return elf_addr_;
    }

    const byte* end() const {
      return (elf_addr_ + elf_size_);
    }

    size_t size() const {
      return elf_size_;
    }

   private:
    OatElfImage(const OatFile* oat_file, const byte* addr, uint32_t size);

    const OatFile* oat_file_;
    const byte* elf_addr_;
    uint32_t elf_size_;

    friend class OatFile;
    DISALLOW_COPY_AND_ASSIGN(OatElfImage);
  };

  const OatDexFile* GetOatDexFile(const std::string& dex_file_location,
                                  bool warn_if_not_found = true) const;
  std::vector<const OatDexFile*> GetOatDexFiles() const;

  const OatElfImage* GetOatElfImage(size_t i) const {
    return oat_elf_images_[i];
  }

  size_t Size() const {
    return End() - Begin();
  }

 private:
  explicit OatFile(const std::string& filename);
  bool Map(File& file, byte* requested_base, bool writable);

  const byte* Begin() const;
  const byte* End() const;

  // The oat file name.
  //
  // The image will embed this to link its associated oat file.
  const std::string location_;

  // backing memory map for oat file
  UniquePtr<MemMap> mem_map_;

  typedef std::map<std::string, const OatDexFile*> Table;
  Table oat_dex_files_;

  std::vector<OatElfImage*> oat_elf_images_;

  friend class OatClass;
  friend class OatDexFile;
  friend class OatDumper;  // For GetBase and GetLimit
  DISALLOW_COPY_AND_ASSIGN(OatFile);
};

}  // namespace art

#endif  // ART_SRC_OAT_WRITER_H_
