/*
 * Copyright (C) 2014 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_COMPILER_DEX_MIR_METHOD_INFO_H_
#define ART_COMPILER_DEX_MIR_METHOD_INFO_H_

#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "invoke_type.h"
#include "method_reference.h"

namespace art {

class CompilerDriver;
class DexCompilationUnit;
class DexFile;

class MirMethodInfo {
 public:
  uint16_t MethodIndex() const {
    return method_idx_;
  }

  bool IsStatic() const {
    return (flags_ & kFlagIsStatic) != 0u;
  }

  bool IsResolved() const {
    return declaring_dex_file_ != nullptr;
  }

  const DexFile* DeclaringDexFile() const {
    return declaring_dex_file_;
  }

  uint16_t DeclaringClassIndex() const {
    return declaring_class_idx_;
  }

  uint16_t DeclaringMethodIndex() const {
    return declaring_method_idx_;
  }

 protected:
  enum {
    kBitIsStatic = 0,
    kMethodInfoBitEnd
  };
  static_assert(kMethodInfoBitEnd <= 16, "Too many flags");
  static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;

  MirMethodInfo(uint16_t method_idx, uint16_t flags)
      : method_idx_(method_idx),
        flags_(flags),
        declaring_method_idx_(0u),
        declaring_class_idx_(0u),
        declaring_dex_file_(nullptr) {
  }

  // Make copy-ctor/assign/dtor protected to avoid slicing.
  MirMethodInfo(const MirMethodInfo& other) = default;
  MirMethodInfo& operator=(const MirMethodInfo& other) = default;
  ~MirMethodInfo() = default;

  // The method index in the compiling method's dex file.
  uint16_t method_idx_;
  // Flags, for volatility and derived class data.
  uint16_t flags_;
  // The method index in the dex file that defines the method, 0 if unresolved.
  uint16_t declaring_method_idx_;
  // The type index of the class declaring the method, 0 if unresolved.
  uint16_t declaring_class_idx_;
  // The dex file that defines the class containing the method and the method,
  // nullptr if unresolved.
  const DexFile* declaring_dex_file_;
};

class MirMethodLoweringInfo : public MirMethodInfo {
 public:
  // For each requested method retrieve the method's declaring location (dex file, class
  // index and method index) and compute whether we can fast path the method call. For fast
  // path methods, retrieve the method's vtable index and direct code and method when applicable.
  static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit,
                      MirMethodLoweringInfo* method_infos, size_t count)
      LOCKS_EXCLUDED(Locks::mutator_lock_);

  MirMethodLoweringInfo(uint16_t method_idx, InvokeType type)
      : MirMethodInfo(method_idx,
                      ((type == kStatic) ? kFlagIsStatic : 0u) |
                      (static_cast<uint16_t>(type) << kBitInvokeTypeBegin) |
                      (static_cast<uint16_t>(type) << kBitSharpTypeBegin)),
        direct_code_(0u),
        direct_method_(0u),
        target_dex_file_(nullptr),
        target_method_idx_(0u),
        vtable_idx_(0u),
        stats_flags_(0) {
  }

  void SetDevirtualizationTarget(const MethodReference& ref) {
    DCHECK(target_dex_file_ == nullptr);
    DCHECK_EQ(target_method_idx_, 0u);
    DCHECK_LE(ref.dex_method_index, 0xffffu);
    target_dex_file_ = ref.dex_file;
    target_method_idx_ = ref.dex_method_index;
  }

  bool FastPath() const {
    return (flags_ & kFlagFastPath) != 0u;
  }

  bool IsReferrersClass() const {
    return (flags_ & kFlagIsReferrersClass) != 0;
  }

  bool IsClassInitialized() const {
    return (flags_ & kFlagClassIsInitialized) != 0u;
  }

  InvokeType GetInvokeType() const {
    return static_cast<InvokeType>((flags_ >> kBitInvokeTypeBegin) & kInvokeTypeMask);
  }

  art::InvokeType GetSharpType() const {
    return static_cast<InvokeType>((flags_ >> kBitSharpTypeBegin) & kInvokeTypeMask);
  }

  MethodReference GetTargetMethod() const {
    return MethodReference(target_dex_file_, target_method_idx_);
  }

  uint16_t VTableIndex() const {
    return vtable_idx_;
  }

  uintptr_t DirectCode() const {
    return direct_code_;
  }

  uintptr_t DirectMethod() const {
    return direct_method_;
  }

  int StatsFlags() const {
    return stats_flags_;
  }

 private:
  enum {
    kBitFastPath = kMethodInfoBitEnd,
    kBitInvokeTypeBegin,
    kBitInvokeTypeEnd = kBitInvokeTypeBegin + 3,  // 3 bits for invoke type.
    kBitSharpTypeBegin,
    kBitSharpTypeEnd = kBitSharpTypeBegin + 3,  // 3 bits for sharp type.
    kBitIsReferrersClass = kBitSharpTypeEnd,
    kBitClassIsInitialized,
    kMethodLoweringInfoBitEnd
  };
  static_assert(kMethodLoweringInfoBitEnd <= 16, "Too many flags");
  static constexpr uint16_t kFlagFastPath = 1u << kBitFastPath;
  static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
  static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized;
  static constexpr uint16_t kInvokeTypeMask = 7u;
  static_assert((1u << (kBitInvokeTypeEnd - kBitInvokeTypeBegin)) - 1u == kInvokeTypeMask,
                "assert invoke type bits failed");
  static_assert((1u << (kBitSharpTypeEnd - kBitSharpTypeBegin)) - 1u == kInvokeTypeMask,
                "assert sharp type bits failed");

  uintptr_t direct_code_;
  uintptr_t direct_method_;
  // Before Resolve(), target_dex_file_ and target_method_idx_ hold the verification-based
  // devirtualized invoke target if available, nullptr and 0u otherwise.
  // After Resolve() they hold the actual target method that will be called; it will be either
  // a devirtualized target method or the compilation's unit's dex file and MethodIndex().
  const DexFile* target_dex_file_;
  uint16_t target_method_idx_;
  uint16_t vtable_idx_;
  int stats_flags_;

  friend class MirOptimizationTest;
};

}  // namespace art

#endif  // ART_COMPILER_DEX_MIR_METHOD_INFO_H_
