Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Unified Diff: src/code-stubs.cc

Issue 1761783004: [WIP] EqualStub and NotEqualStub. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@StringRelationalComparison
Patch Set: Updates Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698