| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/code_patcher.h" | 5 #include "vm/code_patcher.h" |
| 6 #include "vm/cpu.h" | 6 #include "vm/cpu.h" |
| 7 #include "vm/instructions.h" | 7 #include "vm/instructions.h" |
| 8 #include "vm/object.h" | 8 #include "vm/object.h" |
| 9 #include "vm/virtual_memory.h" |
| 9 | 10 |
| 10 namespace dart { | 11 namespace dart { |
| 11 | 12 |
| 13 DEFINE_FLAG(bool, write_protect_code, true, "Write protect jitted code"); |
| 14 |
| 15 |
| 16 WritableInstructionsScope::WritableInstructionsScope(uword address, |
| 17 intptr_t size) |
| 18 : address_(address), size_(size) { |
| 19 if (FLAG_write_protect_code) { |
| 20 bool status = |
| 21 VirtualMemory::Protect(reinterpret_cast<void*>(address), |
| 22 size, |
| 23 VirtualMemory::kReadWrite); |
| 24 ASSERT(status); |
| 25 } |
| 26 } |
| 27 |
| 28 |
| 29 WritableInstructionsScope::~WritableInstructionsScope() { |
| 30 if (FLAG_write_protect_code) { |
| 31 bool status = |
| 32 VirtualMemory::Protect(reinterpret_cast<void*>(address_), |
| 33 size_, |
| 34 VirtualMemory::kReadExecute); |
| 35 ASSERT(status); |
| 36 } |
| 37 } |
| 38 |
| 39 |
| 12 static void SwapCode(intptr_t num_bytes, char* code, char* buffer) { | 40 static void SwapCode(intptr_t num_bytes, char* code, char* buffer) { |
| 13 uword code_address = reinterpret_cast<uword>(code); | 41 uword code_address = reinterpret_cast<uword>(code); |
| 14 for (intptr_t i = 0; i < num_bytes; i++) { | 42 for (intptr_t i = 0; i < num_bytes; i++) { |
| 15 char tmp = *code; | 43 char tmp = *code; |
| 16 *code = *buffer; | 44 *code = *buffer; |
| 17 *buffer = tmp; | 45 *buffer = tmp; |
| 18 code++; | 46 code++; |
| 19 buffer++; | 47 buffer++; |
| 20 } | 48 } |
| 21 CPU::FlushICache(code_address, num_bytes); | 49 CPU::FlushICache(code_address, num_bytes); |
| 22 // The buffer is not executed. No need to flush. | 50 // The buffer is not executed. No need to flush. |
| 23 } | 51 } |
| 24 | 52 |
| 25 | 53 |
| 26 // The patch code buffer contains the jmp code which will be inserted at | 54 // The patch code buffer contains the jmp code which will be inserted at |
| 27 // entry point. | 55 // entry point. |
| 28 void CodePatcher::PatchEntry(const Code& code) { | 56 void CodePatcher::PatchEntry(const Code& code) { |
| 29 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 57 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 30 PcDescriptors::kEntryPatch); | 58 PcDescriptors::kEntryPatch); |
| 31 ASSERT(patch_addr != 0); | 59 ASSERT(patch_addr != 0); |
| 32 JumpPattern jmp_entry(patch_addr, code); | 60 JumpPattern jmp_entry(patch_addr, code); |
| 33 ASSERT(!jmp_entry.IsValid()); | 61 ASSERT(!jmp_entry.IsValid()); |
| 34 const uword patch_buffer = code.GetPatchCodePc(); | 62 const uword patch_buffer = code.GetPatchCodePc(); |
| 35 ASSERT(patch_buffer != 0); | 63 ASSERT(patch_buffer != 0); |
| 36 JumpPattern jmp_patch(patch_buffer, code); | 64 JumpPattern jmp_patch(patch_buffer, code); |
| 37 ASSERT(jmp_patch.IsValid()); | 65 ASSERT(jmp_patch.IsValid()); |
| 38 const uword jump_target = jmp_patch.TargetAddress(); | 66 const uword jump_target = jmp_patch.TargetAddress(); |
| 39 SwapCode(jmp_patch.pattern_length_in_bytes(), | 67 intptr_t length = jmp_patch.pattern_length_in_bytes(); |
| 40 reinterpret_cast<char*>(patch_addr), | 68 { |
| 41 reinterpret_cast<char*>(patch_buffer)); | 69 WritableInstructionsScope writable_code(patch_addr, length); |
| 42 jmp_entry.SetTargetAddress(jump_target); | 70 WritableInstructionsScope writable_buffer(patch_buffer, length); |
| 71 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 72 reinterpret_cast<char*>(patch_addr), |
| 73 reinterpret_cast<char*>(patch_buffer)); |
| 74 jmp_entry.SetTargetAddress(jump_target); |
| 75 } |
| 43 } | 76 } |
| 44 | 77 |
| 45 | 78 |
| 46 // The entry point is a jmp instruction, the patch code buffer contains | 79 // The entry point is a jmp instruction, the patch code buffer contains |
| 47 // original code, the entry point contains the jump instruction. | 80 // original code, the entry point contains the jump instruction. |
| 48 void CodePatcher::RestoreEntry(const Code& code) { | 81 void CodePatcher::RestoreEntry(const Code& code) { |
| 49 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 82 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 50 PcDescriptors::kEntryPatch); | 83 PcDescriptors::kEntryPatch); |
| 51 ASSERT(patch_addr != 0); | 84 ASSERT(patch_addr != 0); |
| 52 JumpPattern jmp_entry(patch_addr, code); | 85 JumpPattern jmp_entry(patch_addr, code); |
| 53 ASSERT(jmp_entry.IsValid()); | 86 ASSERT(jmp_entry.IsValid()); |
| 54 const uword jump_target = jmp_entry.TargetAddress(); | 87 const uword jump_target = jmp_entry.TargetAddress(); |
| 55 const uword patch_buffer = code.GetPatchCodePc(); | 88 const uword patch_buffer = code.GetPatchCodePc(); |
| 56 ASSERT(patch_buffer != 0); | 89 ASSERT(patch_buffer != 0); |
| 57 // 'patch_buffer' contains original entry code. | 90 // 'patch_buffer' contains original entry code. |
| 58 JumpPattern jmp_patch(patch_buffer, code); | 91 JumpPattern jmp_patch(patch_buffer, code); |
| 59 ASSERT(!jmp_patch.IsValid()); | 92 ASSERT(!jmp_patch.IsValid()); |
| 60 SwapCode(jmp_patch.pattern_length_in_bytes(), | 93 intptr_t length = jmp_patch.pattern_length_in_bytes(); |
| 61 reinterpret_cast<char*>(patch_addr), | 94 { |
| 62 reinterpret_cast<char*>(patch_buffer)); | 95 WritableInstructionsScope writable_code(patch_addr, length); |
| 63 ASSERT(jmp_patch.IsValid()); | 96 WritableInstructionsScope writable_buffer(patch_buffer, length); |
| 64 jmp_patch.SetTargetAddress(jump_target); | 97 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 98 reinterpret_cast<char*>(patch_addr), |
| 99 reinterpret_cast<char*>(patch_buffer)); |
| 100 ASSERT(jmp_patch.IsValid()); |
| 101 jmp_patch.SetTargetAddress(jump_target); |
| 102 } |
| 65 } | 103 } |
| 66 | 104 |
| 67 | 105 |
| 68 bool CodePatcher::IsEntryPatched(const Code& code) { | 106 bool CodePatcher::IsEntryPatched(const Code& code) { |
| 69 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 107 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 70 PcDescriptors::kEntryPatch); | 108 PcDescriptors::kEntryPatch); |
| 71 if (patch_addr == 0) { | 109 if (patch_addr == 0) { |
| 72 return false; | 110 return false; |
| 73 } | 111 } |
| 74 JumpPattern jmp_entry(patch_addr, code); | 112 JumpPattern jmp_entry(patch_addr, code); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 93 const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint(); | 131 const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
| 94 const uword obj_end = obj_start + kWordSize; | 132 const uword obj_end = obj_start + kWordSize; |
| 95 if ((obj_start < limit) && (obj_end > patch_addr)) { | 133 if ((obj_start < limit) && (obj_end > patch_addr)) { |
| 96 return false; | 134 return false; |
| 97 } | 135 } |
| 98 } | 136 } |
| 99 return true; | 137 return true; |
| 100 } | 138 } |
| 101 | 139 |
| 102 } // namespace dart | 140 } // namespace dart |
| OLD | NEW |