1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#if V8_TARGET_ARCH_MIPS
6
7#include "src/codegen.h"
8#include "src/ic/ic.h"
9#include "src/ic/stub-cache.h"
10
11namespace v8 {
12namespace internal {
13
14
15Condition CompareIC::ComputeCondition(Token::Value op) {
16  switch (op) {
17    case Token::EQ_STRICT:
18    case Token::EQ:
19      return eq;
20    case Token::LT:
21      return lt;
22    case Token::GT:
23      return gt;
24    case Token::LTE:
25      return le;
26    case Token::GTE:
27      return ge;
28    default:
29      UNREACHABLE();
30      return kNoCondition;
31  }
32}
33
34
35bool CompareIC::HasInlinedSmiCode(Address address) {
36  // The address of the instruction following the call.
37  Address andi_instruction_address =
38      address + Assembler::kCallTargetAddressOffset;
39
40  // If the instruction following the call is not a andi at, rx, #yyy, nothing
41  // was inlined.
42  Instr instr = Assembler::instr_at(andi_instruction_address);
43  return Assembler::IsAndImmediate(instr) &&
44         Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
45}
46
47
48void PatchInlinedSmiCode(Isolate* isolate, Address address,
49                         InlinedSmiCheck check) {
50  Address andi_instruction_address =
51      address + Assembler::kCallTargetAddressOffset;
52
53  // If the instruction following the call is not a andi at, rx, #yyy, nothing
54  // was inlined.
55  Instr instr = Assembler::instr_at(andi_instruction_address);
56  if (!(Assembler::IsAndImmediate(instr) &&
57        Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
58    return;
59  }
60
61  // The delta to the start of the map check instruction and the
62  // condition code uses at the patched jump.
63  int delta = Assembler::GetImmediate16(instr);
64  delta += Assembler::GetRs(instr) * kImm16Mask;
65  // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
66  // signals that nothing was inlined.
67  if (delta == 0) {
68    return;
69  }
70
71  if (FLAG_trace_ic) {
72    LOG(isolate, PatchIC(address, andi_instruction_address, delta));
73  }
74
75  Address patch_address =
76      andi_instruction_address - delta * Instruction::kInstrSize;
77  Instr instr_at_patch = Assembler::instr_at(patch_address);
78  // This is patching a conditional "jump if not smi/jump if smi" site.
79  // Enabling by changing from
80  //   andi at, rx, 0
81  //   Branch <target>, eq, at, Operand(zero_reg)
82  // to:
83  //   andi at, rx, #kSmiTagMask
84  //   Branch <target>, ne, at, Operand(zero_reg)
85  // and vice-versa to be disabled again.
86  CodePatcher patcher(isolate, patch_address, 2);
87  Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
88  if (check == ENABLE_INLINED_SMI_CHECK) {
89    DCHECK(Assembler::IsAndImmediate(instr_at_patch));
90    DCHECK_EQ(0u, Assembler::GetImmediate16(instr_at_patch));
91    patcher.masm()->andi(at, reg, kSmiTagMask);
92  } else {
93    DCHECK_EQ(check, DISABLE_INLINED_SMI_CHECK);
94    DCHECK(Assembler::IsAndImmediate(instr_at_patch));
95    patcher.masm()->andi(at, reg, 0);
96  }
97  Instr branch_instr =
98      Assembler::instr_at(patch_address + Instruction::kInstrSize);
99  DCHECK(Assembler::IsBranch(branch_instr));
100
101  uint32_t opcode = Assembler::GetOpcodeField(branch_instr);
102  // Currently only the 'eq' and 'ne' cond values are supported and the simple
103  // branch instructions and their r6 variants (with opcode being the branch
104  // type). There are some special cases (see Assembler::IsBranch()) so
105  // extending this would be tricky.
106  DCHECK(opcode == BEQ ||    // BEQ
107         opcode == BNE ||    // BNE
108         opcode == POP10 ||  // BEQC
109         opcode == POP30 ||  // BNEC
110         opcode == POP66 ||  // BEQZC
111         opcode == POP76);   // BNEZC
112  switch (opcode) {
113    case BEQ:
114      opcode = BNE;  // change BEQ to BNE.
115      break;
116    case POP10:
117      opcode = POP30;  // change BEQC to BNEC.
118      break;
119    case POP66:
120      opcode = POP76;  // change BEQZC to BNEZC.
121      break;
122    case BNE:
123      opcode = BEQ;  // change BNE to BEQ.
124      break;
125    case POP30:
126      opcode = POP10;  // change BNEC to BEQC.
127      break;
128    case POP76:
129      opcode = POP66;  // change BNEZC to BEQZC.
130      break;
131    default:
132      UNIMPLEMENTED();
133  }
134  patcher.ChangeBranchCondition(branch_instr, opcode);
135}
136}  // namespace internal
137}  // namespace v8
138
139#endif  // V8_TARGET_ARCH_MIPS
140