/*
 * Copyright (C) 2018 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.
 */

#include "resolver.h"

#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/primitive.h"
#include "hidden_api.h"
#include "veridex.h"

namespace art {

void VeridexResolver::Run() {
  for (ClassAccessor accessor : dex_file_.GetClasses()) {
    std::string name(accessor.GetDescriptor());
    auto existing = type_map_.find(name);
    const uint32_t type_idx = accessor.GetClassIdx().index_;
    if (existing != type_map_.end()) {
      // Class already exists, cache it and move on.
      type_infos_[type_idx] = *existing->second;
      continue;
    }
    type_infos_[type_idx] = VeriClass(Primitive::Type::kPrimNot, 0, &accessor.GetClassDef());
    type_map_[name] = &type_infos_[type_idx];
    for (const ClassAccessor::Field& field : accessor.GetFields()) {
      field_infos_[field.GetIndex()] = field.GetDataPointer();
    }
    for (const ClassAccessor::Method& method : accessor.GetMethods()) {
      method_infos_[method.GetIndex()] = method.GetDataPointer();
    }
  }
}

static bool HasSameNameAndSignature(const DexFile& dex_file,
                                    const dex::MethodId& method_id,
                                    const char* method_name,
                                    const char* type) {
  return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
      strcmp(type, dex_file.GetMethodSignature(method_id).ToString().c_str()) == 0;
}

static bool HasSameNameAndSignature(const DexFile& dex_file,
                                    const dex::MethodId& method_id,
                                    const char* method_name,
                                    const Signature& signature) {
  return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
      dex_file.GetMethodSignature(method_id) == signature;
}

static bool HasSameNameAndType(const DexFile& dex_file,
                               const dex::FieldId& field_id,
                               const char* field_name,
                               const char* field_type) {
  return strcmp(field_name, dex_file.GetFieldName(field_id)) == 0 &&
      strcmp(field_type, dex_file.GetFieldTypeDescriptor(field_id)) == 0;
}

VeriClass* VeridexResolver::GetVeriClass(dex::TypeIndex index) {
  CHECK_LT(index.index_, dex_file_.NumTypeIds());
  // Lookup in our local cache.
  VeriClass* cls = &type_infos_[index.index_];
  if (cls->IsUninitialized()) {
    // Class is defined in another dex file. Lookup in the global cache.
    std::string name(dex_file_.StringByTypeIdx(index));
    auto existing = type_map_.find(name);
    if (existing == type_map_.end()) {
      // Class hasn't been defined, so check if it's an array class.
      size_t last_array = name.find_last_of('[');
      if (last_array == std::string::npos) {
        // There is no such class.
        return nullptr;
      } else {
        // Class is an array class. Check if its most enclosed component type (which is not
        // an array class) has been defined.
        std::string klass_name = name.substr(last_array + 1);
        existing = type_map_.find(klass_name);
        if (existing == type_map_.end()) {
          // There is no such class, so there is no such array.
          return nullptr;
        } else {
          // Create the type, and cache it locally and globally.
          type_infos_[index.index_] = VeriClass(
              existing->second->GetKind(), last_array + 1, existing->second->GetClassDef());
          cls = &(type_infos_[index.index_]);
          type_map_[name] = cls;
        }
      }
    } else {
      // Cache the found class.
      cls = existing->second;
      type_infos_[index.index_] = *cls;
    }
  }
  return cls;
}

VeridexResolver* VeridexResolver::GetResolverOf(const VeriClass& kls) const {
  auto resolver_it = dex_resolvers_.lower_bound(reinterpret_cast<uintptr_t>(kls.GetClassDef()));
  --resolver_it;

  // Check the class def pointer is indeed in the mapped dex file range.
  const DexFile& dex_file = resolver_it->second->dex_file_;
  CHECK_LT(reinterpret_cast<uintptr_t>(dex_file.Begin()),
           reinterpret_cast<uintptr_t>(kls.GetClassDef()));
  CHECK_GT(reinterpret_cast<uintptr_t>(dex_file.Begin()) + dex_file.Size(),
           reinterpret_cast<uintptr_t>(kls.GetClassDef()));
  return resolver_it->second;
}

VeriMethod VeridexResolver::LookupMethodIn(const VeriClass& kls,
                                           const char* method_name,
                                           const Signature& method_signature) {
  if (kls.IsPrimitive()) {
    // Primitive classes don't have methods.
    return nullptr;
  }
  if (kls.IsArray()) {
    // Array classes don't have methods, but inherit the ones in j.l.Object.
    return LookupMethodIn(*VeriClass::object_, method_name, method_signature);
  }
  // Get the resolver where `kls` is from.
  VeridexResolver* resolver = GetResolverOf(kls);

  // Look at methods declared in `kls`.
  const DexFile& other_dex_file = resolver->dex_file_;
  ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
  for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
    const dex::MethodId& other_method_id = other_dex_file.GetMethodId(method.GetIndex());
    if (HasSameNameAndSignature(other_dex_file,
                                other_method_id,
                                method_name,
                                method_signature)) {
      return method.GetDataPointer();
    }
  }

