Make strict equality checks faster on IA32 by doing
more work in the CompareStub. I'll port this to ARM once I'm satisfied with the performance improvements. Review URL: http://codereview.chromium.org/7014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@481 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
89c762edf4
commit
1c89cef32d
@ -1127,9 +1127,8 @@ void CodeGenerator::Comparison(Condition cc, bool strict) {
|
||||
__ pop(edx);
|
||||
}
|
||||
|
||||
// Check for the smi case.
|
||||
Label is_smi, done;
|
||||
CompareStub stub(cc, strict);
|
||||
|
||||
__ mov(ecx, Operand(eax));
|
||||
__ or_(ecx, Operand(edx));
|
||||
__ test(ecx, Immediate(kSmiTagMask));
|
||||
@ -1137,8 +1136,13 @@ void CodeGenerator::Comparison(Condition cc, bool strict) {
|
||||
|
||||
// When non-smi, call out to the compare stub. "parameters" setup by
|
||||
// calling code in edx and eax and "result" is returned in the flags.
|
||||
CompareStub stub(cc, strict);
|
||||
__ CallStub(&stub);
|
||||
__ cmp(eax, 0);
|
||||
if (cc == equal) {
|
||||
__ test(eax, Operand(eax));
|
||||
} else {
|
||||
__ cmp(eax, 0);
|
||||
}
|
||||
__ jmp(&done);
|
||||
|
||||
// Test smi equality by pointer comparison.
|
||||
@ -4484,6 +4488,73 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
||||
|
||||
void CompareStub::Generate(MacroAssembler* masm) {
|
||||
Label call_builtin, done;
|
||||
|
||||
// If we're doing a strict equality comparison, we generate code
|
||||
// to do fast comparison for objects and oddballs. Numbers and
|
||||
// strings still go through the usual slow-case code.
|
||||
if (strict_) {
|
||||
Label slow;
|
||||
__ test(eax, Immediate(kSmiTagMask));
|
||||
__ j(zero, &slow);
|
||||
|
||||
// Get the type of the first operand.
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
|
||||
// If the first object is an object, we do pointer comparison.
|
||||
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
||||
Label non_object;
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(less, &non_object);
|
||||
__ sub(eax, Operand(edx));
|
||||
__ ret(0);
|
||||
|
||||
// Check for oddballs: true, false, null, undefined.
|
||||
__ bind(&non_object);
|
||||
__ cmp(ecx, ODDBALL_TYPE);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
// If the oddball isn't undefined, we do pointer comparison. For
|
||||
// the undefined value, we have to be careful and check for
|
||||
// 'undetectable' objects too.
|
||||
Label undefined;
|
||||
__ cmp(Operand(eax), Immediate(Factory::undefined_value()));
|
||||
__ j(equal, &undefined);
|
||||
__ sub(eax, Operand(edx));
|
||||
__ ret(0);
|
||||
|
||||
// Undefined case: If the other operand isn't undefined too, we
|
||||
// have to check if it's 'undetectable'.
|
||||
Label check_undetectable;
|
||||
__ bind(&undefined);
|
||||
__ cmp(Operand(edx), Immediate(Factory::undefined_value()));
|
||||
__ j(not_equal, &check_undetectable);
|
||||
__ Set(eax, Immediate(0));
|
||||
__ ret(0);
|
||||
|
||||
// Check for undetectability of the other operand.
|
||||
Label not_strictly_equal;
|
||||
__ bind(&check_undetectable);
|
||||
__ test(edx, Immediate(kSmiTagMask));
|
||||
__ j(zero, ¬_strictly_equal);
|
||||
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
|
||||
__ and_(ecx, 1 << Map::kIsUndetectable);
|
||||
__ cmp(ecx, 1 << Map::kIsUndetectable);
|
||||
__ j(not_equal, ¬_strictly_equal);
|
||||
__ Set(eax, Immediate(0));
|
||||
__ ret(0);
|
||||
|
||||
// No cigar: Objects aren't strictly equal. Register eax contains
|
||||
// a non-smi value so it can't be 0. Just return.
|
||||
ASSERT(kHeapTag != 0);
|
||||
__ bind(¬_strictly_equal);
|
||||
__ ret(0);
|
||||
|
||||
// Fall through to the general case.
|
||||
__ bind(&slow);
|
||||
}
|
||||
|
||||
// Save the return address (and get it off the stack).
|
||||
__ pop(ecx);
|
||||
|
||||
|
@ -91,26 +91,23 @@ function EQUALS(y) {
|
||||
|
||||
// ECMA-262, section 11.9.4, page 56.
|
||||
function STRICT_EQUALS(x) {
|
||||
if (IS_NUMBER(this)) {
|
||||
if (!IS_NUMBER(x)) return 1; // not equal
|
||||
return %NumberEquals(this, x);
|
||||
}
|
||||
|
||||
if (IS_STRING(this)) {
|
||||
if (!IS_STRING(x)) return 1; // not equal
|
||||
return %StringEquals(this, x);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_BOOLEAN(this)) {
|
||||
if (!IS_BOOLEAN(x)) return 1; // not equal
|
||||
if (this) return x ? 0 : 1;
|
||||
else return x ? 1 : 0;
|
||||
}
|
||||
if (IS_NUMBER(this)) {
|
||||
if (!IS_NUMBER(x)) return 1; // not equal
|
||||
return %NumberEquals(this, x);
|
||||
}
|
||||
|
||||
if (IS_UNDEFINED(this)) { // both undefined and undetectable
|
||||
if (IS_UNDEFINED(this)) {
|
||||
// Both undefined and undetectable.
|
||||
return IS_UNDEFINED(x) ? 0 : 1;
|
||||
}
|
||||
|
||||
// Objects, null, booleans and functions are all that's left.
|
||||
// They can all be compared with a simple identity check.
|
||||
return %_ObjectEquals(this, x) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user