// 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/code_patcher.h"
#include "vm/cpu.h"
#include "vm/instructions.h"
#include "vm/object.h"
#include "vm/virtual_memory.h"

namespace dart {

DEFINE_FLAG(bool, write_protect_code, true, "Write protect jitted code");


WritableInstructionsScope::WritableInstructionsScope(uword address,
                                                     intptr_t size)
    : address_(address), size_(size) {
  if (FLAG_write_protect_code) {
    bool status =
        VirtualMemory::Protect(reinterpret_cast<void*>(address),
                               size,
                               VirtualMemory::kReadWrite);
    ASSERT(status);
  }
}


WritableInstructionsScope::~WritableInstructionsScope() {
  if (FLAG_write_protect_code) {
    bool status =
        VirtualMemory::Protect(reinterpret_cast<void*>(address_),
                               size_,
                               VirtualMemory::kReadExecute);
    ASSERT(status);
  }
}


static void SwapCode(intptr_t num_bytes, char* code, char* buffer) {
  uword code_address = reinterpret_cast<uword>(code);
  for (intptr_t i = 0; i < num_bytes; i++) {
    char tmp = *code;
    *code = *buffer;
    *buffer = tmp;
    code++;
    buffer++;
  }
  CPU::FlushICache(code_address, num_bytes);
  // The buffer is not executed. No need to flush.
}


// The patch code buffer contains the jmp code which will be inserted at
// entry point.
void CodePatcher::PatchEntry(const Code& code) {
  const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                PcDescriptors::kEntryPatch);
  ASSERT(patch_addr != 0);
  JumpPattern jmp_entry(patch_addr, code);
  ASSERT(!jmp_entry.IsValid());
  const uword patch_buffer = code.GetPatchCodePc();
  ASSERT(patch_buffer != 0);
  JumpPattern jmp_patch(patch_buffer, code);
  ASSERT(jmp_patch.IsValid());
  const uword jump_target = jmp_patch.TargetAddress();
  intptr_t length = jmp_patch.pattern_length_in_bytes();
  {
    WritableInstructionsScope writable_code(patch_addr, length);
    WritableInstructionsScope writable_buffer(patch_buffer, length);
    SwapCode(jmp_patch.pattern_length_in_bytes(),
             reinterpret_cast<char*>(patch_addr),
             reinterpret_cast<char*>(patch_buffer));
    jmp_entry.SetTargetAddress(jump_target);
  }
}


// The entry point is a jmp instruction, the patch code buffer contains
// original code, the entry point contains the jump instruction.
void CodePatcher::RestoreEntry(const Code& code) {
  const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                PcDescriptors::kEntryPatch);
  ASSERT(patch_addr != 0);
  JumpPattern jmp_entry(patch_addr, code);
  ASSERT(jmp_entry.IsValid());
  const uword jump_target = jmp_entry.TargetAddress();
  const uword patch_buffer = code.GetPatchCodePc();
  ASSERT(patch_buffer != 0);
  // 'patch_buffer' contains original entry code.
  JumpPattern jmp_patch(patch_buffer, code);
  ASSERT(!jmp_patch.IsValid());
  intptr_t length = jmp_patch.pattern_length_in_bytes();
  {
    WritableInstructionsScope writable_code(patch_addr, length);
    WritableInstructionsScope writable_buffer(patch_buffer, length);
    SwapCode(jmp_patch.pattern_length_in_bytes(),
             reinterpret_cast<char*>(patch_addr),
             reinterpret_cast<char*>(patch_buffer));
    ASSERT(jmp_patch.IsValid());
    jmp_patch.SetTargetAddress(jump_target);
  }
}


bool CodePatcher::IsEntryPatched(const Code& code) {
  const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                PcDescriptors::kEntryPatch);
  if (patch_addr == 0) {
    return false;
  }
  JumpPattern jmp_entry(patch_addr, code);
  return jmp_entry.IsValid();
}


bool CodePatcher::CodeIsPatchable(const Code& code) {
  const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                PcDescriptors::kEntryPatch);
  // kEntryPatch may not exist which means the function is not patchable.
  if (patch_addr == 0) {
    return false;
  }
  JumpPattern jmp_entry(patch_addr, code);
  if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) {
    return false;
  }
  const uword limit = patch_addr + jmp_entry.pattern_length_in_bytes();
  // Check no object stored between patch_addr .. limit.
  for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) {
    const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint();
    const uword obj_end  = obj_start + kWordSize;
    if ((obj_start < limit) && (obj_end > patch_addr)) {
      return false;
    }
  }
  return true;
}

}  // namespace dart
