//===-- RelativePointer.h - Relative Pointer Support ------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Some data structures emitted by the Swift compiler use relative indirect
// addresses in order to minimize startup cost for a process. By referring to
// the offset of the global offset table entry for a symbol, instead of directly
// referring to the symbol, compiler-emitted data structures avoid requiring
// unnecessary relocation at dynamic linking time. This header contains types
// to help dereference these relative addresses.
//
//===----------------------------------------------------------------------===//

#include <cstdint>

namespace swift {

/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template<typename ValueTy>
class RelativeIndirectablePointer {
private:
  /// The relative offset of the pointer's memory from the `this` pointer.
  /// If the low bit is clear, this is a direct reference; otherwise, it is
  /// an indirect reference.
  int32_t RelativeOffset;

  /// RelativePointers should appear in statically-generated metadata. They
  /// shouldn't be constructed or copied.
  RelativeIndirectablePointer() = delete;
  RelativeIndirectablePointer(RelativeIndirectablePointer &&) = delete;
  RelativeIndirectablePointer(const RelativeIndirectablePointer &) = delete;
  RelativeIndirectablePointer &operator=(RelativeIndirectablePointer &&)
    = delete;
  RelativeIndirectablePointer &operator=(const RelativeIndirectablePointer &)
    = delete;

  const ValueTy *get() const & {
    // The pointer is offset relative to `this`.
    auto base = reinterpret_cast<intptr_t>(this);
    intptr_t address = base + (RelativeOffset & ~1);

    // If the low bit is set, then this is an indirect address. Otherwise,
    // it's direct.
    if (RelativeOffset & 1) {
      return *reinterpret_cast<const ValueTy * const *>(address);
    } else {
      return reinterpret_cast<const ValueTy *>(address);
    }
  }

public:
  operator const ValueTy* () const & {
    return get();
  }

  const ValueTy &operator*() const & {
    return *get();
  }

  const ValueTy *operator->() const & {
    return get();
  }
};

/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T>
class RelativeDirectPointerImpl {
private:
  /// The relative offset of the function's entry point from *this.
  int32_t RelativeOffset;

  /// RelativePointers should appear in statically-generated metadata. They
  /// shouldn't be constructed or copied.
  RelativeDirectPointerImpl() = delete;
  RelativeDirectPointerImpl(RelativeDirectPointerImpl &&) = delete;
  RelativeDirectPointerImpl(const RelativeDirectPointerImpl &) = delete;
  RelativeDirectPointerImpl &operator=(RelativeDirectPointerImpl &&)
    = delete;
  RelativeDirectPointerImpl &operator=(const RelativeDirectPointerImpl&)
    = delete;

public:
  using ValueTy = T;
  using PointerTy = T*;

  PointerTy get() const & {
    // The function entry point is addressed relative to `this`.
    auto base = reinterpret_cast<intptr_t>(this);
    intptr_t absolute = base + RelativeOffset;
    return reinterpret_cast<PointerTy>(absolute);
  }

};

/// A direct relative reference to an object.
template<typename T>
class RelativeDirectPointer :
  private RelativeDirectPointerImpl<T>
{
  using super = RelativeDirectPointerImpl<T>;
public:
  operator typename super::PointerTy() const & {
    return this->get();
  }

  const typename super::ValueTy &operator*() const & {
    return *this->get();
  }

  const typename super::ValueTy *operator->() const & {
    return this->get();
  }
};

/// A specialization of RelativeDirectPointer for function pointers,
/// allowing for calls.
template<typename RetTy, typename...ArgTy>
class RelativeDirectPointer<RetTy (ArgTy...)> :
  private RelativeDirectPointerImpl<RetTy (ArgTy...)>
{
  using super = RelativeDirectPointerImpl<RetTy (ArgTy...)>;
public:
  operator typename super::PointerTy() const & {
    return this->get();
  }

  RetTy operator()(ArgTy...arg) {
    return this->get()(std::forward<ArgTy>(arg)...);
  }
};

}

