| 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/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/instructions.h" | 12 #include "vm/instructions.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 #include "vm/raw_object.h" | 14 #include "vm/raw_object.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 // The expected pattern of a Dart unoptimized call (static and instance): | 18 // The expected pattern of a Dart unoptimized call (static and instance): |
| 19 // 00: 48 bb imm64 mov RBX, ic-data | 19 // 00: 49 8b 9f imm32 mov RBX, [PP + off] |
| 20 // 10: 49 bb imm64 mov R11, target_address | 20 // OR: |
| 21 // 20: 41 ff d3 call R11 | 21 // 00: 49 8b 5f imm8 mov RBX, [PP + off] |
| 22 // 23 <- return address | 22 // 04: 0f 1f 00 nop |
| 23 // Then: |
| 24 // 07: 4d 8b 9f imm32 mov R11, [PP + off] |
| 25 // OR: |
| 26 // 07: 4d 8b 5f imm8 mov R11, [PP + off] |
| 27 // 11: 0f 1f 00 nop |
| 28 // Then: |
| 29 // 14: 41 ff d3 call R11 |
| 30 // 17 <- return address |
| 23 class UnoptimizedCall : public ValueObject { | 31 class UnoptimizedCall : public ValueObject { |
| 24 public: | 32 public: |
| 25 explicit UnoptimizedCall(uword return_address) | 33 UnoptimizedCall(uword return_address, const Code& code) |
| 26 : start_(return_address - kCallPatternSize) { | 34 : start_(return_address - kCallPatternSize), |
| 35 object_pool_(Array::Handle(code.ObjectPool())) { |
| 27 ASSERT(IsValid(return_address)); | 36 ASSERT(IsValid(return_address)); |
| 28 ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize); | 37 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); |
| 29 } | 38 } |
| 30 | 39 |
| 31 static const int kCallPatternSize = 23; | 40 static const int kCallPatternSize = 17; |
| 32 | 41 |
| 33 static bool IsValid(uword return_address) { | 42 static bool IsValid(uword return_address) { |
| 34 uint8_t* code_bytes = | 43 uint8_t* code_bytes = |
| 35 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 44 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
| 36 return (code_bytes[00] == 0x48) && (code_bytes[01] == 0xBB) && | 45 return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) && |
| 37 (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) && | 46 ((code_bytes[2] == 0x5F) || (code_bytes[2] == 0x9F)) && |
| 38 (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) && | 47 (code_bytes[7] == 0x4D) && (code_bytes[8] == 0x8B) && |
| 39 (code_bytes[22] == 0xD3); | 48 ((code_bytes[9] == 0x5F) || (code_bytes[9] == 0x9F)) && |
| 49 (code_bytes[14] == 0x41) && (code_bytes[15] == 0xFF) && |
| 50 (code_bytes[16] == 0xD3); |
| 40 } | 51 } |
| 41 | 52 |
| 42 RawObject* ic_data() const { | 53 RawObject* ic_data() const { |
| 43 return *reinterpret_cast<RawObject**>(start_ + 0 + 2); | 54 int index = InstructionPattern::IndexFromPPLoad(start_ + 2); |
| 55 return object_pool_.At(index); |
| 44 } | 56 } |
| 45 | 57 |
| 46 uword target() const { | 58 uword target() const { |
| 47 return *reinterpret_cast<uword*>(start_ + 10 + 2); | 59 int index = InstructionPattern::IndexFromPPLoad(start_ + 9); |
| 60 return reinterpret_cast<uword>(object_pool_.At(index)); |
| 48 } | 61 } |
| 49 | 62 |
| 50 void set_target(uword target) const { | 63 void set_target(uword target) const { |
| 51 uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2); | 64 int index = InstructionPattern::IndexFromPPLoad(start_ + 9); |
| 52 *target_addr = target; | 65 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); |
| 53 CPU::FlushICache(start_ + 10, 2 + 8); | 66 object_pool_.SetAt(index, smi); |
| 67 // No need to flush the instruction cache, since the code is not modified. |
| 54 } | 68 } |
| 55 | 69 |
| 56 private: | 70 private: |
| 57 uword start_; | 71 uword start_; |
| 72 const Array& object_pool_; |
| 58 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); | 73 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); |
| 59 }; | 74 }; |
| 60 | 75 |
| 61 | 76 |
| 62 class InstanceCall : public UnoptimizedCall { | 77 class InstanceCall : public UnoptimizedCall { |
| 63 public: | 78 public: |
| 64 explicit InstanceCall(uword return_address) | 79 InstanceCall(uword return_address, const Code& code) |
| 65 : UnoptimizedCall(return_address) { | 80 : UnoptimizedCall(return_address, code) { |
| 66 #if defined(DEBUG) | 81 #if defined(DEBUG) |
| 67 ICData& test_ic_data = ICData::Handle(); | 82 ICData& test_ic_data = ICData::Handle(); |
| 68 test_ic_data ^= ic_data(); | 83 test_ic_data ^= ic_data(); |
| 69 ASSERT(test_ic_data.num_args_tested() > 0); | 84 ASSERT(test_ic_data.num_args_tested() > 0); |
| 70 #endif // DEBUG | 85 #endif // DEBUG |
| 71 } | 86 } |
| 72 | 87 |
| 73 private: | 88 private: |
| 74 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall); | 89 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall); |
| 75 }; | 90 }; |
| 76 | 91 |
| 77 | 92 |
| 78 class UnoptimizedStaticCall : public UnoptimizedCall { | 93 class UnoptimizedStaticCall : public UnoptimizedCall { |
| 79 public: | 94 public: |
| 80 explicit UnoptimizedStaticCall(uword return_address) | 95 UnoptimizedStaticCall(uword return_address, const Code& code) |
| 81 : UnoptimizedCall(return_address) { | 96 : UnoptimizedCall(return_address, code) { |
| 82 #if defined(DEBUG) | 97 #if defined(DEBUG) |
| 83 ICData& test_ic_data = ICData::Handle(); | 98 ICData& test_ic_data = ICData::Handle(); |
| 84 test_ic_data ^= ic_data(); | 99 test_ic_data ^= ic_data(); |
| 85 ASSERT(test_ic_data.num_args_tested() >= 0); | 100 ASSERT(test_ic_data.num_args_tested() >= 0); |
| 86 #endif // DEBUG | 101 #endif // DEBUG |
| 87 } | 102 } |
| 88 | 103 |
| 89 private: | 104 private: |
| 90 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); | 105 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); |
| 91 }; | 106 }; |
| 92 | 107 |
| 93 | 108 |
| 94 // The expected pattern of a dart static call: | 109 // The expected pattern of a dart static call: |
| 95 // mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls) | 110 // 00 mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls) |
| 96 // mov R11, target_address (10 bytes) | 111 // 11: 4d 8b 9f imm32 mov R11, [PP + off] |
| 97 // call R11 (3 bytes) | 112 // OR: |
| 113 // 11: 4d 8b 5f imm8 mov R11, [PP + off] |
| 114 // 15: 0f 1f 00 nop |
| 115 // Then: |
| 116 // 16: call R11 (3 bytes) |
| 98 // <- return address | 117 // <- return address |
| 99 class StaticCall : public ValueObject { | 118 class StaticCall : public ValueObject { |
| 100 public: | 119 public: |
| 101 explicit StaticCall(uword return_address) | 120 explicit StaticCall(uword return_address, const Code& code) |
| 102 : start_(return_address - kCallPatternSize) { | 121 : start_(return_address - kCallPatternSize), |
| 122 object_pool_(Array::Handle(code.ObjectPool())) { |
| 103 ASSERT(IsValid(return_address)); | 123 ASSERT(IsValid(return_address)); |
| 104 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); | 124 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); |
| 105 } | 125 } |
| 106 | 126 |
| 107 static const int kCallPatternSize = 13; | 127 static const int kCallPatternSize = 10; |
| 108 | 128 |
| 109 static bool IsValid(uword return_address) { | 129 static bool IsValid(uword return_address) { |
| 110 uint8_t* code_bytes = | 130 uint8_t* code_bytes = |
| 111 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 131 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
| 112 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBB) && | 132 return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) && |
| 113 (code_bytes[10] == 0x41) && (code_bytes[11] == 0xFF) && | 133 ((code_bytes[2] == 0x5F) || (code_bytes[2] == 0x9F)) && |
| 114 (code_bytes[12] == 0xD3); | 134 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && |
| 135 (code_bytes[9] == 0xD3); |
| 115 } | 136 } |
| 116 | 137 |
| 117 uword target() const { | 138 uword target() const { |
| 118 return *reinterpret_cast<uword*>(start_ + 2); | 139 int index = InstructionPattern::IndexFromPPLoad(start_ + 2); |
| 140 return reinterpret_cast<uword>(object_pool_.At(index)); |
| 119 } | 141 } |
| 120 | 142 |
| 121 void set_target(uword target) const { | 143 void set_target(uword target) const { |
| 122 uword* target_addr = reinterpret_cast<uword*>(start_ + 2); | 144 int index = InstructionPattern::IndexFromPPLoad(start_ + 2); |
| 123 *target_addr = target; | 145 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); |
| 124 CPU::FlushICache(start_, 2 + 8); | 146 object_pool_.SetAt(index, smi); |
| 147 // No need to flush the instruction cache, since the code is not modified. |
| 125 } | 148 } |
| 126 | 149 |
| 127 private: | 150 private: |
| 128 uword start_; | 151 uword start_; |
| 129 | 152 const Array& object_pool_; |
| 130 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); | 153 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); |
| 131 }; | 154 }; |
| 132 | 155 |
| 133 | 156 |
| 134 // The expected code pattern of a dart closure call: | 157 // The expected code pattern of a dart closure call: |
| 135 // 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes | 158 // 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes |
| 136 // 10: 49 bb imm64 mov R11, target_address ; 10 bytes | 159 // 10: 4d 8b 9f imm32 mov R11, [PP + off] |
| 137 // 20: 41 ff d3 call R11 ; 3 bytes | 160 // OR: |
| 138 // 23: <- return_address | 161 // 10: 4d 8b 5f imm8 mov R11, [PP + off] |
| 162 // 14: 0f 1f 00 nop |
| 163 // Then: |
| 164 // 17: 41 ff d3 call R11 ; 3 bytes |
| 165 // 20: <- return_address |
| 139 class ClosureCall : public ValueObject { | 166 class ClosureCall : public ValueObject { |
| 140 public: | 167 public: |
| 141 explicit ClosureCall(uword return_address) | 168 explicit ClosureCall(uword return_address) |
| 142 : start_(return_address - kCallPatternSize) { | 169 : start_(return_address - kCallPatternSize) { |
| 143 ASSERT(IsValid(return_address)); | 170 ASSERT(IsValid(return_address)); |
| 144 } | 171 } |
| 145 | 172 |
| 146 static bool IsValid(uword return_address) { | 173 static bool IsValid(uword return_address) { |
| 147 uint8_t* code_bytes = | 174 uint8_t* code_bytes = |
| 148 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 175 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
| 149 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) && | 176 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) && |
| 150 (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) && | 177 (code_bytes[10] == 0x4D) && (code_bytes[11] == 0x8B) && |
| 151 (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) && | 178 ((code_bytes[12] == 0x5F) || (code_bytes[12] == 0x9F)) && |
| 152 (code_bytes[22] == 0xD3); | 179 (code_bytes[17] == 0x41) && (code_bytes[18] == 0xFF) && |
| 180 (code_bytes[19] == 0xD3); |
| 153 } | 181 } |
| 154 | 182 |
| 155 RawArray* arguments_descriptor() const { | 183 RawArray* arguments_descriptor() const { |
| 156 return *reinterpret_cast<RawArray**>(start_ + 2); | 184 return *reinterpret_cast<RawArray**>(start_ + 2); |
| 157 } | 185 } |
| 158 | 186 |
| 159 private: | 187 private: |
| 160 static const int kCallPatternSize = 10 + 10 + 3; | 188 static const int kCallPatternSize = 10 + 7 + 3; |
| 161 uword start_; | 189 uword start_; |
| 162 DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall); | 190 DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall); |
| 163 }; | 191 }; |
| 164 | 192 |
| 165 | 193 |
| 166 RawArray* CodePatcher::GetClosureArgDescAt(uword return_address, | 194 RawArray* CodePatcher::GetClosureArgDescAt(uword return_address, |
| 167 const Code& code) { | 195 const Code& code) { |
| 168 ASSERT(code.ContainsInstructionAt(return_address)); | 196 ASSERT(code.ContainsInstructionAt(return_address)); |
| 169 ClosureCall call(return_address); | 197 ClosureCall call(return_address); |
| 170 return call.arguments_descriptor(); | 198 return call.arguments_descriptor(); |
| 171 } | 199 } |
| 172 | 200 |
| 173 | 201 |
| 174 uword CodePatcher::GetStaticCallTargetAt(uword return_address, | 202 uword CodePatcher::GetStaticCallTargetAt(uword return_address, |
| 175 const Code& code) { | 203 const Code& code) { |
| 176 ASSERT(code.ContainsInstructionAt(return_address)); | 204 ASSERT(code.ContainsInstructionAt(return_address)); |
| 177 StaticCall call(return_address); | 205 StaticCall call(return_address, code); |
| 178 return call.target(); | 206 return call.target(); |
| 179 } | 207 } |
| 180 | 208 |
| 181 | 209 |
| 182 void CodePatcher::PatchStaticCallAt(uword return_address, | 210 void CodePatcher::PatchStaticCallAt(uword return_address, |
| 183 const Code& code, | 211 const Code& code, |
| 184 uword new_target) { | 212 uword new_target) { |
| 185 ASSERT(code.ContainsInstructionAt(return_address)); | 213 ASSERT(code.ContainsInstructionAt(return_address)); |
| 186 StaticCall call(return_address); | 214 StaticCall call(return_address, code); |
| 187 call.set_target(new_target); | 215 call.set_target(new_target); |
| 188 } | 216 } |
| 189 | 217 |
| 190 | 218 |
| 191 void CodePatcher::PatchInstanceCallAt(uword return_address, | 219 void CodePatcher::PatchInstanceCallAt(uword return_address, |
| 192 const Code& code, | 220 const Code& code, |
| 193 uword new_target) { | 221 uword new_target) { |
| 194 ASSERT(code.ContainsInstructionAt(return_address)); | 222 ASSERT(code.ContainsInstructionAt(return_address)); |
| 195 InstanceCall call(return_address); | 223 InstanceCall call(return_address, code); |
| 196 call.set_target(new_target); | 224 call.set_target(new_target); |
| 197 } | 225 } |
| 198 | 226 |
| 199 | 227 |
| 200 uword CodePatcher::GetInstanceCallAt(uword return_address, | 228 uword CodePatcher::GetInstanceCallAt(uword return_address, |
| 201 const Code& code, | 229 const Code& code, |
| 202 ICData* ic_data) { | 230 ICData* ic_data) { |
| 203 ASSERT(code.ContainsInstructionAt(return_address)); | 231 ASSERT(code.ContainsInstructionAt(return_address)); |
| 204 InstanceCall call(return_address); | 232 InstanceCall call(return_address, code); |
| 205 if (ic_data != NULL) { | 233 if (ic_data != NULL) { |
| 206 *ic_data ^= call.ic_data(); | 234 *ic_data ^= call.ic_data(); |
| 207 } | 235 } |
| 208 return call.target(); | 236 return call.target(); |
| 209 } | 237 } |
| 210 | 238 |
| 211 | 239 |
| 212 intptr_t CodePatcher::InstanceCallSizeInBytes() { | 240 intptr_t CodePatcher::InstanceCallSizeInBytes() { |
| 213 return InstanceCall::kCallPatternSize; | 241 return InstanceCall::kCallPatternSize; |
| 214 } | 242 } |
| 215 | 243 |
| 216 | 244 |
| 217 void CodePatcher::InsertCallAt(uword start, uword target) { | 245 void CodePatcher::InsertCallAt(uword start, uword target) { |
| 218 // The inserted call should not overlap the lazy deopt jump code. | 246 // The inserted call should not overlap the lazy deopt jump code. |
| 219 ASSERT(start + ShortCallPattern::InstructionLength() <= target); | 247 ASSERT(start + ShortCallPattern::InstructionLength() <= target); |
| 220 *reinterpret_cast<uint8_t*>(start) = 0xE8; | 248 *reinterpret_cast<uint8_t*>(start) = 0xE8; |
| 221 ShortCallPattern call(start); | 249 ShortCallPattern call(start); |
| 222 call.SetTargetAddress(target); | 250 call.SetTargetAddress(target); |
| 223 CPU::FlushICache(start, ShortCallPattern::InstructionLength()); | 251 CPU::FlushICache(start, ShortCallPattern::InstructionLength()); |
| 224 } | 252 } |
| 225 | 253 |
| 226 | 254 |
| 227 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( | 255 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( |
| 228 uword return_address, const Code& code, ICData* ic_data_result) { | 256 uword return_address, const Code& code, ICData* ic_data_result) { |
| 229 ASSERT(code.ContainsInstructionAt(return_address)); | 257 ASSERT(code.ContainsInstructionAt(return_address)); |
| 230 UnoptimizedStaticCall static_call(return_address); | 258 UnoptimizedStaticCall static_call(return_address, code); |
| 231 ICData& ic_data = ICData::Handle(); | 259 ICData& ic_data = ICData::Handle(); |
| 232 ic_data ^= static_call.ic_data(); | 260 ic_data ^= static_call.ic_data(); |
| 233 if (ic_data_result != NULL) { | 261 if (ic_data_result != NULL) { |
| 234 *ic_data_result = ic_data.raw(); | 262 *ic_data_result = ic_data.raw(); |
| 235 } | 263 } |
| 236 return ic_data.GetTargetAt(0); | 264 return ic_data.GetTargetAt(0); |
| 237 } | 265 } |
| 238 | 266 |
| 239 } // namespace dart | 267 } // namespace dart |
| 240 | 268 |
| 241 #endif // defined TARGET_ARCH_X64 | 269 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |