Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: src/ia32/code-stubs-ia32.cc

Issue 6932010: Unroll more StringDictionary lookup probes both for positive and negative dictionary lookups. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: ported to arm&x64, cleaned up ia32 impl Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 5841 matching lines...) Expand 10 before | Expand all | Expand 10 after
5852 __ pop(ecx); 5852 __ pop(ecx);
5853 __ pop(eax); 5853 __ pop(eax);
5854 __ pop(edx); 5854 __ pop(edx);
5855 __ push(ecx); 5855 __ push(ecx);
5856 5856
5857 // Do a tail call to the rewritten stub. 5857 // Do a tail call to the rewritten stub.
5858 __ jmp(Operand(edi)); 5858 __ jmp(Operand(edi));
5859 } 5859 }
5860 5860
5861 5861
5862 // Helper function used to check that the dictionary doesn't contain
5863 // the property. This function may return false negatives, so miss_label
5864 // must always call a backup property check that is complete.
5865 // This function is safe to call if the receiver has fast properties.
5866 // Name must be a symbol and receiver must be a heap object.
5867 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
5868 Label* miss,
5869 Label* done,
5870 Register properties,
5871 String* name,
5872 Register r0) {
5873 ASSERT(name->IsSymbol());
5874
5875 // If names of slots in range from 1 to kProbes - 1 for the hash value are
5876 // not equal to the name and kProbes-th slot is not used (its name is the
5877 // undefined value), it guarantees the hash table doesn't contain the
5878 // property. It's true even if some slots represent deleted properties
5879 // (their names are the null value).
5880 for (int i = 0; i < kInlinedProbes; i++) {
5881 // Compute the masked index: (hash + i + i * i) & mask.
5882 Register index = r0;
5883 // Capacity is smi 2^n.
5884 __ mov(index, FieldOperand(properties, kCapacityOffset));
5885 __ dec(index);
5886 __ and_(Operand(index),
5887 Immediate(Smi::FromInt(name->Hash() +
5888 StringDictionary::GetProbeOffset(i))));
5889
5890 // Scale the index by multiplying by the entry size.
5891 ASSERT(StringDictionary::kEntrySize == 3);
5892 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
5893 Register entity_name = r0;
5894 // Having undefined at this place means the name is not contained.
5895 ASSERT_EQ(kSmiTagSize, 1);
5896 __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
5897 kElementsStartOffset - kHeapObjectTag));
5898 __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
5899 __ j(equal, done, taken);
5900
5901 // Stop if found the property.
5902 __ cmp(entity_name, Handle<String>(name));
5903 __ j(equal, miss, not_taken);
5904
5905 // Check if the entry name is not a symbol.
5906 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
5907 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
5908 kIsSymbolMask);
5909 __ j(zero, miss, not_taken);
5910 }
5911
5912 StringDictionaryLookupStub stub(properties,
5913 r0,
5914 r0,
5915 StringDictionaryLookupStub::NEGATIVE_LOOKUP);
5916 __ push(Immediate(Handle<Object>(name)));
5917 __ push(Immediate(name->Hash()));
5918 __ CallStub(&stub);
5919 __ test(r0, Operand(r0));
5920 __ j(not_zero, miss);
5921 __ jmp(done);
5922 }
5923
5924
5925 // Probe the string dictionary in the |elements| register. Jump to the
5926 // |done| label if a property with the given name is found leaving the
5927 // index into the dictionary in |r0|. Jump to the |miss| label
5928 // otherwise.
5929 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
5930 Label* miss,
5931 Label* done,
5932 Register elements,
5933 Register name,
5934 Register r0,
5935 Register r1) {
5936 // Assert that name contains a string.
5937 if (FLAG_debug_code) __ AbortIfNotString(name);
5938
5939 __ mov(r1, FieldOperand(elements, kCapacityOffset));
5940 __ shr(r1, kSmiTagSize); // convert smi to int
5941 __ dec(r1);
5942
5943 // Generate an unrolled loop that performs a few probes before
5944 // giving up. Measurements done on Gmail indicate that 2 probes
5945 // cover ~93% of loads from dictionaries.
5946 for (int i = 0; i < kInlinedProbes; i++) {
5947 // Compute the masked index: (hash + i + i * i) & mask.
5948 __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
5949 __ shr(r0, String::kHashShift);
5950 if (i > 0) {
5951 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
5952 }
5953 __ and_(r0, Operand(r1));
5954
5955 // Scale the index by multiplying by the entry size.
5956 ASSERT(StringDictionary::kEntrySize == 3);
5957 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
5958
5959 // Check if the key is identical to the name.
5960 __ cmp(name, Operand(elements,
5961 r0,
5962 times_4,
5963 kElementsStartOffset - kHeapObjectTag));
5964 __ j(equal, done, taken);
5965 }
5966
5967 StringDictionaryLookupStub stub(elements,
5968 r1,
5969 r0,
5970 POSITIVE_LOOKUP);
5971 __ push(name);
5972 __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
5973 __ shr(r0, String::kHashShift);
5974 __ push(r0);
5975 __ CallStub(&stub);
5976
5977 __ test(r1, Operand(r1));
5978 __ j(zero, miss);
5979 __ jmp(done);
5980 }
5981
5982
5983 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
5984 // Stack frame on entry:
5985 // esp[0 * kPointerSize]: return address.
5986 // esp[1 * kPointerSize]: key's hash.
5987 // esp[2 * kPointerSize]: key.
5988 // Registers:
5989 // dictionary_: StringDictionary to probe.
5990 // result_: used as scratch.
5991 // index_: will hold an index of entry if lookup is successful.
5992 // might alias with result_.
5993 // Returns:
5994 // result_ is zero if lookup failed, non zero otherwise.
5995
5996 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
5997
5998 Register scratch = result_;
5999
6000 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
6001 __ dec(scratch);
6002 __ SmiUntag(scratch);
6003 __ push(scratch);
6004
6005 // If names of slots in range from 1 to kProbes - 1 for the hash value are
6006 // not equal to the name and kProbes-th slot is not used (its name is the
6007 // undefined value), it guarantees the hash table doesn't contain the
6008 // property. It's true even if some slots represent deleted properties
6009 // (their names are the null value).
6010 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6011 // Compute the masked index: (hash + i + i * i) & mask.
6012 __ mov(scratch, Operand(esp, 2 * kPointerSize));
6013 if (i > 0) {
6014 __ add(Operand(scratch),
6015 Immediate(StringDictionary::GetProbeOffset(i)));
6016 }
6017 __ and_(scratch, Operand(esp, 0));
6018
6019 // Scale the index by multiplying by the entry size.
6020 ASSERT(StringDictionary::kEntrySize == 3);
6021 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
6022
6023 // Having undefined at this place means the name is not contained.
6024 ASSERT_EQ(kSmiTagSize, 1);
6025 __ mov(scratch, Operand(dictionary_,
6026 index_,
6027 times_pointer_size,
6028 kElementsStartOffset - kHeapObjectTag));
6029 __ cmp(scratch, masm->isolate()->factory()->undefined_value());
6030 __ j(equal, &not_in_dictionary);
6031
6032 // Stop if found the property.
6033 __ cmp(scratch, Operand(esp, 3 * kPointerSize));
6034 __ j(equal, &in_dictionary);
6035
6036 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
6037 // If we hit a non symbol key during negative lookup
6038 // we have to bailout as this key might be equal to the
6039 // key we are looking for.
6040
6041 // Check if the entry name is not a symbol.
6042 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
6043 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
6044 kIsSymbolMask);
6045 __ j(zero, &maybe_in_dictionary);
6046 }
6047 }
6048
6049 __ bind(&maybe_in_dictionary);
6050 // If we are doing negative lookup then probing failure should be
6051 // treated as a lookup success. For positive lookup probing failure
6052 // should be treated as lookup failure.
6053 if (mode_ == POSITIVE_LOOKUP) {
6054 __ mov(result_, Immediate(0));
6055 __ Drop(1);
6056 __ ret(2 * kPointerSize);
6057 }
6058
6059 __ bind(&in_dictionary);
6060 __ mov(result_, Immediate(1));
6061 __ Drop(1);
6062 __ ret(2 * kPointerSize);
6063
6064 __ bind(&not_in_dictionary);
6065 __ mov(result_, Immediate(0));
6066 __ Drop(1);
6067 __ ret(2 * kPointerSize);
6068 }
6069
6070
5862 #undef __ 6071 #undef __
5863 6072
5864 } } // namespace v8::internal 6073 } } // namespace v8::internal
5865 6074
5866 #endif // V8_TARGET_ARCH_IA32 6075 #endif // V8_TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698