| 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);
|
|
|