/*
 * Copyright (C) 2016 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 "java_lang_reflect_Executable.h"

#include "android-base/stringprintf.h"
#include "nativehelper/jni_macros.h"

#include "art_method-inl.h"
#include "dex/dex_file_annotations.h"
#include "handle.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "native_util.h"
#include "reflection.h"
#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"

namespace art {

using android::base::StringPrintf;

static jobjectArray Executable_getDeclaredAnnotationsNative(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  if (method->GetDeclaringClass()->IsProxyClass()) {
    // Return an empty array instead of a null pointer.
    ObjPtr<mirror::Class> annotation_array_class =
        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
    ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
    return soa.AddLocalReference<jobjectArray>(empty_array);
  }
  return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
}

static jobject Executable_getAnnotationNative(JNIEnv* env,
                                              jobject javaMethod,
                                              jclass annotationType) {
  ScopedFastNativeObjectAccess soa(env);
  StackHandleScope<1> hs(soa.Self());
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  if (method->IsProxyMethod()) {
    return nullptr;
  } else {
    Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
    return soa.AddLocalReference<jobject>(annotations::GetAnnotationForMethod(method, klass));
  }
}

static jobjectArray Executable_getSignatureAnnotation(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  if (method->GetDeclaringClass()->IsProxyClass()) {
    return nullptr;
  }
  StackHandleScope<1> hs(soa.Self());
  return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForMethod(method));
}


static jobjectArray Executable_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  if (method->IsProxyMethod()) {
    return nullptr;
  } else {
    return soa.AddLocalReference<jobjectArray>(annotations::GetParameterAnnotations(method));
  }
}

static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  Thread* self = soa.Self();
  StackHandleScope<8> hs(self);

  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method>(javaMethod));
  ArtMethod* art_method = executable.Get()->GetArtMethod();
  if (art_method->GetDeclaringClass()->IsProxyClass()) {
    return nullptr;
  }

  // Find the MethodParameters system annotation.
  MutableHandle<mirror::ObjectArray<mirror::String>> names =
      hs.NewHandle<mirror::ObjectArray<mirror::String>>(nullptr);
  MutableHandle<mirror::IntArray> access_flags = hs.NewHandle<mirror::IntArray>(nullptr);
  if (!annotations::GetParametersMetadataForMethod(art_method, &names, &access_flags)) {
    return nullptr;
  }

  // Validate the MethodParameters system annotation data.
  if (UNLIKELY(names == nullptr || access_flags == nullptr)) {
    ThrowIllegalArgumentException(
        StringPrintf("Missing parameter metadata for names or access flags for %s",
                     art_method->PrettyMethod().c_str()).c_str());
    return nullptr;
  }

  // Check array sizes match each other
  int32_t names_count = names.Get()->GetLength();
  int32_t access_flags_count = access_flags.Get()->GetLength();
  if (names_count != access_flags_count) {
    ThrowIllegalArgumentException(
        StringPrintf(
            "Inconsistent parameter metadata for %s. names length: %d, access flags length: %d",
            art_method->PrettyMethod().c_str(),
            names_count,
            access_flags_count).c_str());
    return nullptr;
  }

  // Instantiate a Parameter[] to hold the result.
  Handle<mirror::Class> parameter_array_class =
      hs.NewHandle(
          soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter__array));
  Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
      hs.NewHandle(
          mirror::ObjectArray<mirror::Object>::Alloc(self,
                                                     parameter_array_class.Get(),
                                                     names_count));
  if (UNLIKELY(parameter_array == nullptr)) {
    self->AssertPendingException();
    return nullptr;
  }

  Handle<mirror::Class> parameter_class =
      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter));
  ArtMethod* parameter_init =
      jni::DecodeArtMethod(WellKnownClasses::java_lang_reflect_Parameter_init);

  // Mutable handles used in the loop below to ensure cleanup without scaling the number of
  // handles by the number of parameters.
  MutableHandle<mirror::String> name = hs.NewHandle<mirror::String>(nullptr);
  MutableHandle<mirror::Object> parameter = hs.NewHandle<mirror::Object>(nullptr);

  // Populate the Parameter[] to return.
  for (int32_t parameter_index = 0; parameter_index < names_count; parameter_index++) {
    name.Assign(names.Get()->Get(parameter_index));
    int32_t modifiers = access_flags.Get()->Get(parameter_index);

    // Allocate / initialize the Parameter to add to parameter_array.
    parameter.Assign(parameter_class->AllocObject(self));
    if (UNLIKELY(parameter == nullptr)) {
      self->AssertPendingOOMException();
      return nullptr;
    }

    uint32_t args[5] = { PointerToLowMemUInt32(parameter.Get()),
                         PointerToLowMemUInt32(name.Get()),
                         static_cast<uint32_t>(modifiers),
                         PointerToLowMemUInt32(executable.Get()),
                         static_cast<uint32_t>(parameter_index)
    };
    JValue result;
    static const char* method_signature = "VLILI";  // return + parameter types
    parameter_init->Invoke(self, args, sizeof(args), &result, method_signature);
    if (UNLIKELY(self->IsExceptionPending())) {
      return nullptr;
    }

    // Store the Parameter in the Parameter[].
    parameter_array.Get()->Set(parameter_index, parameter.Get());
    if (UNLIKELY(self->IsExceptionPending())) {
      return nullptr;
    }
  }
  return soa.AddLocalReference<jobjectArray>(parameter_array.Get());
}

static jboolean Executable_isAnnotationPresentNative(JNIEnv* env,
                                                     jobject javaMethod,
                                                     jclass annotationType) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  if (method->GetDeclaringClass()->IsProxyClass()) {
    return false;
  }
  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
  return annotations::IsMethodAnnotationPresent(method, klass);
}

static jint Executable_compareMethodParametersInternal(JNIEnv* env,
                                                       jobject thisMethod,
                                                       jobject otherMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* this_method = ArtMethod::FromReflectedMethod(soa, thisMethod);
  ArtMethod* other_method = ArtMethod::FromReflectedMethod(soa, otherMethod);

  this_method = this_method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
  other_method = other_method->GetInterfaceMethodIfProxy(kRuntimePointerSize);

  const DexFile::TypeList* this_list = this_method->GetParameterTypeList();
  const DexFile::TypeList* other_list = other_method->GetParameterTypeList();

  if (this_list == other_list) {
    return 0;
  }

  if (this_list == nullptr && other_list != nullptr) {
    return -1;
  }

  if (other_list == nullptr && this_list != nullptr) {
    return 1;
  }

  const int32_t this_size = this_list->Size();
  const int32_t other_size = other_list->Size();

  if (this_size != other_size) {
    return (this_size - other_size);
  }

  for (int32_t i = 0; i < this_size; ++i) {
    const DexFile::TypeId& lhs = this_method->GetDexFile()->GetTypeId(
        this_list->GetTypeItem(i).type_idx_);
    const DexFile::TypeId& rhs = other_method->GetDexFile()->GetTypeId(
        other_list->GetTypeItem(i).type_idx_);

    uint32_t lhs_len, rhs_len;
    const char* lhs_data = this_method->GetDexFile()->StringDataAndUtf16LengthByIdx(
        lhs.descriptor_idx_, &lhs_len);
    const char* rhs_data = other_method->GetDexFile()->StringDataAndUtf16LengthByIdx(
        rhs.descriptor_idx_, &rhs_len);

    int cmp = strcmp(lhs_data, rhs_data);
    if (cmp != 0) {
      return (cmp < 0) ? -1 : 1;
    }
  }

  return 0;
}

static jobject Executable_getMethodNameInternal(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
  return soa.AddLocalReference<jobject>(method->GetNameAsString(soa.Self()));
}

static jobject Executable_getMethodReturnTypeInternal(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
  ObjPtr<mirror::Class> return_type(method->ResolveReturnType());
  if (return_type.IsNull()) {
    CHECK(soa.Self()->IsExceptionPending());
    return nullptr;
  }

  return soa.AddLocalReference<jobject>(return_type);
}

// TODO: Move this to mirror::Class ? Other mirror types that commonly appear
// as arrays have a GetArrayClass() method. This is duplicated in
// java_lang_Class.cc as well.
static ObjPtr<mirror::Class> GetClassArrayClass(Thread* self)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
  return Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_class);
}

static jobjectArray Executable_getParameterTypesInternal(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);

  const DexFile::TypeList* params = method->GetParameterTypeList();
  if (params == nullptr) {
    return nullptr;
  }

  const uint32_t num_params = params->Size();

  StackHandleScope<3> hs(soa.Self());
  Handle<mirror::Class> class_array_class = hs.NewHandle(GetClassArrayClass(soa.Self()));
  Handle<mirror::ObjectArray<mirror::Class>> ptypes = hs.NewHandle(
      mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class.Get(), num_params));
  if (ptypes.IsNull()) {
    DCHECK(soa.Self()->IsExceptionPending());
    return nullptr;
  }

  MutableHandle<mirror::Class> param(hs.NewHandle<mirror::Class>(nullptr));
  for (uint32_t i = 0; i < num_params; ++i) {
    const dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
    param.Assign(Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method));
    if (param.Get() == nullptr) {
      DCHECK(soa.Self()->IsExceptionPending());
      return nullptr;
    }
    ptypes->SetWithoutChecks<false>(i, param.Get());
  }

  return soa.AddLocalReference<jobjectArray>(ptypes.Get());
}

static jint Executable_getParameterCountInternal(JNIEnv* env, jobject javaMethod) {
  ScopedFastNativeObjectAccess soa(env);
  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);

  const DexFile::TypeList* params = method->GetParameterTypeList();
  return (params == nullptr) ? 0 : params->Size();
}


static JNINativeMethod gMethods[] = {
  FAST_NATIVE_METHOD(Executable, compareMethodParametersInternal,
                     "(Ljava/lang/reflect/Method;)I"),
  FAST_NATIVE_METHOD(Executable, getAnnotationNative,
                     "(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
  FAST_NATIVE_METHOD(Executable, getDeclaredAnnotationsNative,
                     "()[Ljava/lang/annotation/Annotation;"),
  FAST_NATIVE_METHOD(Executable, getParameterAnnotationsNative,
                     "()[[Ljava/lang/annotation/Annotation;"),
  FAST_NATIVE_METHOD(Executable, getMethodNameInternal, "()Ljava/lang/String;"),
  FAST_NATIVE_METHOD(Executable, getMethodReturnTypeInternal, "()Ljava/lang/Class;"),
  FAST_NATIVE_METHOD(Executable, getParameterTypesInternal, "()[Ljava/lang/Class;"),
  FAST_NATIVE_METHOD(Executable, getParameterCountInternal, "()I"),
  FAST_NATIVE_METHOD(Executable, getParameters0, "()[Ljava/lang/reflect/Parameter;"),
  FAST_NATIVE_METHOD(Executable, getSignatureAnnotation, "()[Ljava/lang/String;"),
  FAST_NATIVE_METHOD(Executable, isAnnotationPresentNative, "(Ljava/lang/Class;)Z"),
};

void register_java_lang_reflect_Executable(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("java/lang/reflect/Executable");
}

}  // namespace art
