| 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/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/instructions.h" | 13 #include "vm/instructions.h" |
| 14 #include "vm/object.h" | 14 #include "vm/object.h" |
| 15 #include "vm/raw_object.h" | 15 #include "vm/raw_object.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 // The expected pattern of a Dart unoptimized call (static and instance): | 19 // The expected pattern of a Dart unoptimized call (static and instance): |
| 20 // 00: 49 8b 9f imm32 mov RBX, [PP + off] | 20 // 0: 49 8b 9f imm32 mov RBX, [PP + off] |
| 21 // 07: 4d 8b 9f imm32 mov R11, [PP + off] | 21 // 7: 41 ff 97 imm32 call [PP + off] |
| 22 // 14: 41 ff d3 call R11 | 22 // 14 <- return address |
| 23 // 17 <- return address | |
| 24 class UnoptimizedCall : public ValueObject { | 23 class UnoptimizedCall : public ValueObject { |
| 25 public: | 24 public: |
| 26 UnoptimizedCall(uword return_address, const Code& code) | 25 UnoptimizedCall(uword return_address, const Code& code) |
| 27 : start_(return_address - kCallPatternSize), | 26 : start_(return_address - kCallPatternSize), |
| 28 object_pool_(Array::Handle(code.ObjectPool())) { | 27 object_pool_(Array::Handle(code.ObjectPool())) { |
| 29 ASSERT(IsValid(return_address)); | 28 ASSERT(IsValid(return_address)); |
| 30 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); | 29 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); |
| 31 } | 30 } |
| 32 | 31 |
| 33 static const int kCallPatternSize = 17; | 32 static const int kCallPatternSize = 14; |
| 34 | 33 |
| 35 static bool IsValid(uword return_address) { | 34 static bool IsValid(uword return_address) { |
| 36 uint8_t* code_bytes = | 35 uint8_t* code_bytes = |
| 37 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 36 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
| 38 return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) && | 37 return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) && |
| 39 (code_bytes[2] == 0x9F) && | 38 (code_bytes[2] == 0x9F) && |
| 40 (code_bytes[7] == 0x4D) && (code_bytes[8] == 0x8B) && | 39 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && |
| 41 (code_bytes[9] == 0x9F) && | 40 (code_bytes[9] == 0x97); |
| 42 (code_bytes[14] == 0x41) && (code_bytes[15] == 0xFF) && | |
| 43 (code_bytes[16] == 0xD3); | |
| 44 } | 41 } |
| 45 | 42 |
| 46 RawObject* ic_data() const { | 43 RawObject* ic_data() const { |
| 47 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); | 44 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); |
| 48 return object_pool_.At(index); | 45 return object_pool_.At(index); |
| 49 } | 46 } |
| 50 | 47 |
| 51 uword target() const { | 48 uword target() const { |
| 52 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10); | 49 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10); |
| 53 return reinterpret_cast<uword>(object_pool_.At(index)); | 50 return reinterpret_cast<uword>(object_pool_.At(index)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 test_ic_data ^= ic_data(); | 89 test_ic_data ^= ic_data(); |
| 93 ASSERT(test_ic_data.NumArgsTested() >= 0); | 90 ASSERT(test_ic_data.NumArgsTested() >= 0); |
| 94 #endif // DEBUG | 91 #endif // DEBUG |
| 95 } | 92 } |
| 96 | 93 |
| 97 private: | 94 private: |
| 98 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); | 95 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); |
| 99 }; | 96 }; |
| 100 | 97 |
| 101 | 98 |
| 102 // The expected pattern of a dart static call: | |
| 103 // 00 mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls) | |
| 104 // 11: 4d 8b 9f imm32 mov R11, [PP + off] | |
| 105 // 16: call R11 (3 bytes) | |
| 106 // <- return address | |
| 107 class StaticCall : public ValueObject { | |
| 108 public: | |
| 109 explicit StaticCall(uword return_address, const Code& code) | |
| 110 : start_(return_address - kCallPatternSize), | |
| 111 object_pool_(Array::Handle(code.ObjectPool())) { | |
| 112 ASSERT(IsValid(return_address)); | |
| 113 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); | |
| 114 } | |
| 115 | |
| 116 static const int kCallPatternSize = 10; | |
| 117 | |
| 118 static bool IsValid(uword return_address) { | |
| 119 uint8_t* code_bytes = | |
| 120 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | |
| 121 return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) && | |
| 122 (code_bytes[2] == 0x9F) && | |
| 123 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && | |
| 124 (code_bytes[9] == 0xD3); | |
| 125 } | |
| 126 | |
| 127 uword target() const { | |
| 128 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); | |
| 129 return reinterpret_cast<uword>(object_pool_.At(index)); | |
| 130 } | |
| 131 | |
| 132 void set_target(uword target) const { | |
| 133 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); | |
| 134 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); | |
| 135 object_pool_.SetAt(index, smi); | |
| 136 // No need to flush the instruction cache, since the code is not modified. | |
| 137 } | |
| 138 | |
| 139 private: | |
| 140 uword start_; | |
| 141 const Array& object_pool_; | |
| 142 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); | |
| 143 }; | |
| 144 | |
| 145 | |
| 146 // The expected pattern of a call where the target is loaded from | 99 // The expected pattern of a call where the target is loaded from |
| 147 // the object pool: | 100 // the object pool: |
| 148 // 00: 4d 8b 9f imm32 mov R11, [PP + off] | 101 // 0: 41 ff 97 imm32 call [PP + off] |
| 149 // 07: 41 ff d3 call R11 | 102 // 7: <- return address |
| 150 // 10 <- return address | |
| 151 class PoolPointerCall : public ValueObject { | 103 class PoolPointerCall : public ValueObject { |
| 152 public: | 104 public: |
| 153 explicit PoolPointerCall(uword return_address) | 105 explicit PoolPointerCall(uword return_address) |
| 154 : start_(return_address - kCallPatternSize) { | 106 : start_(return_address - kCallPatternSize) { |
| 155 ASSERT(IsValid(return_address)); | 107 ASSERT(IsValid(return_address)); |
| 156 } | 108 } |
| 157 | 109 |
| 110 static const int kCallPatternSize = 7; |
| 111 |
| 158 static bool IsValid(uword return_address) { | 112 static bool IsValid(uword return_address) { |
| 159 uint8_t* code_bytes = | 113 uint8_t* code_bytes = |
| 160 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 114 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
| 161 return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) && | 115 return (code_bytes[0] == 0x41) && (code_bytes[1] == 0xFF) && |
| 162 (code_bytes[2] == 0x9F) && | 116 (code_bytes[2] == 0x97); |
| 163 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && | |
| 164 (code_bytes[9] == 0xD3); | |
| 165 } | 117 } |
| 166 | 118 |
| 167 int32_t pp_offset() const { | 119 int32_t pp_offset() const { |
| 168 return *reinterpret_cast<int32_t*>(start_ + 3); | 120 return *reinterpret_cast<int32_t*>(start_ + 3); |
| 169 } | 121 } |
| 170 | 122 |
| 171 void set_pp_offset(int32_t offset) const { | 123 void set_pp_offset(int32_t offset) const { |
| 172 *reinterpret_cast<int32_t*>(start_ + 3) = offset; | 124 *reinterpret_cast<int32_t*>(start_ + 3) = offset; |
| 173 CPU::FlushICache(start_, kCallPatternSize); | 125 CPU::FlushICache(start_, kCallPatternSize); |
| 174 } | 126 } |
| 175 | 127 |
| 128 protected: |
| 129 uword start_; |
| 130 |
| 176 private: | 131 private: |
| 177 static const int kCallPatternSize = 7 + 3; | |
| 178 uword start_; | |
| 179 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall); | 132 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall); |
| 180 }; | 133 }; |
| 181 | 134 |
| 182 | 135 |
| 183 // The expected code pattern of a Dart closure call: | 136 // The expected pattern of a dart static call: |
| 184 // 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes | 137 // 0: 41 ff 97 imm32 call [PP + off] |
| 185 // 10: 4d 8b 9f imm32 mov R11, [PP + off] | 138 // 7: <- return address |
| 186 // 17: 41 ff d3 call R11 ; 3 bytes | 139 class StaticCall : public PoolPointerCall { |
| 187 // 20: <- return_address | |
| 188 class ClosureCall : public ValueObject { | |
| 189 public: | 140 public: |
| 190 explicit ClosureCall(uword return_address) | 141 StaticCall(uword return_address, const Code& code) |
| 191 : start_(return_address - kCallPatternSize) { | 142 : PoolPointerCall(return_address), |
| 143 object_pool_(Array::Handle(code.ObjectPool())) { |
| 192 ASSERT(IsValid(return_address)); | 144 ASSERT(IsValid(return_address)); |
| 145 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); |
| 193 } | 146 } |
| 194 | 147 |
| 195 static bool IsValid(uword return_address) { | 148 uword target() const { |
| 196 uint8_t* code_bytes = | 149 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); |
| 197 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 150 return reinterpret_cast<uword>(object_pool_.At(index)); |
| 198 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) && | |
| 199 (code_bytes[10] == 0x4D) && (code_bytes[11] == 0x8B) && | |
| 200 (code_bytes[12] == 0x9F) && | |
| 201 (code_bytes[17] == 0x41) && (code_bytes[18] == 0xFF) && | |
| 202 (code_bytes[19] == 0xD3); | |
| 203 } | 151 } |
| 204 | 152 |
| 205 RawArray* arguments_descriptor() const { | 153 void set_target(uword target) const { |
| 206 return *reinterpret_cast<RawArray**>(start_ + 2); | 154 intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); |
| 155 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); |
| 156 object_pool_.SetAt(index, smi); |
| 157 // No need to flush the instruction cache, since the code is not modified. |
| 207 } | 158 } |
| 208 | 159 |
| 209 private: | 160 private: |
| 210 static const int kCallPatternSize = 10 + 7 + 3; | 161 const Array& object_pool_; |
| 211 uword start_; | 162 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); |
| 212 DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall); | |
| 213 }; | 163 }; |
| 214 | 164 |
| 215 | 165 |
| 216 RawArray* CodePatcher::GetClosureArgDescAt(uword return_address, | |
| 217 const Code& code) { | |
| 218 ASSERT(code.ContainsInstructionAt(return_address)); | |
| 219 ClosureCall call(return_address); | |
| 220 return call.arguments_descriptor(); | |
| 221 } | |
| 222 | |
| 223 | |
| 224 uword CodePatcher::GetStaticCallTargetAt(uword return_address, | 166 uword CodePatcher::GetStaticCallTargetAt(uword return_address, |
| 225 const Code& code) { | 167 const Code& code) { |
| 226 ASSERT(code.ContainsInstructionAt(return_address)); | 168 ASSERT(code.ContainsInstructionAt(return_address)); |
| 227 StaticCall call(return_address, code); | 169 StaticCall call(return_address, code); |
| 228 return call.target(); | 170 return call.target(); |
| 229 } | 171 } |
| 230 | 172 |
| 231 | 173 |
| 232 void CodePatcher::PatchStaticCallAt(uword return_address, | 174 void CodePatcher::PatchStaticCallAt(uword return_address, |
| 233 const Code& code, | 175 const Code& code, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 | 268 |
| 327 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { | 269 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { |
| 328 ASSERT(code.ContainsInstructionAt(pc)); | 270 ASSERT(code.ContainsInstructionAt(pc)); |
| 329 EdgeCounter counter(pc, code); | 271 EdgeCounter counter(pc, code); |
| 330 return counter.edge_counter(); | 272 return counter.edge_counter(); |
| 331 } | 273 } |
| 332 | 274 |
| 333 } // namespace dart | 275 } // namespace dart |
| 334 | 276 |
| 335 #endif // defined TARGET_ARCH_X64 | 277 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |