| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/instructions.h" | 8 #include "vm/instructions.h" |
| 9 #include "vm/instructions_mips.h" | 9 #include "vm/instructions_mips.h" |
| 10 | 10 |
| 11 #include "vm/constants_mips.h" | 11 #include "vm/constants_mips.h" |
| 12 #include "vm/cpu.h" | 12 #include "vm/cpu.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 | 14 |
| 15 namespace dart { | 15 namespace dart { |
| 16 | 16 |
| 17 CallPattern::CallPattern(uword pc, const Code& code) | 17 CallPattern::CallPattern(uword pc, const Code& code) |
| 18 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 18 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
| 19 end_(pc), | 19 end_(pc), |
| 20 ic_data_load_end_(0), | 20 ic_data_load_end_(0), |
| 21 target_code_pool_index_(-1), | 21 target_code_pool_index_(-1), |
| 22 ic_data_(ICData::Handle()) { | 22 ic_data_(ICData::Handle()) { |
| 23 ASSERT(code.ContainsInstructionAt(pc)); | 23 ASSERT(code.ContainsInstructionAt(pc)); |
| 24 // Last instruction: jalr RA, T9(=R25). | 24 // Last instruction: jalr RA, T9(=R25). |
| 25 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); | 25 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); |
| 26 Register reg; | 26 Register reg; |
| 27 // The end of the pattern is the instruction after the delay slot of the jalr. | 27 // The end of the pattern is the instruction after the delay slot of the jalr. |
| 28 ic_data_load_end_ = | 28 ic_data_load_end_ = InstructionPattern::DecodeLoadWordFromPool( |
| 29 InstructionPattern::DecodeLoadWordFromPool(end_ - (3 * Instr::kInstrSize), | 29 end_ - (3 * Instr::kInstrSize), ®, &target_code_pool_index_); |
| 30 ®, | |
| 31 &target_code_pool_index_); | |
| 32 ASSERT(reg == CODE_REG); | 30 ASSERT(reg == CODE_REG); |
| 33 } | 31 } |
| 34 | 32 |
| 35 | 33 |
| 36 // Decodes a load sequence ending at 'end' (the last instruction of the load | 34 // Decodes a load sequence ending at 'end' (the last instruction of the load |
| 37 // sequence is the instruction before the one at end). Returns a pointer to | 35 // sequence is the instruction before the one at end). Returns a pointer to |
| 38 // the first instruction in the sequence. Returns the register being loaded | 36 // the first instruction in the sequence. Returns the register being loaded |
| 39 // and the loaded object in the output parameters 'reg' and 'obj' | 37 // and the loaded object in the output parameters 'reg' and 'obj' |
| 40 // respectively. | 38 // respectively. |
| 41 uword InstructionPattern::DecodeLoadObject(uword end, | 39 uword InstructionPattern::DecodeLoadObject(uword end, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 ASSERT(instr->OpcodeField() == LUI); | 114 ASSERT(instr->OpcodeField() == LUI); |
| 117 ASSERT(instr->RtField() == *reg); | 115 ASSERT(instr->RtField() == *reg); |
| 118 // Offset is signed, so add the upper 16 bits. | 116 // Offset is signed, so add the upper 16 bits. |
| 119 offset += (instr->UImmField() << 16); | 117 offset += (instr->UImmField() << 16); |
| 120 } | 118 } |
| 121 *index = ObjectPool::IndexFromOffset(offset); | 119 *index = ObjectPool::IndexFromOffset(offset); |
| 122 return start; | 120 return start; |
| 123 } | 121 } |
| 124 | 122 |
| 125 | 123 |
| 126 bool DecodeLoadObjectFromPoolOrThread(uword pc, | 124 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { |
| 127 const Code& code, | |
| 128 Object* obj) { | |
| 129 ASSERT(code.ContainsInstructionAt(pc)); | 125 ASSERT(code.ContainsInstructionAt(pc)); |
| 130 | 126 |
| 131 Instr* instr = Instr::At(pc); | 127 Instr* instr = Instr::At(pc); |
| 132 if ((instr->OpcodeField() == LW)) { | 128 if ((instr->OpcodeField() == LW)) { |
| 133 intptr_t offset = instr->SImmField(); | 129 intptr_t offset = instr->SImmField(); |
| 134 if (instr->RsField() == PP) { | 130 if (instr->RsField() == PP) { |
| 135 intptr_t index = ObjectPool::IndexFromOffset(offset); | 131 intptr_t index = ObjectPool::IndexFromOffset(offset); |
| 136 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); | 132 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); |
| 137 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { | 133 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { |
| 138 *obj = pool.ObjectAt(index); | 134 *obj = pool.ObjectAt(index); |
| 139 return true; | 135 return true; |
| 140 } | 136 } |
| 141 } else if (instr->RsField() == THR) { | 137 } else if (instr->RsField() == THR) { |
| 142 return Thread::ObjectAtOffset(offset, obj); | 138 return Thread::ObjectAtOffset(offset, obj); |
| 143 } | 139 } |
| 144 } | 140 } |
| 145 // TODO(rmacnak): Sequence for loads beyond 16 bits. | 141 // TODO(rmacnak): Sequence for loads beyond 16 bits. |
| 146 | 142 |
| 147 return false; | 143 return false; |
| 148 } | 144 } |
| 149 | 145 |
| 150 | 146 |
| 151 RawICData* CallPattern::IcData() { | 147 RawICData* CallPattern::IcData() { |
| 152 if (ic_data_.IsNull()) { | 148 if (ic_data_.IsNull()) { |
| 153 Register reg; | 149 Register reg; |
| 154 InstructionPattern::DecodeLoadObject(ic_data_load_end_, | 150 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, |
| 155 object_pool_, | |
| 156 ®, | |
| 157 &ic_data_); | 151 &ic_data_); |
| 158 ASSERT(reg == S5); | 152 ASSERT(reg == S5); |
| 159 } | 153 } |
| 160 return ic_data_.raw(); | 154 return ic_data_.raw(); |
| 161 } | 155 } |
| 162 | 156 |
| 163 | 157 |
| 164 RawCode* CallPattern::TargetCode() const { | 158 RawCode* CallPattern::TargetCode() const { |
| 165 return reinterpret_cast<RawCode*>( | 159 return reinterpret_cast<RawCode*>( |
| 166 object_pool_.ObjectAt(target_code_pool_index_)); | 160 object_pool_.ObjectAt(target_code_pool_index_)); |
| 167 } | 161 } |
| 168 | 162 |
| 169 | 163 |
| 170 void CallPattern::SetTargetCode(const Code& target) const { | 164 void CallPattern::SetTargetCode(const Code& target) const { |
| 171 object_pool_.SetObjectAt(target_code_pool_index_, target); | 165 object_pool_.SetObjectAt(target_code_pool_index_, target); |
| 172 // No need to flush the instruction cache, since the code is not modified. | 166 // No need to flush the instruction cache, since the code is not modified. |
| 173 } | 167 } |
| 174 | 168 |
| 175 | 169 |
| 176 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) | 170 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) |
| 177 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 171 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
| 178 end_(pc), | 172 end_(pc), |
| 179 native_function_pool_index_(-1), | 173 native_function_pool_index_(-1), |
| 180 target_code_pool_index_(-1) { | 174 target_code_pool_index_(-1) { |
| 181 ASSERT(code.ContainsInstructionAt(pc)); | 175 ASSERT(code.ContainsInstructionAt(pc)); |
| 182 // Last instruction: jalr RA, T9(=R25). | 176 // Last instruction: jalr RA, T9(=R25). |
| 183 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); | 177 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); |
| 184 | 178 |
| 185 Register reg; | 179 Register reg; |
| 186 uword native_function_load_end = | 180 uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool( |
| 187 InstructionPattern::DecodeLoadWordFromPool(end_ - 3 * Instr::kInstrSize, | 181 end_ - 3 * Instr::kInstrSize, ®, &target_code_pool_index_); |
| 188 ®, | |
| 189 &target_code_pool_index_); | |
| 190 ASSERT(reg == CODE_REG); | 182 ASSERT(reg == CODE_REG); |
| 191 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, | 183 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, ®, |
| 192 ®, | |
| 193 &native_function_pool_index_); | 184 &native_function_pool_index_); |
| 194 ASSERT(reg == T5); | 185 ASSERT(reg == T5); |
| 195 } | 186 } |
| 196 | 187 |
| 197 | 188 |
| 198 RawCode* NativeCallPattern::target() const { | 189 RawCode* NativeCallPattern::target() const { |
| 199 return reinterpret_cast<RawCode*>( | 190 return reinterpret_cast<RawCode*>( |
| 200 object_pool_.ObjectAt(target_code_pool_index_)); | 191 object_pool_.ObjectAt(target_code_pool_index_)); |
| 201 } | 192 } |
| 202 | 193 |
| 203 | 194 |
| 204 void NativeCallPattern::set_target(const Code& target) const { | 195 void NativeCallPattern::set_target(const Code& target) const { |
| 205 object_pool_.SetObjectAt(target_code_pool_index_, target); | 196 object_pool_.SetObjectAt(target_code_pool_index_, target); |
| 206 // No need to flush the instruction cache, since the code is not modified. | 197 // No need to flush the instruction cache, since the code is not modified. |
| 207 } | 198 } |
| 208 | 199 |
| 209 | 200 |
| 210 NativeFunction NativeCallPattern::native_function() const { | 201 NativeFunction NativeCallPattern::native_function() const { |
| 211 return reinterpret_cast<NativeFunction>( | 202 return reinterpret_cast<NativeFunction>( |
| 212 object_pool_.RawValueAt(native_function_pool_index_)); | 203 object_pool_.RawValueAt(native_function_pool_index_)); |
| 213 } | 204 } |
| 214 | 205 |
| 215 | 206 |
| 216 void NativeCallPattern::set_native_function(NativeFunction func) const { | 207 void NativeCallPattern::set_native_function(NativeFunction func) const { |
| 217 object_pool_.SetRawValueAt(native_function_pool_index_, | 208 object_pool_.SetRawValueAt(native_function_pool_index_, |
| 218 reinterpret_cast<uword>(func)); | 209 reinterpret_cast<uword>(func)); |
| 219 } | 210 } |
| 220 | 211 |
| 221 | 212 |
| 222 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) | 213 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) |
| 223 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 214 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
| 224 data_pool_index_(-1), | 215 data_pool_index_(-1), |
| 225 target_pool_index_(-1) { | 216 target_pool_index_(-1) { |
| 226 ASSERT(code.ContainsInstructionAt(pc)); | 217 ASSERT(code.ContainsInstructionAt(pc)); |
| 227 // Last instruction: jalr t9. | 218 // Last instruction: jalr t9. |
| 228 ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0); // Delay slot. | 219 ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0); // Delay slot. |
| 229 ASSERT(*(reinterpret_cast<uword*>(pc) - 2) == 0x0320f809); | 220 ASSERT(*(reinterpret_cast<uword*>(pc) - 2) == 0x0320f809); |
| 230 | 221 |
| 231 Register reg; | 222 Register reg; |
| 232 uword data_load_end = | 223 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( |
| 233 InstructionPattern::DecodeLoadWordFromPool(pc - 2 * Instr::kInstrSize, | 224 pc - 2 * Instr::kInstrSize, ®, &data_pool_index_); |
| 234 ®, | |
| 235 &data_pool_index_); | |
| 236 ASSERT(reg == S5); | 225 ASSERT(reg == S5); |
| 237 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, | 226 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, |
| 238 ®, | 227 ®, &target_pool_index_); |
| 239 &target_pool_index_); | |
| 240 ASSERT(reg == CODE_REG); | 228 ASSERT(reg == CODE_REG); |
| 241 } | 229 } |
| 242 | 230 |
| 243 | 231 |
| 244 RawObject* SwitchableCallPattern::data() const { | 232 RawObject* SwitchableCallPattern::data() const { |
| 245 return object_pool_.ObjectAt(data_pool_index_); | 233 return object_pool_.ObjectAt(data_pool_index_); |
| 246 } | 234 } |
| 247 | 235 |
| 248 | 236 |
| 249 RawCode* SwitchableCallPattern::target() const { | 237 RawCode* SwitchableCallPattern::target() const { |
| 250 return reinterpret_cast<RawCode*>( | 238 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); |
| 251 object_pool_.ObjectAt(target_pool_index_)); | |
| 252 } | 239 } |
| 253 | 240 |
| 254 | 241 |
| 255 void SwitchableCallPattern::SetData(const Object& data) const { | 242 void SwitchableCallPattern::SetData(const Object& data) const { |
| 256 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); | 243 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); |
| 257 object_pool_.SetObjectAt(data_pool_index_, data); | 244 object_pool_.SetObjectAt(data_pool_index_, data); |
| 258 } | 245 } |
| 259 | 246 |
| 260 | 247 |
| 261 void SwitchableCallPattern::SetTarget(const Code& target) const { | 248 void SwitchableCallPattern::SetTarget(const Code& target) const { |
| 262 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); | 249 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); |
| 263 object_pool_.SetObjectAt(target_pool_index_, target); | 250 object_pool_.SetObjectAt(target_pool_index_, target); |
| 264 } | 251 } |
| 265 | 252 |
| 266 | 253 |
| 267 ReturnPattern::ReturnPattern(uword pc) | 254 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} |
| 268 : pc_(pc) { | |
| 269 } | |
| 270 | 255 |
| 271 | 256 |
| 272 bool ReturnPattern::IsValid() const { | 257 bool ReturnPattern::IsValid() const { |
| 273 Instr* jr = Instr::At(pc_); | 258 Instr* jr = Instr::At(pc_); |
| 274 return (jr->OpcodeField() == SPECIAL) && | 259 return (jr->OpcodeField() == SPECIAL) && (jr->FunctionField() == JR) && |
| 275 (jr->FunctionField() == JR) && | |
| 276 (jr->RsField() == RA); | 260 (jr->RsField() == RA); |
| 277 } | 261 } |
| 278 | 262 |
| 279 } // namespace dart | 263 } // namespace dart |
| 280 | 264 |
| 281 #endif // defined TARGET_ARCH_MIPS | 265 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |