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 |