1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved. 2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file. 4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_MIPS 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/ic.h" 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/stub-cache.h" 10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 { 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal { 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCondition CompareIC::ComputeCondition(Token::Value op) { 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch switch (op) { 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::EQ_STRICT: 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::EQ: 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return eq; 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::LT: 21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return lt; 22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::GT: 23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return gt; 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::LTE: 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return le; 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Token::GTE: 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return ge; 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default: 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch UNREACHABLE(); 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return kNoCondition; 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbool CompareIC::HasInlinedSmiCode(Address address) { 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The address of the instruction following the call. 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address andi_instruction_address = 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch address + Assembler::kCallTargetAddressOffset; 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // If the instruction following the call is not a andi at, rx, #yyy, nothing 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // was inlined. 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Instr instr = Assembler::instr_at(andi_instruction_address); 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return Assembler::IsAndImmediate(instr) && 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()); 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid PatchInlinedSmiCode(Isolate* isolate, Address address, 49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch InlinedSmiCheck check) { 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address andi_instruction_address = 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch address + Assembler::kCallTargetAddressOffset; 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // If the instruction following the call is not a andi at, rx, #yyy, nothing 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // was inlined. 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Instr instr = Assembler::instr_at(andi_instruction_address); 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (!(Assembler::IsAndImmediate(instr) && 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) { 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return; 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The delta to the start of the map check instruction and the 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // condition code uses at the patched jump. 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int delta = Assembler::GetImmediate16(instr); 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch delta += Assembler::GetRs(instr) * kImm16Mask; 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // If the delta is 0 the instruction is andi at, zero_reg, #0 which also 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // signals that nothing was inlined. 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (delta == 0) { 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return; 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (FLAG_trace_ic) { 7262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch LOG(isolate, PatchIC(address, andi_instruction_address, delta)); 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address patch_address = 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch andi_instruction_address - delta * Instruction::kInstrSize; 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Instr instr_at_patch = Assembler::instr_at(patch_address); 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // This is patching a conditional "jump if not smi/jump if smi" site. 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Enabling by changing from 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // andi at, rx, 0 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Branch <target>, eq, at, Operand(zero_reg) 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // to: 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // andi at, rx, #kSmiTagMask 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Branch <target>, ne, at, Operand(zero_reg) 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // and vice-versa to be disabled again. 86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CodePatcher patcher(isolate, patch_address, 2); 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (check == ENABLE_INLINED_SMI_CHECK) { 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Assembler::IsAndImmediate(instr_at_patch)); 90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(0u, Assembler::GetImmediate16(instr_at_patch)); 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch patcher.masm()->andi(at, reg, kSmiTagMask); 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(check, DISABLE_INLINED_SMI_CHECK); 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Assembler::IsAndImmediate(instr_at_patch)); 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch patcher.masm()->andi(at, reg, 0); 96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Instr branch_instr = 98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Assembler::instr_at(patch_address + Instruction::kInstrSize); 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Assembler::IsBranch(branch_instr)); 100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t opcode = Assembler::GetOpcodeField(branch_instr); 102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Currently only the 'eq' and 'ne' cond values are supported and the simple 103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // branch instructions and their r6 variants (with opcode being the branch 104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // type). There are some special cases (see Assembler::IsBranch()) so 105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // extending this would be tricky. 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(opcode == BEQ || // BEQ 107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode == BNE || // BNE 108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode == POP10 || // BEQC 109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode == POP30 || // BNEC 110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode == POP66 || // BEQZC 111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode == POP76); // BNEZC 112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch switch (opcode) { 113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case BEQ: 114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = BNE; // change BEQ to BNE. 115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case POP10: 117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = POP30; // change BEQC to BNEC. 118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case POP66: 120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = POP76; // change BEQZC to BNEZC. 121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case BNE: 123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = BEQ; // change BNE to BEQ. 124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case POP30: 126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = POP10; // change BNEC to BEQC. 127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch case POP76: 129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch opcode = POP66; // change BNEZC to BEQZC. 130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch break; 131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch default: 132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch UNIMPLEMENTED(); 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch patcher.ChangeBranchCondition(branch_instr, opcode); 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif // V8_TARGET_ARCH_MIPS 140