Jay Freeman <saurik@saurik.com>
Daniel James <dnljms@gmail.com>
Paolo Giarrusso <p.giarrusso@gmail.com>
+Daniel Andersson <kodandersson@gmail.com>
// -- esp[4] : name
// -- esp[8] : receiver
// -----------------------------------
- Label slow, fast, check_string;
+ Label slow, fast, check_string, index_int, index_string;
__ mov(eax, (Operand(esp, kPointerSize)));
__ mov(ecx, (Operand(esp, 2 * kPointerSize)));
__ j(not_zero, &check_string, not_taken);
__ sar(eax, kSmiTagSize);
// Get the elements array of the object.
+ __ bind(&index_int);
__ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary).
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
// Check if the key is a symbol that is not an array index.
__ bind(&check_string);
+ __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
+ __ test(ebx, Immediate(String::kIsArrayIndexMask));
+ __ j(not_zero, &index_string, not_taken);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ test(ebx, Immediate(kIsSymbolMask));
- __ j(zero, &slow, not_taken);
- __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
- __ test(ebx, Immediate(String::kIsArrayIndexMask));
__ j(not_zero, &slow, not_taken);
// Probe the dictionary leaving result in ecx.
GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
__ mov(eax, Operand(ecx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
+ // Array index string: If short enough use cache in length/hash field (ebx).
+ __ bind(&index_string);
+ const int kLengthFieldLimit =
+ (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
+ __ cmp(ebx, kLengthFieldLimit);
+ __ j(above_equal, &slow);
+ __ mov(eax, Operand(ebx));
+ __ and_(eax, (1 << String::kShortLengthShift) - 1);
+ __ shr(eax, String::kLongLengthShift);
+ __ jmp(&index_int);
// Fast case: Do the load.
__ bind(&fast);
__ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));
// Fast case: has hash code already been computed?
uint32_t field = length_field();
if (field & kHashComputedMask) return field >> kHashShift;
- // Slow case: compute hash code and set it..
+ // Slow case: compute hash code and set it.
return ComputeAndSetHash();
}
void StringHasher::AddCharacter(uc32 c) {
- // Note: the Jenkins one-at-a-time hash function
+ // Use the Jenkins one-at-a-time hash function to update the hash
+ // for the given character.
raw_running_hash_ += c;
raw_running_hash_ += (raw_running_hash_ << 10);
raw_running_hash_ ^= (raw_running_hash_ >> 6);
- // Incremental array index computation
+ // Incremental array index computation.
if (is_array_index_) {
if (c < '0' || c > '9') {
is_array_index_ = false;
bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
uint32_t* index,
int length) {
- if (length == 0) return false;
+ if (length == 0 || length > kMaxArrayIndexSize) return false;
uc32 ch = buffer->GetNext();
// If the string begins with a '0' character, it must only consist
bool String::SlowAsArrayIndex(uint32_t* index) {
- StringInputBuffer buffer(this);
- return ComputeArrayIndex(&buffer, index, length());
+ if (length() <= kMaxCachedArrayIndexLength) {
+ Hash(); // force computation of hash code
+ uint32_t field = length_field();
+ if ((field & kIsArrayIndexMask) == 0) return false;
+ *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
+ return true;
+ } else {
+ StringInputBuffer buffer(this);
+ return ComputeArrayIndex(&buffer, index, length());
+ }
}
// Very long strings have a trivial hash that doesn't inspect the
// string contents.
- if (hasher.has_trivial_hash())
+ if (hasher.has_trivial_hash()) {
return hasher.GetHashField();
+ }
// Do the iterative array index computation as long as there is a
// chance this is an array index.
- while (buffer->has_more() && hasher.is_array_index())
+ while (buffer->has_more() && hasher.is_array_index()) {
hasher.AddCharacter(buffer->GetNext());
+ }
// Process the remaining characters without updating the array
// index.
- while (buffer->has_more())
+ while (buffer->has_more()) {
hasher.AddCharacterNoIndex(buffer->GetNext());
+ }
return hasher.GetHashField();
}
// Max ascii char code.
static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
- // Minimum lenth for a cons or sliced string.
+ // Minimum length for a cons or sliced string.
static const int kMinNonFlatLength = 13;
// Mask constant for checking if a string has a computed hash code
static const int kIsArrayIndexMask = 1 << 1;
static const int kNofLengthBitFields = 2;
+ // Array index strings this short can keep their index in the hash
+ // field.
+ static const int kMaxCachedArrayIndexLength = 6;
+
// Shift constants for retriving length and hash code from
// length/hash field.
static const int kHashShift = kNofLengthBitFields;
static const int kMediumLengthShift = 2 * kBitsPerByte;
static const int kLongLengthShift = kHashShift;
-
// Limit for truncation in short printing.
static const int kMaxShortPrintLength = 1024;