Index: src/code-stubs.cc |
diff --git a/src/code-stubs.cc b/src/code-stubs.cc |
index 2c4445f59ddf22316137d67c95693bdd3bb1e411..c5f7fb4fa1273f945115eae0e3bd9d48d60fb191 100644 |
--- a/src/code-stubs.cc |
+++ b/src/code-stubs.cc |
@@ -473,6 +473,290 @@ void StringLengthStub::GenerateAssembly( |
assembler->Return(result); |
} |
+void StrictEqualStub::GenerateAssembly( |
+ compiler::CodeStubAssembler* assembler) const { |
+ // Here's pseudo-code for the algorithm below: |
+ // |
+ // if (lhs == rhs) { |
+ // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
+ // return true; |
+ // } |
+ // if (!lhs->IsSmi()) { |
+ // if (lhs->IsHeapNumber()) { |
+ // if (rhs->IsSmi()) { |
+ // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); |
+ // } else if (rhs->IsHeapNumber()) { |
+ // return HeapNumber::cast(rhs)->value() == |
+ // HeapNumber::cast(lhs)->value(); |
+ // } else { |
+ // return false; |
+ // } |
+ // } else { |
+ // if (rhs->IsSmi()) { |
+ // return false; |
+ // } else { |
+ // if (lhs->IsString()) { |
+ // if (rhs->IsString()) { |
+ // return %StringEqual(lhs, rhs); |
+ // } else { |
+ // return false; |
+ // } |
+ // } else if (lhs->IsSimd128()) { |
+ // if (rhs->IsSimd128()) { |
+ // return %StrictEqual(lhs, rhs); |
+ // } |
+ // } else { |
+ // return false; |
+ // } |
+ // } |
+ // } |
+ // } else { |
+ // if (rhs->IsSmi()) { |
+ // return false; |
+ // } else { |
+ // if (rhs->IsHeapNumber()) { |
+ // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); |
+ // } else { |
+ // return false; |
+ // } |
+ // } |
+ // } |
+ |
+ typedef compiler::CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ |
+ Node* lhs = assembler->Parameter(0); |
+ Node* rhs = assembler->Parameter(1); |
+ Node* context = assembler->Parameter(2); |
+ |
+ Label if_true(assembler), if_false(assembler); |
+ |
+ // Check if {lhs} and {rhs} refer to the same object. |
+ Label if_same(assembler), if_notsame(assembler); |
+ assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
+ |
+ assembler->Bind(&if_same); |
+ { |
+ // The {lhs} and {rhs} reference the exact same value, yet we need special |
+ // treatment for HeapNumber, as NaN is not equal to NaN. |
+ // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
+ // seems to be what is tested in the current SIMD.js testsuite. |
+ |
+ // Check if {lhs} (and therefore {rhs}) is a Smi or a HeapObject. |
+ Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
+ |
+ assembler->Bind(&if_lhsisnotsmi); |
+ { |
+ // Load the map of {lhs}. |
+ Node* lhs_map = assembler->LoadObjectField(lhs, HeapObject::kMapOffset); |
+ |
+ // Check if {lhs} (and therefore {rhs}) is a HeapNumber. |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); |
+ assembler->Branch(assembler->WordEqual(lhs_map, number_map), |
+ &if_lhsisnumber, &if_lhsisnotnumber); |
+ |
+ assembler->Bind(&if_lhsisnumber); |
+ { |
+ // Convert {lhs} (and therefore {rhs}) to floating point value. |
+ Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
+ |
+ // Check if the HeapNumber value is a NaN. |
+ assembler->BranchIfFloat64IsNaN(lhs_value, &if_false, &if_true); |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotnumber); |
+ assembler->Goto(&if_true); |
+ } |
+ |
+ assembler->Bind(&if_lhsissmi); |
+ assembler->Goto(&if_true); |
+ } |
+ |
+ assembler->Bind(&if_notsame); |
+ { |
+ // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, |
+ // String and Simd128Value they can still be considered equal. |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ |
+ // Check if {lhs} is a Smi or a HeapObject. |
+ Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
+ |
+ assembler->Bind(&if_lhsisnotsmi); |
+ { |
+ // Load the map of {lhs}. |
+ Node* lhs_map = assembler->LoadObjectField(lhs, HeapObject::kMapOffset); |
+ |
+ // Check if {lhs} is a HeapNumber. |
+ Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); |
+ assembler->Branch(assembler->WordEqual(lhs_map, number_map), |
+ &if_lhsisnumber, &if_lhsisnotnumber); |
+ |
+ assembler->Bind(&if_lhsisnumber); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
+ &if_rhsisnotsmi); |
+ |
+ assembler->Bind(&if_rhsissmi); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
+ Node* rhs_value = assembler->SmiToFloat64(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, |
+ &if_false); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = |
+ assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
+ |
+ // Check if {rhs} is also a HeapNumber. |
+ Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); |
+ assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ assembler->Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
+ Node* rhs_value = assembler->LoadHeapNumberValue(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, |
+ &if_false); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotnumber); |
+ assembler->Goto(&if_false); |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotnumber); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
+ &if_rhsisnotsmi); |
+ |
+ assembler->Bind(&if_rhsissmi); |
+ assembler->Goto(&if_false); |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the instance type of {lhs}. |
+ Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); |
+ |
+ // Check if {lhs} is a String. |
+ Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); |
+ assembler->Branch(assembler->Int32LessThan( |
+ lhs_instance_type, |
+ assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
+ &if_lhsisstring, &if_lhsisnotstring); |
+ |
+ assembler->Bind(&if_lhsisstring); |
+ { |
+ // Load the instance type of {rhs}. |
+ Node* rhs_instance_type = assembler->LoadInstanceType(rhs); |
+ |
+ // Check if {rhs} is also a String. |
+ Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); |
+ assembler->Branch(assembler->Int32LessThan( |
+ rhs_instance_type, assembler->Int32Constant( |
+ FIRST_NONSTRING_TYPE)), |
+ &if_rhsisstring, &if_rhsisnotstring); |
+ |
+ assembler->Bind(&if_rhsisstring); |
+ { |
+ // TODO(bmeurer): Optimize this further once the StringEqual |
+ // functionality is available in TurboFan land. |
+ assembler->TailCallRuntime(Runtime::kStringEqual, context, lhs, |
+ rhs); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotstring); |
+ assembler->Goto(&if_false); |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotstring); |
+ { |
+ // Check if {lhs} is a Simd128Value. |
+ Label if_lhsissimd128value(assembler), |
+ if_lhsisnotsimd128value(assembler); |
+ assembler->Branch(assembler->Word32Equal( |
+ lhs_instance_type, |
+ assembler->Int32Constant(SIMD128_VALUE_TYPE)), |
+ &if_lhsissimd128value, &if_lhsisnotsimd128value); |
+ |
+ assembler->Bind(&if_lhsissimd128value); |
+ { |
+ // TODO(bmeurer): Inline the Simd128Value equality check. |
+ assembler->TailCallRuntime(Runtime::kStrictEqual, context, lhs, |
+ rhs); |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotsimd128value); |
+ assembler->Goto(&if_false); |
+ } |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsissmi); |
+ { |
+ // We already know that {lhs} and {rhs} are not reference equal, and {lhs} |
+ // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a |
+ // HeapNumber with an equal floating point value. |
+ |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
+ &if_rhsisnotsmi); |
+ |
+ assembler->Bind(&if_rhsissmi); |
+ assembler->Goto(&if_false); |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of the {rhs}. |
+ Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
+ |
+ // The {rhs} could be a HeapNumber with the same value as {lhs}. |
+ Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); |
+ assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ assembler->Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = assembler->SmiToFloat64(lhs); |
+ Node* rhs_value = assembler->LoadHeapNumberValue(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, |
+ &if_false); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotnumber); |
+ assembler->Goto(&if_false); |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&if_true); |
+ assembler->Return(assembler->BooleanConstant(true)); |
+ |
+ assembler->Bind(&if_false); |
+ assembler->Return(assembler->BooleanConstant(false)); |
+} |
+ |
void ToBooleanStub::GenerateAssembly( |
compiler::CodeStubAssembler* assembler) const { |
typedef compiler::Node Node; |