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_X64 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 8958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#include "src/ic/ic.h" 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/stub-cache.h" 10958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#include "src/interface-descriptors.h" 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 { 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal { 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ ACCESS_MASM(masm) 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochstatic void ProbeTable(StubCache* stub_cache, MacroAssembler* masm, 18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch StubCache::Table table, Register receiver, Register name, 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The offset is scaled by 4, based on 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // kCacheIndexShift, which is two bits 21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register offset) { 22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We need to scale up the pointer by 2 when the offset is scaled by less 23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // than the pointer size. 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(kPointerSize == kInt64Size 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ? kPointerSizeLog2 == StubCache::kCacheIndexShift + 1 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch : kPointerSizeLog2 == StubCache::kCacheIndexShift); 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ScaleFactor scale_factor = kPointerSize == kInt64Size ? times_2 : times_1; 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(3u * kPointerSize, sizeof(StubCache::Entry)); 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The offset register holds the entry offset times four (due to masking 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // and shifting optimizations). 32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ExternalReference key_offset(stub_cache->key_reference(table)); 33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ExternalReference value_offset(stub_cache->value_reference(table)); 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label miss; 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Multiply by 3 because there are 3 fields per entry (name, code, map). 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ leap(offset, Operand(offset, offset, times_2, 0)); 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadAddress(kScratchRegister, key_offset); 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check that the key in the entry matches the name. 42958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier __ cmpp(name, Operand(kScratchRegister, offset, scale_factor, 0)); 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ j(not_equal, &miss); 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the map entry from the cache. 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use key_offset + kPointerSize * 2, rather than loading map_offset. 47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch DCHECK(stub_cache->map_reference(table).address() - 48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stub_cache->key_reference(table).address() == 49958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier kPointerSize * 2); 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movp(kScratchRegister, 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2)); 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ cmpp(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset)); 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ j(not_equal, &miss); 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the code entry from the cache. 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadAddress(kScratchRegister, value_offset); 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movp(kScratchRegister, Operand(kScratchRegister, offset, scale_factor, 0)); 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(&miss); 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(&miss); 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Jump to the first instruction in the code stub. 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag)); 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(kScratchRegister); 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&miss); 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid StubCache::GenerateProbe(MacroAssembler* masm, Register receiver, 75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Register name, Register scratch, Register extra, 76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Register extra2, Register extra3) { 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label miss; 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra); // The register extra is not used on the X64 platform. 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra2); // The register extra2 is not used on the X64 platform. 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra3); // The register extra2 is not used on the X64 platform. 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Make sure that code is valid. The multiplying code relies on the 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // entry size being 3 * kPointerSize. 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(sizeof(Entry) == 3 * kPointerSize); 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Make sure that there are no register conflicts. 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(receiver)); 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(name)); 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check scratch register is valid, extra and extra2 are unused. 90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(no_reg)); 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(extra2.is(no_reg)); 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(extra3.is(no_reg)); 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 94958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#ifdef DEBUG 95958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // If vector-based ics are in use, ensure that scratch doesn't conflict with 96958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // the vector and slot registers, which need to be preserved for a handler 97958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // call or miss. 98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (IC::ICUseVector(ic_kind_)) { 99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC) { 100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Register vector = LoadWithVectorDescriptor::VectorRegister(); 101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Register slot = LoadDescriptor::SlotRegister(); 102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(!AreAliased(vector, slot, scratch)); 103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } else { 104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch DCHECK(ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC); 105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Register vector = StoreWithVectorDescriptor::VectorRegister(); 106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch Register slot = StoreWithVectorDescriptor::SlotRegister(); 107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(!AreAliased(vector, slot, scratch)); 108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 109958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier } 110958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#endif 111958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Counters* counters = masm->isolate()->counters(); 113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); 114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check that the receiver isn't a smi. 116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfSmi(receiver, &miss); 117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the map of the receiver and compute the hash. 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset)); 120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use only the low 32 bits of the map pointer. 121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 122f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch __ xorp(scratch, Immediate(kPrimaryMagic)); 123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We mask out the last two bits because they are not part of the hash and 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // they are always 01 for maps. Also in the two 'and' instructions below. 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift)); 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Probe the primary table. 128f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ProbeTable(this, masm, kPrimary, receiver, name, scratch); 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Primary miss: Compute hash for secondary probe. 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset)); 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch __ xorp(scratch, Immediate(kPrimaryMagic)); 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift)); 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ subl(scratch, name); 136f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch __ addl(scratch, Immediate(kSecondaryMagic)); 137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift)); 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Probe the secondary table. 140f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ProbeTable(this, masm, kSecondary, receiver, name, scratch); 141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Cache miss: Fall-through and let caller handle the miss by 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // entering the runtime system. 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&miss); 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __ 150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif // V8_TARGET_ARCH_X64 154