Index: src/code-stubs.cc |
diff --git a/src/code-stubs.cc b/src/code-stubs.cc |
index e72a43b430dbc331eb256581afa3bda8301ec34b..e29a471194ab2f50805f53f6d0c2cfcd0972fcb5 100644 |
--- a/src/code-stubs.cc |
+++ b/src/code-stubs.cc |
@@ -848,6 +848,556 @@ void GenerateAbstractRelationalComparison( |
enum ResultMode { kDontNegateResult, kNegateResult }; |
+void GenerateEqual_Same(compiler::CodeStubAssembler* assembler, |
+ compiler::Node* value, |
+ compiler::CodeStubAssembler::Label* if_equal, |
+ compiler::CodeStubAssembler::Label* if_notequal) { |
+ // In case of abstract or strict equality checks, we need additional checks |
+ // for NaN values because they are not considered equal, even if both the |
+ // left and the right hand side reference exactly the same value. |
+ // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
+ // seems to be what is tested in the current SIMD.js testsuite. |
+ |
+ typedef compiler::CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ |
+ // Check if {value} is a Smi or a HeapObject. |
+ Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, |
+ &if_valueisnotsmi); |
+ |
+ assembler->Bind(&if_valueisnotsmi); |
+ { |
+ // Load the map of {value}. |
+ Node* value_map = assembler->LoadObjectField(value, HeapObject::kMapOffset); |
+ |
+ // Check if {value} (and therefore {rhs}) is a HeapNumber. |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); |
+ assembler->Branch(assembler->WordEqual(value_map, number_map), |
+ &if_valueisnumber, &if_valueisnotnumber); |
+ |
+ assembler->Bind(&if_valueisnumber); |
+ { |
+ // Convert {value} (and therefore {rhs}) to floating point value. |
+ Node* value_value = assembler->LoadHeapNumberValue(value); |
+ |
+ // Check if the HeapNumber value is a NaN. |
+ assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); |
+ } |
+ |
+ assembler->Bind(&if_valueisnotnumber); |
+ assembler->Goto(if_equal); |
+ } |
+ |
+ assembler->Bind(&if_valueissmi); |
+ assembler->Goto(if_equal); |
+} |
+ |
+void GenerateEqual(compiler::CodeStubAssembler* assembler, ResultMode mode) { |
+ typedef compiler::CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ typedef compiler::CodeStubAssembler::Variable Variable; |
+ |
+ Node* context = assembler->Parameter(2); |
+ |
+ Label if_equal(assembler), if_notequal(assembler); |
+ |
+ // Shared entry for floating point comparison. |
+ Label do_fcmp(assembler); |
+ Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), |
+ var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); |
+ |
+ // Shared entry for runtime comparison. |
+ Label do_rcmp(assembler); |
+ Variable var_rcmp_lhs(assembler, MachineRepresentation::kTagged), |
+ var_rcmp_rhs(assembler, MachineRepresentation::kTagged); |
+ |
+ // We might need to loop several times due to ToPrimitive and/or ToNumber |
+ // conversions. |
+ Variable var_lhs(assembler, MachineRepresentation::kTagged), |
+ var_rhs(assembler, MachineRepresentation::kTagged); |
+ Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
+ Label loop(assembler, 2, loop_vars); |
+ var_lhs.Bind(assembler->Parameter(0)); |
+ var_rhs.Bind(assembler->Parameter(1)); |
+ assembler->Goto(&loop); |
+ assembler->Bind(&loop); |
+ { |
+ // Load the current {lhs} and {rhs} values. |
+ Node* lhs = var_lhs.value(); |
+ Node* rhs = var_rhs.value(); |
+ |
+ // 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. |
+ GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); |
+ } |
+ |
+ assembler->Bind(&if_notsame); |
+ { |
+ // 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_lhsissmi); |
+ { |
+ // 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_notequal); |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = |
+ assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
+ |
+ // Check if {rhs} is a HeapNumber. |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ Label if_rhsisnumber(assembler), |
+ if_rhsisnotnumber(assembler, Label::kDeferred); |
+ assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ assembler->Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); |
+ var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
+ assembler->Goto(&do_fcmp); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotnumber); |
+ { |
+ // Load the instance type of the {rhs}. |
+ Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); |
+ |
+ // Check if the {rhs} is a String. |
+ Label if_rhsisstring(assembler, Label::kDeferred), |
+ if_rhsisnotstring(assembler, Label::kDeferred); |
+ assembler->Branch(assembler->Int32LessThan( |
+ rhs_instance_type, assembler->Int32Constant( |
+ FIRST_NONSTRING_TYPE)), |
+ &if_rhsisstring, &if_rhsisnotstring); |
+ |
+ assembler->Bind(&if_rhsisstring); |
+ { |
+ // Convert the {rhs} to a Number. |
+ Callable callable = CodeFactory::ToNumber(assembler->isolate()); |
+ var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotstring); |
+ { |
+ // Check if the {rhs} is a Boolean. |
+ Node* boolean_map = assembler->BooleanMapConstant(); |
+ Label if_rhsisboolean(assembler, Label::kDeferred), |
+ if_rhsisnotboolean(assembler, Label::kDeferred); |
+ assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), |
+ &if_rhsisboolean, &if_rhsisnotboolean); |
+ |
+ assembler->Bind(&if_rhsisboolean); |
+ { |
+ // The {rhs} is a Boolean, load its number value. |
+ var_rhs.Bind( |
+ assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotboolean); |
+ { |
+ // Check if the {rhs} is a Receiver. |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
+ Label if_rhsisreceiver(assembler, Label::kDeferred), |
+ if_rhsisnotreceiver(assembler, Label::kDeferred); |
+ assembler->Branch( |
+ assembler->Int32LessThanOrEqual( |
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
+ rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ assembler->Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first (passing no hint). |
+ // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
+ var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
+ context, rhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotreceiver); |
+ assembler->Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotsmi); |
+ { |
+ // 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); |
+ { |
+ // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} |
+ // and {rhs} is not observable and doesn't matter for the result, so |
+ // we can just swap them and use the Smi handling above (for {lhs} |
+ // being a Smi). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ Label if_lhsisstring(assembler), if_lhsisnumber(assembler), |
+ if_lhsissymbol(assembler), if_lhsissimd128value(assembler), |
+ if_lhsisoddball(assembler), if_lhsisreceiver(assembler); |
+ |
+ // Both {lhs} and {rhs} are HeapObjects, load their maps |
+ // and their instance types. |
+ Node* lhs_map = |
+ assembler->LoadObjectField(lhs, HeapObject::kMapOffset); |
+ Node* rhs_map = |
+ assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
+ |
+ // Load the instance types of {lhs} and {rhs}. |
+ Node* lhs_instancetype = assembler->LoadMapInstanceType(lhs_map); |
+ Node* rhs_instancetype = assembler->LoadMapInstanceType(rhs_map); |
+ |
+ // Dispatch based on the instance type of {lhs}. |
+ size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; |
+ Label* case_labels[kNumCases]; |
+ int32_t case_values[kNumCases]; |
+ for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
+ case_labels[i] = new Label(assembler); |
+ case_values[i] = i; |
+ } |
+ case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; |
+ case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; |
+ case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; |
+ case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; |
+ case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; |
+ case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; |
+ case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; |
+ case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; |
+ assembler->Switch(lhs_instancetype, &if_lhsisreceiver, case_values, |
+ case_labels, arraysize(case_values)); |
+ for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
+ assembler->Bind(case_labels[i]); |
+ assembler->Goto(&if_lhsisstring); |
+ delete case_labels[i]; |
+ } |
+ |
+ assembler->Bind(&if_lhsisstring); |
+ { |
+ // Check if {rhs} is also a String. |
+ Label if_rhsisstring(assembler), |
+ if_rhsisnotstring(assembler, Label::kDeferred); |
+ assembler->Branch(assembler->Int32LessThan( |
+ rhs_instancetype, assembler->Int32Constant( |
+ FIRST_NONSTRING_TYPE)), |
+ &if_rhsisstring, &if_rhsisnotstring); |
+ |
+ assembler->Bind(&if_rhsisstring); |
+ { |
+ // Both {lhs} and {rhs} are of type String, just do the |
+ // string comparison then. |
+ Callable callable = |
+ (mode == kDontNegateResult) |
+ ? CodeFactory::StringEqual(assembler->isolate()) |
+ : CodeFactory::StringNotEqual(assembler->isolate()); |
+ assembler->TailCallStub(callable, context, lhs, rhs); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotstring); |
+ { |
+ // Check if {rhs} is a HeapNumber. |
+ Label if_rhsisnumber(assembler, Label::kDeferred), |
+ if_rhsisnotnumber(assembler); |
+ assembler->Branch(assembler->Word32Equal( |
+ rhs_instancetype, |
+ assembler->Int32Constant(HEAP_NUMBER_TYPE)), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ assembler->Bind(&if_rhsisnumber); |
+ { |
+ // The {lhs} is a String and the {rhs} is a HeapNumber; we need |
+ // to convert the {lhs} to a Number and compare the output to |
+ // the Number on the {rhs}. |
+ Callable callable = CodeFactory::ToNumber(assembler->isolate()); |
+ var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotnumber); |
+ { |
+ // The {lhs} is a String, but the {rhs} is neither a String nor |
+ // a Number. Check if {rhs} is a Boolean. |
+ Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); |
+ Node* boolean_map = assembler->BooleanMapConstant(); |
+ assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), |
+ &if_rhsisboolean, &if_rhsisnotboolean); |
+ |
+ assembler->Bind(&if_rhsisboolean); |
+ { |
+ // The {rhs} is a Boolean, convert it to Number first. |
+ var_rhs.Bind(assembler->LoadObjectField( |
+ rhs, Oddball::kToNumberOffset)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotboolean); |
+ { |
+ // The {lhs} is a String, but the {rhs} is none of String, |
+ // Number or Boolean. Check if {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(assembler, Label::kDeferred), |
+ if_rhsisnotreceiver(assembler); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ assembler->Branch( |
+ assembler->Int32LessThanOrEqual( |
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
+ rhs_instancetype), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ assembler->Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first (passing no hint). |
+ // TODO(bmeurer): Hook up ToPrimitiveStub here. |
+ var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
+ context, rhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotreceiver); |
+ { |
+ // The {lhs} is a String, but the {rhs} is neither a String, |
+ // nor Number, nor Boolean, nor JSReceiver, so the two |
+ // values cannot be considered equal. |
+ assembler->Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsisnumber); |
+ { |
+ // Check if {rhs} is also a HeapNumber. |
+ Label if_rhsisnumber(assembler), |
+ if_rhsisnotnumber(assembler, Label::kDeferred); |
+ assembler->Branch( |
+ assembler->Word32Equal(lhs_instancetype, rhs_instancetype), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ assembler->Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
+ var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
+ assembler->Goto(&do_fcmp); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotnumber); |
+ { |
+ // The {lhs} is a Number, the {rhs} is some other HeapObject. |
+ // TODO(bmeurer): Make this fast! |
+ var_rcmp_lhs.Bind(lhs); |
+ var_rcmp_rhs.Bind(rhs); |
+ assembler->Goto(&do_rcmp); |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsisoddball); |
+ { |
+ // The {lhs} is an Oddball and {rhs} is some other HeapObject. |
+ Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); |
+ Node* boolean_map = assembler->BooleanMapConstant(); |
+ assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), |
+ &if_lhsisboolean, &if_lhsisnotboolean); |
+ |
+ assembler->Bind(&if_lhsisboolean); |
+ { |
+ // The {lhs} is a Boolean, convert it to a Number first. |
+ var_lhs.Bind( |
+ assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_lhsisnotboolean); |
+ { |
+ // The {lhs} is either Null or Undefined; check if the {rhs} is |
+ // undetectable (i.e. either also Null or Undefined or some |
+ // undetectable JSReceiver). |
+ Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); |
+ assembler->BranchIfWord32Equal( |
+ assembler->Word32And( |
+ rhs_bitfield, |
+ assembler->Int32Constant(1 << Map::kIsUndetectable)), |
+ assembler->Int32Constant(0), &if_notequal, &if_equal); |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsissymbol); |
+ { |
+ // Check if the {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(assembler, Label::kDeferred), |
+ if_rhsisnotreceiver(assembler); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ assembler->Branch( |
+ assembler->Int32LessThanOrEqual( |
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
+ rhs_instancetype), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ assembler->Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first (passing no hint). |
+ // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
+ var_rhs.Bind( |
+ assembler->CallRuntime(Runtime::kToPrimitive, context, rhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotreceiver); |
+ { |
+ // The {rhs} is not a JSReceiver and also not the same Symbol |
+ // as the {lhs}, so this is equality check is considered false. |
+ assembler->Goto(&if_notequal); |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsissimd128value); |
+ { |
+ // Check if the {rhs} is also a Simd128Value. |
+ Label if_rhsissimd128value(assembler), |
+ if_rhsisnotsimd128value(assembler); |
+ assembler->Branch( |
+ assembler->Word32Equal(lhs_instancetype, rhs_instancetype), |
+ &if_rhsissimd128value, &if_rhsisnotsimd128value); |
+ |
+ assembler->Bind(&if_rhsissimd128value); |
+ { |
+ // The {lhs} is a Simd128Value. |
+ // TODO(bmeurer): Make this fast! |
+ var_rcmp_lhs.Bind(lhs); |
+ var_rcmp_rhs.Bind(rhs); |
+ assembler->Goto(&do_rcmp); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotsimd128value); |
+ { |
+ // Check if the {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(assembler, Label::kDeferred), |
+ if_rhsisnotreceiver(assembler); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ assembler->Branch( |
+ assembler->Int32LessThanOrEqual( |
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
+ rhs_instancetype), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ assembler->Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first (passing no hint). |
+ // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
+ var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
+ context, rhs)); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotreceiver); |
+ { |
+ // The {rhs} is some other Primitive. |
+ assembler->Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&if_lhsisreceiver); |
+ { |
+ // Check if the {rhs} is also a JSReceiver. |
+ Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ assembler->Branch( |
+ assembler->Int32LessThanOrEqual( |
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
+ rhs_instancetype), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ assembler->Bind(&if_rhsisreceiver); |
+ { |
+ // Both {lhs} and {rhs} are different JSReceiver references, so |
+ // this cannot be considered equal. |
+ assembler->Goto(&if_notequal); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotreceiver); |
+ { |
+ // The {lhs} is a JSReceiver and the {rhs} is a Primitive. |
+ // Swapping {lhs} and {rhs} is not observable and doesn't |
+ // matter for the result, so we can just swap them and use |
+ // the Primitive handling above (for {lhs} being a Primitive). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ assembler->Goto(&loop); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ assembler->Bind(&do_fcmp); |
+ { |
+ // Load the {lhs} and {rhs} floating point values. |
+ Node* lhs = var_fcmp_lhs.value(); |
+ Node* rhs = var_fcmp_rhs.value(); |
+ |
+ // Perform a fast floating point comparison. |
+ assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); |
+ } |
+ |
+ assembler->Bind(&do_rcmp); |
+ { |
+ // Load the {lhs} and {rhs} floating point values. |
+ Node* lhs = var_rcmp_lhs.value(); |
+ Node* rhs = var_rcmp_rhs.value(); |
+ |
+ // Perform a slow runtime comparison. |
+ switch (mode) { |
+ case kDontNegateResult: |
+ assembler->TailCallRuntime(Runtime::kEqual, context, lhs, rhs); |
+ break; |
+ case kNegateResult: |
+ assembler->TailCallRuntime(Runtime::kNotEqual, context, lhs, rhs); |
+ break; |
+ } |
+ } |
+ |
+ assembler->Bind(&if_equal); |
+ assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
+ |
+ assembler->Bind(&if_notequal); |
+ assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
+} |
+ |
void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, |
ResultMode mode) { |
// Here's pseudo-code for the algorithm below in case of kDontNegateResult |
@@ -915,39 +1465,7 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, |
{ |
// 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_notequal, &if_equal); |
- } |
- |
- assembler->Bind(&if_lhsisnotnumber); |
- assembler->Goto(&if_equal); |
- } |
- |
- assembler->Bind(&if_lhsissmi); |
- assembler->Goto(&if_equal); |
+ GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); |
} |
assembler->Bind(&if_notsame); |
@@ -1518,6 +2036,15 @@ void GreaterThanOrEqualStub::GenerateAssembly( |
GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual); |
} |
+void EqualStub::GenerateAssembly(compiler::CodeStubAssembler* assembler) const { |
+ GenerateEqual(assembler, kDontNegateResult); |
+} |
+ |
+void NotEqualStub::GenerateAssembly( |
+ compiler::CodeStubAssembler* assembler) const { |
+ GenerateEqual(assembler, kNegateResult); |
+} |
+ |
void StrictEqualStub::GenerateAssembly( |
compiler::CodeStubAssembler* assembler) const { |
GenerateStrictEqual(assembler, kDontNegateResult); |