| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
| 6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
| 7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
| 8 #include "src/frames.h" | 8 #include "src/frames.h" |
| 9 #include "src/ic/stub-cache.h" | 9 #include "src/ic/stub-cache.h" |
| 10 | 10 |
| (...skipping 2712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2723 var_handler->Bind(handler); | 2723 var_handler->Bind(handler); |
| 2724 Goto(if_handler); | 2724 Goto(if_handler); |
| 2725 | 2725 |
| 2726 Bind(&next_entry); | 2726 Bind(&next_entry); |
| 2727 var_index.Bind(Int32Add(index, Int32Constant(kEntrySize))); | 2727 var_index.Bind(Int32Add(index, Int32Constant(kEntrySize))); |
| 2728 Goto(&loop); | 2728 Goto(&loop); |
| 2729 } | 2729 } |
| 2730 } | 2730 } |
| 2731 | 2731 |
| 2732 compiler::Node* CodeStubAssembler::StubCachePrimaryOffset(compiler::Node* name, | 2732 compiler::Node* CodeStubAssembler::StubCachePrimaryOffset(compiler::Node* name, |
| 2733 Code::Flags flags, |
| 2733 compiler::Node* map) { | 2734 compiler::Node* map) { |
| 2734 // See v8::internal::StubCache::PrimaryOffset(). | 2735 // See v8::internal::StubCache::PrimaryOffset(). |
| 2735 STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift); | 2736 STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift); |
| 2736 // Compute the hash of the name (use entire hash field). | 2737 // Compute the hash of the name (use entire hash field). |
| 2737 Node* hash_field = LoadNameHashField(name); | 2738 Node* hash_field = LoadNameHashField(name); |
| 2738 Assert(WordEqual( | 2739 Assert(WordEqual( |
| 2739 Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), | 2740 Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), |
| 2740 Int32Constant(0))); | 2741 Int32Constant(0))); |
| 2741 | 2742 |
| 2742 // Using only the low bits in 64-bit mode is unlikely to increase the | 2743 // Using only the low bits in 64-bit mode is unlikely to increase the |
| 2743 // risk of collision even if the heap is spread over an area larger than | 2744 // risk of collision even if the heap is spread over an area larger than |
| 2744 // 4Gb (and not at all if it isn't). | 2745 // 4Gb (and not at all if it isn't). |
| 2745 Node* hash = Int32Add(hash_field, map); | 2746 Node* hash = Int32Add(hash_field, map); |
| 2746 // Base the offset on a simple combination of name and map. | 2747 // We always set the in_loop bit to zero when generating the lookup code |
| 2748 // so do it here too so the hash codes match. |
| 2749 uint32_t iflags = |
| 2750 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); |
| 2751 // Base the offset on a simple combination of name, flags, and map. |
| 2752 hash = Word32Xor(hash, Int32Constant(iflags)); |
| 2747 uint32_t mask = (StubCache::kPrimaryTableSize - 1) | 2753 uint32_t mask = (StubCache::kPrimaryTableSize - 1) |
| 2748 << StubCache::kCacheIndexShift; | 2754 << StubCache::kCacheIndexShift; |
| 2749 return Word32And(hash, Int32Constant(mask)); | 2755 return Word32And(hash, Int32Constant(mask)); |
| 2750 } | 2756 } |
| 2751 | 2757 |
| 2752 compiler::Node* CodeStubAssembler::StubCacheSecondaryOffset( | 2758 compiler::Node* CodeStubAssembler::StubCacheSecondaryOffset( |
| 2753 compiler::Node* name, compiler::Node* seed) { | 2759 compiler::Node* name, Code::Flags flags, compiler::Node* seed) { |
| 2754 // See v8::internal::StubCache::SecondaryOffset(). | 2760 // See v8::internal::StubCache::SecondaryOffset(). |
| 2755 | 2761 |
| 2756 // Use the seed from the primary cache in the secondary cache. | 2762 // Use the seed from the primary cache in the secondary cache. |
| 2757 Node* hash = Int32Sub(seed, name); | 2763 Node* hash = Int32Sub(seed, name); |
| 2764 // We always set the in_loop bit to zero when generating the lookup code |
| 2765 // so do it here too so the hash codes match. |
| 2766 uint32_t iflags = |
| 2767 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); |
| 2768 hash = Int32Add(hash, Int32Constant(iflags)); |
| 2758 int32_t mask = (StubCache::kSecondaryTableSize - 1) | 2769 int32_t mask = (StubCache::kSecondaryTableSize - 1) |
| 2759 << StubCache::kCacheIndexShift; | 2770 << StubCache::kCacheIndexShift; |
| 2760 return Word32And(hash, Int32Constant(mask)); | 2771 return Word32And(hash, Int32Constant(mask)); |
| 2761 } | 2772 } |
| 2762 | 2773 |
| 2763 enum CodeStubAssembler::StubCacheTable : int { | 2774 enum CodeStubAssembler::StubCacheTable : int { |
| 2764 kPrimary = static_cast<int>(StubCache::kPrimary), | 2775 kPrimary = static_cast<int>(StubCache::kPrimary), |
| 2765 kSecondary = static_cast<int>(StubCache::kSecondary) | 2776 kSecondary = static_cast<int>(StubCache::kSecondary) |
| 2766 }; | 2777 }; |
| 2767 | 2778 |
| 2768 void CodeStubAssembler::TryProbeStubCacheTable( | 2779 void CodeStubAssembler::TryProbeStubCacheTable( |
| 2769 StubCache* stub_cache, StubCacheTable table_id, | 2780 StubCache* stub_cache, StubCacheTable table_id, |
| 2770 compiler::Node* entry_offset, compiler::Node* name, compiler::Node* map, | 2781 compiler::Node* entry_offset, compiler::Node* name, Code::Flags flags, |
| 2771 Label* if_handler, Variable* var_handler, Label* if_miss) { | 2782 compiler::Node* map, Label* if_handler, Variable* var_handler, |
| 2783 Label* if_miss) { |
| 2772 StubCache::Table table = static_cast<StubCache::Table>(table_id); | 2784 StubCache::Table table = static_cast<StubCache::Table>(table_id); |
| 2773 #ifdef DEBUG | 2785 #ifdef DEBUG |
| 2774 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { | 2786 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { |
| 2775 Goto(if_miss); | 2787 Goto(if_miss); |
| 2776 return; | 2788 return; |
| 2777 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { | 2789 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { |
| 2778 Goto(if_miss); | 2790 Goto(if_miss); |
| 2779 return; | 2791 return; |
| 2780 } | 2792 } |
| 2781 #endif | 2793 #endif |
| 2782 // The {table_offset} holds the entry offset times four (due to masking | 2794 // The {table_offset} holds the entry offset times four (due to masking |
| 2783 // and shifting optimizations). | 2795 // and shifting optimizations). |
| 2784 const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift; | 2796 const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift; |
| 2785 entry_offset = Int32Mul(entry_offset, Int32Constant(kMultiplier)); | 2797 entry_offset = Int32Mul(entry_offset, Int32Constant(kMultiplier)); |
| 2786 | 2798 |
| 2787 // Check that the key in the entry matches the name. | 2799 // Check that the key in the entry matches the name. |
| 2788 Node* key_base = | 2800 Node* key_base = |
| 2789 ExternalConstant(ExternalReference(stub_cache->key_reference(table))); | 2801 ExternalConstant(ExternalReference(stub_cache->key_reference(table))); |
| 2790 Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset); | 2802 Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset); |
| 2791 GotoIf(WordNotEqual(name, entry_key), if_miss); | 2803 GotoIf(WordNotEqual(name, entry_key), if_miss); |
| 2792 | 2804 |
| 2793 // Get the map entry from the cache. | 2805 // Get the map entry from the cache. |
| 2794 DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() - | 2806 DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() - |
| 2795 stub_cache->key_reference(table).address()); | 2807 stub_cache->key_reference(table).address()); |
| 2796 Node* entry_map = | 2808 Node* entry_map = |
| 2797 Load(MachineType::Pointer(), key_base, | 2809 Load(MachineType::Pointer(), key_base, |
| 2798 Int32Add(entry_offset, Int32Constant(kPointerSize * 2))); | 2810 Int32Add(entry_offset, Int32Constant(kPointerSize * 2))); |
| 2799 GotoIf(WordNotEqual(map, entry_map), if_miss); | 2811 GotoIf(WordNotEqual(map, entry_map), if_miss); |
| 2800 | 2812 |
| 2813 // Check that the flags match what we're looking for. |
| 2801 DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() - | 2814 DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() - |
| 2802 stub_cache->key_reference(table).address()); | 2815 stub_cache->key_reference(table).address()); |
| 2803 Node* code = Load(MachineType::Pointer(), key_base, | 2816 Node* code = Load(MachineType::Pointer(), key_base, |
| 2804 Int32Add(entry_offset, Int32Constant(kPointerSize))); | 2817 Int32Add(entry_offset, Int32Constant(kPointerSize))); |
| 2805 | 2818 |
| 2806 // Check that the flags match what we're looking for. | |
| 2807 Code::Flags flags = Code::RemoveHolderFromFlags( | |
| 2808 Code::ComputeHandlerFlags(stub_cache->ic_kind())); | |
| 2809 Node* code_flags = | 2819 Node* code_flags = |
| 2810 LoadObjectField(code, Code::kFlagsOffset, MachineType::Uint32()); | 2820 LoadObjectField(code, Code::kFlagsOffset, MachineType::Uint32()); |
| 2811 Assert(Word32Equal( | 2821 GotoIf(Word32NotEqual(Int32Constant(flags), |
| 2812 Int32Constant(flags), | 2822 Word32And(code_flags, |
| 2813 Word32And(code_flags, Int32Constant(~Code::kFlagsNotUsedInLookup)))); | 2823 Int32Constant(~Code::kFlagsNotUsedInLookup))), |
| 2824 if_miss); |
| 2814 | 2825 |
| 2815 // We found the handler. | 2826 // We found the handler. |
| 2816 var_handler->Bind(code); | 2827 var_handler->Bind(code); |
| 2817 Goto(if_handler); | 2828 Goto(if_handler); |
| 2818 } | 2829 } |
| 2819 | 2830 |
| 2820 void CodeStubAssembler::TryProbeStubCache( | 2831 void CodeStubAssembler::TryProbeStubCache( |
| 2821 StubCache* stub_cache, compiler::Node* receiver, compiler::Node* name, | 2832 StubCache* stub_cache, compiler::Node* receiver, compiler::Node* name, |
| 2822 Label* if_handler, Variable* var_handler, Label* if_miss) { | 2833 Label* if_handler, Variable* var_handler, Label* if_miss) { |
| 2834 Code::Flags flags = Code::RemoveHolderFromFlags( |
| 2835 Code::ComputeHandlerFlags(stub_cache->ic_kind())); |
| 2836 |
| 2823 Label try_secondary(this), miss(this); | 2837 Label try_secondary(this), miss(this); |
| 2824 | 2838 |
| 2825 Counters* counters = isolate()->counters(); | 2839 Counters* counters = isolate()->counters(); |
| 2826 IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); | 2840 IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); |
| 2827 | 2841 |
| 2828 // Check that the {receiver} isn't a smi. | 2842 // Check that the {receiver} isn't a smi. |
| 2829 GotoIf(WordIsSmi(receiver), &miss); | 2843 GotoIf(WordIsSmi(receiver), &miss); |
| 2830 | 2844 |
| 2831 Node* receiver_map = LoadMap(receiver); | 2845 Node* receiver_map = LoadMap(receiver); |
| 2832 | 2846 |
| 2833 // Probe the primary table. | 2847 // Probe the primary table. |
| 2834 Node* primary_offset = StubCachePrimaryOffset(name, receiver_map); | 2848 Node* primary_offset = StubCachePrimaryOffset(name, flags, receiver_map); |
| 2835 TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name, | 2849 TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name, flags, |
| 2836 receiver_map, if_handler, var_handler, &try_secondary); | 2850 receiver_map, if_handler, var_handler, &try_secondary); |
| 2837 | 2851 |
| 2838 Bind(&try_secondary); | 2852 Bind(&try_secondary); |
| 2839 { | 2853 { |
| 2840 // Probe the secondary table. | 2854 // Probe the secondary table. |
| 2841 Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset); | 2855 Node* secondary_offset = |
| 2856 StubCacheSecondaryOffset(name, flags, primary_offset); |
| 2842 TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name, | 2857 TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name, |
| 2843 receiver_map, if_handler, var_handler, &miss); | 2858 flags, receiver_map, if_handler, var_handler, &miss); |
| 2844 } | 2859 } |
| 2845 | 2860 |
| 2846 Bind(&miss); | 2861 Bind(&miss); |
| 2847 { | 2862 { |
| 2848 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); | 2863 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); |
| 2849 Goto(if_miss); | 2864 Goto(if_miss); |
| 2850 } | 2865 } |
| 2851 } | 2866 } |
| 2852 | 2867 |
| 2853 void CodeStubAssembler::LoadIC(const LoadICParameters* p) { | 2868 void CodeStubAssembler::LoadIC(const LoadICParameters* p) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2929 } | 2944 } |
| 2930 Bind(&miss); | 2945 Bind(&miss); |
| 2931 { | 2946 { |
| 2932 TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->slot, | 2947 TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->slot, |
| 2933 p->vector); | 2948 p->vector); |
| 2934 } | 2949 } |
| 2935 } | 2950 } |
| 2936 | 2951 |
| 2937 } // namespace internal | 2952 } // namespace internal |
| 2938 } // namespace v8 | 2953 } // namespace v8 |
| OLD | NEW |