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