Files
sdk/runtime/vm/code_patcher.cc
T
fschneider@google.com c2fad4230c VM: Enable collection of unoptimized code for optimized functions.
Until now, code GC was limited to function that have not been optimized.
With lazy generation of unoptimized code on deoptimization we can now
collect unoptimized code for optimized functions as well.

R=vegorov@google.com

Review URL: https://codereview.chromium.org//1067383002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45062 260f80e4-7a28-3924-810f-c04153c831b5
2015-04-10 12:02:30 +00:00

137 lines
4.5 KiB
C++

// 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) {
ASSERT(!IsEntryPatched(code));
const uword patch_addr = code.GetEntryPatchPc();
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) {
if (!IsEntryPatched(code)) return;
const uword patch_addr = code.GetEntryPatchPc();
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.GetEntryPatchPc();
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.GetEntryPatchPc();
// Zero means means that 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