Port optimized comparison of a string to a constant single character string to X64 platform. Fix small mistake on ia32 platform.
Review URL: http://codereview.chromium.org/1627014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4398 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7bca61c11d
commit
f720592ac3
@ -2432,7 +2432,8 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
left_side_constant_null = left_side.handle()->IsNull();
|
left_side_constant_null = left_side.handle()->IsNull();
|
||||||
left_side_constant_1_char_string =
|
left_side_constant_1_char_string =
|
||||||
(left_side.handle()->IsString() &&
|
(left_side.handle()->IsString() &&
|
||||||
(String::cast(*left_side.handle())->length() == 1));
|
String::cast(*left_side.handle())->length() == 1 &&
|
||||||
|
String::cast(*left_side.handle())->IsAsciiRepresentation());
|
||||||
}
|
}
|
||||||
bool right_side_constant_smi = false;
|
bool right_side_constant_smi = false;
|
||||||
bool right_side_constant_null = false;
|
bool right_side_constant_null = false;
|
||||||
@ -2442,7 +2443,8 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
right_side_constant_null = right_side.handle()->IsNull();
|
right_side_constant_null = right_side.handle()->IsNull();
|
||||||
right_side_constant_1_char_string =
|
right_side_constant_1_char_string =
|
||||||
(right_side.handle()->IsString() &&
|
(right_side.handle()->IsString() &&
|
||||||
(String::cast(*right_side.handle())->length() == 1));
|
String::cast(*right_side.handle())->length() == 1 &&
|
||||||
|
String::cast(*right_side.handle())->IsAsciiRepresentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left_side_constant_smi || right_side_constant_smi) {
|
if (left_side_constant_smi || right_side_constant_smi) {
|
||||||
@ -2631,6 +2633,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
JumpTarget is_not_string, is_string;
|
JumpTarget is_not_string, is_string;
|
||||||
Register left_reg = left_side.reg();
|
Register left_reg = left_side.reg();
|
||||||
Handle<Object> right_val = right_side.handle();
|
Handle<Object> right_val = right_side.handle();
|
||||||
|
ASSERT(StringShape(String::cast(*right_val)).IsSymbol());
|
||||||
__ test(left_side.reg(), Immediate(kSmiTagMask));
|
__ test(left_side.reg(), Immediate(kSmiTagMask));
|
||||||
is_not_string.Branch(zero, &left_side);
|
is_not_string.Branch(zero, &left_side);
|
||||||
Result temp = allocator_->Allocate();
|
Result temp = allocator_->Allocate();
|
||||||
@ -2655,7 +2658,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
dest->false_target()->Branch(not_equal);
|
dest->false_target()->Branch(not_equal);
|
||||||
__ bind(¬_a_symbol);
|
__ bind(¬_a_symbol);
|
||||||
}
|
}
|
||||||
// If the receiver is not a string of the type we handle call the stub.
|
// Call the compare stub if the left side is not a flat ascii string.
|
||||||
__ and_(temp.reg(),
|
__ and_(temp.reg(),
|
||||||
kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
|
kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
|
||||||
__ cmp(temp.reg(), kStringTag | kSeqStringTag | kAsciiStringTag);
|
__ cmp(temp.reg(), kStringTag | kSeqStringTag | kAsciiStringTag);
|
||||||
@ -2673,7 +2676,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
dest->false_target()->Jump();
|
dest->false_target()->Jump();
|
||||||
|
|
||||||
is_string.Bind(&left_side);
|
is_string.Bind(&left_side);
|
||||||
// Here we know we have a sequential ASCII string.
|
// left_side is a sequential ASCII string.
|
||||||
left_side = Result(left_reg);
|
left_side = Result(left_reg);
|
||||||
right_side = Result(right_val);
|
right_side = Result(right_val);
|
||||||
Result temp2 = allocator_->Allocate();
|
Result temp2 = allocator_->Allocate();
|
||||||
@ -2685,7 +2688,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
Immediate(1));
|
Immediate(1));
|
||||||
__ j(not_equal, &comparison_done);
|
__ j(not_equal, &comparison_done);
|
||||||
uint8_t char_value =
|
uint8_t char_value =
|
||||||
static_cast<uint8_t>(String::cast(*right_side.handle())->Get(0));
|
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
||||||
__ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
|
__ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
|
||||||
char_value);
|
char_value);
|
||||||
__ bind(&comparison_done);
|
__ bind(&comparison_done);
|
||||||
@ -2694,17 +2697,17 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
FieldOperand(left_side.reg(), String::kLengthOffset));
|
FieldOperand(left_side.reg(), String::kLengthOffset));
|
||||||
__ sub(Operand(temp2.reg()), Immediate(1));
|
__ sub(Operand(temp2.reg()), Immediate(1));
|
||||||
Label comparison;
|
Label comparison;
|
||||||
// If the length is 0 then our subtraction gave -1 which compares less
|
// If the length is 0 then the subtraction gave -1 which compares less
|
||||||
// than any character.
|
// than any character.
|
||||||
__ j(negative, &comparison);
|
__ j(negative, &comparison);
|
||||||
// Otherwise load the first character.
|
// Otherwise load the first character.
|
||||||
__ movzx_b(temp2.reg(),
|
__ movzx_b(temp2.reg(),
|
||||||
FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize));
|
FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize));
|
||||||
__ bind(&comparison);
|
__ bind(&comparison);
|
||||||
// Compare the first character of the string with out constant
|
// Compare the first character of the string with the
|
||||||
// 1-character string.
|
// constant 1-character string.
|
||||||
uint8_t char_value =
|
uint8_t char_value =
|
||||||
static_cast<uint8_t>(String::cast(*right_side.handle())->Get(0));
|
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
||||||
__ cmp(Operand(temp2.reg()), Immediate(char_value));
|
__ cmp(Operand(temp2.reg()), Immediate(char_value));
|
||||||
Label characters_were_different;
|
Label characters_were_different;
|
||||||
__ j(not_equal, &characters_were_different);
|
__ j(not_equal, &characters_were_different);
|
||||||
|
@ -5241,14 +5241,28 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
ASSERT(cc == less || cc == equal || cc == greater_equal);
|
ASSERT(cc == less || cc == equal || cc == greater_equal);
|
||||||
|
|
||||||
// If either side is a constant smi, optimize the comparison.
|
// If either side is a constant smi, optimize the comparison.
|
||||||
bool left_side_constant_smi =
|
bool left_side_constant_smi = false;
|
||||||
left_side.is_constant() && left_side.handle()->IsSmi();
|
bool left_side_constant_null = false;
|
||||||
bool right_side_constant_smi =
|
bool left_side_constant_1_char_string = false;
|
||||||
right_side.is_constant() && right_side.handle()->IsSmi();
|
if (left_side.is_constant()) {
|
||||||
bool left_side_constant_null =
|
left_side_constant_smi = left_side.handle()->IsSmi();
|
||||||
left_side.is_constant() && left_side.handle()->IsNull();
|
left_side_constant_null = left_side.handle()->IsNull();
|
||||||
bool right_side_constant_null =
|
left_side_constant_1_char_string =
|
||||||
right_side.is_constant() && right_side.handle()->IsNull();
|
(left_side.handle()->IsString() &&
|
||||||
|
String::cast(*left_side.handle())->length() == 1 &&
|
||||||
|
String::cast(*left_side.handle())->IsAsciiRepresentation());
|
||||||
|
}
|
||||||
|
bool right_side_constant_smi = false;
|
||||||
|
bool right_side_constant_null = false;
|
||||||
|
bool right_side_constant_1_char_string = false;
|
||||||
|
if (right_side.is_constant()) {
|
||||||
|
right_side_constant_smi = right_side.handle()->IsSmi();
|
||||||
|
right_side_constant_null = right_side.handle()->IsNull();
|
||||||
|
right_side_constant_1_char_string =
|
||||||
|
(right_side.handle()->IsString() &&
|
||||||
|
String::cast(*right_side.handle())->length() == 1 &&
|
||||||
|
String::cast(*right_side.handle())->IsAsciiRepresentation());
|
||||||
|
}
|
||||||
|
|
||||||
if (left_side_constant_smi || right_side_constant_smi) {
|
if (left_side_constant_smi || right_side_constant_smi) {
|
||||||
if (left_side_constant_smi && right_side_constant_smi) {
|
if (left_side_constant_smi && right_side_constant_smi) {
|
||||||
@ -5388,6 +5402,141 @@ void CodeGenerator::Comparison(AstNode* node,
|
|||||||
operand.Unuse();
|
operand.Unuse();
|
||||||
dest->Split(not_zero);
|
dest->Split(not_zero);
|
||||||
}
|
}
|
||||||
|
} else if (left_side_constant_1_char_string ||
|
||||||
|
right_side_constant_1_char_string) {
|
||||||
|
if (left_side_constant_1_char_string && right_side_constant_1_char_string) {
|
||||||
|
// Trivial case, comparing two constants.
|
||||||
|
int left_value = String::cast(*left_side.handle())->Get(0);
|
||||||
|
int right_value = String::cast(*right_side.handle())->Get(0);
|
||||||
|
switch (cc) {
|
||||||
|
case less:
|
||||||
|
dest->Goto(left_value < right_value);
|
||||||
|
break;
|
||||||
|
case equal:
|
||||||
|
dest->Goto(left_value == right_value);
|
||||||
|
break;
|
||||||
|
case greater_equal:
|
||||||
|
dest->Goto(left_value >= right_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Only one side is a constant 1 character string.
|
||||||
|
// If left side is a constant 1-character string, reverse the operands.
|
||||||
|
// Since one side is a constant string, conversion order does not matter.
|
||||||
|
if (left_side_constant_1_char_string) {
|
||||||
|
Result temp = left_side;
|
||||||
|
left_side = right_side;
|
||||||
|
right_side = temp;
|
||||||
|
cc = ReverseCondition(cc);
|
||||||
|
// This may reintroduce greater or less_equal as the value of cc.
|
||||||
|
// CompareStub and the inline code both support all values of cc.
|
||||||
|
}
|
||||||
|
// Implement comparison against a constant string, inlining the case
|
||||||
|
// where both sides are strings.
|
||||||
|
left_side.ToRegister();
|
||||||
|
|
||||||
|
// Here we split control flow to the stub call and inlined cases
|
||||||
|
// before finally splitting it to the control destination. We use
|
||||||
|
// a jump target and branching to duplicate the virtual frame at
|
||||||
|
// the first split. We manually handle the off-frame references
|
||||||
|
// by reconstituting them on the non-fall-through path.
|
||||||
|
JumpTarget is_not_string, is_string;
|
||||||
|
Register left_reg = left_side.reg();
|
||||||
|
Handle<Object> right_val = right_side.handle();
|
||||||
|
ASSERT(StringShape(String::cast(*right_val)).IsSymbol());
|
||||||
|
Condition is_smi = masm()->CheckSmi(left_reg);
|
||||||
|
is_not_string.Branch(is_smi, &left_side);
|
||||||
|
Result temp = allocator_->Allocate();
|
||||||
|
ASSERT(temp.is_valid());
|
||||||
|
__ movq(temp.reg(),
|
||||||
|
FieldOperand(left_reg, HeapObject::kMapOffset));
|
||||||
|
__ movzxbl(temp.reg(),
|
||||||
|
FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
|
||||||
|
// If we are testing for equality then make use of the symbol shortcut.
|
||||||
|
// Check if the left hand side has the same type as the right hand
|
||||||
|
// side (which is always a symbol).
|
||||||
|
if (cc == equal) {
|
||||||
|
Label not_a_symbol;
|
||||||
|
ASSERT(kSymbolTag != 0);
|
||||||
|
// Ensure that no non-strings have the symbol bit set.
|
||||||
|
ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE);
|
||||||
|
__ testb(temp.reg(), Immediate(kIsSymbolMask)); // Test the symbol bit.
|
||||||
|
__ j(zero, ¬_a_symbol);
|
||||||
|
// They are symbols, so do identity compare.
|
||||||
|
__ Cmp(left_reg, right_side.handle());
|
||||||
|
dest->true_target()->Branch(equal);
|
||||||
|
dest->false_target()->Branch(not_equal);
|
||||||
|
__ bind(¬_a_symbol);
|
||||||
|
}
|
||||||
|
// Call the compare stub if the left side is not a flat ascii string.
|
||||||
|
__ andb(temp.reg(),
|
||||||
|
Immediate(kIsNotStringMask |
|
||||||
|
kStringRepresentationMask |
|
||||||
|
kStringEncodingMask));
|
||||||
|
__ cmpb(temp.reg(),
|
||||||
|
Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
|
||||||
|
temp.Unuse();
|
||||||
|
is_string.Branch(equal, &left_side);
|
||||||
|
|
||||||
|
// Setup and call the compare stub.
|
||||||
|
is_not_string.Bind(&left_side);
|
||||||
|
CompareStub stub(cc, strict, kCantBothBeNaN);
|
||||||
|
Result result = frame_->CallStub(&stub, &left_side, &right_side);
|
||||||
|
result.ToRegister();
|
||||||
|
__ SmiCompare(result.reg(), Smi::FromInt(0));
|
||||||
|
result.Unuse();
|
||||||
|
dest->true_target()->Branch(cc);
|
||||||
|
dest->false_target()->Jump();
|
||||||
|
|
||||||
|
is_string.Bind(&left_side);
|
||||||
|
// left_side is a sequential ASCII string.
|
||||||
|
ASSERT(left_side.reg().is(left_reg));
|
||||||
|
right_side = Result(right_val);
|
||||||
|
Result temp2 = allocator_->Allocate();
|
||||||
|
ASSERT(temp2.is_valid());
|
||||||
|
// Test string equality and comparison.
|
||||||
|
if (cc == equal) {
|
||||||
|
Label comparison_done;
|
||||||
|
__ cmpl(FieldOperand(left_side.reg(), String::kLengthOffset),
|
||||||
|
Immediate(1));
|
||||||
|
__ j(not_equal, &comparison_done);
|
||||||
|
uint8_t char_value =
|
||||||
|
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
||||||
|
__ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
|
||||||
|
Immediate(char_value));
|
||||||
|
__ bind(&comparison_done);
|
||||||
|
} else {
|
||||||
|
__ movl(temp2.reg(),
|
||||||
|
FieldOperand(left_side.reg(), String::kLengthOffset));
|
||||||
|
__ subl(temp2.reg(), Immediate(1));
|
||||||
|
Label comparison;
|
||||||
|
// If the length is 0 then the subtraction gave -1 which compares less
|
||||||
|
// than any character.
|
||||||
|
__ j(negative, &comparison);
|
||||||
|
// Otherwise load the first character.
|
||||||
|
__ movzxbl(temp2.reg(),
|
||||||
|
FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize));
|
||||||
|
__ bind(&comparison);
|
||||||
|
// Compare the first character of the string with the
|
||||||
|
// constant 1-character string.
|
||||||
|
uint8_t char_value =
|
||||||
|
static_cast<uint8_t>(String::cast(*right_side.handle())->Get(0));
|
||||||
|
__ cmpb(temp2.reg(), Immediate(char_value));
|
||||||
|
Label characters_were_different;
|
||||||
|
__ j(not_equal, &characters_were_different);
|
||||||
|
// If the first character is the same then the long string sorts after
|
||||||
|
// the short one.
|
||||||
|
__ cmpl(FieldOperand(left_side.reg(), String::kLengthOffset),
|
||||||
|
Immediate(1));
|
||||||
|
__ bind(&characters_were_different);
|
||||||
|
}
|
||||||
|
temp2.Unuse();
|
||||||
|
left_side.Unuse();
|
||||||
|
right_side.Unuse();
|
||||||
|
dest->Split(cc);
|
||||||
|
}
|
||||||
} else { // Neither side is a constant Smi or null.
|
} else { // Neither side is a constant Smi or null.
|
||||||
// If either side is a non-smi constant, skip the smi check.
|
// If either side is a non-smi constant, skip the smi check.
|
||||||
bool known_non_smi =
|
bool known_non_smi =
|
||||||
|
Loading…
Reference in New Issue
Block a user