// Copyright (c) 2012, 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.

#include "vm/globals.h"  // Needed here to get TARGET_ARCH_X64.
#if defined(TARGET_ARCH_X64)

#include "vm/code_patcher.h"
#include "vm/cpu.h"
#include "vm/dart_entry.h"
#include "vm/instructions.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/raw_object.h"
#include "vm/reverse_pc_lookup_cache.h"

namespace dart {

// callq [CODE_REG + entry_point_offset (disp8)]
static const int16_t kCallPatternJIT[] = {
    0x41, 0xff, 0x54, 0x24, -1,
};

// callq [TMP + entry_point_offset (disp8)]
static const int16_t kCallPatternAOT[] = {
    0x41,
    0xff,
    0x53,
    -1,
};

static const intptr_t kLoadCodeFromPoolInstructionLength = 3;
static const intptr_t kLoadCodeFromPoolDisp8PatternLength =
    kLoadCodeFromPoolInstructionLength + 1;
static const intptr_t kLoadCodeFromPoolDisp32PatternLength =
    kLoadCodeFromPoolInstructionLength + 4;

// movq CODE_REG, [PP + disp8]
static const int16_t
    kLoadCodeFromPoolDisp8JIT[kLoadCodeFromPoolDisp8PatternLength] = {
        0x4d,
        0x8b,
        0x67,
        -1,
};

// movq CODE_REG, [PP + disp32]
static const int16_t
    kLoadCodeFromPoolDisp32JIT[kLoadCodeFromPoolDisp32PatternLength] = {
        0x4d, 0x8b, 0xa7, -1, -1, -1, -1,
};

// movq TMP, [PP + disp8]
static const int16_t
    kLoadCodeFromPoolDisp8AOT[kLoadCodeFromPoolDisp8PatternLength] = {
        0x4d,
        0x8b,
        0x5f,
        -1,
};

// movq TMP, [PP + disp32]
static const int16_t
    kLoadCodeFromPoolDisp32AOT[kLoadCodeFromPoolDisp32PatternLength] = {
        0x4d, 0x8b, 0x9f, -1, -1, -1, -1,
};

static void MatchCallPattern(uword* pc) {
  const int16_t* call_pattern =
      FLAG_precompiled_mode ? kCallPatternAOT : kCallPatternJIT;
  const intptr_t call_pattern_length = FLAG_precompiled_mode
                                           ? ARRAY_SIZE(kCallPatternAOT)
                                           : ARRAY_SIZE(kCallPatternJIT);

  // callq [reg + entry_point_offset]
  if (MatchesPattern(*pc, call_pattern, call_pattern_length)) {
    *pc -= call_pattern_length;
  } else {
    FATAL("Expected `call [%s + offs]` at %" Px,
          FLAG_precompiled_mode ? "TMP" : "CODE_REG", *pc);
  }
}

static void MatchDataLoadFromPool(uword* pc, intptr_t* data_index) {
  // movq RBX, [PP + offset]
  static int16_t load_data_disp8[] = {
      0x49,
      0x8b,
      0x5f,
      -1,  //
  };
  static int16_t load_data_disp32[] = {
      0x49, 0x8b, 0x9f, -1, -1, -1, -1,
  };
  if (MatchesPattern(*pc, load_data_disp8, ARRAY_SIZE(load_data_disp8))) {
    *pc -= ARRAY_SIZE(load_data_disp8);
    *data_index = IndexFromPPLoadDisp8(*pc + 3);
  } else if (MatchesPattern(*pc, load_data_disp32,
                            ARRAY_SIZE(load_data_disp32))) {
    *pc -= ARRAY_SIZE(load_data_disp32);
    *data_index = IndexFromPPLoadDisp32(*pc + 3);
  } else {
    FATAL("Expected `movq RBX, [PP + imm8|imm32]` at %" Px, *pc);
  }
}

static void MatchCodeLoadFromPool(uword* pc, intptr_t* code_index) {
  const int16_t* load_code_disp8_pattern = FLAG_precompiled_mode
                                               ? kLoadCodeFromPoolDisp8AOT
                                               : kLoadCodeFromPoolDisp8JIT;
  const int16_t* load_code_disp32_pattern = FLAG_precompiled_mode
                                                ? kLoadCodeFromPoolDisp32AOT
                                                : kLoadCodeFromPoolDisp32JIT;

  if (MatchesPattern(*pc, load_code_disp8_pattern,
                     kLoadCodeFromPoolDisp8PatternLength)) {
    *pc -= kLoadCodeFromPoolDisp8PatternLength;
    *code_index =
        IndexFromPPLoadDisp8(*pc + kLoadCodeFromPoolInstructionLength);
  } else if (MatchesPattern(*pc, load_code_disp32_pattern,
                            kLoadCodeFromPoolDisp32PatternLength)) {
    *pc -= kLoadCodeFromPoolDisp32PatternLength;
    *code_index =
        IndexFromPPLoadDisp32(*pc + kLoadCodeFromPoolInstructionLength);
  } else {
    FATAL("Expected `movq %s, [PP + imm8|imm32]` at %" Px,
          FLAG_precompiled_mode ? "TMP" : "CODE_REG", *pc);
  }
}

class UnoptimizedCall : public ValueObject {
 public:
  UnoptimizedCall(uword return_address, const Code& code)
      : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
        code_index_(-1),
        argument_index_(-1) {
    uword pc = return_address;
    MatchCallPattern(&pc);
    MatchDataLoadFromPool(&pc, &argument_index_);
    MatchCodeLoadFromPool(&pc, &code_index_);
    ASSERT(Object::Handle(object_pool_.ObjectAt(code_index_)).IsCode());
  }

