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

Unified Diff: src/code-stubs.cc

Issue 1759133002: [compiler] Initial TurboFan code stubs for abstract relational comparison. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 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 3814986e438fd3493566a8b023e5782e071b4d75..c253daa3d2f50430c25fbe58e328c9460b15692b 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -501,10 +501,353 @@ void StringLengthStub::GenerateAssembly(
namespace {
+enum AbstractRelationalComparisonMode {
+ kLessThan,
+ kLessThanOrEqual,
+ kGreaterThan,
+ kGreaterThanOrEqual
+};
+
+void GenerateAbstractRelationalComparison(
+ compiler::CodeStubAssembler* assembler,
+ AbstractRelationalComparisonMode mode) {
+ typedef compiler::CodeStubAssembler::Label Label;
+ typedef compiler::Node Node;
+ typedef compiler::CodeStubAssembler::Variable Variable;
+
+ Node* context = assembler->Parameter(2);
+
+ Label return_true(assembler), return_false(assembler);
+
+ // Shared entry for floating point comparison.
+ Label do_fcmp(assembler);
+ Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
+ var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
+
+ // 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 the {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);
+ {
+ // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
+ switch (mode) {
+ case kLessThan:
+ assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ case kLessThanOrEqual:
+ assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ case kGreaterThan:
+ assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
+ &return_false);
+ break;
+ case kGreaterThanOrEqual:
+ assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
+ &return_false);
+ break;
+ }
+ }
+
+ assembler->Bind(&if_rhsisnotsmi);
+ {
+ // Load the map of {rhs}.
+ Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
+
+ // Check if the {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 the {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);
+ {
+ // 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::ToNumber(assembler->isolate());
+ var_rhs.Bind(assembler->CallStub(callable, context, rhs));
+ assembler->Goto(&loop);
+ }
+ }
+ }
+
+ assembler->Bind(&if_lhsisnotsmi);
+ {
+ // Load the HeapNumber map for later comparisons.
+ Node* number_map = assembler->HeapNumberMapConstant();
+
+ // Load the map of {lhs}.
+ Node* lhs_map = assembler->LoadObjectField(lhs, HeapObject::kMapOffset);
+
+ // 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);
+ {
+ // Check if the {lhs} is a HeapNumber.
+ Label if_lhsisnumber(assembler),
+ if_lhsisnotnumber(assembler, Label::kDeferred);
+ assembler->Branch(assembler->WordEqual(lhs_map, number_map),
+ &if_lhsisnumber, &if_lhsisnotnumber);
+
+ assembler->Bind(&if_lhsisnumber);
+ {
+ // Convert the {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->SmiToFloat64(rhs));
+ assembler->Goto(&do_fcmp);
+ }
+
+ assembler->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::ToNumber(assembler->isolate());
+ var_lhs.Bind(assembler->CallStub(callable, context, lhs));
+ assembler->Goto(&loop);
+ }
+ }
+
+ assembler->Bind(&if_rhsisnotsmi);
+ {
+ // Load the map of {rhs}.
+ Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
+
+ // Check if {lhs} is a HeapNumber.
+ Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
+ assembler->Branch(assembler->WordEqual(lhs_map, number_map),
+ &if_lhsisnumber, &if_lhsisnotnumber);
+
+ assembler->Bind(&if_lhsisnumber);
+ {
+ // Check if {rhs} is also a HeapNumber.
+ Label if_rhsisnumber(assembler),
+ if_rhsisnotnumber(assembler, Label::kDeferred);
+ assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
+ &if_rhsisnumber, &if_rhsisnotnumber);
+
+ assembler->Bind(&if_rhsisnumber);
+ {
+ // Convert the {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);
+ {
+ // 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::ToNumber(assembler->isolate());
+ var_rhs.Bind(assembler->CallStub(callable, context, rhs));
+ assembler->Goto(&loop);
+ }
+ }
+
+ assembler->Bind(&if_lhsisnotnumber);
+ {
+ // Load the instance type of {lhs}.
+ Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
+
+ // Check if {lhs} is a String.
+ Label if_lhsisstring(assembler),
+ if_lhsisnotstring(assembler, Label::kDeferred);
+ assembler->Branch(assembler->Int32LessThan(
+ lhs_instance_type,
+ assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
+ &if_lhsisstring, &if_lhsisnotstring);
+
+ assembler->Bind(&if_lhsisstring);
+ {
+ // Load the instance type of {rhs}.
+ Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
+
+ // Check if {rhs} is also a String.
+ Label if_rhsisstring(assembler),
+ 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);
+ {
+ // Both {lhs} and {rhs} are strings.
+ // TODO(bmeurer): Hook up String<Compare>Stub once we have it.
+ switch (mode) {
+ case kLessThan:
+ assembler->TailCallRuntime(Runtime::kStringLessThan, context,
+ lhs, rhs);
+ break;
+ case kLessThanOrEqual:
+ assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual,
+ context, lhs, rhs);
+ break;
+ case kGreaterThan:
+ assembler->TailCallRuntime(Runtime::kStringGreaterThan,
+ context, lhs, rhs);
+ break;
+ case kGreaterThanOrEqual:
+ assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
+ context, lhs, rhs);
+ break;
+ }
+ }
+
+ assembler->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(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 Number hint.
+ // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
+ var_rhs.Bind(assembler->CallRuntime(
+ Runtime::kToPrimitive_Number, context, rhs));
+ assembler->Goto(&loop);
+ }
+
+ assembler->Bind(&if_rhsisnotreceiver);
+ {
+ // Convert both {lhs} and {rhs} to Number.
+ Callable callable = CodeFactory::ToNumber(assembler->isolate());
+ var_lhs.Bind(assembler->CallStub(callable, context, lhs));
+ var_rhs.Bind(assembler->CallStub(callable, context, rhs));
+ assembler->Goto(&loop);
+ }
+ }
+ }
+
+ assembler->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(assembler, Label::kDeferred),
+ if_lhsisnotreceiver(assembler, Label::kDeferred);
+ assembler->Branch(
+ assembler->Int32LessThanOrEqual(
+ assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
+ lhs_instance_type),
+ &if_lhsisreceiver, &if_lhsisnotreceiver);
+
+ assembler->Bind(&if_lhsisreceiver);
+ {
+ // Convert {lhs} to a primitive first passing Number hint.
+ // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
+ var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
+ context, lhs));
+ assembler->Goto(&loop);
+ }
+
+ assembler->Bind(&if_lhsisnotreceiver);
+ {
+ // Convert both {lhs} and {rhs} to Number.
+ Callable callable = CodeFactory::ToNumber(assembler->isolate());
+ var_lhs.Bind(assembler->CallStub(callable, context, lhs));
+ var_rhs.Bind(assembler->CallStub(callable, context, rhs));
+ 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.
+ switch (mode) {
+ case kLessThan:
+ assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ case kLessThanOrEqual:
+ assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ case kGreaterThan:
+ assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ case kGreaterThanOrEqual:
+ assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
+ &return_false);
+ break;
+ }
+ }
+
+ assembler->Bind(&return_true);
+ assembler->Return(assembler->BooleanConstant(true));
+
+ assembler->Bind(&return_false);
+ assembler->Return(assembler->BooleanConstant(false));
+}
+
enum ResultMode { kDontNegateResult, kNegateResult };
void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
- Isolate* isolate, ResultMode mode) {
+ ResultMode mode) {
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
// mode; for kNegateResult mode we properly negate the result.
//
@@ -706,9 +1049,10 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
assembler->Bind(&if_rhsisstring);
{
- Callable callable = (mode == kDontNegateResult)
- ? CodeFactory::StringEqual(isolate)
- : CodeFactory::StringNotEqual(isolate);
+ Callable callable =
+ (mode == kDontNegateResult)
+ ? CodeFactory::StringEqual(assembler->isolate())
+ : CodeFactory::StringNotEqual(assembler->isolate());
assembler->TailCallStub(callable, context, lhs, rhs);
}
@@ -969,14 +1313,34 @@ void GenerateStringEqual(compiler::CodeStubAssembler* assembler,
} // namespace
+void LessThanStub::GenerateAssembly(
+ compiler::CodeStubAssembler* assembler) const {
+ GenerateAbstractRelationalComparison(assembler, kLessThan);
+}
+
+void LessThanOrEqualStub::GenerateAssembly(
+ compiler::CodeStubAssembler* assembler) const {
+ GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual);
+}
+
+void GreaterThanStub::GenerateAssembly(
+ compiler::CodeStubAssembler* assembler) const {
+ GenerateAbstractRelationalComparison(assembler, kGreaterThan);
+}
+
+void GreaterThanOrEqualStub::GenerateAssembly(
+ compiler::CodeStubAssembler* assembler) const {
+ GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual);
+}
+
void StrictEqualStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
- GenerateStrictEqual(assembler, isolate(), kDontNegateResult);
+ GenerateStrictEqual(assembler, kDontNegateResult);
}
void StrictNotEqualStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
- GenerateStrictEqual(assembler, isolate(), kNegateResult);
+ GenerateStrictEqual(assembler, kNegateResult);
}
void StringEqualStub::GenerateAssembly(
« 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