OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "vm/code_patcher.h" |
| 6 #include "vm/instructions.h" |
| 7 #include "vm/object.h" |
| 8 |
| 9 namespace dart { |
| 10 |
| 11 static void SwapCode(intptr_t num_bytes, char* a, char* b) { |
| 12 for (intptr_t i = 0; i < num_bytes; i++) { |
| 13 char tmp = *a; |
| 14 *a = *b; |
| 15 *b = tmp; |
| 16 a++; |
| 17 b++; |
| 18 } |
| 19 } |
| 20 |
| 21 |
| 22 // The patch code buffer contains the jmp code which will be inserted at |
| 23 // entry point. |
| 24 void CodePatcher::PatchEntry(const Code& code) { |
| 25 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 26 PcDescriptors::kEntryPatch); |
| 27 JumpPattern jmp_entry(patch_addr); |
| 28 ASSERT(!jmp_entry.IsValid()); |
| 29 const uword patch_buffer = code.GetPatchCodePc(); |
| 30 ASSERT(patch_buffer != 0); |
| 31 JumpPattern jmp_patch(patch_buffer); |
| 32 ASSERT(jmp_patch.IsValid()); |
| 33 const uword jump_target = jmp_patch.TargetAddress(); |
| 34 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 35 reinterpret_cast<char*>(patch_addr), |
| 36 reinterpret_cast<char*>(patch_buffer)); |
| 37 jmp_entry.SetTargetAddress(jump_target); |
| 38 } |
| 39 |
| 40 |
| 41 // The entry point is a jmp instruction, the patch code buffer contains |
| 42 // original code, the entry point contains the jump instruction. |
| 43 void CodePatcher::RestoreEntry(const Code& code) { |
| 44 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 45 PcDescriptors::kEntryPatch); |
| 46 JumpPattern jmp_entry(patch_addr); |
| 47 ASSERT(jmp_entry.IsValid()); |
| 48 const uword jump_target = jmp_entry.TargetAddress(); |
| 49 const uword patch_buffer = code.GetPatchCodePc(); |
| 50 ASSERT(patch_buffer != 0); |
| 51 // 'patch_buffer' contains original entry code. |
| 52 JumpPattern jmp_patch(patch_buffer); |
| 53 ASSERT(!jmp_patch.IsValid()); |
| 54 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 55 reinterpret_cast<char*>(patch_addr), |
| 56 reinterpret_cast<char*>(patch_buffer)); |
| 57 ASSERT(jmp_patch.IsValid()); |
| 58 jmp_patch.SetTargetAddress(jump_target); |
| 59 } |
| 60 |
| 61 |
| 62 bool CodePatcher::CodeIsPatchable(const Code& code) { |
| 63 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
| 64 PcDescriptors::kEntryPatch); |
| 65 // kEntryPatch may not exist which means the function is not patchable. |
| 66 if (patch_addr == 0) { |
| 67 return true; |
| 68 } |
| 69 JumpPattern jmp_entry(patch_addr); |
| 70 if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) { |
| 71 return false; |
| 72 } |
| 73 const uword limit = patch_addr + jmp_entry.pattern_length_in_bytes(); |
| 74 // Check no object stored between patch_addr .. limit. |
| 75 for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { |
| 76 const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
| 77 const uword obj_end = obj_start + kWordSize; |
| 78 if ((obj_start < limit) && (obj_end > patch_addr)) { |
| 79 return false; |
| 80 } |
| 81 } |
| 82 return true; |
| 83 } |
| 84 |
| 85 } // namespace dart |
OLD | NEW |