  intptr_t argument_index() const { return argument_index_; }

  CodePtr target() const {
    Code& code = Code::Handle();
    code ^= object_pool_.ObjectAt(code_index_);
    return code.ptr();
  }

  void set_target(const Code& target) const {
    object_pool_.SetObjectAt<std::memory_order_release>(code_index_, target);
    // No need to flush the instruction cache, since the code is not modified.
  }

 protected:
  const ObjectPool& object_pool_;
  intptr_t code_index_;
  intptr_t argument_index_;

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall);
};

class NativeCall : public ValueObject {
 public:
  NativeCall(uword return_address, const Code& code)
      : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
        code_index_(-1),
        argument_index_(-1) {
    uword pc = return_address;
    MatchCallPattern(&pc);
    MatchCodeLoadFromPool(&pc, &code_index_);
    MatchDataLoadFromPool(&pc, &argument_index_);
    ASSERT(Object::Handle(object_pool_.ObjectAt(code_index_)).IsCode());
  }

  intptr_t argument_index() const { return argument_index_; }

  NativeFunction native_function() const {
    return reinterpret_cast<NativeFunction>(
        object_pool_.RawValueAt(argument_index()));
  }

  void set_native_function(NativeFunction func) const {
    object_pool_.SetRawValueAt<std::memory_order_relaxed>(
        argument_index(), reinterpret_cast<uword>(func));
  }

  CodePtr target() const {
    Code& code = Code::Handle();
    code ^= object_pool_.ObjectAt(code_index_);
    return code.ptr();
  }

  void set_target(const Code& target) const {
    object_pool_.SetObjectAt<std::memory_order_release>(code_index_, target);
    // No need to flush the instruction cache, since the code is not modified.
  }

 private:
  const ObjectPool& object_pool_;
  intptr_t code_index_;
  intptr_t argument_index_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(NativeCall);
};

class InstanceCall : public UnoptimizedCall {
 public:
  InstanceCall(uword return_address, const Code& code)
      : UnoptimizedCall(return_address, code) {
#if defined(DEBUG)
    Object& test_data = Object::Handle(data());
    ASSERT(test_data.IsArray() || test_data.IsICData() ||
           test_data.IsMegamorphicCache());
    if (test_data.IsICData()) {
      ASSERT(ICData::Cast(test_data).NumArgsTested() > 0);
    }
#endif  // DEBUG
  }

  ObjectPtr data() const { return object_pool_.ObjectAt(argument_index()); }
  void set_data(const Object& data) const {
    ASSERT(data.IsArray() || data.IsICData() || data.IsMegamorphicCache());
    object_pool_.SetObjectAt<std::memory_order_release>(argument_index(), data);
  }

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall);
};

