stub-cache-x64.cc revision 958fae7ec3f466955f8e5b50fa5b8d38b9e91675
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#include "src/v8.h" 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_X64 8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 10958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#include "src/ic/ic.h" 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/stub-cache.h" 12958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#include "src/interface-descriptors.h" 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 { 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal { 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ ACCESS_MASM(masm) 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void ProbeTable(Isolate* isolate, MacroAssembler* masm, 21958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Code::Kind ic_kind, Code::Flags flags, bool leave_frame, 22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch StubCache::Table table, Register receiver, Register name, 23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The offset is scaled by 4, based on 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // kCacheIndexShift, which is two bits 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register offset) { 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We need to scale up the pointer by 2 when the offset is scaled by less 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // than the pointer size. 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(kPointerSize == kInt64Size 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ? kPointerSizeLog2 == StubCache::kCacheIndexShift + 1 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch : kPointerSizeLog2 == StubCache::kCacheIndexShift); 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ScaleFactor scale_factor = kPointerSize == kInt64Size ? times_2 : times_1; 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK_EQ(3 * kPointerSize, sizeof(StubCache::Entry)); 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The offset register holds the entry offset times four (due to masking 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // and shifting optimizations). 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label miss; 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Multiply by 3 because there are 3 fields per entry (name, code, map). 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ leap(offset, Operand(offset, offset, times_2, 0)); 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadAddress(kScratchRegister, key_offset); 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check that the key in the entry matches the name. 46958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier __ cmpp(name, Operand(kScratchRegister, offset, scale_factor, 0)); 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ j(not_equal, &miss); 48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the map entry from the cache. 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use key_offset + kPointerSize * 2, rather than loading map_offset. 51958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier DCHECK(isolate->stub_cache()->map_reference(table).address() - 52958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier isolate->stub_cache()->key_reference(table).address() == 53958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier kPointerSize * 2); 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movp(kScratchRegister, 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2)); 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ cmpp(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset)); 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ j(not_equal, &miss); 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the code entry from the cache. 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadAddress(kScratchRegister, value_offset); 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movp(kScratchRegister, Operand(kScratchRegister, offset, scale_factor, 0)); 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check that the flags match what we're looking for. 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset)); 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(offset, Immediate(~Code::kFlagsNotUsedInLookup)); 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ cmpl(offset, Immediate(flags)); 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ j(not_equal, &miss); 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(&miss); 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(&miss); 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (leave_frame) __ leave(); 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Jump to the first instruction in the code stub. 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag)); 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ jmp(kScratchRegister); 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&miss); 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 87958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Berniervoid StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind, 88958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Code::Flags flags, bool leave_frame, 89958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Register receiver, Register name, 90958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Register scratch, Register extra, Register extra2, 91958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Register extra3) { 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Isolate* isolate = masm->isolate(); 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label miss; 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra); // The register extra is not used on the X64 platform. 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra2); // The register extra2 is not used on the X64 platform. 96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch USE(extra3); // The register extra2 is not used on the X64 platform. 97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Make sure that code is valid. The multiplying code relies on the 98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // entry size being 3 * kPointerSize. 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(sizeof(Entry) == 3 * kPointerSize); 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Make sure the flags do not name a specific type. 102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Code::ExtractTypeFromFlags(flags) == 0); 103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Make sure that there are no register conflicts. 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(receiver)); 106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(name)); 107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check scratch register is valid, extra and extra2 are unused. 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!scratch.is(no_reg)); 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(extra2.is(no_reg)); 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(extra3.is(no_reg)); 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 113958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#ifdef DEBUG 114958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // If vector-based ics are in use, ensure that scratch doesn't conflict with 115958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // the vector and slot registers, which need to be preserved for a handler 116958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // call or miss. 117958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier if (IC::ICUseVector(ic_kind)) { 118958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Register vector = VectorLoadICDescriptor::VectorRegister(); 119958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier Register slot = VectorLoadICDescriptor::SlotRegister(); 120958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier DCHECK(!AreAliased(vector, slot, scratch)); 121958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier } 122958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#endif 123958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Counters* counters = masm->isolate()->counters(); 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check that the receiver isn't a smi. 128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfSmi(receiver, &miss); 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the map of the receiver and compute the hash. 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset)); 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use only the low 32 bits of the map pointer. 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ xorp(scratch, Immediate(flags)); 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We mask out the last two bits because they are not part of the hash and 136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // they are always 01 for maps. Also in the two 'and' instructions below. 137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift)); 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Probe the primary table. 140958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver, 141958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier name, scratch); 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Primary miss: Compute hash for secondary probe. 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset)); 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ xorp(scratch, Immediate(flags)); 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift)); 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ subl(scratch, name); 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addl(scratch, Immediate(flags)); 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift)); 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Probe the secondary table. 153958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver, 154958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier name, scratch); 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Cache miss: Fall-through and let caller handle the miss by 157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // entering the runtime system. 158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&miss); 159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __ 164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} // namespace v8::internal 166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif // V8_TARGET_ARCH_X64 168