  // Look at methods in `kls`'s super class hierarchy.
  if (kls.GetClassDef()->superclass_idx_.IsValid()) {
    VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
    if (super != nullptr) {
      VeriMethod super_method = resolver->LookupMethodIn(*super, method_name, method_signature);
      if (super_method != nullptr) {
        return super_method;
      }
    }
  }

  // Look at methods in `kls`'s interface hierarchy.
  const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
  if (interfaces != nullptr) {
    for (size_t i = 0; i < interfaces->Size(); i++) {
      dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
      VeriClass* itf = resolver->GetVeriClass(idx);
      if (itf != nullptr) {
        VeriMethod itf_method = resolver->LookupMethodIn(*itf, method_name, method_signature);
        if (itf_method != nullptr) {
          return itf_method;
        }
      }
    }
  }
  return nullptr;
}

VeriField VeridexResolver::LookupFieldIn(const VeriClass& kls,
                                         const char* field_name,
                                         const char* field_type) {
  if (kls.IsPrimitive()) {
    // Primitive classes don't have fields.
    return nullptr;
  }
  if (kls.IsArray()) {
    // Array classes don't have fields.
    return nullptr;
  }
  // Get the resolver where `kls` is from.
  VeridexResolver* resolver = GetResolverOf(kls);

  // Look at fields declared in `kls`.
  const DexFile& other_dex_file = resolver->dex_file_;
  ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
  for (const ClassAccessor::Field& field : other_dex_accessor.GetFields()) {
    const dex::FieldId& other_field_id = other_dex_file.GetFieldId(field.GetIndex());
    if (HasSameNameAndType(other_dex_file,
                           other_field_id,
                           field_name,
                           field_type)) {
      return field.GetDataPointer();
    }
  }

  // Look at fields in `kls`'s interface hierarchy.
  const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
  if (interfaces != nullptr) {
    for (size_t i = 0; i < interfaces->Size(); i++) {
      dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
      VeriClass* itf = resolver->GetVeriClass(idx);
      if (itf != nullptr) {
        VeriField itf_field = resolver->LookupFieldIn(*itf, field_name, field_type);
        if (itf_field != nullptr) {
          return itf_field;
        }
      }
    }
  }

  // Look at fields in `kls`'s super class hierarchy.
  if (kls.GetClassDef()->superclass_idx_.IsValid()) {
    VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
    if (super != nullptr) {
      VeriField super_field = resolver->LookupFieldIn(*super, field_name, field_type);
      if (super_field != nullptr) {
        return super_field;
      }
    }
  }
  return nullptr;
}

VeriMethod VeridexResolver::LookupDeclaredMethodIn(const VeriClass& kls,
                                                   const char* method_name,
                                                   const char* type) const {
  if (kls.IsPrimitive()) {
    return nullptr;
  }
  if (kls.IsArray()) {
    return nullptr;
  }
  VeridexResolver* resolver = GetResolverOf(kls);
  const DexFile& other_dex_file = resolver->dex_file_;
  ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
  for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
    if (HasSameNameAndSignature(other_dex_file,
                                other_dex_file.GetMethodId(method.GetIndex()),
                                method_name,
                                type)) {
      return method.GetDataPointer();
    }
  }
  return nullptr;
}

VeriMethod VeridexResolver::GetMethod(uint32_t method_index) {
  VeriMethod method_info = method_infos_[method_index];
  if (method_info == nullptr) {
    // Method is defined in another dex file.
    const dex::MethodId& method_id = dex_file_.GetMethodId(method_index);
    VeriClass* kls = GetVeriClass(method_id.class_idx_);
    if (kls == nullptr) {
      return nullptr;
    }
    // Class found, now lookup the method in it.
    method_info = LookupMethodIn(*kls,
                                 dex_file_.GetMethodName(method_id),
                                 dex_file_.GetMethodSignature(method_id));
    method_infos_[method_index] = method_info;
  }
  return method_info;
}

VeriField VeridexResolver::GetField(uint32_t field_index) {
  VeriField field_info = field_infos_[field_index];
  if (field_info == nullptr) {
    // Field is defined in another dex file.
    const dex::FieldId& field_id = dex_file_.GetFieldId(field_index);
    VeriClass* kls = GetVeriClass(field_id.class_idx_);
    if (kls == nullptr) {
      return nullptr;
    }
    // Class found, now lookup the field in it.
    field_info = LookupFieldIn(*kls,
                               dex_file_.GetFieldName(field_id),
                               dex_file_.GetFieldTypeDescriptor(field_id));
    field_infos_[field_index] = field_info;
  }
  return field_info;
}

void VeridexResolver::ResolveAll() {
  for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) {
    if (GetVeriClass(dex::TypeIndex(i)) == nullptr) {
      LOG(WARNING) << "Unresolved " << dex_file_.PrettyType(dex::TypeIndex(i));
    }
  }

  for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) {
    if (GetMethod(i) == nullptr) {
      LOG(WARNING) << "Unresolved: " << dex_file_.PrettyMethod(i);
    }
  }

  for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
    if (GetField(i) == nullptr) {
      LOG(WARNING) << "Unresolved: " << dex_file_.PrettyField(i);
    }
  }
}

}  // namespace art
