| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 // mov ECX, ic-data | 20 // mov ECX, ic-data |
| 21 // mov EDI, target-code-object |
| 21 // call target_address (stub) | 22 // call target_address (stub) |
| 22 // <- return address | 23 // <- return address |
| 23 class UnoptimizedCall : public ValueObject { | 24 class UnoptimizedCall : public ValueObject { |
| 24 public: | 25 public: |
| 25 explicit UnoptimizedCall(uword return_address) | 26 explicit UnoptimizedCall(uword return_address) |
| 26 : start_(return_address - (kNumInstructions * kInstructionSize)) { | 27 : start_(return_address - kPatternSize) { |
| 27 ASSERT(IsValid(return_address)); | 28 ASSERT(IsValid()); |
| 28 ASSERT(kInstructionSize == Assembler::kCallExternalLabelSize); | |
| 29 } | |
| 30 | |
| 31 static bool IsValid(uword return_address) { | |
| 32 uint8_t* code_bytes = | |
| 33 reinterpret_cast<uint8_t*>( | |
| 34 return_address - (kNumInstructions * kInstructionSize)); | |
| 35 return (code_bytes[0] == 0xB9) && | |
| 36 (code_bytes[1 * kInstructionSize] == 0xE8); | |
| 37 } | |
| 38 | |
| 39 uword target() const { | |
| 40 const uword offset = *reinterpret_cast<uword*>(call_address() + 1); | |
| 41 return return_address() + offset; | |
| 42 } | |
| 43 | |
| 44 void set_target(uword target) const { | |
| 45 uword* target_addr = reinterpret_cast<uword*>(call_address() + 1); | |
| 46 uword offset = target - return_address(); | |
| 47 WritableInstructionsScope writable(reinterpret_cast<uword>(target_addr), | |
| 48 sizeof(offset)); | |
| 49 *target_addr = offset; | |
| 50 CPU::FlushICache(call_address(), kInstructionSize); | |
| 51 } | 29 } |
| 52 | 30 |
| 53 RawObject* ic_data() const { | 31 RawObject* ic_data() const { |
| 54 return *reinterpret_cast<RawObject**>(start_ + 1); | 32 return *reinterpret_cast<RawObject**>(start_ + 1); |
| 55 } | 33 } |
| 56 | 34 |
| 57 static const int kNumInstructions = 2; | 35 static const int kMovInstructionSize = 5; |
| 58 static const int kInstructionSize = 5; // All instructions have same length. | 36 static const int kCallInstructionSize = 3; |
| 37 static const int kPatternSize = |
| 38 2 * kMovInstructionSize + kCallInstructionSize; |
| 59 | 39 |
| 60 private: | 40 private: |
| 41 bool IsValid() { |
| 42 uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_); |
| 43 return (code_bytes[0] == 0xB9) && |
| 44 (code_bytes[2 * kMovInstructionSize] == 0xFF); |
| 45 } |
| 46 |
| 61 uword return_address() const { | 47 uword return_address() const { |
| 62 return start_ + kNumInstructions * kInstructionSize; | 48 return start_ + kPatternSize; |
| 63 } | 49 } |
| 64 | 50 |
| 65 uword call_address() const { | 51 uword call_address() const { |
| 66 return start_ + 1 * kInstructionSize; | 52 return start_ + 2 * kMovInstructionSize; |
| 67 } | 53 } |
| 68 | 54 |
| 69 protected: | 55 protected: |
| 70 uword start_; | 56 uword start_; |
| 71 | 57 |
| 72 private: | 58 private: |
| 73 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); | 59 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); |
| 74 }; | 60 }; |
| 75 | 61 |
| 76 | 62 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 #endif // DEBUG | 106 #endif // DEBUG |
| 121 } | 107 } |
| 122 | 108 |
| 123 private: | 109 private: |
| 124 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); | 110 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); |
| 125 }; | 111 }; |
| 126 | 112 |
| 127 | 113 |
| 128 // The expected pattern of a dart static call: | 114 // The expected pattern of a dart static call: |
| 129 // mov EDX, arguments_descriptor_array (optional in polymorphic calls) | 115 // mov EDX, arguments_descriptor_array (optional in polymorphic calls) |
| 130 // call target_address | 116 // mov EDI, Immediate(code_object) |
| 117 // call [EDI + entry_point_offset] |
| 131 // <- return address | 118 // <- return address |
| 132 class StaticCall : public ValueObject { | 119 class StaticCall : public ValueObject { |
| 133 public: | 120 public: |
| 134 explicit StaticCall(uword return_address) | 121 explicit StaticCall(uword return_address) |
| 135 : start_(return_address - (kNumInstructions * kInstructionSize)) { | 122 : start_(return_address - (kMovInstructionSize + kCallInstructionSize)) { |
| 136 ASSERT(IsValid(return_address)); | 123 ASSERT(IsValid()); |
| 137 ASSERT(kInstructionSize == Assembler::kCallExternalLabelSize); | |
| 138 } | 124 } |
| 139 | 125 |
| 140 static bool IsValid(uword return_address) { | 126 bool IsValid() { |
| 141 uint8_t* code_bytes = | 127 uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_); |
| 142 reinterpret_cast<uint8_t*>( | 128 return (code_bytes[0] == 0xBF) && (code_bytes[5] == 0xFF); |
| 143 return_address - (kNumInstructions * kInstructionSize)); | |
| 144 return (code_bytes[0] == 0xE8); | |
| 145 } | 129 } |
| 146 | 130 |
| 147 uword target() const { | 131 RawCode* target() const { |
| 148 const uword offset = *reinterpret_cast<uword*>(call_address() + 1); | 132 const uword imm = *reinterpret_cast<uword*>(start_ + 1); |
| 149 return return_address() + offset; | 133 return reinterpret_cast<RawCode*>(imm); |
| 150 } | 134 } |
| 151 | 135 |
| 152 void set_target(uword target) const { | 136 void set_target(const Code& target) const { |
| 153 uword* target_addr = reinterpret_cast<uword*>(call_address() + 1); | 137 uword* target_addr = reinterpret_cast<uword*>(start_ + 1); |
| 154 uword offset = target - return_address(); | 138 uword imm = reinterpret_cast<uword>(target.raw()); |
| 155 *target_addr = offset; | 139 *target_addr = imm; |
| 156 CPU::FlushICache(call_address(), kInstructionSize); | 140 CPU::FlushICache(start_ + 1, sizeof(imm)); |
| 157 } | 141 } |
| 158 | 142 |
| 159 static const int kNumInstructions = 1; | 143 static const int kMovInstructionSize = 5; |
| 160 static const int kInstructionSize = 5; // All instructions have same length. | 144 static const int kCallInstructionSize = 3; |
| 161 | 145 |
| 162 private: | 146 private: |
| 163 uword return_address() const { | 147 uword return_address() const { |
| 164 return start_ + kNumInstructions * kInstructionSize; | 148 return start_ + kMovInstructionSize + kCallInstructionSize; |
| 165 } | 149 } |
| 166 | 150 |
| 167 uword call_address() const { | 151 uword call_address() const { |
| 168 return start_; | 152 return start_ + kMovInstructionSize; |
| 169 } | 153 } |
| 170 | 154 |
| 171 uword start_; | 155 uword start_; |
| 172 | 156 |
| 173 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); | 157 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); |
| 174 }; | 158 }; |
| 175 | 159 |
| 176 | 160 |
| 177 uword CodePatcher::GetStaticCallTargetAt(uword return_address, | 161 RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address, |
| 178 const Code& code) { | 162 const Code& code) { |
| 179 ASSERT(code.ContainsInstructionAt(return_address)); | 163 ASSERT(code.ContainsInstructionAt(return_address)); |
| 180 StaticCall call(return_address); | 164 StaticCall call(return_address); |
| 181 return call.target(); | 165 return call.target(); |
| 182 } | 166 } |
| 183 | 167 |
| 184 | 168 |
| 185 void CodePatcher::PatchStaticCallAt(uword return_address, | 169 void CodePatcher::PatchStaticCallAt(uword return_address, |
| 186 const Code& code, | 170 const Code& code, |
| 187 uword new_target) { | 171 const Code& new_target) { |
| 172 const Instructions& instrs = Instructions::Handle(code.instructions()); |
| 173 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
| 188 ASSERT(code.ContainsInstructionAt(return_address)); | 174 ASSERT(code.ContainsInstructionAt(return_address)); |
| 189 StaticCall call(return_address); | 175 StaticCall call(return_address); |
| 190 call.set_target(new_target); | 176 call.set_target(new_target); |
| 191 } | 177 } |
| 192 | 178 |
| 193 | 179 |
| 194 void CodePatcher::PatchInstanceCallAt(uword return_address, | 180 void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) { |
| 195 const Code& code, | |
| 196 uword new_target) { | |
| 197 ASSERT(code.ContainsInstructionAt(return_address)); | |
| 198 InstanceCall call(return_address); | |
| 199 call.set_target(new_target); | |
| 200 } | |
| 201 | |
| 202 | |
| 203 void CodePatcher::InsertCallAt(uword start, uword target) { | |
| 204 // The inserted call should not overlap the lazy deopt jump code. | 181 // The inserted call should not overlap the lazy deopt jump code. |
| 205 ASSERT(start + CallPattern::pattern_length_in_bytes() <= target); | 182 ASSERT(start + CallPattern::pattern_length_in_bytes() <= target); |
| 206 *reinterpret_cast<uint8_t*>(start) = 0xE8; | 183 *reinterpret_cast<uint8_t*>(start) = 0xE8; |
| 207 CallPattern call(start); | 184 CallPattern call(start); |
| 208 call.SetTargetAddress(target); | 185 call.SetTargetAddress(target); |
| 209 CPU::FlushICache(start, CallPattern::pattern_length_in_bytes()); | 186 CPU::FlushICache(start, CallPattern::pattern_length_in_bytes()); |
| 210 } | 187 } |
| 211 | 188 |
| 212 | 189 |
| 213 uword CodePatcher::GetInstanceCallAt( | 190 RawCode* CodePatcher::GetInstanceCallAt( |
| 214 uword return_address, const Code& code, ICData* ic_data) { | 191 uword return_address, const Code& code, ICData* ic_data) { |
| 215 ASSERT(code.ContainsInstructionAt(return_address)); | 192 ASSERT(code.ContainsInstructionAt(return_address)); |
| 216 InstanceCall call(return_address); | 193 InstanceCall call(return_address); |
| 217 if (ic_data != NULL) { | 194 if (ic_data != NULL) { |
| 218 *ic_data ^= call.ic_data(); | 195 *ic_data ^= call.ic_data(); |
| 219 } | 196 } |
| 220 return call.target(); | 197 return Code::null(); |
| 221 } | 198 } |
| 222 | 199 |
| 223 | 200 |
| 224 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( | 201 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( |
| 225 uword return_address, const Code& code, ICData* ic_data_result) { | 202 uword return_address, const Code& code, ICData* ic_data_result) { |
| 226 ASSERT(code.ContainsInstructionAt(return_address)); | 203 ASSERT(code.ContainsInstructionAt(return_address)); |
| 227 UnoptimizedStaticCall static_call(return_address); | 204 UnoptimizedStaticCall static_call(return_address); |
| 228 ICData& ic_data = ICData::Handle(); | 205 ICData& ic_data = ICData::Handle(); |
| 229 ic_data ^= static_call.ic_data(); | 206 ic_data ^= static_call.ic_data(); |
| 230 if (ic_data_result != NULL) { | 207 if (ic_data_result != NULL) { |
| 231 *ic_data_result = ic_data.raw(); | 208 *ic_data_result = ic_data.raw(); |
| 232 } | 209 } |
| 233 return ic_data.GetTargetAt(0); | 210 return ic_data.GetTargetAt(0); |
| 234 } | 211 } |
| 235 | 212 |
| 236 | 213 |
| 237 void CodePatcher::PatchNativeCallAt(uword return_address, | 214 void CodePatcher::PatchNativeCallAt(uword return_address, |
| 238 const Code& code, | 215 const Code& code, |
| 239 NativeFunction target, | 216 NativeFunction target, |
| 240 const Code& trampoline) { | 217 const Code& trampoline) { |
| 241 ASSERT(code.ContainsInstructionAt(return_address)); | 218 UNREACHABLE(); |
| 242 NativeCall call(return_address); | |
| 243 call.set_target(trampoline.EntryPoint()); | |
| 244 call.set_native_function(target); | |
| 245 } | 219 } |
| 246 | 220 |
| 247 | 221 |
| 248 uword CodePatcher::GetNativeCallAt(uword return_address, | 222 RawCode* CodePatcher::GetNativeCallAt(uword return_address, |
| 249 const Code& code, | 223 const Code& code, |
| 250 NativeFunction* target) { | 224 NativeFunction* target) { |
| 251 ASSERT(code.ContainsInstructionAt(return_address)); | 225 UNREACHABLE(); |
| 252 NativeCall call(return_address); | 226 return NULL; |
| 253 *target = call.native_function(); | |
| 254 return call.target(); | |
| 255 } | 227 } |
| 256 | 228 |
| 257 | 229 |
| 258 | 230 |
| 259 intptr_t CodePatcher::InstanceCallSizeInBytes() { | 231 intptr_t CodePatcher::InstanceCallSizeInBytes() { |
| 260 return InstanceCall::kNumInstructions * InstanceCall::kInstructionSize; | 232 return InstanceCall::kPatternSize; |
| 261 } | 233 } |
| 262 | 234 |
| 263 | 235 |
| 264 // The expected code pattern of an edge counter in unoptimized code: | 236 // The expected code pattern of an edge counter in unoptimized code: |
| 265 // b8 imm32 mov EAX, immediate | 237 // b8 imm32 mov EAX, immediate |
| 266 class EdgeCounter : public ValueObject { | 238 class EdgeCounter : public ValueObject { |
| 267 public: | 239 public: |
| 268 EdgeCounter(uword pc, const Code& ignored) | 240 EdgeCounter(uword pc, const Code& ignored) |
| 269 : end_(pc - FlowGraphCompiler::EdgeCounterIncrementSizeInBytes()) { | 241 : end_(pc - FlowGraphCompiler::EdgeCounterIncrementSizeInBytes()) { |
| 270 ASSERT(IsValid(end_)); | 242 ASSERT(IsValid(end_)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 285 | 257 |
| 286 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { | 258 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { |
| 287 ASSERT(code.ContainsInstructionAt(pc)); | 259 ASSERT(code.ContainsInstructionAt(pc)); |
| 288 EdgeCounter counter(pc, code); | 260 EdgeCounter counter(pc, code); |
| 289 return counter.edge_counter(); | 261 return counter.edge_counter(); |
| 290 } | 262 } |
| 291 | 263 |
| 292 } // namespace dart | 264 } // namespace dart |
| 293 | 265 |
| 294 #endif // defined TARGET_ARCH_IA32 | 266 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |