// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#ifndef RUNTIME_VM_COMPILER_RELOCATION_H_
#define RUNTIME_VM_COMPILER_RELOCATION_H_

#include "vm/allocation.h"
#include "vm/image_snapshot.h"
#include "vm/intrusive_dlist.h"
#include "vm/object.h"
#include "vm/type_testing_stubs.h"
#include "vm/visitor.h"

namespace dart {

#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) &&                  \
    !defined(TARGET_ARCH_IA32)

// Represents a pc-relative call which has not been patched up with the final
// destination.
class UnresolvedCall : public IntrusiveDListEntry<UnresolvedCall>,
                       public IntrusiveDListEntry<UnresolvedCall, 2> {
 public:
  UnresolvedCall(RawCode* caller,
                 intptr_t call_offset,
                 intptr_t text_offset,
                 RawCode* callee,
                 intptr_t offset_into_target)
      : caller(caller),
        call_offset(call_offset),
        text_offset(text_offset),
        callee(callee),
        offset_into_target(offset_into_target) {}

  UnresolvedCall(const UnresolvedCall& other)
      : IntrusiveDListEntry<UnresolvedCall>(),
        IntrusiveDListEntry<UnresolvedCall, 2>(),
        caller(other.caller),
        call_offset(other.call_offset),
        text_offset(other.text_offset),
        callee(other.callee),
        offset_into_target(other.offset_into_target) {}

  // The caller which has an unresolved call.
  RawCode* caller;
  // The offset from the payload of the calling code which performs the call.
  intptr_t call_offset;
  // The offset in the .text segment where the call happens.
  intptr_t text_offset;
  // The target of the forward call.
  RawCode* callee;
  // The extra offset into the target.
  intptr_t offset_into_target;
};

// A list of all unresolved calls.
using AllUnresolvedCallsList = IntrusiveDList<UnresolvedCall>;

// A list of all unresolved calls which call the same destination.
using SameDestinationUnresolvedCallsList = IntrusiveDList<UnresolvedCall, 2>;

// Represents a trampoline which has not been patched up with the final
// destination.
//
// The [CodeRelocator] will insert trampolines into the ".text" segment which
// increase the range of PC-relative calls.  If a pc-relative call in normal
// code is too far away from it's destination, it will call a trampoline
// instead (which will tail-call the destination).
class UnresolvedTrampoline : public IntrusiveDListEntry<UnresolvedTrampoline> {
 public:
  UnresolvedTrampoline(RawCode* callee,
                       intptr_t offset_into_target,
                       uint8_t* trampoline_bytes,
                       intptr_t text_offset)
      : callee(callee),
        offset_into_target(offset_into_target),
        trampoline_bytes(trampoline_bytes),
        text_offset(text_offset) {}

  // The target of the forward call.
  RawCode* callee;
  // The extra offset into the target.
  intptr_t offset_into_target;

  // The trampoline buffer.
  uint8_t* trampoline_bytes;
  // The offset in the .text segment where the trampoline starts.
  intptr_t text_offset;
};

using UnresolvedTrampolineList = IntrusiveDList<UnresolvedTrampoline>;

template <typename ValueType, ValueType kNoValue>
class InstructionsMapTraits {
 public:
  struct Pair {
    RawInstructions* instructions;
    ValueType value;

    Pair() : instructions(nullptr), value(kNoValue) {}
    Pair(RawInstructions* i, const ValueType& value)
        : instructions(i), value(value) {}
  };

  typedef const RawInstructions* Key;
  typedef const ValueType Value;

