PPC: Mark null and undefined as undetectable, and use it to handle abstract equality comparison in the generic compare ic

Port 3ce9e808c5

Original commit message:
    Marking as undetectable makes abstract equality of null, undefined, and
    other undetectable objects easier. Supporting it in the generic compare
    IC significantly speeds up dynamic comparison between those values and
    JSReceivers by not falling back to the runtime.

R=verwaest@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=

Review URL: https://codereview.chromium.org/1684133003

Cr-Commit-Position: refs/heads/master@{#33876}
This commit is contained in:
mbrandy 2016-02-10 12:08:03 -08:00 committed by Commit bot
parent 0ecdd93282
commit d4bdd76726
3 changed files with 32 additions and 23 deletions

View File

@ -5478,8 +5478,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, Label* false_label,
final_branch_condition = eq;
} else if (String::Equals(type_name, factory->undefined_string())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ beq(true_label);
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ beq(false_label);
__ JumpIfSmi(input, false_label);
// Check for undetectable objects => true.
__ LoadP(scratch, FieldMemOperand(input, HeapObject::kMapOffset));

View File

@ -514,7 +514,7 @@ void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_,
false_label_);
DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
DCHECK(lit->IsNull() || lit->IsUndefined() || !lit->IsUndetectableObject());
if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
if (false_label_ != fall_through_) __ b(false_label_);
} else if (lit->IsTrue() || lit->IsJSObject()) {
@ -4295,8 +4295,8 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ CompareRoot(r3, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through);
} else if (String::Equals(check, factory->undefined_string())) {
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ beq(if_true);
__ CompareRoot(r3, Heap::kNullValueRootIndex);
__ beq(if_false);
__ JumpIfSmi(r3, if_false);
// Check for undetectable objects => true.
__ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset));

View File

@ -515,40 +515,49 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, Register lhs,
static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
Register lhs, Register rhs,
Label* possible_strings,
Label* not_both_strings) {
Label* runtime_call) {
DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3)));
// r5 is object type of rhs.
Label object_test;
Label object_test, return_unequal, undetectable;
STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
__ andi(r0, r5, Operand(kIsNotStringMask));
__ bne(&object_test, cr0);
__ andi(r0, r5, Operand(kIsNotInternalizedMask));
__ bne(possible_strings, cr0);
__ CompareObjectType(lhs, r6, r6, FIRST_NONSTRING_TYPE);
__ bge(not_both_strings);
__ bge(runtime_call);
__ andi(r0, r6, Operand(kIsNotInternalizedMask));
__ bne(possible_strings, cr0);
// Both are internalized. We already checked they weren't the same pointer
// so they are not equal.
__ li(r3, Operand(NOT_EQUAL));
// Both are internalized. We already checked they weren't the same pointer so
// they are not equal. Return non-equal by returning the non-zero object
// pointer in r3.
__ Ret();
__ bind(&object_test);
__ cmpi(r5, Operand(FIRST_JS_RECEIVER_TYPE));
__ blt(not_both_strings);
__ CompareObjectType(lhs, r5, r6, FIRST_JS_RECEIVER_TYPE);
__ blt(not_both_strings);
// If both objects are undetectable, they are equal. Otherwise, they
// are not equal, since they are different objects and an object is not
// equal to undefined.
__ LoadP(r5, FieldMemOperand(lhs, HeapObject::kMapOffset));
__ LoadP(r6, FieldMemOperand(rhs, HeapObject::kMapOffset));
__ lbz(r5, FieldMemOperand(r5, Map::kBitFieldOffset));
__ lbz(r6, FieldMemOperand(r6, Map::kBitFieldOffset));
__ and_(r3, r5, r6);
__ andi(r3, r3, Operand(1 << Map::kIsUndetectable));
__ xori(r3, r3, Operand(1 << Map::kIsUndetectable));
__ lbz(r7, FieldMemOperand(r5, Map::kBitFieldOffset));
__ lbz(r8, FieldMemOperand(r6, Map::kBitFieldOffset));
__ andi(r0, r7, Operand(1 << Map::kIsUndetectable));
__ bne(&undetectable, cr0);
__ andi(r0, r8, Operand(1 << Map::kIsUndetectable));
__ bne(&return_unequal, cr0);
__ CompareInstanceType(r5, r5, FIRST_JS_RECEIVER_TYPE);
__ blt(runtime_call);
__ CompareInstanceType(r6, r6, FIRST_JS_RECEIVER_TYPE);
__ blt(runtime_call);
__ bind(&return_unequal);
// Return non-equal by returning the non-zero object pointer in r3.
__ Ret();
__ bind(&undetectable);
__ andi(r0, r8, Operand(1 << Map::kIsUndetectable));
__ beq(&return_unequal, cr0);
__ li(r3, Operand(EQUAL));
__ Ret();
}