Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 7d04ed51b273dedcd220a78b04142780f2b1a2d4..2d8e55ca29a75ece438945adf38799dc1633f0f5 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -5803,5 +5803,1349 @@ void CodeStubAssembler::BuildFastFixedArrayForEach( |
: IndexAdvanceMode::kPost); |
} |
+compiler::Node* CodeStubAssembler::RelationalComparison( |
+ RelationalComparisonMode mode, compiler::Node* lhs, compiler::Node* rhs, |
+ compiler::Node* context) { |
+ typedef compiler::Node Node; |
+ |
+ Label return_true(this), return_false(this), end(this); |
+ Variable result(this, MachineRepresentation::kTagged); |
+ |
+ // Shared entry for floating point comparison. |
+ Label do_fcmp(this); |
+ Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64), |
+ var_fcmp_rhs(this, MachineRepresentation::kFloat64); |
+ |
+ // We might need to loop several times due to ToPrimitive and/or ToNumber |
+ // conversions. |
+ Variable var_lhs(this, MachineRepresentation::kTagged), |
+ var_rhs(this, MachineRepresentation::kTagged); |
+ Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
+ Label loop(this, 2, loop_vars); |
+ var_lhs.Bind(lhs); |
+ var_rhs.Bind(rhs); |
+ Goto(&loop); |
+ Bind(&loop); |
+ { |
+ // Load the current {lhs} and {rhs} values. |
+ lhs = var_lhs.value(); |
+ rhs = var_rhs.value(); |
+ |
+ // Check if the {lhs} is a Smi or a HeapObject. |
+ Label if_lhsissmi(this), if_lhsisnotsmi(this); |
+ Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
+ |
+ Bind(&if_lhsissmi); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ { |
+ // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. |
+ switch (mode) { |
+ case kLessThan: |
+ BranchIfSmiLessThan(lhs, rhs, &return_true, &return_false); |
+ break; |
+ case kLessThanOrEqual: |
+ BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, &return_false); |
+ break; |
+ case kGreaterThan: |
+ BranchIfSmiLessThan(rhs, lhs, &return_true, &return_false); |
+ break; |
+ case kGreaterThanOrEqual: |
+ BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, &return_false); |
+ break; |
+ } |
+ } |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Check if the {rhs} is a HeapNumber. |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
+ Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert the {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(SmiToFloat64(lhs)); |
+ var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
+ Goto(&do_fcmp); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ { |
+ // Convert the {rhs} to a Number; we don't need to perform the |
+ // dedicated ToPrimitive(rhs, hint Number) operation, as the |
+ // ToNumber(rhs) will by itself already invoke ToPrimitive with |
+ // a Number hint. |
+ Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnotsmi); |
+ { |
+ // Load the HeapNumber map for later comparisons. |
+ Node* number_map = HeapNumberMapConstant(); |
+ |
+ // Load the map of {lhs}. |
+ Node* lhs_map = LoadMap(lhs); |
+ |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ { |
+ // Check if the {lhs} is a HeapNumber. |
+ Label if_lhsisnumber(this), if_lhsisnotnumber(this, Label::kDeferred); |
+ Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
+ &if_lhsisnotnumber); |
+ |
+ Bind(&if_lhsisnumber); |
+ { |
+ // Convert the {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
+ var_fcmp_rhs.Bind(SmiToFloat64(rhs)); |
+ Goto(&do_fcmp); |
+ } |
+ |
+ Bind(&if_lhsisnotnumber); |
+ { |
+ // Convert the {lhs} to a Number; we don't need to perform the |
+ // dedicated ToPrimitive(lhs, hint Number) operation, as the |
+ // ToNumber(lhs) will by itself already invoke ToPrimitive with |
+ // a Number hint. |
+ Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
+ var_lhs.Bind(CallStub(callable, context, lhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Check if {lhs} is a HeapNumber. |
+ Label if_lhsisnumber(this), if_lhsisnotnumber(this); |
+ Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
+ &if_lhsisnotnumber); |
+ |
+ Bind(&if_lhsisnumber); |
+ { |
+ // Check if {rhs} is also a HeapNumber. |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
+ Branch(WordEqual(lhs_map, rhs_map), &if_rhsisnumber, |
+ &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert the {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
+ var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
+ Goto(&do_fcmp); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ { |
+ // Convert the {rhs} to a Number; we don't need to perform |
+ // dedicated ToPrimitive(rhs, hint Number) operation, as the |
+ // ToNumber(rhs) will by itself already invoke ToPrimitive with |
+ // a Number hint. |
+ Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnotnumber); |
+ { |
+ // Load the instance type of {lhs}. |
+ Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
+ |
+ // Check if {lhs} is a String. |
+ Label if_lhsisstring(this), if_lhsisnotstring(this, Label::kDeferred); |
+ Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring, |
+ &if_lhsisnotstring); |
+ |
+ Bind(&if_lhsisstring); |
+ { |
+ // Load the instance type of {rhs}. |
+ Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
+ |
+ // Check if {rhs} is also a String. |
+ Label if_rhsisstring(this, Label::kDeferred), |
+ if_rhsisnotstring(this, Label::kDeferred); |
+ Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
+ &if_rhsisnotstring); |
+ |
+ Bind(&if_rhsisstring); |
+ { |
+ // Both {lhs} and {rhs} are strings. |
+ switch (mode) { |
+ case kLessThan: |
+ result.Bind(CallStub(CodeFactory::StringLessThan(isolate()), |
+ context, lhs, rhs)); |
+ Goto(&end); |
+ break; |
+ case kLessThanOrEqual: |
+ result.Bind( |
+ CallStub(CodeFactory::StringLessThanOrEqual(isolate()), |
+ context, lhs, rhs)); |
+ Goto(&end); |
+ break; |
+ case kGreaterThan: |
+ result.Bind( |
+ CallStub(CodeFactory::StringGreaterThan(isolate()), |
+ context, lhs, rhs)); |
+ Goto(&end); |
+ break; |
+ case kGreaterThanOrEqual: |
+ result.Bind( |
+ CallStub(CodeFactory::StringGreaterThanOrEqual(isolate()), |
+ context, lhs, rhs)); |
+ Goto(&end); |
+ break; |
+ } |
+ } |
+ |
+ Bind(&if_rhsisnotstring); |
+ { |
+ // The {lhs} is a String, while {rhs} is neither a Number nor a |
+ // String, so we need to call ToPrimitive(rhs, hint Number) if |
+ // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the |
+ // other cases. |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
+ Label if_rhsisreceiver(this, Label::kDeferred), |
+ if_rhsisnotreceiver(this, Label::kDeferred); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first passing Number hint. |
+ Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
+ isolate(), ToPrimitiveHint::kNumber); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotreceiver); |
+ { |
+ // Convert both {lhs} and {rhs} to Number. |
+ Callable callable = CodeFactory::ToNumber(isolate()); |
+ var_lhs.Bind(CallStub(callable, context, lhs)); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnotstring); |
+ { |
+ // The {lhs} is neither a Number nor a String, so we need to call |
+ // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or |
+ // ToNumber(lhs) and ToNumber(rhs) in the other cases. |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
+ Label if_lhsisreceiver(this, Label::kDeferred), |
+ if_lhsisnotreceiver(this, Label::kDeferred); |
+ Branch(IsJSReceiverInstanceType(lhs_instance_type), |
+ &if_lhsisreceiver, &if_lhsisnotreceiver); |
+ |
+ Bind(&if_lhsisreceiver); |
+ { |
+ // Convert {lhs} to a primitive first passing Number hint. |
+ Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
+ isolate(), ToPrimitiveHint::kNumber); |
+ var_lhs.Bind(CallStub(callable, context, lhs)); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_lhsisnotreceiver); |
+ { |
+ // Convert both {lhs} and {rhs} to Number. |
+ Callable callable = CodeFactory::ToNumber(isolate()); |
+ var_lhs.Bind(CallStub(callable, context, lhs)); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ 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. |
+ switch (mode) { |
+ case kLessThan: |
+ BranchIfFloat64LessThan(lhs, rhs, &return_true, &return_false); |
+ break; |
+ case kLessThanOrEqual: |
+ BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, &return_false); |
+ break; |
+ case kGreaterThan: |
+ BranchIfFloat64GreaterThan(lhs, rhs, &return_true, &return_false); |
+ break; |
+ case kGreaterThanOrEqual: |
+ BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, |
+ &return_false); |
+ break; |
+ } |
+ } |
+ |
+ Bind(&return_true); |
+ { |
+ result.Bind(BooleanConstant(true)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&return_false); |
+ { |
+ result.Bind(BooleanConstant(false)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return result.value(); |
+} |
+ |
+namespace { |
+ |
+void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, |
+ CodeStubAssembler::Label* if_equal, |
+ 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 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->LoadMap(value); |
+ |
+ // Check if {value} (and therefore {rhs}) is a HeapNumber. |
+ Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); |
+ assembler->Branch(assembler->IsHeapNumberMap(value_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_Simd128Value_HeapObject( |
+ CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, |
+ compiler::Node* rhs, compiler::Node* rhs_map, |
+ CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { |
+ assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal, |
+ if_notequal); |
+} |
+ |
+} // namespace |
+ |
+// ES6 section 7.2.12 Abstract Equality Comparison |
+compiler::Node* CodeStubAssembler::Equal(ResultMode mode, compiler::Node* lhs, |
+ compiler::Node* rhs, |
+ compiler::Node* context) { |
+ // This is a slightly optimized version of Object::Equals represented as |
+ // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you |
+ // change something functionality wise in here, remember to update the |
+ // Object::Equals method as well. |
+ typedef compiler::Node Node; |
+ |
+ Label if_equal(this), if_notequal(this), |
+ do_rhsstringtonumber(this, Label::kDeferred), end(this); |
+ Variable result(this, MachineRepresentation::kTagged); |
+ |
+ // Shared entry for floating point comparison. |
+ Label do_fcmp(this); |
+ Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64), |
+ var_fcmp_rhs(this, MachineRepresentation::kFloat64); |
+ |
+ // We might need to loop several times due to ToPrimitive and/or ToNumber |
+ // conversions. |
+ Variable var_lhs(this, MachineRepresentation::kTagged), |
+ var_rhs(this, MachineRepresentation::kTagged); |
+ Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
+ Label loop(this, 2, loop_vars); |
+ var_lhs.Bind(lhs); |
+ var_rhs.Bind(rhs); |
+ Goto(&loop); |
+ Bind(&loop); |
+ { |
+ // Load the current {lhs} and {rhs} values. |
+ lhs = var_lhs.value(); |
+ rhs = var_rhs.value(); |
+ |
+ // Check if {lhs} and {rhs} refer to the same object. |
+ Label if_same(this), if_notsame(this); |
+ Branch(WordEqual(lhs, rhs), &if_same, &if_notsame); |
+ |
+ 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(this, lhs, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_notsame); |
+ { |
+ // Check if {lhs} is a Smi or a HeapObject. |
+ Label if_lhsissmi(this), if_lhsisnotsmi(this); |
+ Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
+ |
+ Bind(&if_lhsissmi); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ // We have already checked for {lhs} and {rhs} being the same value, so |
+ // if both are Smis when we get here they must not be equal. |
+ Goto(&if_notequal); |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Check if {rhs} is a HeapNumber. |
+ Node* number_map = HeapNumberMapConstant(); |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
+ Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
+ &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(SmiToFloat64(lhs)); |
+ var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
+ Goto(&do_fcmp); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ { |
+ // Load the instance type of the {rhs}. |
+ Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
+ |
+ // Check if the {rhs} is a String. |
+ Label if_rhsisstring(this, Label::kDeferred), |
+ if_rhsisnotstring(this); |
+ Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
+ &if_rhsisnotstring); |
+ |
+ Bind(&if_rhsisstring); |
+ { |
+ // The {rhs} is a String and the {lhs} is a Smi; we need |
+ // to convert the {rhs} to a Number and compare the output to |
+ // the Number on the {lhs}. |
+ Goto(&do_rhsstringtonumber); |
+ } |
+ |
+ Bind(&if_rhsisnotstring); |
+ { |
+ // Check if the {rhs} is a Boolean. |
+ Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
+ Branch(IsBooleanMap(rhs_map), &if_rhsisboolean, |
+ &if_rhsisnotboolean); |
+ |
+ Bind(&if_rhsisboolean); |
+ { |
+ // The {rhs} is a Boolean, load its number value. |
+ var_rhs.Bind(LoadObjectField(rhs, Oddball::kToNumberOffset)); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotboolean); |
+ { |
+ // Check if the {rhs} is a Receiver. |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
+ Label if_rhsisreceiver(this, Label::kDeferred), |
+ if_rhsisnotreceiver(this); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // Convert {rhs} to a primitive first (passing no hint). |
+ Callable callable = |
+ CodeFactory::NonPrimitiveToPrimitive(isolate()); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotreceiver); |
+ Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnotsmi); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ 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); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ Label if_lhsisstring(this), if_lhsisnumber(this), |
+ if_lhsissymbol(this), if_lhsissimd128value(this), |
+ if_lhsisoddball(this), if_lhsisreceiver(this); |
+ |
+ // Both {lhs} and {rhs} are HeapObjects, load their maps |
+ // and their instance types. |
+ Node* lhs_map = LoadMap(lhs); |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Load the instance types of {lhs} and {rhs}. |
+ Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
+ Node* rhs_instance_type = 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(this); |
+ 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; |
+ Switch(lhs_instance_type, &if_lhsisreceiver, case_values, case_labels, |
+ arraysize(case_values)); |
+ for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
+ Bind(case_labels[i]); |
+ Goto(&if_lhsisstring); |
+ delete case_labels[i]; |
+ } |
+ |
+ Bind(&if_lhsisstring); |
+ { |
+ // Check if {rhs} is also a String. |
+ Label if_rhsisstring(this, Label::kDeferred), |
+ if_rhsisnotstring(this); |
+ Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
+ &if_rhsisnotstring); |
+ |
+ Bind(&if_rhsisstring); |
+ { |
+ // Both {lhs} and {rhs} are of type String, just do the |
+ // string comparison then. |
+ Callable callable = (mode == kDontNegateResult) |
+ ? CodeFactory::StringEqual(isolate()) |
+ : CodeFactory::StringNotEqual(isolate()); |
+ result.Bind(CallStub(callable, context, lhs, rhs)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&if_rhsisnotstring); |
+ { |
+ // The {lhs} is a String and the {rhs} is some other HeapObject. |
+ // Swapping {lhs} and {rhs} is not observable and doesn't matter |
+ // for the result, so we can just swap them and use the String |
+ // handling below (for {rhs} being a String). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ Goto(&loop); |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnumber); |
+ { |
+ // Check if {rhs} is also a HeapNumber. |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
+ Branch(Word32Equal(lhs_instance_type, rhs_instance_type), |
+ &if_rhsisnumber, &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values, and |
+ // perform a floating point comparison. |
+ var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
+ var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
+ Goto(&do_fcmp); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ { |
+ // The {lhs} is a Number, the {rhs} is some other HeapObject. |
+ Label if_rhsisstring(this, Label::kDeferred), |
+ if_rhsisnotstring(this); |
+ Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
+ &if_rhsisnotstring); |
+ |
+ Bind(&if_rhsisstring); |
+ { |
+ // The {rhs} is a String and the {lhs} is a HeapNumber; we need |
+ // to convert the {rhs} to a Number and compare the output to |
+ // the Number on the {lhs}. |
+ Goto(&do_rhsstringtonumber); |
+ } |
+ |
+ Bind(&if_rhsisnotstring); |
+ { |
+ // Check if the {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
+ // Swapping {lhs} and {rhs} is not observable and doesn't |
+ // matter for the result, so we can just swap them and use |
+ // the JSReceiver handling below (for {lhs} being a |
+ // JSReceiver). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotreceiver); |
+ { |
+ // Check if {rhs} is a Boolean. |
+ Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
+ Branch(IsBooleanMap(rhs_map), &if_rhsisboolean, |
+ &if_rhsisnotboolean); |
+ |
+ Bind(&if_rhsisboolean); |
+ { |
+ // The {rhs} is a Boolean, convert it to a Smi first. |
+ var_rhs.Bind( |
+ LoadObjectField(rhs, Oddball::kToNumberOffset)); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotboolean); |
+ Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_lhsisoddball); |
+ { |
+ // The {lhs} is an Oddball and {rhs} is some other HeapObject. |
+ Label if_lhsisboolean(this), if_lhsisnotboolean(this); |
+ Node* boolean_map = BooleanMapConstant(); |
+ Branch(WordEqual(lhs_map, boolean_map), &if_lhsisboolean, |
+ &if_lhsisnotboolean); |
+ |
+ Bind(&if_lhsisboolean); |
+ { |
+ // The {lhs} is a Boolean, check if {rhs} is also a Boolean. |
+ Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
+ Branch(WordEqual(rhs_map, boolean_map), &if_rhsisboolean, |
+ &if_rhsisnotboolean); |
+ |
+ Bind(&if_rhsisboolean); |
+ { |
+ // Both {lhs} and {rhs} are distinct Boolean values. |
+ Goto(&if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotboolean); |
+ { |
+ // Convert the {lhs} to a Number first. |
+ var_lhs.Bind(LoadObjectField(lhs, Oddball::kToNumberOffset)); |
+ Goto(&loop); |
+ } |
+ } |
+ |
+ 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 = LoadMapBitField(rhs_map); |
+ BranchIfWord32Equal( |
+ Word32And(rhs_bitfield, |
+ Int32Constant(1 << Map::kIsUndetectable)), |
+ Int32Constant(0), &if_notequal, &if_equal); |
+ } |
+ } |
+ |
+ Bind(&if_lhsissymbol); |
+ { |
+ // Check if the {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
+ // Swapping {lhs} and {rhs} is not observable and doesn't |
+ // matter for the result, so we can just swap them and use |
+ // the JSReceiver handling below (for {lhs} being a JSReceiver). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ Goto(&loop); |
+ } |
+ |
+ 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. |
+ Goto(&if_notequal); |
+ } |
+ } |
+ |
+ Bind(&if_lhsissimd128value); |
+ { |
+ // Check if the {rhs} is also a Simd128Value. |
+ Label if_rhsissimd128value(this), if_rhsisnotsimd128value(this); |
+ Branch(Word32Equal(lhs_instance_type, rhs_instance_type), |
+ &if_rhsissimd128value, &if_rhsisnotsimd128value); |
+ |
+ Bind(&if_rhsissimd128value); |
+ { |
+ // Both {lhs} and {rhs} is a Simd128Value. |
+ GenerateEqual_Simd128Value_HeapObject( |
+ this, lhs, lhs_map, rhs, rhs_map, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotsimd128value); |
+ { |
+ // Check if the {rhs} is a JSReceiver. |
+ Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
+ // Swapping {lhs} and {rhs} is not observable and doesn't |
+ // matter for the result, so we can just swap them and use |
+ // the JSReceiver handling below (for {lhs} being a JSReceiver). |
+ var_lhs.Bind(rhs); |
+ var_rhs.Bind(lhs); |
+ Goto(&loop); |
+ } |
+ |
+ Bind(&if_rhsisnotreceiver); |
+ { |
+ // The {rhs} is some other Primitive. |
+ Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_lhsisreceiver); |
+ { |
+ // Check if the {rhs} is also a JSReceiver. |
+ Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
+ Branch(IsJSReceiverInstanceType(rhs_instance_type), |
+ &if_rhsisreceiver, &if_rhsisnotreceiver); |
+ |
+ Bind(&if_rhsisreceiver); |
+ { |
+ // Both {lhs} and {rhs} are different JSReceiver references, so |
+ // this cannot be considered equal. |
+ Goto(&if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotreceiver); |
+ { |
+ // Check if {rhs} is Null or Undefined (an undetectable check |
+ // is sufficient here, since we already know that {rhs} is not |
+ // a JSReceiver). |
+ Label if_rhsisundetectable(this), |
+ if_rhsisnotundetectable(this, Label::kDeferred); |
+ Node* rhs_bitfield = LoadMapBitField(rhs_map); |
+ BranchIfWord32Equal( |
+ Word32And(rhs_bitfield, |
+ Int32Constant(1 << Map::kIsUndetectable)), |
+ Int32Constant(0), &if_rhsisnotundetectable, |
+ &if_rhsisundetectable); |
+ |
+ Bind(&if_rhsisundetectable); |
+ { |
+ // Check if {lhs} is an undetectable JSReceiver. |
+ Node* lhs_bitfield = LoadMapBitField(lhs_map); |
+ BranchIfWord32Equal( |
+ Word32And(lhs_bitfield, |
+ Int32Constant(1 << Map::kIsUndetectable)), |
+ Int32Constant(0), &if_notequal, &if_equal); |
+ } |
+ |
+ Bind(&if_rhsisnotundetectable); |
+ { |
+ // The {rhs} is some Primitive different from Null and |
+ // Undefined, need to convert {lhs} to Primitive first. |
+ Callable callable = |
+ CodeFactory::NonPrimitiveToPrimitive(isolate()); |
+ var_lhs.Bind(CallStub(callable, context, lhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ Bind(&do_rhsstringtonumber); |
+ { |
+ Callable callable = CodeFactory::StringToNumber(isolate()); |
+ var_rhs.Bind(CallStub(callable, context, rhs)); |
+ Goto(&loop); |
+ } |
+ } |
+ |
+ 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. |
+ BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_equal); |
+ { |
+ result.Bind(BooleanConstant(mode == kDontNegateResult)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&if_notequal); |
+ { |
+ result.Bind(BooleanConstant(mode == kNegateResult)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return result.value(); |
+} |
+ |
+compiler::Node* CodeStubAssembler::StrictEqual(ResultMode mode, |
+ compiler::Node* lhs, |
+ compiler::Node* rhs, |
+ compiler::Node* context) { |
+ // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
+ // mode; for kNegateResult mode we properly negate the result. |
+ // |
+ // 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::Node Node; |
+ |
+ Label if_equal(this), if_notequal(this), end(this); |
+ Variable result(this, MachineRepresentation::kTagged); |
+ |
+ // Check if {lhs} and {rhs} refer to the same object. |
+ Label if_same(this), if_notsame(this); |
+ Branch(WordEqual(lhs, rhs), &if_same, &if_notsame); |
+ |
+ 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(this, lhs, &if_equal, &if_notequal); |
+ } |
+ |
+ 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 = HeapNumberMapConstant(); |
+ |
+ // Check if {lhs} is a Smi or a HeapObject. |
+ Label if_lhsissmi(this), if_lhsisnotsmi(this); |
+ Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
+ |
+ Bind(&if_lhsisnotsmi); |
+ { |
+ // Load the map of {lhs}. |
+ Node* lhs_map = LoadMap(lhs); |
+ |
+ // Check if {lhs} is a HeapNumber. |
+ Label if_lhsisnumber(this), if_lhsisnotnumber(this); |
+ Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
+ &if_lhsisnotnumber); |
+ |
+ Bind(&if_lhsisnumber); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = LoadHeapNumberValue(lhs); |
+ Node* rhs_value = SmiToFloat64(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Check if {rhs} is also a HeapNumber. |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
+ Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
+ &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = LoadHeapNumberValue(lhs); |
+ Node* rhs_value = LoadHeapNumberValue(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ Goto(&if_notequal); |
+ } |
+ } |
+ |
+ Bind(&if_lhsisnotnumber); |
+ { |
+ // Check if {rhs} is a Smi or a HeapObject. |
+ Label if_rhsissmi(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ Goto(&if_notequal); |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the instance type of {lhs}. |
+ Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
+ |
+ // Check if {lhs} is a String. |
+ Label if_lhsisstring(this), if_lhsisnotstring(this); |
+ Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring, |
+ &if_lhsisnotstring); |
+ |
+ Bind(&if_lhsisstring); |
+ { |
+ // Load the instance type of {rhs}. |
+ Node* rhs_instance_type = LoadInstanceType(rhs); |
+ |
+ // Check if {rhs} is also a String. |
+ Label if_rhsisstring(this, Label::kDeferred), |
+ if_rhsisnotstring(this); |
+ Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
+ &if_rhsisnotstring); |
+ |
+ Bind(&if_rhsisstring); |
+ { |
+ Callable callable = (mode == kDontNegateResult) |
+ ? CodeFactory::StringEqual(isolate()) |
+ : CodeFactory::StringNotEqual(isolate()); |
+ result.Bind(CallStub(callable, context, lhs, rhs)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&if_rhsisnotstring); |
+ Goto(&if_notequal); |
+ } |
+ |
+ Bind(&if_lhsisnotstring); |
+ { |
+ // Check if {lhs} is a Simd128Value. |
+ Label if_lhsissimd128value(this), if_lhsisnotsimd128value(this); |
+ Branch(Word32Equal(lhs_instance_type, |
+ Int32Constant(SIMD128_VALUE_TYPE)), |
+ &if_lhsissimd128value, &if_lhsisnotsimd128value); |
+ |
+ Bind(&if_lhsissimd128value); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // Check if {rhs} is also a Simd128Value that is equal to {lhs}. |
+ GenerateEqual_Simd128Value_HeapObject( |
+ this, lhs, lhs_map, rhs, rhs_map, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_lhsisnotsimd128value); |
+ Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ } |
+ |
+ 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(this), if_rhsisnotsmi(this); |
+ Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ Bind(&if_rhsissmi); |
+ Goto(&if_notequal); |
+ |
+ Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of the {rhs}. |
+ Node* rhs_map = LoadMap(rhs); |
+ |
+ // The {rhs} could be a HeapNumber with the same value as {lhs}. |
+ Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
+ Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
+ &if_rhsisnotnumber); |
+ |
+ Bind(&if_rhsisnumber); |
+ { |
+ // Convert {lhs} and {rhs} to floating point values. |
+ Node* lhs_value = SmiToFloat64(lhs); |
+ Node* rhs_value = LoadHeapNumberValue(rhs); |
+ |
+ // Perform a floating point comparison of {lhs} and {rhs}. |
+ BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
+ } |
+ |
+ Bind(&if_rhsisnotnumber); |
+ Goto(&if_notequal); |
+ } |
+ } |
+ } |
+ |
+ Bind(&if_equal); |
+ { |
+ result.Bind(BooleanConstant(mode == kDontNegateResult)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&if_notequal); |
+ { |
+ result.Bind(BooleanConstant(mode == kNegateResult)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return result.value(); |
+} |
+ |
+compiler::Node* CodeStubAssembler::ForInFilter(compiler::Node* key, |
+ compiler::Node* object, |
+ compiler::Node* context) { |
+ Label return_undefined(this, Label::kDeferred), return_to_name(this), |
+ end(this); |
+ |
+ Variable var_result(this, MachineRepresentation::kTagged); |
+ |
+ Node* has_property = |
+ HasProperty(object, key, context, Runtime::kForInHasProperty); |
+ |
+ Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name, |
+ &return_undefined); |
+ |
+ Bind(&return_to_name); |
+ { |
+ var_result.Bind(ToName(context, key)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&return_undefined); |
+ { |
+ var_result.Bind(UndefinedConstant()); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return var_result.value(); |
+} |
+ |
+compiler::Node* CodeStubAssembler::HasProperty( |
+ compiler::Node* object, compiler::Node* key, compiler::Node* context, |
+ Runtime::FunctionId fallback_runtime_function_id) { |
+ typedef compiler::Node Node; |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ Label call_runtime(this, Label::kDeferred), return_true(this), |
+ return_false(this), end(this); |
+ |
+ CodeStubAssembler::LookupInHolder lookup_property_in_holder = |
+ [this, &return_true](Node* receiver, Node* holder, Node* holder_map, |
+ Node* holder_instance_type, Node* unique_name, |
+ Label* next_holder, Label* if_bailout) { |
+ TryHasOwnProperty(holder, holder_map, holder_instance_type, unique_name, |
+ &return_true, next_holder, if_bailout); |
+ }; |
+ |
+ CodeStubAssembler::LookupInHolder lookup_element_in_holder = |
+ [this, &return_true](Node* receiver, Node* holder, Node* holder_map, |
+ Node* holder_instance_type, Node* index, |
+ Label* next_holder, Label* if_bailout) { |
+ TryLookupElement(holder, holder_map, holder_instance_type, index, |
+ &return_true, next_holder, if_bailout); |
+ }; |
+ |
+ TryPrototypeChainLookup(object, key, lookup_property_in_holder, |
+ lookup_element_in_holder, &return_false, |
+ &call_runtime); |
+ |
+ Variable result(this, MachineRepresentation::kTagged); |
+ Bind(&return_true); |
+ { |
+ result.Bind(BooleanConstant(true)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&return_false); |
+ { |
+ result.Bind(BooleanConstant(false)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&call_runtime); |
+ { |
+ result.Bind( |
+ CallRuntime(fallback_runtime_function_id, context, object, key)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return result.value(); |
+} |
+ |
+compiler::Node* CodeStubAssembler::Typeof(compiler::Node* value, |
+ compiler::Node* context) { |
+ Variable result_var(this, MachineRepresentation::kTagged); |
+ |
+ Label return_number(this, Label::kDeferred), if_oddball(this), |
+ return_function(this), return_undefined(this), return_object(this), |
+ return_string(this), return_result(this); |
+ |
+ GotoIf(WordIsSmi(value), &return_number); |
+ |
+ Node* map = LoadMap(value); |
+ |
+ GotoIf(IsHeapNumberMap(map), &return_number); |
+ |
+ Node* instance_type = LoadMapInstanceType(map); |
+ |
+ GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), &if_oddball); |
+ |
+ Node* callable_or_undetectable_mask = Word32And( |
+ LoadMapBitField(map), |
+ Int32Constant(1 << Map::kIsCallable | 1 << Map::kIsUndetectable)); |
+ |
+ GotoIf(Word32Equal(callable_or_undetectable_mask, |
+ Int32Constant(1 << Map::kIsCallable)), |
+ &return_function); |
+ |
+ GotoUnless(Word32Equal(callable_or_undetectable_mask, Int32Constant(0)), |
+ &return_undefined); |
+ |
+ GotoIf(IsJSReceiverInstanceType(instance_type), &return_object); |
+ |
+ GotoIf(IsStringInstanceType(instance_type), &return_string); |
+ |
+#define SIMD128_BRANCH(TYPE, Type, type, lane_count, lane_type) \ |
+ Label return_##type(this); \ |
+ Node* type##_map = HeapConstant(factory()->type##_map()); \ |
+ GotoIf(WordEqual(map, type##_map), &return_##type); |
+ SIMD128_TYPES(SIMD128_BRANCH) |
+#undef SIMD128_BRANCH |
+ |
+ Assert(Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE))); |
+ result_var.Bind(HeapConstant(isolate()->factory()->symbol_string())); |
+ Goto(&return_result); |
+ |
+ Bind(&return_number); |
+ { |
+ result_var.Bind(HeapConstant(isolate()->factory()->number_string())); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&if_oddball); |
+ { |
+ Node* type = LoadObjectField(value, Oddball::kTypeOfOffset); |
+ result_var.Bind(type); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&return_function); |
+ { |
+ result_var.Bind(HeapConstant(isolate()->factory()->function_string())); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&return_undefined); |
+ { |
+ result_var.Bind(HeapConstant(isolate()->factory()->undefined_string())); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&return_object); |
+ { |
+ result_var.Bind(HeapConstant(isolate()->factory()->object_string())); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&return_string); |
+ { |
+ result_var.Bind(HeapConstant(isolate()->factory()->string_string())); |
+ Goto(&return_result); |
+ } |
+ |
+#define SIMD128_BIND_RETURN(TYPE, Type, type, lane_count, lane_type) \ |
+ Bind(&return_##type); \ |
+ { \ |
+ result_var.Bind(HeapConstant(isolate()->factory()->type##_string())); \ |
+ Goto(&return_result); \ |
+ } |
+ SIMD128_TYPES(SIMD128_BIND_RETURN) |
+#undef SIMD128_BIND_RETURN |
+ |
+ Bind(&return_result); |
+ return result_var.value(); |
+} |
+ |
+compiler::Node* CodeStubAssembler::InstanceOf(compiler::Node* object, |
+ compiler::Node* callable, |
+ compiler::Node* context) { |
+ Label return_runtime(this, Label::kDeferred), end(this); |
+ Variable result(this, MachineRepresentation::kTagged); |
+ |
+ // Check if no one installed @@hasInstance somewhere. |
+ GotoUnless( |
+ WordEqual(LoadObjectField(LoadRoot(Heap::kHasInstanceProtectorRootIndex), |
+ PropertyCell::kValueOffset), |
+ SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
+ &return_runtime); |
+ |
+ // Check if {callable} is a valid receiver. |
+ GotoIf(WordIsSmi(callable), &return_runtime); |
+ GotoIf(Word32Equal(Word32And(LoadMapBitField(LoadMap(callable)), |
+ Int32Constant(1 << Map::kIsCallable)), |
+ Int32Constant(0)), |
+ &return_runtime); |
+ |
+ // Use the inline OrdinaryHasInstance directly. |
+ result.Bind(OrdinaryHasInstance(context, callable, object)); |
+ Goto(&end); |
+ |
+ // TODO(bmeurer): Use GetPropertyStub here once available. |
+ Bind(&return_runtime); |
+ { |
+ result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return result.value(); |
+} |
+ |
} // namespace internal |
} // namespace v8 |