Home | History | Annotate | Download | only in x87
      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_X87
      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 
     18 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
     19                        Code::Kind ic_kind, Code::Flags flags,
     20                        StubCache::Table table, Register name, Register receiver,
     21                        // Number of the cache entry pointer-size scaled.
     22                        Register offset, Register extra) {
     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   ExternalReference virtual_register =
     27       ExternalReference::virtual_handler_register(masm->isolate());
     28 
     29   Label miss;
     30   bool is_vector_store =
     31       IC::ICUseVector(ic_kind) &&
     32       (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
     33 
     34   // Multiply by 3 because there are 3 fields per entry (name, code, map).
     35   __ lea(offset, Operand(offset, offset, times_2, 0));
     36 
     37   if (extra.is_valid()) {
     38     // Get the code entry from the cache.
     39     __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
     40 
     41     // Check that the key in the entry matches the name.
     42     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
     43     __ j(not_equal, &miss);
     44 
     45     // Check the map matches.
     46     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
     47     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
     48     __ j(not_equal, &miss);
     49 
     50     // Check that the flags match what we're looking for.
     51     __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
     52     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
     53     __ cmp(offset, flags);
     54     __ j(not_equal, &miss);
     55 
     56 #ifdef DEBUG
     57     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
     58       __ jmp(&miss);
     59     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
     60       __ jmp(&miss);
     61     }
     62 #endif
     63 
     64     // The vector and slot were pushed onto the stack before starting the
     65     // probe, and need to be dropped before calling the handler.
     66     if (is_vector_store) {
     67       // The overlap here is rather embarrassing. One does what one must.
     68       Register vector = VectorStoreICDescriptor::VectorRegister();
     69       DCHECK(extra.is(VectorStoreICDescriptor::SlotRegister()));
     70       __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
     71       __ pop(vector);
     72       __ mov(Operand::StaticVariable(virtual_register), extra);
     73       __ pop(extra);  // Pop "slot".
     74       // Jump to the first instruction in the code stub.
     75       __ jmp(Operand::StaticVariable(virtual_register));
     76     } else {
     77       __ pop(LoadWithVectorDescriptor::VectorRegister());
     78       __ pop(LoadDescriptor::SlotRegister());
     79       __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
     80       __ jmp(extra);
     81     }
     82 
     83     __ bind(&miss);
     84   } else {
     85     DCHECK(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
     86 
     87     // Save the offset on the stack.
     88     __ push(offset);
     89 
     90     // Check that the key in the entry matches the name.
     91     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
     92     __ j(not_equal, &miss);
     93 
     94     // Check the map matches.
     95     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
     96     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
     97     __ j(not_equal, &miss);
     98 
     99     // Restore offset register.
    100     __ mov(offset, Operand(esp, 0));
    101 
    102     // Get the code entry from the cache.
    103     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
    104 
    105     // Check that the flags match what we're looking for.
    106     __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
    107     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
    108     __ cmp(offset, flags);
    109     __ j(not_equal, &miss);
    110 
    111 #ifdef DEBUG
    112     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
    113       __ jmp(&miss);
    114     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
    115       __ jmp(&miss);
    116     }
    117 #endif
    118 
    119     // Restore offset and re-load code entry from cache.
    120     __ pop(offset);
    121     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
    122 
    123     // Jump to the first instruction in the code stub.
    124     if (is_vector_store) {
    125       // The vector and slot were pushed onto the stack before starting the
    126       // probe, and need to be dropped before calling the handler.
    127       Register vector = VectorStoreICDescriptor::VectorRegister();
    128       DCHECK(offset.is(VectorStoreICDescriptor::SlotRegister()));
    129       __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
    130       __ mov(Operand::StaticVariable(virtual_register), offset);
    131       __ pop(vector);
    132       __ pop(offset);  // Pop "slot".
    133       __ jmp(Operand::StaticVariable(virtual_register));
    134     } else {
    135       __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
    136       __ jmp(offset);
    137     }
    138 
    139     // Pop at miss.
    140     __ bind(&miss);
    141     __ pop(offset);
    142   }
    143 }
    144 
    145 
    146 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
    147                               Code::Flags flags, Register receiver,
    148                               Register name, Register scratch, Register extra,
    149                               Register extra2, Register extra3) {
    150   Label miss;
    151 
    152   // Assert that code is valid.  The multiplying code relies on the entry size
    153   // being 12.
    154   DCHECK(sizeof(Entry) == 12);
    155 
    156   // Assert that there are no register conflicts.
    157   DCHECK(!scratch.is(receiver));
    158   DCHECK(!scratch.is(name));
    159   DCHECK(!extra.is(receiver));
    160   DCHECK(!extra.is(name));
    161   DCHECK(!extra.is(scratch));
    162 
    163   // Assert scratch and extra registers are valid, and extra2/3 are unused.
    164   DCHECK(!scratch.is(no_reg));
    165   DCHECK(extra2.is(no_reg));
    166   DCHECK(extra3.is(no_reg));
    167 
    168   Register offset = scratch;
    169   scratch = no_reg;
    170 
    171   Counters* counters = masm->isolate()->counters();
    172   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
    173 
    174   // Check that the receiver isn't a smi.
    175   __ JumpIfSmi(receiver, &miss);
    176 
    177   // Get the map of the receiver and compute the hash.
    178   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
    179   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
    180   __ xor_(offset, flags);
    181   // We mask out the last two bits because they are not part of the hash and
    182   // they are always 01 for maps.  Also in the two 'and' instructions below.
    183   __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
    184   // ProbeTable expects the offset to be pointer scaled, which it is, because
    185   // the heap object tag size is 2 and the pointer size log 2 is also 2.
    186   DCHECK(kCacheIndexShift == kPointerSizeLog2);
    187 
    188   // Probe the primary table.
    189   ProbeTable(isolate(), masm, ic_kind, flags, kPrimary, name, receiver, offset,
    190              extra);
    191 
    192   // Primary miss: Compute hash for secondary probe.
    193   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
    194   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
    195   __ xor_(offset, flags);
    196   __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
    197   __ sub(offset, name);
    198   __ add(offset, Immediate(flags));
    199   __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
    200 
    201   // Probe the secondary table.
    202   ProbeTable(isolate(), masm, ic_kind, flags, kSecondary, name, receiver,
    203              offset, extra);
    204 
    205   // Cache miss: Fall-through and let caller handle the miss by
    206   // entering the runtime system.
    207   __ bind(&miss);
    208   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
    209 }
    210 
    211 
    212 #undef __
    213 }  // namespace internal
    214 }  // namespace v8
    215 
    216 #endif  // V8_TARGET_ARCH_X87
    217