Home | History | Annotate | Download | only in mips64
      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 #include "src/interface-descriptors.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 #define __ ACCESS_MASM(masm)
     16 
     17 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
     18                        Code::Flags flags, StubCache::Table table,
     19                        Register receiver, Register name,
     20                        // Number of the cache entry, not scaled.
     21                        Register offset, Register scratch, Register scratch2,
     22                        Register offset_scratch) {
     23   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
     24   ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
     25   ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
     26 
     27   uint64_t key_off_addr = reinterpret_cast<uint64_t>(key_offset.address());
     28   uint64_t value_off_addr = reinterpret_cast<uint64_t>(value_offset.address());
     29   uint64_t map_off_addr = reinterpret_cast<uint64_t>(map_offset.address());
     30 
     31   // Check the relative positions of the address fields.
     32   DCHECK(value_off_addr > key_off_addr);
     33   DCHECK((value_off_addr - key_off_addr) % 4 == 0);
     34   DCHECK((value_off_addr - key_off_addr) < (256 * 4));
     35   DCHECK(map_off_addr > key_off_addr);
     36   DCHECK((map_off_addr - key_off_addr) % 4 == 0);
     37   DCHECK((map_off_addr - key_off_addr) < (256 * 4));
     38 
     39   Label miss;
     40   Register base_addr = scratch;
     41   scratch = no_reg;
     42 
     43   // Multiply by 3 because there are 3 fields per entry (name, code, map).
     44   __ Dlsa(offset_scratch, offset, offset, 1);
     45 
     46   // Calculate the base address of the entry.
     47   __ li(base_addr, Operand(key_offset));
     48   __ Dlsa(base_addr, base_addr, offset_scratch, kPointerSizeLog2);
     49 
     50   // Check that the key in the entry matches the name.
     51   __ ld(at, MemOperand(base_addr, 0));
     52   __ Branch(&miss, ne, name, Operand(at));
     53 
     54   // Check the map matches.
     55   __ ld(at, MemOperand(base_addr,
     56                        static_cast<int32_t>(map_off_addr - key_off_addr)));
     57   __ ld(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
     58   __ Branch(&miss, ne, at, Operand(scratch2));
     59 
     60   // Get the code entry from the cache.
     61   Register code = scratch2;
     62   scratch2 = no_reg;
     63   __ ld(code, MemOperand(base_addr,
     64                          static_cast<int32_t>(value_off_addr - key_off_addr)));
     65 
     66   // Check that the flags match what we're looking for.
     67   Register flags_reg = base_addr;
     68   base_addr = no_reg;
     69   __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
     70   __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
     71   __ Branch(&miss, ne, flags_reg, Operand(flags));
     72 
     73 #ifdef DEBUG
     74   if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
     75     __ jmp(&miss);
     76   } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
     77     __ jmp(&miss);
     78   }
     79 #endif
     80 
     81   // Jump to the first instruction in the code stub.
     82   __ Daddu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
     83   __ Jump(at);
     84 
     85   // Miss: fall through.
     86   __ bind(&miss);
     87 }
     88 
     89 
     90 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
     91                               Code::Flags flags, Register receiver,
     92                               Register name, Register scratch, Register extra,
     93                               Register extra2, Register extra3) {
     94   Isolate* isolate = masm->isolate();
     95   Label miss;
     96 
     97   // Make sure that code is valid. The multiplying code relies on the
     98   // entry size being 12.
     99   // DCHECK(sizeof(Entry) == 12);
    100   // DCHECK(sizeof(Entry) == 3 * kPointerSize);
    101 
    102   // Make sure that there are no register conflicts.
    103   DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
    104 
    105   // Check register validity.
    106   DCHECK(!scratch.is(no_reg));
    107   DCHECK(!extra.is(no_reg));
    108   DCHECK(!extra2.is(no_reg));
    109   DCHECK(!extra3.is(no_reg));
    110 
    111 #ifdef DEBUG
    112   // If vector-based ics are in use, ensure that scratch, extra, extra2 and
    113   // extra3 don't conflict with the vector and slot registers, which need
    114   // to be preserved for a handler call or miss.
    115   if (IC::ICUseVector(ic_kind)) {
    116     Register vector, slot;
    117     if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
    118       vector = VectorStoreICDescriptor::VectorRegister();
    119       slot = VectorStoreICDescriptor::SlotRegister();
    120     } else {
    121       vector = LoadWithVectorDescriptor::VectorRegister();
    122       slot = LoadWithVectorDescriptor::SlotRegister();
    123     }
    124     DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
    125   }
    126 #endif
    127 
    128   Counters* counters = masm->isolate()->counters();
    129   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
    130                       extra3);
    131 
    132   // Check that the receiver isn't a smi.
    133   __ JumpIfSmi(receiver, &miss);
    134 
    135   // Get the map of the receiver and compute the hash.
    136   __ ld(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
    137   __ ld(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
    138   __ Daddu(scratch, scratch, at);
    139   uint64_t mask = kPrimaryTableSize - 1;
    140   // We shift out the last two bits because they are not part of the hash and
    141   // they are always 01 for maps.
    142   __ dsrl(scratch, scratch, kCacheIndexShift);
    143   __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask));
    144   __ And(scratch, scratch, Operand(mask));
    145 
    146   // Probe the primary table.
    147   ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
    148              extra2, extra3);
    149 
    150   // Primary miss: Compute hash for secondary probe.
    151   __ dsrl(at, name, kCacheIndexShift);
    152   __ Dsubu(scratch, scratch, at);
    153   uint64_t mask2 = kSecondaryTableSize - 1;
    154   __ Daddu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2));
    155   __ And(scratch, scratch, Operand(mask2));
    156 
    157   // Probe the secondary table.
    158   ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
    159              extra2, extra3);
    160 
    161   // Cache miss: Fall-through and let caller handle the miss by
    162   // entering the runtime system.
    163   __ bind(&miss);
    164   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
    165                       extra3);
    166 }
    167 
    168 
    169 #undef __
    170 }  // namespace internal
    171 }  // namespace v8
    172 
    173 #endif  // V8_TARGET_ARCH_MIPS64
    174