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. |