class UnoptimizedStaticCall : public UnoptimizedCall {
 public:
  UnoptimizedStaticCall(uword return_address, const Code& caller_code)
      : UnoptimizedCall(return_address, caller_code) {
#if defined(DEBUG)
    ICData& test_ic_data = ICData::Handle();
    test_ic_data ^= ic_data();
    ASSERT(test_ic_data.NumArgsTested() >= 0);
#endif  // DEBUG
  }

  ObjectPtr ic_data() const { return object_pool_.ObjectAt(argument_index()); }

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall);
};

// The expected pattern of a call where the target is loaded from
// the object pool.
class PoolPointerCall : public ValueObject {
 public:
  explicit PoolPointerCall(uword return_address, const Code& caller_code)
      : object_pool_(ObjectPool::Handle(caller_code.GetObjectPool())),
        code_index_(-1) {
    uword pc = return_address;

    MatchCallPattern(&pc);
    MatchCodeLoadFromPool(&pc, &code_index_);
    ASSERT(Object::Handle(object_pool_.ObjectAt(code_index_)).IsCode());
  }

  CodePtr Target() const {
    Code& code = Code::Handle();
    code ^= object_pool_.ObjectAt(code_index_);
    return code.ptr();
  }

  void SetTarget(const Code& target) const {
    object_pool_.SetObjectAt<std::memory_order_release>(code_index_, target);
    // No need to flush the instruction cache, since the code is not modified.
  }

 protected:
  const ObjectPool& object_pool_;
  intptr_t code_index_;

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall);
};

// Instance call that can switch between a direct monomorphic call, an IC call,
// and a megamorphic call.
//   load guarded cid            load ICData             load MegamorphicCache
//   load monomorphic target <-> load ICLookup stub  ->  load MMLookup stub
//   call target.entry           call stub.entry         call stub.entry
class SwitchableCallBase : public ValueObject {
 public:
  explicit SwitchableCallBase(const ObjectPool& object_pool)
      : object_pool_(object_pool), target_index_(-1), data_index_(-1) {}

  intptr_t data_index() const { return data_index_; }
  intptr_t target_index() const { return target_index_; }

  ObjectPtr data() const {
    return object_pool_.ObjectAt<std::memory_order_relaxed>(data_index());
  }

  void SetDataRelease(const Object& data) const {
    ASSERT(!Object::Handle(object_pool_.ObjectAt(data_index())).IsCode());
    object_pool_.SetObjectAt<std::memory_order_release>(data_index(), data);
    // No need to flush the instruction cache, since the code is not modified.
  }

 protected:
  const ObjectPool& object_pool_;
  intptr_t target_index_;
  intptr_t data_index_;

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(SwitchableCallBase);
};

// See [SwitchableCallBase] for a switchable calls in general.
//
// The target slot is always a [Code] object: Either the code of the
// monomorphic function or a stub code.
class SwitchableCall : public SwitchableCallBase {
 public:
  SwitchableCall(uword return_address, const Code& caller_code)
      : SwitchableCallBase(ObjectPool::Handle(caller_code.GetObjectPool())) {
    ASSERT(caller_code.ContainsInstructionAt(return_address));
    uword pc = return_address;

    // callq [CODE_REG + entrypoint_offset]
    static int16_t call_pattern[] = {
        0x41, 0xff, 0x54, 0x24, -1,  //
    };
    if (MatchesPattern(pc, call_pattern, ARRAY_SIZE(call_pattern))) {
      pc -= ARRAY_SIZE(call_pattern);
    } else {
      FATAL("Failed to decode at %" Px, pc);
    }

    // movq RBX, [PP + offset]
    MatchDataLoadFromPool(&pc, &data_index_);

    // movq CODE_REG, [PP + offset]
    static int16_t load_code_disp8[] = {
        0x4d,
        0x8b,
        0x67,
        -1,  //
    };
    static int16_t load_code_disp32[] = {
        0x4d, 0x8b, 0xa7, -1, -1, -1, -1,
    };
    if (MatchesPattern(pc, load_code_disp8, ARRAY_SIZE(load_code_disp8))) {
      pc -= ARRAY_SIZE(load_code_disp8);
      target_index_ = IndexFromPPLoadDisp8(pc + 3);
    } else if (MatchesPattern(pc, load_code_disp32,
                              ARRAY_SIZE(load_code_disp32))) {
      pc -= ARRAY_SIZE(load_code_disp32);
      target_index_ = IndexFromPPLoadDisp32(pc + 3);
    } else {
      FATAL("Failed to decode at %" Px, pc);
    }
    ASSERT(Object::Handle(object_pool_.ObjectAt(target_index_)).IsCode());
  }

