Home | History | Annotate | Download | only in s390
      1 // Copyright 2015 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_S390
      6 
      7 #include "src/ic/ic.h"
      8 #include "src/codegen.h"
      9 #include "src/ic/stub-cache.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 
     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 bool CompareIC::HasInlinedSmiCode(Address address) {
     35   // The address of the instruction following the call.
     36   Address cmp_instruction_address =
     37       Assembler::return_address_from_call_start(address);
     38 
     39   // If the instruction following the call is not a CHI, nothing
     40   // was inlined.
     41   return (Instruction::S390OpcodeValue(cmp_instruction_address) == CHI);
     42 }
     43 
     44 //
     45 // This code is paired with the JumpPatchSite class in full-codegen-s390.cc
     46 //
     47 void PatchInlinedSmiCode(Isolate* isolate, Address address,
     48                          InlinedSmiCheck check) {
     49   Address cmp_instruction_address =
     50       Assembler::return_address_from_call_start(address);
     51 
     52   // If the instruction following the call is not a cmp rx, #yyy, nothing
     53   // was inlined.
     54   Instr instr = Assembler::instr_at(cmp_instruction_address);
     55   if (Instruction::S390OpcodeValue(cmp_instruction_address) != CHI) {
     56     return;
     57   }
     58 
     59   if (Instruction::S390OpcodeValue(address) != BRASL) {
     60     return;
     61   }
     62   // The delta to the start of the map check instruction and the
     63   // condition code uses at the patched jump.
     64   int delta = instr & 0x0000ffff;
     65 
     66   // If the delta is 0 the instruction is cmp r0, #0 which also signals that
     67   // nothing was inlined.
     68   if (delta == 0) {
     69     return;
     70   }
     71 
     72   if (FLAG_trace_ic) {
     73     LOG(isolate, PatchIC(address, cmp_instruction_address, delta));
     74   }
     75 
     76   // Expected sequence to enable by changing the following
     77   //   CR/CGR  Rx, Rx    // 2 / 4 bytes
     78   //   LR  R0, R0        // 2 bytes   // 31-bit only!
     79   //   BRC/BRCL          // 4 / 6 bytes
     80   // into
     81   //   TMLL    Rx, XXX   // 4 bytes
     82   //   BRC/BRCL          // 4 / 6 bytes
     83   // And vice versa to disable.
     84 
     85   // The following constant is the size of the CR/CGR + LR + LR
     86   const int kPatchAreaSizeNoBranch = 4;
     87   Address patch_address = cmp_instruction_address - delta;
     88   Address branch_address = patch_address + kPatchAreaSizeNoBranch;
     89 
     90   Instr instr_at_patch = Assembler::instr_at(patch_address);
     91   SixByteInstr branch_instr = Assembler::instr_at(branch_address);
     92 
     93   // This is patching a conditional "jump if not smi/jump if smi" site.
     94   size_t patch_size = 0;
     95   if (Instruction::S390OpcodeValue(branch_address) == BRC) {
     96     patch_size = kPatchAreaSizeNoBranch + 4;
     97   } else if (Instruction::S390OpcodeValue(branch_address) == BRCL) {
     98     patch_size = kPatchAreaSizeNoBranch + 6;
     99   } else {
    100     DCHECK(false);
    101   }
    102   CodePatcher patcher(isolate, patch_address, patch_size);
    103   Register reg;
    104   reg.reg_code = instr_at_patch & 0xf;
    105   if (check == ENABLE_INLINED_SMI_CHECK) {
    106     patcher.masm()->TestIfSmi(reg);
    107   } else {
    108     // Emit the NOP to ensure sufficient place for patching
    109     // (replaced by LR + NILL)
    110     DCHECK(check == DISABLE_INLINED_SMI_CHECK);
    111     patcher.masm()->CmpP(reg, reg);
    112 #ifndef V8_TARGET_ARCH_S390X
    113     patcher.masm()->nop();
    114 #endif
    115   }
    116 
    117   Condition cc = al;
    118   if (Instruction::S390OpcodeValue(branch_address) == BRC) {
    119     cc = static_cast<Condition>((branch_instr & 0x00f00000) >> 20);
    120     DCHECK((cc == ne) || (cc == eq));
    121     cc = (cc == ne) ? eq : ne;
    122     patcher.masm()->brc(cc, Operand(branch_instr & 0xffff));
    123   } else if (Instruction::S390OpcodeValue(branch_address) == BRCL) {
    124     cc = static_cast<Condition>(
    125         (branch_instr & (static_cast<uint64_t>(0x00f0) << 32)) >> 36);
    126     DCHECK((cc == ne) || (cc == eq));
    127     cc = (cc == ne) ? eq : ne;
    128     patcher.masm()->brcl(cc, Operand(branch_instr & 0xffffffff));
    129   } else {
    130     DCHECK(false);
    131   }
    132 }
    133 
    134 }  // namespace internal
    135 }  // namespace v8
    136 
    137 #endif  // V8_TARGET_ARCH_S390
    138