mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 12:22:09 +00:00
4a26c88735
Re-enable write protection of code pages. I added cc tests that cover two corner conditions that caused the old code to crash. TEST=vm/FreeList R=asiva@google.com Review URL: https://codereview.chromium.org//150563007 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32647 260f80e4-7a28-3924-810f-c04153c831b5
141 lines
4.8 KiB
C++
141 lines
4.8 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) {
|
|
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
|