• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_MIPS64
6 
7 #include "src/codegen.h"
8 #include "src/ic/ic.h"
9 #include "src/ic/stub-cache.h"
10 
11 namespace v8 {
12 namespace internal {
13 
14 
ComputeCondition(Token::Value op)15 Condition 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 
HasInlinedSmiCode(Address address)35 bool 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 
PatchInlinedSmiCode(Isolate * isolate,Address address,InlinedSmiCheck check)48 void 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_MIPS64
140