/*
 * 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 "intrinsic_objects.h"

#include "art_field-inl.h"
#include "base/logging.h"
#include "class_root.h"
#include "handle.h"
#include "obj_ptr-inl.h"
#include "mirror/object_array-alloc-inl.h"
#include "mirror/object_array-inl.h"

namespace art {

static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache(Thread* self,
                                                                      ClassLinker* class_linker)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  ObjPtr<mirror::Class> integer_cache_class = class_linker->LookupClass(
      self, "Ljava/lang/Integer$IntegerCache;", /* class_loader= */ nullptr);
  if (integer_cache_class == nullptr || !integer_cache_class->IsInitialized()) {
    return nullptr;
  }
  ArtField* cache_field =
      integer_cache_class->FindDeclaredStaticField("cache", "[Ljava/lang/Integer;");
  CHECK(cache_field != nullptr);
  ObjPtr<mirror::ObjectArray<mirror::Object>> integer_cache =
      ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
          cache_field->GetObject(integer_cache_class));
  CHECK(integer_cache != nullptr);
  return integer_cache;
}

ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::AllocateBootImageLiveObjects(
    Thread* self,
    ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) {
  // The objects used for the Integer.valueOf() intrinsic must remain live even if references
  // to them are removed using reflection. Image roots are not accessible through reflection,
  // so the array we construct here shall keep them alive.
  StackHandleScope<1> hs(self);
  Handle<mirror::ObjectArray<mirror::Object>> integer_cache =
      hs.NewHandle(LookupIntegerCache(self, class_linker));
  size_t live_objects_size =
      (integer_cache != nullptr) ? (/* cache */ 1u + integer_cache->GetLength()) : 0u;
  ObjPtr<mirror::ObjectArray<mirror::Object>> live_objects =
      mirror::ObjectArray<mirror::Object>::Alloc(
          self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker), live_objects_size);
  int32_t index = 0;
  if (integer_cache != nullptr) {
    live_objects->Set(index++, integer_cache.Get());
    for (int32_t i = 0, length = integer_cache->GetLength(); i != length; ++i) {
      live_objects->Set(index++, integer_cache->Get(i));
    }
  }
  CHECK_EQ(index, live_objects->GetLength());

  if (kIsDebugBuild && integer_cache != nullptr) {
    CHECK_EQ(integer_cache.Get(), GetIntegerValueOfCache(live_objects));
    for (int32_t i = 0, len = integer_cache->GetLength(); i != len; ++i) {
      CHECK_EQ(integer_cache->GetWithoutChecks(i), GetIntegerValueOfObject(live_objects, i));
    }
  }
  return live_objects;
}

ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::GetIntegerValueOfCache(
    ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) {
  DCHECK(boot_image_live_objects != nullptr);
  if (boot_image_live_objects->GetLength() == 0u) {
    return nullptr;  // No intrinsic objects.
  }
  // No need for read barrier for boot image object or for verifying the value that was just stored.
  ObjPtr<mirror::Object> result =
      boot_image_live_objects->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>(0);
  DCHECK(result != nullptr);
  DCHECK(result->IsObjectArray());
  DCHECK(result->GetClass()->DescriptorEquals("[Ljava/lang/Integer;"));
  return ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(result);
}

ObjPtr<mirror::Object> IntrinsicObjects::GetIntegerValueOfObject(
    ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
    uint32_t index) {
  DCHECK(boot_image_live_objects != nullptr);
  DCHECK_NE(boot_image_live_objects->GetLength(), 0);
  DCHECK_LT(index,
            static_cast<uint32_t>(GetIntegerValueOfCache(boot_image_live_objects)->GetLength()));

  // No need for read barrier for boot image object or for verifying the value that was just stored.
  ObjPtr<mirror::Object> result =
      boot_image_live_objects->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>(
          /* skip the IntegerCache.cache */ 1u + index);
  DCHECK(result != nullptr);
  DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Integer;"));
  return result;
}

MemberOffset IntrinsicObjects::GetIntegerValueOfArrayDataOffset(
    ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) {
  DCHECK_NE(boot_image_live_objects->GetLength(), 0);
  MemberOffset result = mirror::ObjectArray<mirror::Object>::OffsetOfElement(1u);
  DCHECK_EQ(GetIntegerValueOfObject(boot_image_live_objects, 0u),
            (boot_image_live_objects
                 ->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(result)));
  return result;
}

}  // namespace art
