| Index: runtime/vm/intrinsifier_x64.cc
|
| diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
|
| index 93e8521e28f207e5f82bb9af66c109eef1090f95..e3f2ca4d59b8c8608cd31aca435d573fb39a1de2 100644
|
| --- a/runtime/vm/intrinsifier_x64.cc
|
| +++ b/runtime/vm/intrinsifier_x64.cc
|
| @@ -1595,6 +1595,115 @@ void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) {
|
| }
|
|
|
|
|
| +void GenerateSubstringMatchesSpecialization(Assembler* assembler,
|
| + intptr_t receiver_cid,
|
| + intptr_t other_cid,
|
| + Label* return_true,
|
| + Label* return_false) {
|
| + __ movq(R8, FieldAddress(RAX, String::length_offset()));
|
| + __ movq(R9, FieldAddress(RCX, String::length_offset()));
|
| +
|
| + // if (other.length == 0) return true;
|
| + __ testq(R9, R9);
|
| + __ j(ZERO, return_true);
|
| +
|
| + // if (start < 0) return false;
|
| + __ testq(RBX, RBX);
|
| + __ j(SIGN, return_false);
|
| +
|
| + // if (start + other.length > this.length) return false;
|
| + __ movq(R11, RBX);
|
| + __ addq(R11, R9);
|
| + __ cmpq(R11, R8);
|
| + __ j(GREATER, return_false);
|
| +
|
| + __ SmiUntag(RBX); // start
|
| + __ SmiUntag(R9); // other.length
|
| + __ movq(R11, Immediate(0)); // i = 0
|
| +
|
| + // do
|
| + Label loop;
|
| + __ Bind(&loop);
|
| +
|
| + // this.codeUnitAt(i + start)
|
| + // clobbering this.length
|
| + __ movq(R8, R11);
|
| + __ addq(R8, RBX);
|
| + if (receiver_cid == kOneByteStringCid) {
|
| + __ movzxb(R12,
|
| + FieldAddress(RAX, R8, TIMES_1, OneByteString::data_offset()));
|
| + } else {
|
| + ASSERT(receiver_cid == kTwoByteStringCid);
|
| + __ movzxw(R12,
|
| + FieldAddress(RAX, R8, TIMES_2, TwoByteString::data_offset()));
|
| + }
|
| + // other.codeUnitAt(i)
|
| + if (other_cid == kOneByteStringCid) {
|
| + __ movzxb(R13,
|
| + FieldAddress(RCX, R11, TIMES_1, OneByteString::data_offset()));
|
| + } else {
|
| + ASSERT(other_cid == kTwoByteStringCid);
|
| + __ movzxw(R13,
|
| + FieldAddress(RCX, R11, TIMES_2, TwoByteString::data_offset()));
|
| + }
|
| + __ cmpq(R12, R13);
|
| + __ j(NOT_EQUAL, return_false);
|
| +
|
| + // i++, while (i < len)
|
| + __ addq(R11, Immediate(1));
|
| + __ cmpq(R11, R9);
|
| + __ j(LESS, &loop, Assembler::kNearJump);
|
| +
|
| + __ jmp(return_true);
|
| +}
|
| +
|
| +
|
| +// bool _substringMatches(int start, String other)
|
| +// This intrinsic handles a OneByteString or TwoByteString receiver with a
|
| +// OneByteString other.
|
| +void Intrinsifier::StringBaseSubstringMatches(Assembler* assembler) {
|
| + Label fall_through, return_true, return_false, try_two_byte;
|
| + __ movq(RAX, Address(RSP, + 3 * kWordSize)); // receiver
|
| + __ movq(RBX, Address(RSP, + 2 * kWordSize)); // start
|
| + __ movq(RCX, Address(RSP, + 1 * kWordSize)); // other
|
| +
|
| + __ testq(RBX, Immediate(kSmiTagMask));
|
| + __ j(NOT_ZERO, &fall_through); // 'start' is not Smi.
|
| +
|
| + __ CompareClassId(RCX, kOneByteStringCid);
|
| + __ j(NOT_EQUAL, &fall_through);
|
| +
|
| + __ CompareClassId(RAX, kOneByteStringCid);
|
| + __ j(NOT_EQUAL, &try_two_byte);
|
| +
|
| + GenerateSubstringMatchesSpecialization(assembler,
|
| + kOneByteStringCid,
|
| + kOneByteStringCid,
|
| + &return_true,
|
| + &return_false);
|
| +
|
| + __ Bind(&try_two_byte);
|
| + __ CompareClassId(RAX, kTwoByteStringCid);
|
| + __ j(NOT_EQUAL, &fall_through);
|
| +
|
| + GenerateSubstringMatchesSpecialization(assembler,
|
| + kTwoByteStringCid,
|
| + kOneByteStringCid,
|
| + &return_true,
|
| + &return_false);
|
| +
|
| + __ Bind(&return_true);
|
| + __ LoadObject(RAX, Bool::True());
|
| + __ ret();
|
| +
|
| + __ Bind(&return_false);
|
| + __ LoadObject(RAX, Bool::False());
|
| + __ ret();
|
| +
|
| + __ Bind(&fall_through);
|
| +}
|
| +
|
| +
|
| void Intrinsifier::StringBaseCharAt(Assembler* assembler) {
|
| Label fall_through, try_two_byte_string;
|
| __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index.
|
|
|