| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | |
| 6 #if defined(TARGET_ARCH_MIPS) | |
| 7 | |
| 8 #include "vm/instructions.h" | |
| 9 #include "vm/instructions_mips.h" | |
| 10 | |
| 11 #include "vm/constants_mips.h" | |
| 12 #include "vm/cpu.h" | |
| 13 #include "vm/object.h" | |
| 14 | |
| 15 namespace dart { | |
| 16 | |
| 17 CallPattern::CallPattern(uword pc, const Code& code) | |
| 18 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | |
| 19 end_(pc), | |
| 20 ic_data_load_end_(0), | |
| 21 target_code_pool_index_(-1), | |
| 22 ic_data_(ICData::Handle()) { | |
| 23 ASSERT(code.ContainsInstructionAt(pc)); | |
| 24 // Last instruction: jalr RA, T9(=R25). | |
| 25 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); | |
| 26 Register reg; | |
| 27 // The end of the pattern is the instruction after the delay slot of the jalr. | |
| 28 ic_data_load_end_ = InstructionPattern::DecodeLoadWordFromPool( | |
| 29 end_ - (3 * Instr::kInstrSize), ®, &target_code_pool_index_); | |
| 30 ASSERT(reg == CODE_REG); | |
| 31 } | |
| 32 | |
| 33 | |
| 34 // Decodes a load sequence ending at 'end' (the last instruction of the load | |
| 35 // sequence is the instruction before the one at end). Returns a pointer to | |
| 36 // the first instruction in the sequence. Returns the register being loaded | |
| 37 // and the loaded object in the output parameters 'reg' and 'obj' | |
| 38 // respectively. | |
| 39 uword InstructionPattern::DecodeLoadObject(uword end, | |
| 40 const ObjectPool& object_pool, | |
| 41 Register* reg, | |
| 42 Object* obj) { | |
| 43 uword start = 0; | |
| 44 Instr* instr = Instr::At(end - Instr::kInstrSize); | |
| 45 if (instr->OpcodeField() == LW) { | |
| 46 intptr_t index = 0; | |
| 47 start = DecodeLoadWordFromPool(end, reg, &index); | |
| 48 *obj = object_pool.ObjectAt(index); | |
| 49 } else { | |
| 50 intptr_t value = 0; | |
| 51 start = DecodeLoadWordImmediate(end, reg, &value); | |
| 52 *obj = reinterpret_cast<RawObject*>(value); | |
| 53 } | |
| 54 return start; | |
| 55 } | |
| 56 | |
| 57 | |
| 58 // Decodes a load sequence ending at 'end' (the last instruction of the load | |
| 59 // sequence is the instruction before the one at end). Returns a pointer to | |
| 60 // the first instruction in the sequence. Returns the register being loaded | |
| 61 // and the loaded immediate value in the output parameters 'reg' and 'value' | |
| 62 // respectively. | |
| 63 uword InstructionPattern::DecodeLoadWordImmediate(uword end, | |
| 64 Register* reg, | |
| 65 intptr_t* value) { | |
| 66 // The pattern is a fixed size, but match backwards for uniformity with | |
| 67 // DecodeLoadWordFromPool. | |
| 68 uword start = end - Instr::kInstrSize; | |
| 69 Instr* instr = Instr::At(start); | |
| 70 intptr_t imm = 0; | |
| 71 ASSERT(instr->OpcodeField() == ORI); | |
| 72 imm = instr->UImmField(); | |
| 73 *reg = instr->RtField(); | |
| 74 | |
| 75 start -= Instr::kInstrSize; | |
| 76 instr = Instr::At(start); | |
| 77 ASSERT(instr->OpcodeField() == LUI); | |
| 78 ASSERT(instr->RtField() == *reg); | |
| 79 imm |= (instr->UImmField() << 16); | |
| 80 *value = imm; | |
| 81 return start; | |
| 82 } | |
| 83 | |
| 84 | |
| 85 // Decodes a load sequence ending at 'end' (the last instruction of the load | |
| 86 // sequence is the instruction before the one at end). Returns a pointer to | |
| 87 // the first instruction in the sequence. Returns the register being loaded | |
| 88 // and the index in the pool being read from in the output parameters 'reg' | |
| 89 // and 'index' respectively. | |
| 90 uword InstructionPattern::DecodeLoadWordFromPool(uword end, | |
| 91 Register* reg, | |
| 92 intptr_t* index) { | |
| 93 uword start = end - Instr::kInstrSize; | |
| 94 Instr* instr = Instr::At(start); | |
| 95 intptr_t offset = 0; | |
| 96 if ((instr->OpcodeField() == LW) && (instr->RsField() == PP)) { | |
| 97 offset = instr->SImmField(); | |
| 98 *reg = instr->RtField(); | |
| 99 } else { | |
| 100 ASSERT(instr->OpcodeField() == LW); | |
| 101 offset = instr->SImmField(); | |
| 102 *reg = instr->RtField(); | |
| 103 | |
| 104 start -= Instr::kInstrSize; | |
| 105 instr = Instr::At(start); | |
| 106 ASSERT(instr->OpcodeField() == SPECIAL); | |
| 107 ASSERT(instr->FunctionField() == ADDU); | |
| 108 ASSERT(instr->RdField() == *reg); | |
| 109 ASSERT(instr->RsField() == *reg); | |
| 110 ASSERT(instr->RtField() == PP); | |
| 111 | |
| 112 start -= Instr::kInstrSize; | |
| 113 instr = Instr::At(start); | |
| 114 ASSERT(instr->OpcodeField() == LUI); | |
| 115 ASSERT(instr->RtField() == *reg); | |
| 116 // Offset is signed, so add the upper 16 bits. | |
| 117 offset += (instr->UImmField() << 16); | |
| 118 } | |
| 119 *index = ObjectPool::IndexFromOffset(offset); | |
| 120 return start; | |
| 121 } | |
| 122 | |
| 123 | |
| 124 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { | |
| 125 ASSERT(code.ContainsInstructionAt(pc)); | |
| 126 | |
| 127 Instr* instr = Instr::At(pc); | |
| 128 if ((instr->OpcodeField() == LW)) { | |
| 129 intptr_t offset = instr->SImmField(); | |
| 130 if (instr->RsField() == PP) { | |
| 131 intptr_t index = ObjectPool::IndexFromOffset(offset); | |
| 132 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); | |
| 133 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { | |
| 134 *obj = pool.ObjectAt(index); | |
| 135 return true; | |
| 136 } | |
| 137 } else if (instr->RsField() == THR) { | |
| 138 return Thread::ObjectAtOffset(offset, obj); | |
| 139 } | |
| 140 } | |
| 141 // TODO(rmacnak): Sequence for loads beyond 16 bits. | |
| 142 | |
| 143 return false; | |
| 144 } | |
| 145 | |
| 146 | |
| 147 RawICData* CallPattern::IcData() { | |
| 148 if (ic_data_.IsNull()) { | |
| 149 Register reg; | |
| 150 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, | |
| 151 &ic_data_); | |
| 152 ASSERT(reg == S5); | |
| 153 } | |
| 154 return ic_data_.raw(); | |
| 155 } | |
| 156 | |
| 157 | |
| 158 RawCode* CallPattern::TargetCode() const { | |
| 159 return reinterpret_cast<RawCode*>( | |
| 160 object_pool_.ObjectAt(target_code_pool_index_)); | |
| 161 } | |
| 162 | |
| 163 | |
| 164 void CallPattern::SetTargetCode(const Code& target) const { | |
| 165 object_pool_.SetObjectAt(target_code_pool_index_, target); | |
| 166 // No need to flush the instruction cache, since the code is not modified. | |
| 167 } | |
| 168 | |
| 169 | |
| 170 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) | |
| 171 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | |
| 172 end_(pc), | |
| 173 native_function_pool_index_(-1), | |
| 174 target_code_pool_index_(-1) { | |
| 175 ASSERT(code.ContainsInstructionAt(pc)); | |
| 176 // Last instruction: jalr RA, T9(=R25). | |
| 177 ASSERT(*(reinterpret_cast<uword*>(end_) - 2) == 0x0320f809); | |
| 178 | |
| 179 Register reg; | |
| 180 uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool( | |
| 181 end_ - 3 * Instr::kInstrSize, ®, &target_code_pool_index_); | |
| 182 ASSERT(reg == CODE_REG); | |
| 183 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, ®, | |
| 184 &native_function_pool_index_); | |
| 185 ASSERT(reg == T5); | |
| 186 } | |
| 187 | |
| 188 | |
| 189 RawCode* NativeCallPattern::target() const { | |
| 190 return reinterpret_cast<RawCode*>( | |
| 191 object_pool_.ObjectAt(target_code_pool_index_)); | |
| 192 } | |
| 193 | |
| 194 | |
| 195 void NativeCallPattern::set_target(const Code& target) const { | |
| 196 object_pool_.SetObjectAt(target_code_pool_index_, target); | |
| 197 // No need to flush the instruction cache, since the code is not modified. | |
| 198 } | |
| 199 | |
| 200 | |
| 201 NativeFunction NativeCallPattern::native_function() const { | |
| 202 return reinterpret_cast<NativeFunction>( | |
| 203 object_pool_.RawValueAt(native_function_pool_index_)); | |
| 204 } | |
| 205 | |
| 206 | |
| 207 void NativeCallPattern::set_native_function(NativeFunction func) const { | |
| 208 object_pool_.SetRawValueAt(native_function_pool_index_, | |
| 209 reinterpret_cast<uword>(func)); | |
| 210 } | |
| 211 | |
| 212 | |
| 213 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) | |
| 214 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | |
| 215 data_pool_index_(-1), | |
| 216 target_pool_index_(-1) { | |
| 217 ASSERT(code.ContainsInstructionAt(pc)); | |
| 218 // Last instruction: jalr t9. | |
| 219 ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0); // Delay slot. | |
| 220 ASSERT(*(reinterpret_cast<uword*>(pc) - 2) == 0x0320f809); | |
| 221 | |
| 222 Register reg; | |
| 223 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( | |
| 224 pc - 2 * Instr::kInstrSize, ®, &data_pool_index_); | |
| 225 ASSERT(reg == S5); | |
| 226 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, | |
| 227 ®, &target_pool_index_); | |
| 228 ASSERT(reg == CODE_REG); | |
| 229 } | |
| 230 | |
| 231 | |
| 232 RawObject* SwitchableCallPattern::data() const { | |
| 233 return object_pool_.ObjectAt(data_pool_index_); | |
| 234 } | |
| 235 | |
| 236 | |
| 237 RawCode* SwitchableCallPattern::target() const { | |
| 238 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); | |
| 239 } | |
| 240 | |
| 241 | |
| 242 void SwitchableCallPattern::SetData(const Object& data) const { | |
| 243 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); | |
| 244 object_pool_.SetObjectAt(data_pool_index_, data); | |
| 245 } | |
| 246 | |
| 247 | |
| 248 void SwitchableCallPattern::SetTarget(const Code& target) const { | |
| 249 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); | |
| 250 object_pool_.SetObjectAt(target_pool_index_, target); | |
| 251 } | |
| 252 | |
| 253 | |
| 254 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} | |
| 255 | |
| 256 | |
| 257 bool ReturnPattern::IsValid() const { | |
| 258 Instr* jr = Instr::At(pc_); | |
| 259 return (jr->OpcodeField() == SPECIAL) && (jr->FunctionField() == JR) && | |
| 260 (jr->RsField() == RA); | |
| 261 } | |
| 262 | |
| 263 } // namespace dart | |
| 264 | |
| 265 #endif // defined TARGET_ARCH_MIPS | |
| OLD | NEW |