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 WritableInstructionsScope::WritableInstructionsScope(uword address, |
| 14 intptr_t size) |
| 15 : address_(address), size_(size) { |
| 16 bool status = |
| 17 VirtualMemory::Protect(reinterpret_cast<void*>(address), |
| 18 size, |
| 19 VirtualMemory::kReadWriteExecute); |
| 20 ASSERT(status); |
| 21 } |
| 22 |
| 23 |
| 24 WritableInstructionsScope::~WritableInstructionsScope() { |
| 25 bool status = |
| 26 VirtualMemory::Protect(reinterpret_cast<void*>(address_), |
| 27 size_, |
| 28 VirtualMemory::kReadExecute); |
| 29 ASSERT(status); |
| 30 } |
| 31 |
| 32 |
12 static void SwapCode(intptr_t num_bytes, char* code, char* buffer) { | 33 static void SwapCode(intptr_t num_bytes, char* code, char* buffer) { |
13 uword code_address = reinterpret_cast<uword>(code); | 34 uword code_address = reinterpret_cast<uword>(code); |
14 for (intptr_t i = 0; i < num_bytes; i++) { | 35 for (intptr_t i = 0; i < num_bytes; i++) { |
15 char tmp = *code; | 36 char tmp = *code; |
16 *code = *buffer; | 37 *code = *buffer; |
17 *buffer = tmp; | 38 *buffer = tmp; |
18 code++; | 39 code++; |
19 buffer++; | 40 buffer++; |
20 } | 41 } |
21 CPU::FlushICache(code_address, num_bytes); | 42 CPU::FlushICache(code_address, num_bytes); |
22 // The buffer is not executed. No need to flush. | 43 // The buffer is not executed. No need to flush. |
23 } | 44 } |
24 | 45 |
25 | 46 |
26 // The patch code buffer contains the jmp code which will be inserted at | 47 // The patch code buffer contains the jmp code which will be inserted at |
27 // entry point. | 48 // entry point. |
28 void CodePatcher::PatchEntry(const Code& code) { | 49 void CodePatcher::PatchEntry(const Code& code) { |
29 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 50 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
30 PcDescriptors::kEntryPatch); | 51 PcDescriptors::kEntryPatch); |
31 ASSERT(patch_addr != 0); | 52 ASSERT(patch_addr != 0); |
32 JumpPattern jmp_entry(patch_addr, code); | 53 JumpPattern jmp_entry(patch_addr, code); |
33 ASSERT(!jmp_entry.IsValid()); | 54 ASSERT(!jmp_entry.IsValid()); |
34 const uword patch_buffer = code.GetPatchCodePc(); | 55 const uword patch_buffer = code.GetPatchCodePc(); |
35 ASSERT(patch_buffer != 0); | 56 ASSERT(patch_buffer != 0); |
36 JumpPattern jmp_patch(patch_buffer, code); | 57 JumpPattern jmp_patch(patch_buffer, code); |
37 ASSERT(jmp_patch.IsValid()); | 58 ASSERT(jmp_patch.IsValid()); |
38 const uword jump_target = jmp_patch.TargetAddress(); | 59 const uword jump_target = jmp_patch.TargetAddress(); |
39 SwapCode(jmp_patch.pattern_length_in_bytes(), | 60 intptr_t length = jmp_patch.pattern_length_in_bytes(); |
40 reinterpret_cast<char*>(patch_addr), | 61 { |
41 reinterpret_cast<char*>(patch_buffer)); | 62 WritableInstructionsScope writable_code(patch_addr, length); |
42 jmp_entry.SetTargetAddress(jump_target); | 63 WritableInstructionsScope writable_buffer(patch_buffer, length); |
| 64 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 65 reinterpret_cast<char*>(patch_addr), |
| 66 reinterpret_cast<char*>(patch_buffer)); |
| 67 jmp_entry.SetTargetAddress(jump_target); |
| 68 } |
43 } | 69 } |
44 | 70 |
45 | 71 |
46 // The entry point is a jmp instruction, the patch code buffer contains | 72 // The entry point is a jmp instruction, the patch code buffer contains |
47 // original code, the entry point contains the jump instruction. | 73 // original code, the entry point contains the jump instruction. |
48 void CodePatcher::RestoreEntry(const Code& code) { | 74 void CodePatcher::RestoreEntry(const Code& code) { |
49 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 75 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
50 PcDescriptors::kEntryPatch); | 76 PcDescriptors::kEntryPatch); |
51 ASSERT(patch_addr != 0); | 77 ASSERT(patch_addr != 0); |
52 JumpPattern jmp_entry(patch_addr, code); | 78 JumpPattern jmp_entry(patch_addr, code); |
53 ASSERT(jmp_entry.IsValid()); | 79 ASSERT(jmp_entry.IsValid()); |
54 const uword jump_target = jmp_entry.TargetAddress(); | 80 const uword jump_target = jmp_entry.TargetAddress(); |
55 const uword patch_buffer = code.GetPatchCodePc(); | 81 const uword patch_buffer = code.GetPatchCodePc(); |
56 ASSERT(patch_buffer != 0); | 82 ASSERT(patch_buffer != 0); |
57 // 'patch_buffer' contains original entry code. | 83 // 'patch_buffer' contains original entry code. |
58 JumpPattern jmp_patch(patch_buffer, code); | 84 JumpPattern jmp_patch(patch_buffer, code); |
59 ASSERT(!jmp_patch.IsValid()); | 85 ASSERT(!jmp_patch.IsValid()); |
60 SwapCode(jmp_patch.pattern_length_in_bytes(), | 86 intptr_t length = jmp_patch.pattern_length_in_bytes(); |
61 reinterpret_cast<char*>(patch_addr), | 87 { |
62 reinterpret_cast<char*>(patch_buffer)); | 88 WritableInstructionsScope writable_code(patch_addr, length); |
63 ASSERT(jmp_patch.IsValid()); | 89 WritableInstructionsScope writable_buffer(patch_buffer, length); |
64 jmp_patch.SetTargetAddress(jump_target); | 90 SwapCode(jmp_patch.pattern_length_in_bytes(), |
| 91 reinterpret_cast<char*>(patch_addr), |
| 92 reinterpret_cast<char*>(patch_buffer)); |
| 93 ASSERT(jmp_patch.IsValid()); |
| 94 jmp_patch.SetTargetAddress(jump_target); |
| 95 } |
65 } | 96 } |
66 | 97 |
67 | 98 |
68 bool CodePatcher::CodeIsPatchable(const Code& code) { | 99 bool CodePatcher::CodeIsPatchable(const Code& code) { |
69 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, | 100 const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId, |
70 PcDescriptors::kEntryPatch); | 101 PcDescriptors::kEntryPatch); |
71 // kEntryPatch may not exist which means the function is not patchable. | 102 // kEntryPatch may not exist which means the function is not patchable. |
72 if (patch_addr == 0) { | 103 if (patch_addr == 0) { |
73 return true; | 104 return true; |
74 } | 105 } |
75 JumpPattern jmp_entry(patch_addr, code); | 106 JumpPattern jmp_entry(patch_addr, code); |
76 if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) { | 107 if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) { |
77 return false; | 108 return false; |
78 } | 109 } |
79 const uword limit = patch_addr + jmp_entry.pattern_length_in_bytes(); | 110 const uword limit = patch_addr + jmp_entry.pattern_length_in_bytes(); |
80 // Check no object stored between patch_addr .. limit. | 111 // Check no object stored between patch_addr .. limit. |
81 for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { | 112 for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { |
82 const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint(); | 113 const uword obj_start = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
83 const uword obj_end = obj_start + kWordSize; | 114 const uword obj_end = obj_start + kWordSize; |
84 if ((obj_start < limit) && (obj_end > patch_addr)) { | 115 if ((obj_start < limit) && (obj_end > patch_addr)) { |
85 return false; | 116 return false; |
86 } | 117 } |
87 } | 118 } |
88 return true; | 119 return true; |
89 } | 120 } |
90 | 121 |
91 } // namespace dart | 122 } // namespace dart |
OLD | NEW |