1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "assembler_mips.h"
18 
19 #include "base/bit_utils.h"
20 #include "base/casts.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "memory_region.h"
23 #include "thread.h"
24 
25 namespace art {
26 namespace mips {
27 
operator <<(std::ostream & os,const DRegister & rhs)28 std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
29   if (rhs >= D0 && rhs < kNumberOfDRegisters) {
30     os << "d" << static_cast<int>(rhs);
31   } else {
32     os << "DRegister[" << static_cast<int>(rhs) << "]";
33   }
34   return os;
35 }
36 
Emit(int32_t value)37 void MipsAssembler::Emit(int32_t value) {
38   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
39   buffer_.Emit<int32_t>(value);
40 }
41 
EmitR(int opcode,Register rs,Register rt,Register rd,int shamt,int funct)42 void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) {
43   CHECK_NE(rs, kNoRegister);
44   CHECK_NE(rt, kNoRegister);
45   CHECK_NE(rd, kNoRegister);
46   int32_t encoding = opcode << kOpcodeShift |
47                      static_cast<int32_t>(rs) << kRsShift |
48                      static_cast<int32_t>(rt) << kRtShift |
49                      static_cast<int32_t>(rd) << kRdShift |
50                      shamt << kShamtShift |
51                      funct;
52   Emit(encoding);
53 }
54 
EmitI(int opcode,Register rs,Register rt,uint16_t imm)55 void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) {
56   CHECK_NE(rs, kNoRegister);
57   CHECK_NE(rt, kNoRegister);
58   int32_t encoding = opcode << kOpcodeShift |
59                      static_cast<int32_t>(rs) << kRsShift |
60                      static_cast<int32_t>(rt) << kRtShift |
61                      imm;
62   Emit(encoding);
63 }
64 
EmitJ(int opcode,int address)65 void MipsAssembler::EmitJ(int opcode, int address) {
66   int32_t encoding = opcode << kOpcodeShift |
67                      address;
68   Emit(encoding);
69 }
70 
EmitFR(int opcode,int fmt,FRegister ft,FRegister fs,FRegister fd,int funct)71 void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct) {
72   CHECK_NE(ft, kNoFRegister);
73   CHECK_NE(fs, kNoFRegister);
74   CHECK_NE(fd, kNoFRegister);
75   int32_t encoding = opcode << kOpcodeShift |
76                      fmt << kFmtShift |
77                      static_cast<int32_t>(ft) << kFtShift |
78                      static_cast<int32_t>(fs) << kFsShift |
79                      static_cast<int32_t>(fd) << kFdShift |
80                      funct;
81   Emit(encoding);
82 }
83 
EmitFI(int opcode,int fmt,FRegister rt,uint16_t imm)84 void MipsAssembler::EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm) {
85   CHECK_NE(rt, kNoFRegister);
86   int32_t encoding = opcode << kOpcodeShift |
87                      fmt << kFmtShift |
88                      static_cast<int32_t>(rt) << kRtShift |
89                      imm;
90   Emit(encoding);
91 }
92 
EmitBranch(Register rt,Register rs,Label * label,bool equal)93 void MipsAssembler::EmitBranch(Register rt, Register rs, Label* label, bool equal) {
94   int offset;
95   if (label->IsBound()) {
96     offset = label->Position() - buffer_.Size();
97   } else {
98     // Use the offset field of the branch instruction for linking the sites.
99     offset = label->position_;
100     label->LinkTo(buffer_.Size());
101   }
102   if (equal) {
103     Beq(rt, rs, (offset >> 2) & kBranchOffsetMask);
104   } else {
105     Bne(rt, rs, (offset >> 2) & kBranchOffsetMask);
106   }
107 }
108 
EmitJump(Label * label,bool link)109 void MipsAssembler::EmitJump(Label* label, bool link) {
110   int offset;
111   if (label->IsBound()) {
112     offset = label->Position() - buffer_.Size();
113   } else {
114     // Use the offset field of the jump instruction for linking the sites.
115     offset = label->position_;
116     label->LinkTo(buffer_.Size());
117   }
118   if (link) {
119     Jal((offset >> 2) & kJumpOffsetMask);
120   } else {
121     J((offset >> 2) & kJumpOffsetMask);
122   }
123 }
124 
EncodeBranchOffset(int offset,int32_t inst,bool is_jump)125 int32_t MipsAssembler::EncodeBranchOffset(int offset, int32_t inst, bool is_jump) {
126   CHECK_ALIGNED(offset, 4);
127   CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset;
128 
129   // Properly preserve only the bits supported in the instruction.
130   offset >>= 2;
131   if (is_jump) {
132     offset &= kJumpOffsetMask;
133     return (inst & ~kJumpOffsetMask) | offset;
134   } else {
135     offset &= kBranchOffsetMask;
136     return (inst & ~kBranchOffsetMask) | offset;
137   }
138 }
139 
DecodeBranchOffset(int32_t inst,bool is_jump)140 int MipsAssembler::DecodeBranchOffset(int32_t inst, bool is_jump) {
141   // Sign-extend, then left-shift by 2.
142   if (is_jump) {
143     return (((inst & kJumpOffsetMask) << 6) >> 4);
144   } else {
145     return (((inst & kBranchOffsetMask) << 16) >> 14);
146   }
147 }
148 
Bind(Label * label,bool is_jump)149 void MipsAssembler::Bind(Label* label, bool is_jump) {
150   CHECK(!label->IsBound());
151   int bound_pc = buffer_.Size();
152   while (label->IsLinked()) {
153     int32_t position = label->Position();
154     int32_t next = buffer_.Load<int32_t>(position);
155     int32_t offset = is_jump ? bound_pc - position : bound_pc - position - 4;
156     int32_t encoded = MipsAssembler::EncodeBranchOffset(offset, next, is_jump);
157     buffer_.Store<int32_t>(position, encoded);
158     label->position_ = MipsAssembler::DecodeBranchOffset(next, is_jump);
159   }
160   label->BindTo(bound_pc);
161 }
162 
Add(Register rd,Register rs,Register rt)163 void MipsAssembler::Add(Register rd, Register rs, Register rt) {
164   EmitR(0, rs, rt, rd, 0, 0x20);
165 }
166 
Addu(Register rd,Register rs,Register rt)167 void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
168   EmitR(0, rs, rt, rd, 0, 0x21);
169 }
170 
Addi(Register rt,Register rs,uint16_t imm16)171 void MipsAssembler::Addi(Register rt, Register rs, uint16_t imm16) {
172   EmitI(0x8, rs, rt, imm16);
173 }
174 
Addiu(Register rt,Register rs,uint16_t imm16)175 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
176   EmitI(0x9, rs, rt, imm16);
177 }
178 
Sub(Register rd,Register rs,Register rt)179 void MipsAssembler::Sub(Register rd, Register rs, Register rt) {
180   EmitR(0, rs, rt, rd, 0, 0x22);
181 }
182 
Subu(Register rd,Register rs,Register rt)183 void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
184   EmitR(0, rs, rt, rd, 0, 0x23);
185 }
186 
Mult(Register rs,Register rt)187 void MipsAssembler::Mult(Register rs, Register rt) {
188   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18);
189 }
190 
Multu(Register rs,Register rt)191 void MipsAssembler::Multu(Register rs, Register rt) {
192   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19);
193 }
194 
Div(Register rs,Register rt)195 void MipsAssembler::Div(Register rs, Register rt) {
196   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a);
197 }
198 
Divu(Register rs,Register rt)199 void MipsAssembler::Divu(Register rs, Register rt) {
200   EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b);
201 }
202 
And(Register rd,Register rs,Register rt)203 void MipsAssembler::And(Register rd, Register rs, Register rt) {
204   EmitR(0, rs, rt, rd, 0, 0x24);
205 }
206 
Andi(Register rt,Register rs,uint16_t imm16)207 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
208   EmitI(0xc, rs, rt, imm16);
209 }
210 
Or(Register rd,Register rs,Register rt)211 void MipsAssembler::Or(Register rd, Register rs, Register rt) {
212   EmitR(0, rs, rt, rd, 0, 0x25);
213 }
214 
Ori(Register rt,Register rs,uint16_t imm16)215 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
216   EmitI(0xd, rs, rt, imm16);
217 }
218 
Xor(Register rd,Register rs,Register rt)219 void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
220   EmitR(0, rs, rt, rd, 0, 0x26);
221 }
222 
Xori(Register rt,Register rs,uint16_t imm16)223 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
224   EmitI(0xe, rs, rt, imm16);
225 }
226 
Nor(Register rd,Register rs,Register rt)227 void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
228   EmitR(0, rs, rt, rd, 0, 0x27);
229 }
230 
Sll(Register rd,Register rs,int shamt)231 void MipsAssembler::Sll(Register rd, Register rs, int shamt) {
232   EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x00);
233 }
234 
Srl(Register rd,Register rs,int shamt)235 void MipsAssembler::Srl(Register rd, Register rs, int shamt) {
236   EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x02);
237 }
238 
Sra(Register rd,Register rs,int shamt)239 void MipsAssembler::Sra(Register rd, Register rs, int shamt) {
240   EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x03);
241 }
242 
Sllv(Register rd,Register rs,Register rt)243 void MipsAssembler::Sllv(Register rd, Register rs, Register rt) {
244   EmitR(0, rs, rt, rd, 0, 0x04);
245 }
246 
Srlv(Register rd,Register rs,Register rt)247 void MipsAssembler::Srlv(Register rd, Register rs, Register rt) {
248   EmitR(0, rs, rt, rd, 0, 0x06);
249 }
250 
Srav(Register rd,Register rs,Register rt)251 void MipsAssembler::Srav(Register rd, Register rs, Register rt) {
252   EmitR(0, rs, rt, rd, 0, 0x07);
253 }
254 
Lb(Register rt,Register rs,uint16_t imm16)255 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
256   EmitI(0x20, rs, rt, imm16);
257 }
258 
Lh(Register rt,Register rs,uint16_t imm16)259 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
260   EmitI(0x21, rs, rt, imm16);
261 }
262 
Lw(Register rt,Register rs,uint16_t imm16)263 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
264   EmitI(0x23, rs, rt, imm16);
265 }
266 
Lbu(Register rt,Register rs,uint16_t imm16)267 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
268   EmitI(0x24, rs, rt, imm16);
269 }
270 
Lhu(Register rt,Register rs,uint16_t imm16)271 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
272   EmitI(0x25, rs, rt, imm16);
273 }
274 
Lui(Register rt,uint16_t imm16)275 void MipsAssembler::Lui(Register rt, uint16_t imm16) {
276   EmitI(0xf, static_cast<Register>(0), rt, imm16);
277 }
278 
Mfhi(Register rd)279 void MipsAssembler::Mfhi(Register rd) {
280   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10);
281 }
282 
Mflo(Register rd)283 void MipsAssembler::Mflo(Register rd) {
284   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12);
285 }
286 
Sb(Register rt,Register rs,uint16_t imm16)287 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
288   EmitI(0x28, rs, rt, imm16);
289 }
290 
Sh(Register rt,Register rs,uint16_t imm16)291 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
292   EmitI(0x29, rs, rt, imm16);
293 }
294 
Sw(Register rt,Register rs,uint16_t imm16)295 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
296   EmitI(0x2b, rs, rt, imm16);
297 }
298 
Slt(Register rd,Register rs,Register rt)299 void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
300   EmitR(0, rs, rt, rd, 0, 0x2a);
301 }
302 
Sltu(Register rd,Register rs,Register rt)303 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
304   EmitR(0, rs, rt, rd, 0, 0x2b);
305 }
306 
Slti(Register rt,Register rs,uint16_t imm16)307 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
308   EmitI(0xa, rs, rt, imm16);
309 }
310 
Sltiu(Register rt,Register rs,uint16_t imm16)311 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
312   EmitI(0xb, rs, rt, imm16);
313 }
314 
Beq(Register rt,Register rs,uint16_t imm16)315 void MipsAssembler::Beq(Register rt, Register rs, uint16_t imm16) {
316   EmitI(0x4, rs, rt, imm16);
317   Nop();
318 }
319 
Bne(Register rt,Register rs,uint16_t imm16)320 void MipsAssembler::Bne(Register rt, Register rs, uint16_t imm16) {
321   EmitI(0x5, rs, rt, imm16);
322   Nop();
323 }
324 
J(uint32_t address)325 void MipsAssembler::J(uint32_t address) {
326   EmitJ(0x2, address);
327   Nop();
328 }
329 
Jal(uint32_t address)330 void MipsAssembler::Jal(uint32_t address) {
331   EmitJ(0x2, address);
332   Nop();
333 }
334 
Jr(Register rs)335 void MipsAssembler::Jr(Register rs) {
336   EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x09);  // Jalr zero, rs
337   Nop();
338 }
339 
Jalr(Register rs)340 void MipsAssembler::Jalr(Register rs) {
341   EmitR(0, rs, static_cast<Register>(0), RA, 0, 0x09);
342   Nop();
343 }
344 
AddS(FRegister fd,FRegister fs,FRegister ft)345 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
346   EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
347 }
348 
SubS(FRegister fd,FRegister fs,FRegister ft)349 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
350   EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
351 }
352 
MulS(FRegister fd,FRegister fs,FRegister ft)353 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
354   EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
355 }
356 
DivS(FRegister fd,FRegister fs,FRegister ft)357 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
358   EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
359 }
360 
AddD(DRegister fd,DRegister fs,DRegister ft)361 void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) {
362   EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
363          static_cast<FRegister>(fd), 0x0);
364 }
365 
SubD(DRegister fd,DRegister fs,DRegister ft)366 void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) {
367   EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
368          static_cast<FRegister>(fd), 0x1);
369 }
370 
MulD(DRegister fd,DRegister fs,DRegister ft)371 void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) {
372   EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
373          static_cast<FRegister>(fd), 0x2);
374 }
375 
DivD(DRegister fd,DRegister fs,DRegister ft)376 void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) {
377   EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
378          static_cast<FRegister>(fd), 0x3);
379 }
380 
MovS(FRegister fd,FRegister fs)381 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
382   EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6);
383 }
384 
MovD(DRegister fd,DRegister fs)385 void MipsAssembler::MovD(DRegister fd, DRegister fs) {
386   EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs),
387          static_cast<FRegister>(fd), 0x6);
388 }
389 
Mfc1(Register rt,FRegister fs)390 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
391   EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
392 }
393 
Mtc1(FRegister ft,Register rs)394 void MipsAssembler::Mtc1(FRegister ft, Register rs) {
395   EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0);
396 }
397 
Lwc1(FRegister ft,Register rs,uint16_t imm16)398 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
399   EmitI(0x31, rs, static_cast<Register>(ft), imm16);
400 }
401 
Ldc1(DRegister ft,Register rs,uint16_t imm16)402 void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) {
403   EmitI(0x35, rs, static_cast<Register>(ft), imm16);
404 }
405 
Swc1(FRegister ft,Register rs,uint16_t imm16)406 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
407   EmitI(0x39, rs, static_cast<Register>(ft), imm16);
408 }
409 
Sdc1(DRegister ft,Register rs,uint16_t imm16)410 void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) {
411   EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
412 }
413 
Break()414 void MipsAssembler::Break() {
415   EmitR(0, static_cast<Register>(0), static_cast<Register>(0),
416         static_cast<Register>(0), 0, 0xD);
417 }
418 
Nop()419 void MipsAssembler::Nop() {
420   EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
421 }
422 
Move(Register rt,Register rs)423 void MipsAssembler::Move(Register rt, Register rs) {
424   EmitI(0x9, rs, rt, 0);    // Addiu
425 }
426 
Clear(Register rt)427 void MipsAssembler::Clear(Register rt) {
428   EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rt, 0, 0x20);
429 }
430 
Not(Register rt,Register rs)431 void MipsAssembler::Not(Register rt, Register rs) {
432   EmitR(0, static_cast<Register>(0), rs, rt, 0, 0x27);
433 }
434 
Mul(Register rd,Register rs,Register rt)435 void MipsAssembler::Mul(Register rd, Register rs, Register rt) {
436   Mult(rs, rt);
437   Mflo(rd);
438 }
439 
Div(Register rd,Register rs,Register rt)440 void MipsAssembler::Div(Register rd, Register rs, Register rt) {
441   Div(rs, rt);
442   Mflo(rd);
443 }
444 
Rem(Register rd,Register rs,Register rt)445 void MipsAssembler::Rem(Register rd, Register rs, Register rt) {
446   Div(rs, rt);
447   Mfhi(rd);
448 }
449 
AddConstant(Register rt,Register rs,int32_t value)450 void MipsAssembler::AddConstant(Register rt, Register rs, int32_t value) {
451   Addiu(rt, rs, value);
452 }
453 
LoadImmediate(Register rt,int32_t value)454 void MipsAssembler::LoadImmediate(Register rt, int32_t value) {
455   Addiu(rt, ZERO, value);
456 }
457 
EmitLoad(ManagedRegister m_dst,Register src_register,int32_t src_offset,size_t size)458 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
459                              size_t size) {
460   MipsManagedRegister dst = m_dst.AsMips();
461   if (dst.IsNoRegister()) {
462     CHECK_EQ(0u, size) << dst;
463   } else if (dst.IsCoreRegister()) {
464     CHECK_EQ(4u, size) << dst;
465     LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
466   } else if (dst.IsRegisterPair()) {
467     CHECK_EQ(8u, size) << dst;
468     LoadFromOffset(kLoadWord, dst.AsRegisterPairLow(), src_register, src_offset);
469     LoadFromOffset(kLoadWord, dst.AsRegisterPairHigh(), src_register, src_offset + 4);
470   } else if (dst.IsFRegister()) {
471     LoadSFromOffset(dst.AsFRegister(), src_register, src_offset);
472   } else {
473     CHECK(dst.IsDRegister()) << dst;
474     LoadDFromOffset(dst.AsDRegister(), src_register, src_offset);
475   }
476 }
477 
LoadFromOffset(LoadOperandType type,Register reg,Register base,int32_t offset)478 void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
479                                    int32_t offset) {
480   switch (type) {
481     case kLoadSignedByte:
482       Lb(reg, base, offset);
483       break;
484     case kLoadUnsignedByte:
485       Lbu(reg, base, offset);
486       break;
487     case kLoadSignedHalfword:
488       Lh(reg, base, offset);
489       break;
490     case kLoadUnsignedHalfword:
491       Lhu(reg, base, offset);
492       break;
493     case kLoadWord:
494       Lw(reg, base, offset);
495       break;
496     case kLoadWordPair:
497       LOG(FATAL) << "UNREACHABLE";
498       break;
499     default:
500       LOG(FATAL) << "UNREACHABLE";
501   }
502 }
503 
LoadSFromOffset(FRegister reg,Register base,int32_t offset)504 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
505   Lwc1(reg, base, offset);
506 }
507 
LoadDFromOffset(DRegister reg,Register base,int32_t offset)508 void MipsAssembler::LoadDFromOffset(DRegister reg, Register base, int32_t offset) {
509   Ldc1(reg, base, offset);
510 }
511 
StoreToOffset(StoreOperandType type,Register reg,Register base,int32_t offset)512 void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
513                                   int32_t offset) {
514   switch (type) {
515     case kStoreByte:
516       Sb(reg, base, offset);
517       break;
518     case kStoreHalfword:
519       Sh(reg, base, offset);
520       break;
521     case kStoreWord:
522       Sw(reg, base, offset);
523       break;
524     case kStoreWordPair:
525       LOG(FATAL) << "UNREACHABLE";
526       break;
527     default:
528       LOG(FATAL) << "UNREACHABLE";
529   }
530 }
531 
StoreFToOffset(FRegister reg,Register base,int32_t offset)532 void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) {
533   Swc1(reg, base, offset);
534 }
535 
StoreDToOffset(DRegister reg,Register base,int32_t offset)536 void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) {
537   Sdc1(reg, base, offset);
538 }
539 
DWARFReg(Register reg)540 static dwarf::Reg DWARFReg(Register reg) {
541   return dwarf::Reg::MipsCore(static_cast<int>(reg));
542 }
543 
544 constexpr size_t kFramePointerSize = 4;
545 
BuildFrame(size_t frame_size,ManagedRegister method_reg,const std::vector<ManagedRegister> & callee_save_regs,const ManagedRegisterEntrySpills & entry_spills)546 void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
547                                const std::vector<ManagedRegister>& callee_save_regs,
548                                const ManagedRegisterEntrySpills& entry_spills) {
549   CHECK_ALIGNED(frame_size, kStackAlignment);
550 
551   // Increase frame to required size.
552   IncreaseFrameSize(frame_size);
553 
554   // Push callee saves and return address
555   int stack_offset = frame_size - kFramePointerSize;
556   StoreToOffset(kStoreWord, RA, SP, stack_offset);
557   cfi_.RelOffset(DWARFReg(RA), stack_offset);
558   for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
559     stack_offset -= kFramePointerSize;
560     Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
561     StoreToOffset(kStoreWord, reg, SP, stack_offset);
562     cfi_.RelOffset(DWARFReg(reg), stack_offset);
563   }
564 
565   // Write out Method*.
566   StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
567 
568   // Write out entry spills.
569   for (size_t i = 0; i < entry_spills.size(); ++i) {
570     Register reg = entry_spills.at(i).AsMips().AsCoreRegister();
571     StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize));
572   }
573 }
574 
RemoveFrame(size_t frame_size,const std::vector<ManagedRegister> & callee_save_regs)575 void MipsAssembler::RemoveFrame(size_t frame_size,
576                                 const std::vector<ManagedRegister>& callee_save_regs) {
577   CHECK_ALIGNED(frame_size, kStackAlignment);
578   cfi_.RememberState();
579 
580   // Pop callee saves and return address
581   int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
582   for (size_t i = 0; i < callee_save_regs.size(); ++i) {
583     Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
584     LoadFromOffset(kLoadWord, reg, SP, stack_offset);
585     cfi_.Restore(DWARFReg(reg));
586     stack_offset += kFramePointerSize;
587   }
588   LoadFromOffset(kLoadWord, RA, SP, stack_offset);
589   cfi_.Restore(DWARFReg(RA));
590 
591   // Decrease frame to required size.
592   DecreaseFrameSize(frame_size);
593 
594   // Then jump to the return address.
595   Jr(RA);
596 
597   // The CFI should be restored for any code that follows the exit block.
598   cfi_.RestoreState();
599   cfi_.DefCFAOffset(frame_size);
600 }
601 
IncreaseFrameSize(size_t adjust)602 void MipsAssembler::IncreaseFrameSize(size_t adjust) {
603   CHECK_ALIGNED(adjust, kStackAlignment);
604   AddConstant(SP, SP, -adjust);
605   cfi_.AdjustCFAOffset(adjust);
606 }
607 
DecreaseFrameSize(size_t adjust)608 void MipsAssembler::DecreaseFrameSize(size_t adjust) {
609   CHECK_ALIGNED(adjust, kStackAlignment);
610   AddConstant(SP, SP, adjust);
611   cfi_.AdjustCFAOffset(-adjust);
612 }
613 
Store(FrameOffset dest,ManagedRegister msrc,size_t size)614 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
615   MipsManagedRegister src = msrc.AsMips();
616   if (src.IsNoRegister()) {
617     CHECK_EQ(0u, size);
618   } else if (src.IsCoreRegister()) {
619     CHECK_EQ(4u, size);
620     StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
621   } else if (src.IsRegisterPair()) {
622     CHECK_EQ(8u, size);
623     StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
624     StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
625                   SP, dest.Int32Value() + 4);
626   } else if (src.IsFRegister()) {
627     StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value());
628   } else {
629     CHECK(src.IsDRegister());
630     StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value());
631   }
632 }
633 
StoreRef(FrameOffset dest,ManagedRegister msrc)634 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
635   MipsManagedRegister src = msrc.AsMips();
636   CHECK(src.IsCoreRegister());
637   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
638 }
639 
StoreRawPtr(FrameOffset dest,ManagedRegister msrc)640 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
641   MipsManagedRegister src = msrc.AsMips();
642   CHECK(src.IsCoreRegister());
643   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
644 }
645 
StoreImmediateToFrame(FrameOffset dest,uint32_t imm,ManagedRegister mscratch)646 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
647                                           ManagedRegister mscratch) {
648   MipsManagedRegister scratch = mscratch.AsMips();
649   CHECK(scratch.IsCoreRegister()) << scratch;
650   LoadImmediate(scratch.AsCoreRegister(), imm);
651   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
652 }
653 
StoreImmediateToThread32(ThreadOffset<4> dest,uint32_t imm,ManagedRegister mscratch)654 void MipsAssembler::StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm,
655                                            ManagedRegister mscratch) {
656   MipsManagedRegister scratch = mscratch.AsMips();
657   CHECK(scratch.IsCoreRegister()) << scratch;
658   LoadImmediate(scratch.AsCoreRegister(), imm);
659   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
660 }
661 
StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)662 void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,
663                                              FrameOffset fr_offs,
664                                              ManagedRegister mscratch) {
665   MipsManagedRegister scratch = mscratch.AsMips();
666   CHECK(scratch.IsCoreRegister()) << scratch;
667   AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
668   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
669                 S1, thr_offs.Int32Value());
670 }
671 
StoreStackPointerToThread32(ThreadOffset<4> thr_offs)672 void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs) {
673   StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
674 }
675 
StoreSpanning(FrameOffset dest,ManagedRegister msrc,FrameOffset in_off,ManagedRegister mscratch)676 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
677                                   FrameOffset in_off, ManagedRegister mscratch) {
678   MipsManagedRegister src = msrc.AsMips();
679   MipsManagedRegister scratch = mscratch.AsMips();
680   StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
681   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
682   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
683 }
684 
Load(ManagedRegister mdest,FrameOffset src,size_t size)685 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
686   return EmitLoad(mdest, SP, src.Int32Value(), size);
687 }
688 
LoadFromThread32(ManagedRegister mdest,ThreadOffset<4> src,size_t size)689 void MipsAssembler::LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) {
690   return EmitLoad(mdest, S1, src.Int32Value(), size);
691 }
692 
LoadRef(ManagedRegister mdest,FrameOffset src)693 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
694   MipsManagedRegister dest = mdest.AsMips();
695   CHECK(dest.IsCoreRegister());
696   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value());
697 }
698 
LoadRef(ManagedRegister mdest,ManagedRegister base,MemberOffset offs,bool poison_reference)699 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
700                             bool poison_reference) {
701   MipsManagedRegister dest = mdest.AsMips();
702   CHECK(dest.IsCoreRegister() && dest.IsCoreRegister());
703   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
704                  base.AsMips().AsCoreRegister(), offs.Int32Value());
705   if (kPoisonHeapReferences && poison_reference) {
706     Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
707   }
708 }
709 
LoadRawPtr(ManagedRegister mdest,ManagedRegister base,Offset offs)710 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
711                                Offset offs) {
712   MipsManagedRegister dest = mdest.AsMips();
713   CHECK(dest.IsCoreRegister() && dest.IsCoreRegister()) << dest;
714   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
715                  base.AsMips().AsCoreRegister(), offs.Int32Value());
716 }
717 
LoadRawPtrFromThread32(ManagedRegister mdest,ThreadOffset<4> offs)718 void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest,
719                                          ThreadOffset<4> offs) {
720   MipsManagedRegister dest = mdest.AsMips();
721   CHECK(dest.IsCoreRegister());
722   LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
723 }
724 
SignExtend(ManagedRegister,size_t)725 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
726   UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
727 }
728 
ZeroExtend(ManagedRegister,size_t)729 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
730   UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
731 }
732 
Move(ManagedRegister mdest,ManagedRegister msrc,size_t)733 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t /*size*/) {
734   MipsManagedRegister dest = mdest.AsMips();
735   MipsManagedRegister src = msrc.AsMips();
736   if (!dest.Equals(src)) {
737     if (dest.IsCoreRegister()) {
738       CHECK(src.IsCoreRegister()) << src;
739       Move(dest.AsCoreRegister(), src.AsCoreRegister());
740     } else if (dest.IsFRegister()) {
741       CHECK(src.IsFRegister()) << src;
742       MovS(dest.AsFRegister(), src.AsFRegister());
743     } else if (dest.IsDRegister()) {
744       CHECK(src.IsDRegister()) << src;
745       MovD(dest.AsDRegister(), src.AsDRegister());
746     } else {
747       CHECK(dest.IsRegisterPair()) << dest;
748       CHECK(src.IsRegisterPair()) << src;
749       // Ensure that the first move doesn't clobber the input of the second
750       if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) {
751         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
752         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
753       } else {
754         Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh());
755         Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow());
756       }
757     }
758   }
759 }
760 
CopyRef(FrameOffset dest,FrameOffset src,ManagedRegister mscratch)761 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src,
762                             ManagedRegister mscratch) {
763   MipsManagedRegister scratch = mscratch.AsMips();
764   CHECK(scratch.IsCoreRegister()) << scratch;
765   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
766   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
767 }
768 
CopyRawPtrFromThread32(FrameOffset fr_offs,ThreadOffset<4> thr_offs,ManagedRegister mscratch)769 void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
770                                          ThreadOffset<4> thr_offs,
771                                          ManagedRegister mscratch) {
772   MipsManagedRegister scratch = mscratch.AsMips();
773   CHECK(scratch.IsCoreRegister()) << scratch;
774   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
775                  S1, thr_offs.Int32Value());
776   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
777                 SP, fr_offs.Int32Value());
778 }
779 
CopyRawPtrToThread32(ThreadOffset<4> thr_offs,FrameOffset fr_offs,ManagedRegister mscratch)780 void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs,
781                                        FrameOffset fr_offs,
782                                        ManagedRegister mscratch) {
783   MipsManagedRegister scratch = mscratch.AsMips();
784   CHECK(scratch.IsCoreRegister()) << scratch;
785   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
786                  SP, fr_offs.Int32Value());
787   StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
788                 S1, thr_offs.Int32Value());
789 }
790 
Copy(FrameOffset dest,FrameOffset src,ManagedRegister mscratch,size_t size)791 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src,
792                          ManagedRegister mscratch, size_t size) {
793   MipsManagedRegister scratch = mscratch.AsMips();
794   CHECK(scratch.IsCoreRegister()) << scratch;
795   CHECK(size == 4 || size == 8) << size;
796   if (size == 4) {
797     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
798     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
799   } else if (size == 8) {
800     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
801     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
802     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + 4);
803     StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
804   }
805 }
806 
Copy(FrameOffset dest,ManagedRegister src_base,Offset src_offset,ManagedRegister mscratch,size_t size)807 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
808                          ManagedRegister mscratch, size_t size) {
809   Register scratch = mscratch.AsMips().AsCoreRegister();
810   CHECK_EQ(size, 4u);
811   LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value());
812   StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
813 }
814 
Copy(ManagedRegister dest_base,Offset dest_offset,FrameOffset src,ManagedRegister mscratch,size_t size)815 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
816                          ManagedRegister mscratch, size_t size) {
817   Register scratch = mscratch.AsMips().AsCoreRegister();
818   CHECK_EQ(size, 4u);
819   LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
820   StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value());
821 }
822 
Copy(FrameOffset,FrameOffset,Offset,ManagedRegister,size_t)823 void MipsAssembler::Copy(FrameOffset /*dest*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
824                          ManagedRegister /*mscratch*/, size_t /*size*/) {
825   UNIMPLEMENTED(FATAL) << "no mips implementation";
826 }
827 
Copy(ManagedRegister dest,Offset dest_offset,ManagedRegister src,Offset src_offset,ManagedRegister mscratch,size_t size)828 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset,
829                          ManagedRegister src, Offset src_offset,
830                          ManagedRegister mscratch, size_t size) {
831   CHECK_EQ(size, 4u);
832   Register scratch = mscratch.AsMips().AsCoreRegister();
833   LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value());
834   StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value());
835 }
836 
Copy(FrameOffset,Offset,FrameOffset,Offset,ManagedRegister,size_t)837 void MipsAssembler::Copy(FrameOffset /*dest*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/,
838                          ManagedRegister /*mscratch*/, size_t /*size*/) {
839   UNIMPLEMENTED(FATAL) << "no mips implementation";
840 }
841 
MemoryBarrier(ManagedRegister)842 void MipsAssembler::MemoryBarrier(ManagedRegister) {
843   UNIMPLEMENTED(FATAL) << "no mips implementation";
844 }
845 
CreateHandleScopeEntry(ManagedRegister mout_reg,FrameOffset handle_scope_offset,ManagedRegister min_reg,bool null_allowed)846 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
847                                     FrameOffset handle_scope_offset,
848                                     ManagedRegister min_reg, bool null_allowed) {
849   MipsManagedRegister out_reg = mout_reg.AsMips();
850   MipsManagedRegister in_reg = min_reg.AsMips();
851   CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
852   CHECK(out_reg.IsCoreRegister()) << out_reg;
853   if (null_allowed) {
854     Label null_arg;
855     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
856     // the address in the handle scope holding the reference.
857     // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
858     if (in_reg.IsNoRegister()) {
859       LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
860                      SP, handle_scope_offset.Int32Value());
861       in_reg = out_reg;
862     }
863     if (!out_reg.Equals(in_reg)) {
864       LoadImmediate(out_reg.AsCoreRegister(), 0);
865     }
866     EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true);
867     AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
868     Bind(&null_arg, false);
869   } else {
870     AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
871   }
872 }
873 
CreateHandleScopeEntry(FrameOffset out_off,FrameOffset handle_scope_offset,ManagedRegister mscratch,bool null_allowed)874 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
875                                     FrameOffset handle_scope_offset,
876                                     ManagedRegister mscratch,
877                                     bool null_allowed) {
878   MipsManagedRegister scratch = mscratch.AsMips();
879   CHECK(scratch.IsCoreRegister()) << scratch;
880   if (null_allowed) {
881     Label null_arg;
882     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
883                    handle_scope_offset.Int32Value());
884     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
885     // the address in the handle scope holding the reference.
886     // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
887     EmitBranch(scratch.AsCoreRegister(), ZERO, &null_arg, true);
888     AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
889     Bind(&null_arg, false);
890   } else {
891     AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
892   }
893   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
894 }
895 
896 // Given a handle scope entry, load the associated reference.
LoadReferenceFromHandleScope(ManagedRegister mout_reg,ManagedRegister min_reg)897 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
898                                           ManagedRegister min_reg) {
899   MipsManagedRegister out_reg = mout_reg.AsMips();
900   MipsManagedRegister in_reg = min_reg.AsMips();
901   CHECK(out_reg.IsCoreRegister()) << out_reg;
902   CHECK(in_reg.IsCoreRegister()) << in_reg;
903   Label null_arg;
904   if (!out_reg.Equals(in_reg)) {
905     LoadImmediate(out_reg.AsCoreRegister(), 0);
906   }
907   EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true);
908   LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
909                  in_reg.AsCoreRegister(), 0);
910   Bind(&null_arg, false);
911 }
912 
VerifyObject(ManagedRegister,bool)913 void MipsAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
914   // TODO: not validating references
915 }
916 
VerifyObject(FrameOffset,bool)917 void MipsAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
918   // TODO: not validating references
919 }
920 
Call(ManagedRegister mbase,Offset offset,ManagedRegister mscratch)921 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
922   MipsManagedRegister base = mbase.AsMips();
923   MipsManagedRegister scratch = mscratch.AsMips();
924   CHECK(base.IsCoreRegister()) << base;
925   CHECK(scratch.IsCoreRegister()) << scratch;
926   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
927                  base.AsCoreRegister(), offset.Int32Value());
928   Jalr(scratch.AsCoreRegister());
929   // TODO: place reference map on call
930 }
931 
Call(FrameOffset base,Offset offset,ManagedRegister mscratch)932 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
933   MipsManagedRegister scratch = mscratch.AsMips();
934   CHECK(scratch.IsCoreRegister()) << scratch;
935   // Call *(*(SP + base) + offset)
936   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
937                  SP, base.Int32Value());
938   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
939                  scratch.AsCoreRegister(), offset.Int32Value());
940   Jalr(scratch.AsCoreRegister());
941   // TODO: place reference map on call
942 }
943 
CallFromThread32(ThreadOffset<4>,ManagedRegister)944 void MipsAssembler::CallFromThread32(ThreadOffset<4> /*offset*/, ManagedRegister /*mscratch*/) {
945   UNIMPLEMENTED(FATAL) << "no mips implementation";
946 }
947 
GetCurrentThread(ManagedRegister tr)948 void MipsAssembler::GetCurrentThread(ManagedRegister tr) {
949   Move(tr.AsMips().AsCoreRegister(), S1);
950 }
951 
GetCurrentThread(FrameOffset offset,ManagedRegister)952 void MipsAssembler::GetCurrentThread(FrameOffset offset,
953                                      ManagedRegister /*mscratch*/) {
954   StoreToOffset(kStoreWord, S1, SP, offset.Int32Value());
955 }
956 
ExceptionPoll(ManagedRegister mscratch,size_t stack_adjust)957 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
958   MipsManagedRegister scratch = mscratch.AsMips();
959   MipsExceptionSlowPath* slow = new MipsExceptionSlowPath(scratch, stack_adjust);
960   buffer_.EnqueueSlowPath(slow);
961   LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
962                  S1, Thread::ExceptionOffset<4>().Int32Value());
963   EmitBranch(scratch.AsCoreRegister(), ZERO, slow->Entry(), false);
964 }
965 
Emit(Assembler * sasm)966 void MipsExceptionSlowPath::Emit(Assembler* sasm) {
967   MipsAssembler* sp_asm = down_cast<MipsAssembler*>(sasm);
968 #define __ sp_asm->
969   __ Bind(&entry_, false);
970   if (stack_adjust_ != 0) {  // Fix up the frame.
971     __ DecreaseFrameSize(stack_adjust_);
972   }
973   // Pass exception object as argument
974   // Don't care about preserving A0 as this call won't return
975   __ Move(A0, scratch_.AsCoreRegister());
976   // Set up call to Thread::Current()->pDeliverException
977   __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
978   __ Jr(T9);
979   // Call never returns
980   __ Break();
981 #undef __
982 }
983 
984 }  // namespace mips
985 }  // namespace art
986