| Index: src/code-stubs.cc
|
| diff --git a/src/code-stubs.cc b/src/code-stubs.cc
|
| index c253daa3d2f50430c25fbe58e328c9460b15692b..e72a43b430dbc331eb256581afa3bda8301ec34b 100644
|
| --- a/src/code-stubs.cc
|
| +++ b/src/code-stubs.cc
|
| @@ -501,7 +501,7 @@ void StringLengthStub::GenerateAssembly(
|
|
|
| namespace {
|
|
|
| -enum AbstractRelationalComparisonMode {
|
| +enum RelationalComparisonMode {
|
| kLessThan,
|
| kLessThanOrEqual,
|
| kGreaterThan,
|
| @@ -509,8 +509,7 @@ enum AbstractRelationalComparisonMode {
|
| };
|
|
|
| void GenerateAbstractRelationalComparison(
|
| - compiler::CodeStubAssembler* assembler,
|
| - AbstractRelationalComparisonMode mode) {
|
| + compiler::CodeStubAssembler* assembler, RelationalComparisonMode mode) {
|
| typedef compiler::CodeStubAssembler::Label Label;
|
| typedef compiler::Node Node;
|
| typedef compiler::CodeStubAssembler::Variable Variable;
|
| @@ -717,23 +716,26 @@ void GenerateAbstractRelationalComparison(
|
| 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);
|
| + assembler->TailCallStub(
|
| + CodeFactory::StringLessThan(assembler->isolate()),
|
| + context, lhs, rhs);
|
| break;
|
| case kLessThanOrEqual:
|
| - assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual,
|
| - context, lhs, rhs);
|
| + assembler->TailCallStub(
|
| + CodeFactory::StringLessThanOrEqual(assembler->isolate()),
|
| + context, lhs, rhs);
|
| break;
|
| case kGreaterThan:
|
| - assembler->TailCallRuntime(Runtime::kStringGreaterThan,
|
| - context, lhs, rhs);
|
| + assembler->TailCallStub(
|
| + CodeFactory::StringGreaterThan(assembler->isolate()),
|
| + context, lhs, rhs);
|
| break;
|
| case kGreaterThanOrEqual:
|
| - assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
|
| - context, lhs, rhs);
|
| + assembler->TailCallStub(CodeFactory::StringGreaterThanOrEqual(
|
| + assembler->isolate()),
|
| + context, lhs, rhs);
|
| break;
|
| }
|
| }
|
| @@ -1134,6 +1136,189 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
|
| assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
|
| }
|
|
|
| +void GenerateStringRelationalComparison(compiler::CodeStubAssembler* assembler,
|
| + RelationalComparisonMode mode) {
|
| + typedef compiler::CodeStubAssembler::Label Label;
|
| + typedef compiler::Node Node;
|
| + typedef compiler::CodeStubAssembler::Variable Variable;
|
| +
|
| + Node* lhs = assembler->Parameter(0);
|
| + Node* rhs = assembler->Parameter(1);
|
| + Node* context = assembler->Parameter(2);
|
| +
|
| + Label if_less(assembler), if_equal(assembler), if_greater(assembler);
|
| +
|
| + // Fast check to see if {lhs} and {rhs} refer to the same String object.
|
| + Label if_same(assembler), if_notsame(assembler);
|
| + assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
|
| +
|
| + assembler->Bind(&if_same);
|
| + assembler->Goto(&if_equal);
|
| +
|
| + assembler->Bind(&if_notsame);
|
| + {
|
| + // Load instance types of {lhs} and {rhs}.
|
| + Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
|
| + Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
|
| +
|
| + // Combine the instance types into a single 16-bit value, so we can check
|
| + // both of them at once.
|
| + Node* both_instance_types = assembler->Word32Or(
|
| + lhs_instance_type,
|
| + assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
|
| +
|
| + // Check that both {lhs} and {rhs} are flat one-byte strings.
|
| + int const kBothSeqOneByteStringMask =
|
| + kStringEncodingMask | kStringRepresentationMask |
|
| + ((kStringEncodingMask | kStringRepresentationMask) << 8);
|
| + int const kBothSeqOneByteStringTag =
|
| + kOneByteStringTag | kSeqStringTag |
|
| + ((kOneByteStringTag | kSeqStringTag) << 8);
|
| + Label if_bothonebyteseqstrings(assembler),
|
| + if_notbothonebyteseqstrings(assembler);
|
| + assembler->Branch(assembler->Word32Equal(
|
| + assembler->Word32And(both_instance_types,
|
| + assembler->Int32Constant(
|
| + kBothSeqOneByteStringMask)),
|
| + assembler->Int32Constant(kBothSeqOneByteStringTag)),
|
| + &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
|
| +
|
| + assembler->Bind(&if_bothonebyteseqstrings);
|
| + {
|
| + // Load the length of {lhs} and {rhs}.
|
| + Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
|
| + Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
|
| +
|
| + // Determine the minimum length.
|
| + Node* length = assembler->SmiMin(lhs_length, rhs_length);
|
| +
|
| + // Compute the effective offset of the first character.
|
| + Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
|
| + kHeapObjectTag);
|
| +
|
| + // Compute the first offset after the string from the length.
|
| + Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
|
| +
|
| + // Loop over the {lhs} and {rhs} strings to see if they are equal.
|
| + Variable var_offset(assembler, MachineType::PointerRepresentation());
|
| + Label loop(assembler, &var_offset);
|
| + var_offset.Bind(begin);
|
| + assembler->Goto(&loop);
|
| + assembler->Bind(&loop);
|
| + {
|
| + // Check if {offset} equals {end}.
|
| + Node* offset = var_offset.value();
|
| + Label if_done(assembler), if_notdone(assembler);
|
| + assembler->Branch(assembler->WordEqual(offset, end), &if_done,
|
| + &if_notdone);
|
| +
|
| + assembler->Bind(&if_notdone);
|
| + {
|
| + // Load the next characters from {lhs} and {rhs}.
|
| + Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
|
| + Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
|
| +
|
| + // Check if the characters match.
|
| + Label if_valueissame(assembler), if_valueisnotsame(assembler);
|
| + assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
|
| + &if_valueissame, &if_valueisnotsame);
|
| +
|
| + assembler->Bind(&if_valueissame);
|
| + {
|
| + // Advance to next character.
|
| + var_offset.Bind(
|
| + assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
|
| + }
|
| + assembler->Goto(&loop);
|
| +
|
| + assembler->Bind(&if_valueisnotsame);
|
| + assembler->BranchIfInt32LessThan(lhs_value, rhs_value, &if_less,
|
| + &if_greater);
|
| + }
|
| +
|
| + assembler->Bind(&if_done);
|
| + {
|
| + // All characters up to the min length are equal, decide based on
|
| + // string length.
|
| + Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
|
| + assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
|
| + &if_lengthisequal, &if_lengthisnotequal);
|
| +
|
| + assembler->Bind(&if_lengthisequal);
|
| + assembler->Goto(&if_equal);
|
| +
|
| + assembler->Bind(&if_lengthisnotequal);
|
| + assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
|
| + &if_greater);
|
| + }
|
| + }
|
| + }
|
| +
|
| + assembler->Bind(&if_notbothonebyteseqstrings);
|
| + {
|
| + // TODO(bmeurer): Add fast case support for flattened cons strings;
|
| + // also add support for two byte string relational comparisons.
|
| + 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_less);
|
| + switch (mode) {
|
| + case kLessThan:
|
| + case kLessThanOrEqual:
|
| + assembler->Return(assembler->BooleanConstant(true));
|
| + break;
|
| +
|
| + case kGreaterThan:
|
| + case kGreaterThanOrEqual:
|
| + assembler->Return(assembler->BooleanConstant(false));
|
| + break;
|
| + }
|
| +
|
| + assembler->Bind(&if_equal);
|
| + switch (mode) {
|
| + case kLessThan:
|
| + case kGreaterThan:
|
| + assembler->Return(assembler->BooleanConstant(false));
|
| + break;
|
| +
|
| + case kLessThanOrEqual:
|
| + case kGreaterThanOrEqual:
|
| + assembler->Return(assembler->BooleanConstant(true));
|
| + break;
|
| + }
|
| +
|
| + assembler->Bind(&if_greater);
|
| + switch (mode) {
|
| + case kLessThan:
|
| + case kLessThanOrEqual:
|
| + assembler->Return(assembler->BooleanConstant(false));
|
| + break;
|
| +
|
| + case kGreaterThan:
|
| + case kGreaterThanOrEqual:
|
| + assembler->Return(assembler->BooleanConstant(true));
|
| + break;
|
| + }
|
| +}
|
| +
|
| void GenerateStringEqual(compiler::CodeStubAssembler* assembler,
|
| ResultMode mode) {
|
| // Here's pseudo-code for the algorithm below in case of kDontNegateResult
|
| @@ -1353,6 +1538,26 @@ void StringNotEqualStub::GenerateAssembly(
|
| GenerateStringEqual(assembler, kNegateResult);
|
| }
|
|
|
| +void StringLessThanStub::GenerateAssembly(
|
| + compiler::CodeStubAssembler* assembler) const {
|
| + GenerateStringRelationalComparison(assembler, kLessThan);
|
| +}
|
| +
|
| +void StringLessThanOrEqualStub::GenerateAssembly(
|
| + compiler::CodeStubAssembler* assembler) const {
|
| + GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
|
| +}
|
| +
|
| +void StringGreaterThanStub::GenerateAssembly(
|
| + compiler::CodeStubAssembler* assembler) const {
|
| + GenerateStringRelationalComparison(assembler, kGreaterThan);
|
| +}
|
| +
|
| +void StringGreaterThanOrEqualStub::GenerateAssembly(
|
| + compiler::CodeStubAssembler* assembler) const {
|
| + GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
|
| +}
|
| +
|
| void ToBooleanStub::GenerateAssembly(
|
| compiler::CodeStubAssembler* assembler) const {
|
| typedef compiler::Node Node;
|
|
|