Serendipitously arrange the tags so that String.length() becomes a branch-free
operation. I have another version of this change that does not remove the special inline caches for difference sized strings. The other version is ever so slightly faster, but the nice thing about this version is that it removes 253 lines of code. Review URL: http://codereview.chromium.org/8187 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@603 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
724f5648b9
commit
0fc72f2b4e
@ -465,18 +465,8 @@ static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
static void Generate_LoadIC_ShortStringLength(MacroAssembler* masm) {
|
||||
LoadIC::GenerateShortStringLength(masm);
|
||||
}
|
||||
|
||||
|
||||
static void Generate_LoadIC_MediumStringLength(MacroAssembler* masm) {
|
||||
LoadIC::GenerateMediumStringLength(masm);
|
||||
}
|
||||
|
||||
|
||||
static void Generate_LoadIC_LongStringLength(MacroAssembler* masm) {
|
||||
LoadIC::GenerateLongStringLength(masm);
|
||||
static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
|
||||
LoadIC::GenerateStringLength(masm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,9 +69,7 @@ namespace v8 { namespace internal {
|
||||
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
|
||||
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_ShortStringLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_MediumStringLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_LongStringLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
|
||||
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \
|
||||
|
@ -2849,38 +2849,26 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
__ sar(ebx, kSmiTagSize);
|
||||
|
||||
__ bind(&try_again_with_new_string);
|
||||
// Get the type of the heap object into ecx.
|
||||
// Get the type of the heap object into edi.
|
||||
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
|
||||
__ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset));
|
||||
// We don't handle non-strings.
|
||||
__ test(ecx, Immediate(kIsNotStringMask));
|
||||
__ test(edi, Immediate(kIsNotStringMask));
|
||||
__ j(not_zero, &slow_case, not_taken);
|
||||
|
||||
// Here we make assumptions about the tag values and the shifts needed.
|
||||
// See the comment in objects.h.
|
||||
ASSERT(kLongStringTag == 0);
|
||||
ASSERT(kMediumStringTag + String::kLongLengthShift ==
|
||||
String::kMediumLengthShift);
|
||||
ASSERT(kShortStringTag + String::kLongLengthShift ==
|
||||
String::kShortLengthShift);
|
||||
__ mov(ecx, Operand(edi));
|
||||
__ and_(ecx, kStringSizeMask);
|
||||
__ add(Operand(ecx), Immediate(String::kLongLengthShift));
|
||||
// Get the length field.
|
||||
__ mov(edx, FieldOperand(eax, String::kLengthOffset));
|
||||
Label long_string;
|
||||
Label medium_string;
|
||||
Label string_length_shifted;
|
||||
// The code assumes the tags are disjoint.
|
||||
ASSERT((kLongStringTag & kMediumStringTag) == 0);
|
||||
ASSERT(kShortStringTag == 0);
|
||||
__ test(ecx, Immediate(kLongStringTag));
|
||||
__ j(not_zero, &long_string, not_taken);
|
||||
__ test(ecx, Immediate(kMediumStringTag));
|
||||
__ j(not_zero, &medium_string, taken);
|
||||
// Short string.
|
||||
__ shr(edx, String::kShortLengthShift);
|
||||
__ jmp(&string_length_shifted);
|
||||
|
||||
// Medium string.
|
||||
__ bind(&medium_string);
|
||||
__ shr(edx, String::kMediumLengthShift - String::kLongLengthShift);
|
||||
// Fall through to long string.
|
||||
__ bind(&long_string);
|
||||
__ shr(edx, String::kLongLengthShift);
|
||||
|
||||
__ bind(&string_length_shifted);
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ shr(edx); // ecx is implicit operand.
|
||||
// edx is now the length of the string.
|
||||
|
||||
// Check for index out of range.
|
||||
@ -2889,11 +2877,11 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
|
||||
// We need special handling for non-flat strings.
|
||||
ASSERT(kSeqStringTag == 0);
|
||||
__ test(ecx, Immediate(kStringRepresentationMask));
|
||||
__ test(edi, Immediate(kStringRepresentationMask));
|
||||
__ j(not_zero, ¬_a_flat_string, not_taken);
|
||||
|
||||
// Check for 1-byte or 2-byte string.
|
||||
__ test(ecx, Immediate(kStringEncodingMask));
|
||||
__ test(edi, Immediate(kStringEncodingMask));
|
||||
__ j(not_zero, &ascii_string, taken);
|
||||
|
||||
// 2-byte string.
|
||||
@ -2913,11 +2901,10 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
frame_->Push(eax);
|
||||
__ jmp(&end);
|
||||
|
||||
|
||||
// Handle non-flat strings.
|
||||
__ bind(¬_a_flat_string);
|
||||
__ and_(ecx, kStringRepresentationMask);
|
||||
__ cmp(ecx, kConsStringTag);
|
||||
__ and_(edi, kStringRepresentationMask);
|
||||
__ cmp(edi, kConsStringTag);
|
||||
__ j(not_equal, ¬_a_cons_string_either, not_taken);
|
||||
|
||||
// ConsString.
|
||||
@ -2926,7 +2913,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
__ jmp(&try_again_with_new_string);
|
||||
|
||||
__ bind(¬_a_cons_string_either);
|
||||
__ cmp(ecx, kSlicedStringTag);
|
||||
__ cmp(edi, kSlicedStringTag);
|
||||
__ j(not_equal, &slow_case, not_taken);
|
||||
|
||||
// SlicedString.
|
||||
|
@ -138,7 +138,7 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void LoadIC::GenerateShortStringLength(MacroAssembler* masm) {
|
||||
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
@ -149,41 +149,7 @@ void LoadIC::GenerateShortStringLength(MacroAssembler* masm) {
|
||||
|
||||
__ mov(eax, Operand(esp, kPointerSize));
|
||||
|
||||
StubCompiler::GenerateLoadShortStringLength(masm, eax, edx, &miss);
|
||||
__ bind(&miss);
|
||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||
}
|
||||
|
||||
|
||||
void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
Label miss;
|
||||
|
||||
__ mov(eax, Operand(esp, kPointerSize));
|
||||
|
||||
StubCompiler::GenerateLoadMediumStringLength(masm, eax, edx, &miss);
|
||||
__ bind(&miss);
|
||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||
}
|
||||
|
||||
|
||||
void LoadIC::GenerateLongStringLength(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
Label miss;
|
||||
|
||||
__ mov(eax, Operand(esp, kPointerSize));
|
||||
|
||||
StubCompiler::GenerateLoadLongStringLength(masm, eax, edx, &miss);
|
||||
StubCompiler::GenerateLoadStringLength(masm, eax, edx, &miss);
|
||||
__ bind(&miss);
|
||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||
}
|
||||
|
19
src/ic.cc
19
src/ic.cc
@ -459,14 +459,7 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
|
||||
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
|
||||
#endif
|
||||
Code* target = NULL;
|
||||
if (object->IsShortString()) {
|
||||
target = Builtins::builtin(Builtins::LoadIC_ShortStringLength);
|
||||
} else if (object->IsMediumString()) {
|
||||
target = Builtins::builtin(Builtins::LoadIC_MediumStringLength);
|
||||
} else {
|
||||
ASSERT(object->IsLongString());
|
||||
target = Builtins::builtin(Builtins::LoadIC_LongStringLength);
|
||||
}
|
||||
target = Builtins::builtin(Builtins::LoadIC_StringLength);
|
||||
set_target(target);
|
||||
StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
|
||||
return Smi::FromInt(String::cast(*object)->length());
|
||||
@ -637,15 +630,7 @@ Object* KeyedLoadIC::Load(State state,
|
||||
if (object->IsString() && name->Equals(Heap::length_symbol())) {
|
||||
Handle<String> string = Handle<String>::cast(object);
|
||||
Object* code = NULL;
|
||||
if (string->IsShortString()) {
|
||||
code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string);
|
||||
} else if (string->IsMediumString()) {
|
||||
code =
|
||||
StubCache::ComputeKeyedLoadMediumStringLength(*name, *string);
|
||||
} else {
|
||||
ASSERT(string->IsLongString());
|
||||
code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string);
|
||||
}
|
||||
code = StubCache::ComputeKeyedLoadStringLength(*name, *string);
|
||||
if (code->IsFailure()) return code;
|
||||
set_target(Code::cast(code));
|
||||
#ifdef DEBUG
|
||||
|
4
src/ic.h
4
src/ic.h
@ -211,9 +211,7 @@ class LoadIC: public IC {
|
||||
|
||||
// Specialized code generator routines.
|
||||
static void GenerateArrayLength(MacroAssembler* masm);
|
||||
static void GenerateShortStringLength(MacroAssembler* masm);
|
||||
static void GenerateMediumStringLength(MacroAssembler* masm);
|
||||
static void GenerateLongStringLength(MacroAssembler* masm);
|
||||
static void GenerateStringLength(MacroAssembler* masm);
|
||||
static void GenerateFunctionPrototype(MacroAssembler* masm);
|
||||
|
||||
private:
|
||||
|
@ -1271,36 +1271,22 @@ bool String::Equals(String* other) {
|
||||
int String::length() {
|
||||
uint32_t len = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
switch (size_tag()) {
|
||||
case kShortStringTag:
|
||||
return len >> kShortLengthShift;
|
||||
case kMediumStringTag:
|
||||
return len >> kMediumLengthShift;
|
||||
case kLongStringTag:
|
||||
return len >> kLongLengthShift;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
return len >> (size_tag() + kLongLengthShift);
|
||||
}
|
||||
|
||||
|
||||
void String::set_length(int value) {
|
||||
switch (size_tag()) {
|
||||
case kShortStringTag:
|
||||
WRITE_INT_FIELD(this, kLengthOffset, value << kShortLengthShift);
|
||||
break;
|
||||
case kMediumStringTag:
|
||||
WRITE_INT_FIELD(this, kLengthOffset, value << kMediumLengthShift);
|
||||
break;
|
||||
case kLongStringTag:
|
||||
WRITE_INT_FIELD(this, kLengthOffset, value << kLongLengthShift);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
WRITE_INT_FIELD(this,
|
||||
kLengthOffset,
|
||||
value << (size_tag() + kLongLengthShift));
|
||||
}
|
||||
|
||||
|
||||
@ -1484,21 +1470,14 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
|
||||
int SeqTwoByteString::SeqTwoByteStringSize(Map* map) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// TwoByteStringSize is called during GC when maps are encoded.
|
||||
switch (map_size_tag(map)) {
|
||||
case kShortStringTag:
|
||||
length = length >> kShortLengthShift;
|
||||
break;
|
||||
case kMediumStringTag:
|
||||
length = length >> kMediumLengthShift;
|
||||
break;
|
||||
case kLongStringTag:
|
||||
length = length >> kLongLengthShift;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
length >>= map_size_tag(map) + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
||||
@ -1506,21 +1485,13 @@ int SeqTwoByteString::SeqTwoByteStringSize(Map* map) {
|
||||
int SeqAsciiString::SeqAsciiStringSize(Map* map) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// AsciiStringSize is called during GC when maps are encoded.
|
||||
switch (map_size_tag(map)) {
|
||||
case kShortStringTag:
|
||||
length = length >> kShortLengthShift;
|
||||
break;
|
||||
case kMediumStringTag:
|
||||
length = length >> kMediumLengthShift;
|
||||
break;
|
||||
case kLongStringTag:
|
||||
length = length >> kLongLengthShift;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
length >>= map_size_tag(map) + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
@ -3968,10 +3968,12 @@ uint32_t StringHasher::GetHashField() {
|
||||
} else {
|
||||
payload = v8::internal::HashField(GetHash(), false);
|
||||
}
|
||||
return (payload & 0x00FFFFFF) | (length_ << String::kShortLengthShift);
|
||||
return (payload & ((1 << String::kShortLengthShift) - 1)) |
|
||||
(length_ << String::kShortLengthShift);
|
||||
} else if (length_ <= String::kMaxMediumStringSize) {
|
||||
uint32_t payload = v8::internal::HashField(GetHash(), false);
|
||||
return (payload & 0x0000FFFF) | (length_ << String::kMediumLengthShift);
|
||||
return (payload & ((1 << String::kMediumLengthShift) - 1)) |
|
||||
(length_ << String::kMediumLengthShift);
|
||||
} else {
|
||||
return v8::internal::HashField(length_, false);
|
||||
}
|
||||
|
@ -395,29 +395,30 @@ const uint32_t kIsNotStringMask = 0x80;
|
||||
const uint32_t kStringTag = 0x0;
|
||||
const uint32_t kNotStringTag = 0x80;
|
||||
|
||||
// If bit 7 is clear, bits 5 and 6 are the string's size (short, medium, or
|
||||
// long).
|
||||
const uint32_t kStringSizeMask = 0x60;
|
||||
const uint32_t kShortStringTag = 0x0;
|
||||
const uint32_t kMediumStringTag = 0x20;
|
||||
const uint32_t kLongStringTag = 0x40;
|
||||
|
||||
// If bit 7 is clear, bit 4 indicates that the string is a symbol (if set) or
|
||||
// If bit 7 is clear, bit 5 indicates that the string is a symbol (if set) or
|
||||
// not (if cleared).
|
||||
const uint32_t kIsSymbolMask = 0x10;
|
||||
const uint32_t kIsSymbolMask = 0x20;
|
||||
const uint32_t kNotSymbolTag = 0x0;
|
||||
const uint32_t kSymbolTag = 0x10;
|
||||
const uint32_t kSymbolTag = 0x20;
|
||||
|
||||
// If bit 7 is clear, and the string representation is a sequential string,
|
||||
// then bit 3 indicates whether the string consists of two-byte characters or
|
||||
// one-byte characters.
|
||||
const uint32_t kStringEncodingMask = 0x8;
|
||||
// If bit 7 is clear, bits 3 and 4 are the string's size (short, medium or
|
||||
// long). These values are very special in that they are also used to shift
|
||||
// the length field to get the length, removing the hash value. This avoids
|
||||
// using if or switch when getting the length of a string.
|
||||
const uint32_t kStringSizeMask = 0x18;
|
||||
const uint32_t kShortStringTag = 0x18;
|
||||
const uint32_t kMediumStringTag = 0x10;
|
||||
const uint32_t kLongStringTag = 0x00;
|
||||
|
||||
// If bit 7 is clear then bit 2 indicates whether the string consists of
|
||||
// two-byte characters or one-byte characters.
|
||||
const uint32_t kStringEncodingMask = 0x4;
|
||||
const uint32_t kTwoByteStringTag = 0x0;
|
||||
const uint32_t kAsciiStringTag = 0x8;
|
||||
const uint32_t kAsciiStringTag = 0x4;
|
||||
|
||||
// If bit 7 is clear, the low-order 3 bits indicate the representation
|
||||
// If bit 7 is clear, the low-order 2 bits indicate the representation
|
||||
// of the string.
|
||||
const uint32_t kStringRepresentationMask = 0x07;
|
||||
const uint32_t kStringRepresentationMask = 0x03;
|
||||
enum StringRepresentationTag {
|
||||
kSeqStringTag = 0x0,
|
||||
kConsStringTag = 0x1,
|
||||
@ -3169,8 +3170,8 @@ class String: public HeapObject {
|
||||
static const int kSize = kLengthOffset + kIntSize;
|
||||
|
||||
// Limits on sizes of different types of strings.
|
||||
static const int kMaxShortStringSize = 255;
|
||||
static const int kMaxMediumStringSize = 65535;
|
||||
static const int kMaxShortStringSize = 63;
|
||||
static const int kMaxMediumStringSize = 16383;
|
||||
|
||||
static const int kMaxArrayIndexSize = 10;
|
||||
|
||||
@ -3191,14 +3192,14 @@ class String: public HeapObject {
|
||||
|
||||
// Array index strings this short can keep their index in the hash
|
||||
// field.
|
||||
static const int kMaxCachedArrayIndexLength = 6;
|
||||
static const int kMaxCachedArrayIndexLength = 7;
|
||||
|
||||
// Shift constants for retriving length and hash code from
|
||||
// length/hash field.
|
||||
static const int kHashShift = kNofLengthBitFields;
|
||||
static const int kShortLengthShift = 3 * kBitsPerByte;
|
||||
static const int kMediumLengthShift = 2 * kBitsPerByte;
|
||||
static const int kLongLengthShift = kHashShift;
|
||||
static const int kShortLengthShift = kHashShift + kShortStringTag;
|
||||
static const int kMediumLengthShift = kHashShift + kMediumStringTag;
|
||||
static const int kLongLengthShift = kHashShift + kLongStringTag;
|
||||
|
||||
// Limit for truncation in short printing.
|
||||
static const int kMaxShortPrintLength = 1024;
|
||||
|
@ -159,69 +159,29 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadShortStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label) {
|
||||
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label) {
|
||||
// Check that the receiver isn't a smi.
|
||||
__ test(receiver, Immediate(kSmiTagMask));
|
||||
__ j(zero, miss_label, not_taken);
|
||||
|
||||
// Check that the object is a short string.
|
||||
// Check that the object is a string.
|
||||
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
||||
__ and_(scratch, kIsNotStringMask | kStringSizeMask);
|
||||
__ cmp(scratch, kStringTag | kShortStringTag);
|
||||
__ j(not_equal, miss_label, not_taken);
|
||||
ASSERT(kNotStringTag != 0);
|
||||
__ test(scratch, Immediate(kNotStringTag));
|
||||
__ j(not_zero, miss_label, not_taken);
|
||||
|
||||
__ and_(scratch, kStringSizeMask);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
|
||||
__ shr(eax, String::kShortLengthShift);
|
||||
__ shl(eax, kSmiTagSize);
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
void StubCompiler::GenerateLoadMediumStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label) {
|
||||
// Check that the receiver isn't a smi.
|
||||
__ test(receiver, Immediate(kSmiTagMask));
|
||||
__ j(zero, miss_label, not_taken);
|
||||
|
||||
// Check that the object is a short string.
|
||||
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
||||
__ and_(scratch, kIsNotStringMask | kStringSizeMask);
|
||||
__ cmp(scratch, kStringTag | kMediumStringTag);
|
||||
__ j(not_equal, miss_label, not_taken);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
|
||||
__ shr(eax, String::kMediumLengthShift);
|
||||
__ shl(eax, kSmiTagSize);
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadLongStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label) {
|
||||
// Check that the receiver isn't a smi.
|
||||
__ test(receiver, Immediate(kSmiTagMask));
|
||||
__ j(zero, miss_label, not_taken);
|
||||
|
||||
// Check that the object is a short string.
|
||||
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
||||
__ and_(scratch, kIsNotStringMask | kStringSizeMask);
|
||||
__ cmp(scratch, kStringTag | kLongStringTag);
|
||||
__ j(not_equal, miss_label, not_taken);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
|
||||
__ shr(eax, String::kLongLengthShift);
|
||||
// ecx is also the receiver.
|
||||
__ lea(ecx, Operand(scratch, String::kLongLengthShift));
|
||||
__ shr(eax); // ecx is implicit shift register.
|
||||
__ shl(eax, kSmiTagSize);
|
||||
__ ret(0);
|
||||
}
|
||||
@ -1153,7 +1113,7 @@ Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
|
||||
}
|
||||
|
||||
|
||||
Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
|
||||
Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
@ -1170,61 +1130,7 @@ Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
|
||||
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
|
||||
GenerateLoadShortStringLength(masm(), ecx, edx, &miss);
|
||||
__ bind(&miss);
|
||||
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
|
||||
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(CALLBACKS);
|
||||
}
|
||||
|
||||
|
||||
Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8] : receiver
|
||||
// -----------------------------------
|
||||
HandleScope scope;
|
||||
Label miss;
|
||||
|
||||
__ mov(eax, (Operand(esp, kPointerSize)));
|
||||
__ mov(ecx, (Operand(esp, 2 * kPointerSize)));
|
||||
__ IncrementCounter(&Counters::keyed_load_string_length, 1);
|
||||
|
||||
// Check that the name has not changed.
|
||||
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
|
||||
GenerateLoadMediumStringLength(masm(), ecx, edx, &miss);
|
||||
__ bind(&miss);
|
||||
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
|
||||
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(CALLBACKS);
|
||||
}
|
||||
|
||||
|
||||
Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8] : receiver
|
||||
// -----------------------------------
|
||||
HandleScope scope;
|
||||
Label miss;
|
||||
|
||||
__ mov(eax, (Operand(esp, kPointerSize)));
|
||||
__ mov(ecx, (Operand(esp, 2 * kPointerSize)));
|
||||
__ IncrementCounter(&Counters::keyed_load_string_length, 1);
|
||||
|
||||
// Check that the name has not changed.
|
||||
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
|
||||
GenerateLoadLongStringLength(masm(), ecx, edx, &miss);
|
||||
GenerateLoadStringLength(masm(), ecx, edx, &miss);
|
||||
__ bind(&miss);
|
||||
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
|
||||
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
||||
|
@ -263,48 +263,14 @@ Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
|
||||
}
|
||||
|
||||
|
||||
Object* StubCache::ComputeKeyedLoadShortStringLength(String* name,
|
||||
String* receiver) {
|
||||
Object* StubCache::ComputeKeyedLoadStringLength(String* name,
|
||||
String* receiver) {
|
||||
Code::Flags flags =
|
||||
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
KeyedLoadStubCompiler compiler;
|
||||
code = compiler.CompileLoadShortStringLength(name);
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
Object* StubCache::ComputeKeyedLoadMediumStringLength(String* name,
|
||||
String* receiver) {
|
||||
Code::Flags flags =
|
||||
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
KeyedLoadStubCompiler compiler;
|
||||
code = compiler.CompileLoadMediumStringLength(name);
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
Object* StubCache::ComputeKeyedLoadLongStringLength(String* name,
|
||||
String* receiver) {
|
||||
Code::Flags flags =
|
||||
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
KeyedLoadStubCompiler compiler;
|
||||
code = compiler.CompileLoadLongStringLength(name);
|
||||
code = compiler.CompileLoadStringLength(name);
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
|
@ -98,14 +98,8 @@ class StubCache : public AllStatic {
|
||||
|
||||
static Object* ComputeKeyedLoadArrayLength(String* name, JSArray* receiver);
|
||||
|
||||
static Object* ComputeKeyedLoadShortStringLength(String* name,
|
||||
String* receiver);
|
||||
|
||||
static Object* ComputeKeyedLoadMediumStringLength(String* name,
|
||||
String* receiver);
|
||||
|
||||
static Object* ComputeKeyedLoadLongStringLength(String* name,
|
||||
String* receiver);
|
||||
static Object* ComputeKeyedLoadStringLength(String* name,
|
||||
String* receiver);
|
||||
|
||||
static Object* ComputeKeyedLoadFunctionPrototype(String* name,
|
||||
JSFunction* receiver);
|
||||
@ -341,18 +335,10 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
static void GenerateLoadShortStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
static void GenerateLoadMediumStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
static void GenerateLoadLongStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
static void GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
@ -415,9 +401,7 @@ class KeyedLoadStubCompiler: public StubCompiler {
|
||||
JSObject* holder,
|
||||
String* name);
|
||||
Object* CompileLoadArrayLength(String* name);
|
||||
Object* CompileLoadShortStringLength(String* name);
|
||||
Object* CompileLoadMediumStringLength(String* name);
|
||||
Object* CompileLoadLongStringLength(String* name);
|
||||
Object* CompileLoadStringLength(String* name);
|
||||
Object* CompileLoadFunctionPrototype(String* name);
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user