/*
 * Copyright (C) 2011 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_RUNTIME_MIRROR_CLASS_LOADER_H_
#define ART_RUNTIME_MIRROR_CLASS_LOADER_H_

#include "base/locks.h"
#include "obj_ptr.h"
#include "object.h"
#include "object_reference.h"
#include "string.h"

namespace art {

struct ClassLoaderOffsets;
class ClassTable;
class LinearAlloc;

namespace mirror {

class Class;

// C++ mirror of java.lang.ClassLoader
class MANAGED ClassLoader : public Object {
 public:
  MIRROR_CLASS("Ljava/lang/ClassLoader;");

  // Size of an instance of java.lang.ClassLoader.
  static constexpr uint32_t InstanceSize() {
    return sizeof(ClassLoader);
  }

  ObjPtr<ClassLoader> GetParent() REQUIRES_SHARED(Locks::mutator_lock_);

  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
  ClassTable* GetClassTable() REQUIRES_SHARED(Locks::mutator_lock_) {
    return reinterpret_cast<ClassTable*>(
        GetField64<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, class_table_)));
  }

  void SetClassTable(ClassTable* class_table) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetField64<false>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, class_table_),
                      reinterpret_cast<uint64_t>(class_table));
  }

  LinearAlloc* GetAllocator() REQUIRES_SHARED(Locks::mutator_lock_) {
    return reinterpret_cast<LinearAlloc*>(
        GetField64(OFFSET_OF_OBJECT_MEMBER(ClassLoader, allocator_)));
  }

  void SetAllocator(LinearAlloc* allocator) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetField64<false>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, allocator_),
                      reinterpret_cast<uint64_t>(allocator));
  }

 private:
  // Visit instance fields of the class loader as well as its associated classes.
  // Null class loader is handled by ClassLinker::VisitClassRoots.
  template <bool kVisitClasses,
            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
            typename Visitor>
  void VisitReferences(ObjPtr<Class> klass, const Visitor& visitor)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::classlinker_classes_lock_);

  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
  HeapReference<String> name_;
  HeapReference<Object> packages_;
  HeapReference<ClassLoader> parent_;
  HeapReference<Object> proxyCache_;
  uint64_t allocator_;
  uint64_t class_table_;

  friend struct art::ClassLoaderOffsets;  // for verifying offset information
  friend class Object;  // For VisitReferences
  DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
};

}  // namespace mirror
}  // namespace art

#endif  // ART_RUNTIME_MIRROR_CLASS_LOADER_H_
