/*
 * 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.
 */

# include "mir_method_info.h"

#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "driver/compiler_driver-inl.h"
#include "mirror/class_loader.h"  // Only to allow casts in Handle<ClassLoader>.
#include "mirror/dex_cache.h"     // Only to allow casts in Handle<DexCache>.
#include "scoped_thread_state_change.h"
#include "handle_scope-inl.h"

namespace art {

void MirMethodLoweringInfo::Resolve(CompilerDriver* compiler_driver,
                                    const DexCompilationUnit* mUnit,
                                    MirMethodLoweringInfo* method_infos, size_t count) {
  if (kIsDebugBuild) {
    DCHECK(method_infos != nullptr);
    DCHECK_NE(count, 0u);
    for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
      MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType(), it->IsQuickened());
      unresolved.declaring_dex_file_ = it->declaring_dex_file_;
      unresolved.vtable_idx_ = it->vtable_idx_;
      if (it->target_dex_file_ != nullptr) {
        unresolved.target_dex_file_ = it->target_dex_file_;
        unresolved.target_method_idx_ = it->target_method_idx_;
      }
      if (kIsDebugBuild) {
        unresolved.CheckEquals(*it);
      }
    }
  }

  // We're going to resolve methods and check access in a tight loop. It's better to hold
  // the lock and needed references once than re-acquiring them again and again.
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<4> hs(soa.Self());
  Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
  Handle<mirror::Class> referrer_class(hs.NewHandle(
      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
  auto current_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
  // Even if the referrer class is unresolved (i.e. we're compiling a method without class
  // definition) we still want to resolve methods and record all available info.
  const DexFile* const dex_file = mUnit->GetDexFile();
  const bool use_jit = Runtime::Current()->UseJit();
  const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod();

  for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
    // For quickened invokes, the dex method idx is actually the mir offset.
    if (it->IsQuickened()) {
      const auto* dequicken_ref = verified_method->GetDequickenIndex(it->method_idx_);
      CHECK(dequicken_ref != nullptr);
      it->target_dex_file_ = dequicken_ref->dex_file;
      it->target_method_idx_ = dequicken_ref->index;
    }
    // Remember devirtualized invoke target and set the called method to the default.
    MethodReference devirt_ref(it->target_dex_file_, it->target_method_idx_);
    MethodReference* devirt_target = (it->target_dex_file_ != nullptr) ? &devirt_ref : nullptr;
    InvokeType invoke_type = it->GetInvokeType();
    mirror::ArtMethod* resolved_method = nullptr;
    if (!it->IsQuickened()) {
      it->target_dex_file_ = dex_file;
      it->target_method_idx_ = it->MethodIndex();
      current_dex_cache.Assign(dex_cache.Get());
      resolved_method = compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit,
                                                       it->MethodIndex(), invoke_type);
    } else {
      // The method index is actually the dex PC in this case.
      // Calculate the proper dex file and target method idx.
      CHECK(use_jit);
      CHECK_EQ(invoke_type, kVirtual);
      // Don't devirt if we are in a different dex file since we can't have direct invokes in
      // another dex file unless we always put a direct / patch pointer.
      devirt_target = nullptr;
      current_dex_cache.Assign(
          Runtime::Current()->GetClassLinker()->FindDexCache(*it->target_dex_file_));
      CHECK(current_dex_cache.Get() != nullptr);
      DexCompilationUnit cu(
          mUnit->GetCompilationUnit(), mUnit->GetClassLoader(), mUnit->GetClassLinker(),
          *it->target_dex_file_, nullptr /* code_item not used */, 0u /* class_def_idx not used */,
          it->target_method_idx_, 0u /* access_flags not used */,
          nullptr /* verified_method not used */);
      resolved_method = compiler_driver->ResolveMethod(soa, current_dex_cache, class_loader, &cu,
                                                       it->target_method_idx_, invoke_type, false);
      if (resolved_method != nullptr) {
        // Since this was a dequickened virtual, it is guaranteed to be resolved. However, it may be
        // resolved to an interface method. If this is the case then change the invoke type to
        // interface with the assumption that sharp_type will be kVirtual.
        if (resolved_method->GetInvokeType() == kInterface) {
          it->flags_ = (it->flags_ & ~(kInvokeTypeMask << kBitInvokeTypeBegin)) |
              (static_cast<uint16_t>(kInterface) << kBitInvokeTypeBegin);
        }
      }
    }
    if (UNLIKELY(resolved_method == nullptr)) {
      continue;
    }
    compiler_driver->GetResolvedMethodDexFileLocation(resolved_method,
        &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_method_idx_);
    if (!it->IsQuickened()) {
      // For quickened invoke virtuals we may have desharpened to an interface method which
      // wont give us the right method index, in this case blindly dispatch or else we can't
      // compile the method. Converting the invoke to interface dispatch doesn't work since we
      // have no way to get the dex method index for quickened invoke virtuals in the interface
      // trampolines.
      it->vtable_idx_ =
          compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type);
    }

    MethodReference target_method(it->target_dex_file_, it->target_method_idx_);
    int fast_path_flags = compiler_driver->IsFastInvoke(
        soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method,
        &invoke_type, &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
    const bool is_referrers_class = referrer_class.Get() == resolved_method->GetDeclaringClass();
    const bool is_class_initialized =
        compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method);
    uint16_t other_flags = it->flags_ &
        ~(kFlagFastPath | kFlagClassIsInitialized | (kInvokeTypeMask << kBitSharpTypeBegin));
    it->flags_ = other_flags |
        (fast_path_flags != 0 ? kFlagFastPath : 0u) |
        (static_cast<uint16_t>(invoke_type) << kBitSharpTypeBegin) |
        (is_referrers_class ? kFlagIsReferrersClass : 0u) |
        (is_class_initialized ? kFlagClassIsInitialized : 0u);
    it->target_dex_file_ = target_method.dex_file;
    it->target_method_idx_ = target_method.dex_method_index;
    it->stats_flags_ = fast_path_flags;
  }
}

}  // namespace art