  void SetTargetRelease(const Code& target) const {
    ASSERT(Object::Handle(object_pool_.ObjectAt(target_index())).IsCode());
    object_pool_.SetObjectAt<std::memory_order_release>(target_index(), target);
    // No need to flush the instruction cache, since the code is not modified.
  }

  ObjectPtr target() const { return object_pool_.ObjectAt(target_index()); }
};

// See [SwitchableCallBase] for a switchable calls in general.
//
// The target slot is always a direct entrypoint address: Either the entry point
// of the monomorphic function or a stub entry point.
class BareSwitchableCall : public SwitchableCallBase {
 public:
  explicit BareSwitchableCall(uword return_address)
      : SwitchableCallBase(ObjectPool::Handle(
            IsolateGroup::Current()->object_store()->global_object_pool())) {
    uword pc = return_address;

    // callq RCX
    static int16_t call_pattern[] = {
        0xff,
        0xd1,  //
    };
    if (MatchesPattern(pc, call_pattern, ARRAY_SIZE(call_pattern))) {
      pc -= ARRAY_SIZE(call_pattern);
    } else {
      FATAL("Failed to decode at %" Px, pc);
    }

    // movq RBX, [PP + offset]
    static int16_t load_data_disp8[] = {
        0x49,
        0x8b,
        0x5f,
        -1,  //
    };
    static int16_t load_data_disp32[] = {
        0x49, 0x8b, 0x9f, -1, -1, -1, -1,
    };
    if (MatchesPattern(pc, load_data_disp8, ARRAY_SIZE(load_data_disp8))) {
      pc -= ARRAY_SIZE(load_data_disp8);
      data_index_ = IndexFromPPLoadDisp8(pc + 3);
    } else if (MatchesPattern(pc, load_data_disp32,
                              ARRAY_SIZE(load_data_disp32))) {
      pc -= ARRAY_SIZE(load_data_disp32);
      data_index_ = IndexFromPPLoadDisp32(pc + 3);
    } else {
      FATAL("Failed to decode at %" Px, pc);
    }
    ASSERT(!Object::Handle(object_pool_.ObjectAt(data_index_)).IsCode());

    // movq RCX, [PP + offset]
    static int16_t load_code_disp8[] = {
        0x49,
        0x8b,
        0x4f,
        -1,  //
    };
    static int16_t load_code_disp32[] = {
        0x49, 0x8b, 0x8f, -1, -1, -1, -1,
    };
    if (MatchesPattern(pc, load_code_disp8, ARRAY_SIZE(load_code_disp8))) {
      pc -= ARRAY_SIZE(load_code_disp8);
      target_index_ = IndexFromPPLoadDisp8(pc + 3);
    } else if (MatchesPattern(pc, load_code_disp32,
                              ARRAY_SIZE(load_code_disp32))) {
      pc -= ARRAY_SIZE(load_code_disp32);
      target_index_ = IndexFromPPLoadDisp32(pc + 3);
    } else {
      FATAL("Failed to decode at %" Px, pc);
    }
    ASSERT(object_pool_.TypeAt(target_index_) ==
           ObjectPool::EntryType::kImmediate);
  }

  void SetTargetRelease(const Code& target) const {
    ASSERT(object_pool_.TypeAt(target_index()) ==
           ObjectPool::EntryType::kImmediate);
    object_pool_.SetRawValueAt<std::memory_order_release>(
        target_index(), target.MonomorphicEntryPoint());
  }

  uword target_entry() const {
    return object_pool_.RawValueAt<std::memory_order_relaxed>(target_index());
  }
};

CodePtr CodePatcher::GetStaticCallTargetAt(uword return_address,
                                           const Code& code) {
  ASSERT(code.ContainsInstructionAt(return_address));
  PoolPointerCall call(return_address, code);
  return call.Target();
}

void CodePatcher::PatchStaticCallAt(uword return_address,
                                    const Code& code,
                                    const Code& new_target) {
  PoolPointerCall call(return_address, code);
  call.SetTarget(new_target);
}

