Skip to content

Commit b75da76

Browse files
author
kasperl@chromium.org
committed
Apply Daniel's patch for array index strings.
Review URL: http://codereview.chromium.org/7869 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@560 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent 8e675da commit b75da76

5 files changed

Lines changed: 42 additions & 15 deletions

File tree

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ Rafal Krypa <rafal@krypa.net>
1010
Jay Freeman <saurik@saurik.com>
1111
Daniel James <dnljms@gmail.com>
1212
Paolo Giarrusso <p.giarrusso@gmail.com>
13+
Daniel Andersson <kodandersson@gmail.com>

src/ic-ia32.cc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
212212
// -- esp[4] : name
213213
// -- esp[8] : receiver
214214
// -----------------------------------
215-
Label slow, fast, check_string;
215+
Label slow, fast, check_string, index_int, index_string;
216216

217217
__ mov(eax, (Operand(esp, kPointerSize)));
218218
__ mov(ecx, (Operand(esp, 2 * kPointerSize)));
@@ -234,6 +234,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
234234
__ j(not_zero, &check_string, not_taken);
235235
__ sar(eax, kSmiTagSize);
236236
// Get the elements array of the object.
237+
__ bind(&index_int);
237238
__ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
238239
// Check that the object is in fast mode (not dictionary).
239240
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
@@ -248,18 +249,28 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
248249
KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
249250
// Check if the key is a symbol that is not an array index.
250251
__ bind(&check_string);
252+
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
253+
__ test(ebx, Immediate(String::kIsArrayIndexMask));
254+
__ j(not_zero, &index_string, not_taken);
251255
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
252256
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
253257
__ test(ebx, Immediate(kIsSymbolMask));
254-
__ j(zero, &slow, not_taken);
255-
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
256-
__ test(ebx, Immediate(String::kIsArrayIndexMask));
257258
__ j(not_zero, &slow, not_taken);
258259
// Probe the dictionary leaving result in ecx.
259260
GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
260261
__ mov(eax, Operand(ecx));
261262
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
262263
__ ret(0);
264+
// Array index string: If short enough use cache in length/hash field (ebx).
265+
__ bind(&index_string);
266+
const int kLengthFieldLimit =
267+
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
268+
__ cmp(ebx, kLengthFieldLimit);
269+
__ j(above_equal, &slow);
270+
__ mov(eax, Operand(ebx));
271+
__ and_(eax, (1 << String::kShortLengthShift) - 1);
272+
__ shr(eax, String::kLongLengthShift);
273+
__ jmp(&index_int);
263274
// Fast case: Do the load.
264275
__ bind(&fast);
265276
__ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));

src/objects-inl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,7 +2176,7 @@ uint32_t String::Hash() {
21762176
// Fast case: has hash code already been computed?
21772177
uint32_t field = length_field();
21782178
if (field & kHashComputedMask) return field >> kHashShift;
2179-
// Slow case: compute hash code and set it..
2179+
// Slow case: compute hash code and set it.
21802180
return ComputeAndSetHash();
21812181
}
21822182

@@ -2196,11 +2196,12 @@ bool StringHasher::has_trivial_hash() {
21962196

21972197

21982198
void StringHasher::AddCharacter(uc32 c) {
2199-
// Note: the Jenkins one-at-a-time hash function
2199+
// Use the Jenkins one-at-a-time hash function to update the hash
2200+
// for the given character.
22002201
raw_running_hash_ += c;
22012202
raw_running_hash_ += (raw_running_hash_ << 10);
22022203
raw_running_hash_ ^= (raw_running_hash_ >> 6);
2203-
// Incremental array index computation
2204+
// Incremental array index computation.
22042205
if (is_array_index_) {
22052206
if (c < '0' || c > '9') {
22062207
is_array_index_ = false;

src/objects.cc

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3903,7 +3903,7 @@ uint32_t String::ComputeAndSetHash() {
39033903
bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
39043904
uint32_t* index,
39053905
int length) {
3906-
if (length == 0) return false;
3906+
if (length == 0 || length > kMaxArrayIndexSize) return false;
39073907
uc32 ch = buffer->GetNext();
39083908

39093909
// If the string begins with a '0' character, it must only consist
@@ -3931,8 +3931,16 @@ bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
39313931

39323932

39333933
bool String::SlowAsArrayIndex(uint32_t* index) {
3934-
StringInputBuffer buffer(this);
3935-
return ComputeArrayIndex(&buffer, index, length());
3934+
if (length() <= kMaxCachedArrayIndexLength) {
3935+
Hash(); // force computation of hash code
3936+
uint32_t field = length_field();
3937+
if ((field & kIsArrayIndexMask) == 0) return false;
3938+
*index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
3939+
return true;
3940+
} else {
3941+
StringInputBuffer buffer(this);
3942+
return ComputeArrayIndex(&buffer, index, length());
3943+
}
39363944
}
39373945

39383946

@@ -3969,18 +3977,21 @@ uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
39693977

39703978
// Very long strings have a trivial hash that doesn't inspect the
39713979
// string contents.
3972-
if (hasher.has_trivial_hash())
3980+
if (hasher.has_trivial_hash()) {
39733981
return hasher.GetHashField();
3982+
}
39743983

39753984
// Do the iterative array index computation as long as there is a
39763985
// chance this is an array index.
3977-
while (buffer->has_more() && hasher.is_array_index())
3986+
while (buffer->has_more() && hasher.is_array_index()) {
39783987
hasher.AddCharacter(buffer->GetNext());
3988+
}
39793989

39803990
// Process the remaining characters without updating the array
39813991
// index.
3982-
while (buffer->has_more())
3992+
while (buffer->has_more()) {
39833993
hasher.AddCharacterNoIndex(buffer->GetNext());
3994+
}
39843995

39853996
return hasher.GetHashField();
39863997
}

src/objects.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,7 +3099,7 @@ class String: public HeapObject {
30993099
// Max ascii char code.
31003100
static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
31013101

3102-
// Minimum lenth for a cons or sliced string.
3102+
// Minimum length for a cons or sliced string.
31033103
static const int kMinNonFlatLength = 13;
31043104

31053105
// Mask constant for checking if a string has a computed hash code
@@ -3111,14 +3111,17 @@ class String: public HeapObject {
31113111
static const int kIsArrayIndexMask = 1 << 1;
31123112
static const int kNofLengthBitFields = 2;
31133113

3114+
// Array index strings this short can keep their index in the hash
3115+
// field.
3116+
static const int kMaxCachedArrayIndexLength = 6;
3117+
31143118
// Shift constants for retriving length and hash code from
31153119
// length/hash field.
31163120
static const int kHashShift = kNofLengthBitFields;
31173121
static const int kShortLengthShift = 3 * kBitsPerByte;
31183122
static const int kMediumLengthShift = 2 * kBitsPerByte;
31193123
static const int kLongLengthShift = kHashShift;
31203124

3121-
31223125
// Limit for truncation in short printing.
31233126
static const int kMaxShortPrintLength = 1024;
31243127

0 commit comments

Comments
 (0)