  static Key KeyOf(Pair kv) { return kv.instructions; }
  static ValueType ValueOf(Pair kv) { return kv.value; }
  static inline intptr_t Hashcode(Key key) {
    return reinterpret_cast<intptr_t>(key);
  }
  static inline bool IsKeyEqual(Pair pair, Key key) {
    return pair.instructions == key;
  }
};

using InstructionsPosition =
    DirectChainedHashMap<InstructionsMapTraits<intptr_t, -1>>;

using TrampolinesMap = DirectChainedHashMap<
    InstructionsMapTraits<UnresolvedTrampolineList*, nullptr>>;

using InstructionsUnresolvedCalls = DirectChainedHashMap<
    InstructionsMapTraits<SameDestinationUnresolvedCallsList*, nullptr>>;

// Relocates the given code objects by patching the instructions with the
// correct pc offsets.
//
// Produces a set of [ImageWriterCommand]s which tell the image writer in which
// order (and at which offset) to emit instructions.
class CodeRelocator : public StackResource {
 public:
  // Relocates instructions of the code objects provided by patching any
  // pc-relative calls/jumps.
  //
  // Populates the image writer command array which must be used later to write
  // the ".text" segment.
  static void Relocate(Thread* thread,
                       GrowableArray<RawCode*>* code_objects,
                       GrowableArray<ImageWriterCommand>* commands,
                       bool is_vm_isolate) {
    CodeRelocator relocator(thread, code_objects, commands);
    relocator.Relocate(is_vm_isolate);
  }

 private:
  CodeRelocator(Thread* thread,
                GrowableArray<RawCode*>* code_objects,
                GrowableArray<ImageWriterCommand>* commands);

  void Relocate(bool is_vm_isolate);

  void FindInstructionAndCallLimits();

  bool AddInstructionsToText(RawCode* code);
  void ScanCallTargets(const Code& code,
                       const Array& call_targets,
                       intptr_t code_text_offset);

  UnresolvedTrampoline* FindTrampolineFor(UnresolvedCall* unresolved_call);
  void AddTrampolineToText(RawInstructions* destination,
                           uint8_t* trampoline_bytes,
                           intptr_t trampoline_length);

  void EnqueueUnresolvedCall(UnresolvedCall* unresolved_call);
  void EnqueueUnresolvedTrampoline(UnresolvedTrampoline* unresolved_trampoline);

  bool TryResolveBackwardsCall(UnresolvedCall* unresolved_call);
  void ResolveUnresolvedCallsTargeting(const RawInstructions* instructions);
  void ResolveCall(UnresolvedCall* unresolved_call);
  void ResolveCallToDestination(UnresolvedCall* unresolved_call,
                                intptr_t destination_text);
  void ResolveTrampoline(UnresolvedTrampoline* unresolved_trampoline);

  void BuildTrampolinesForAlmostOutOfRangeCalls();

  intptr_t FindDestinationInText(const RawInstructions* destination,
                                 intptr_t offset_into_target);

  bool IsTargetInRangeFor(UnresolvedCall* unresolved_call,
                          intptr_t target_text_offset);

  // The code relocation happens during AOT snapshot writing and operates on raw
  // objects. No allocations can be done.
  NoSafepointScope no_savepoint_scope_;

  const GrowableArray<RawCode*>* code_objects_;
  GrowableArray<ImageWriterCommand>* commands_;

  // The size of largest instructions object in bytes.
  intptr_t max_instructions_size_ = 0;
  // The maximum number of pc-relative calls in an instructions object.
  intptr_t max_calls_ = 0;
  intptr_t max_offset_into_target_ = 0;

  // Data structures used for relocation.
  intptr_t next_text_offset_ = 0;
  InstructionsPosition text_offsets_;
  TrampolinesMap trampolines_by_destination_;
  InstructionsUnresolvedCalls unresolved_calls_by_destination_;
  AllUnresolvedCallsList all_unresolved_calls_;

  // Reusable handles for [ScanCallTargets].
  Smi& kind_type_and_offset_;
  Object& target_;
  Code& destination_;
};

#endif  // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) &&           \
        // !defined(TARGET_ARCH_IA32)

}  // namespace dart

#endif  // RUNTIME_VM_COMPILER_RELOCATION_H_