void CodePatcher::PatchPoolPointerCallAt(uword return_address,
                                         const Code& code,
                                         const Code& new_target) {
  ASSERT(code.ContainsInstructionAt(return_address));
  PoolPointerCall call(return_address, code);
  call.SetTarget(new_target);
}

CodePtr CodePatcher::GetInstanceCallAt(uword return_address,
                                       const Code& caller_code,
                                       Object* data) {
  ASSERT(caller_code.ContainsInstructionAt(return_address));
  InstanceCall call(return_address, caller_code);
  if (data != nullptr) {
    *data = call.data();
  }
  return call.target();
}

void CodePatcher::PatchInstanceCallAt(uword return_address,
                                      const Code& caller_code,
                                      const Object& data,
                                      const Code& target) {
  auto thread = Thread::Current();
  thread->isolate_group()->RunWithStoppedMutators([&]() {
    PatchInstanceCallAtWithMutatorsStopped(thread, return_address, caller_code,
                                           data, target);
  });
}

void CodePatcher::PatchInstanceCallAtWithMutatorsStopped(
    Thread* thread,
    uword return_address,
    const Code& caller_code,
    const Object& data,
    const Code& target) {
  ASSERT(caller_code.ContainsInstructionAt(return_address));
  InstanceCall call(return_address, caller_code);
  call.set_data(data);
  call.set_target(target);
}

FunctionPtr CodePatcher::GetUnoptimizedStaticCallAt(uword return_address,
                                                    const Code& caller_code,
                                                    ICData* ic_data_result) {
  ASSERT(caller_code.ContainsInstructionAt(return_address));
  UnoptimizedStaticCall static_call(return_address, caller_code);
  ICData& ic_data = ICData::Handle();
  ic_data ^= static_call.ic_data();
  if (ic_data_result != nullptr) {
    *ic_data_result = ic_data.ptr();
  }
  return ic_data.GetTargetAt(0);
}

void CodePatcher::PatchSwitchableCallAt(uword return_address,
                                        const Code& caller_code,
                                        const Object& data,
                                        const Code& target) {
  // We lock to block other writers but don't start a safepoint to block readers
  // (i.e., Dart execution).
  // First update target to a stub that does not read 'data' so that concurrent
  // Dart execution cannot observe the new stub with the old data or the old
  // stub with the new data.
  SafepointMutexLocker ml(IsolateGroup::Current()->type_feedback_mutex());
  if (FLAG_precompiled_mode) {
    BareSwitchableCall call(return_address);
    call.SetTargetRelease(StubCode::SwitchableCallMiss());
    call.SetDataRelease(data);
    call.SetTargetRelease(target);
  } else {
    SwitchableCall call(return_address, caller_code);
    call.SetTargetRelease(StubCode::SwitchableCallMiss());
    call.SetDataRelease(data);
    call.SetTargetRelease(target);
  }
}

uword CodePatcher::GetSwitchableCallTargetEntryAt(uword return_address,
                                                  const Code& caller_code) {
  if (FLAG_precompiled_mode) {
    BareSwitchableCall call(return_address);
    return call.target_entry();
  } else {
    UNREACHABLE();
  }
}

ObjectPtr CodePatcher::GetSwitchableCallDataAt(uword return_address,
                                               const Code& caller_code) {
  if (FLAG_precompiled_mode) {
    BareSwitchableCall call(return_address);
    return call.data();
  } else {
    SwitchableCall call(return_address, caller_code);
    return call.data();
  }
}

void CodePatcher::PatchNativeCallAt(uword return_address,
                                    const Code& caller_code,
                                    NativeFunction target,
                                    const Code& trampoline) {
  Thread::Current()->isolate_group()->RunWithStoppedMutators([&]() {
    ASSERT(caller_code.ContainsInstructionAt(return_address));
    NativeCall call(return_address, caller_code);
    call.set_target(trampoline);
    call.set_native_function(target);
  });
}

CodePtr CodePatcher::GetNativeCallAt(uword return_address,
                                     const Code& caller_code,
                                     NativeFunction* target) {
  ASSERT(caller_code.ContainsInstructionAt(return_address));
  NativeCall call(return_address, caller_code);
  *target = call.native_function();
  return call.target();
}

}  // namespace dart

#endif  // defined TARGET_ARCH_X64
