diff options
| author | 2015-08-14 23:49:45 +0000 | |
|---|---|---|
| committer | 2015-08-14 23:49:45 +0000 | |
| commit | 63fdedf3c46a42c77713b5cc5abce47defaf5550 (patch) | |
| tree | 63457fff11e3fc28348c57fe4a249d6f67d61a0f /compiler | |
| parent | b31de31c4559c8434aa37701ef2f9e0ba3d2ad44 (diff) | |
| parent | f8cfb20cfa00f8987227204211e99486bc38572f (diff) | |
Merge "Optimizing String.Equals as an intrinsic (x86_64)"
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 92 |
1 files changed, 91 insertions, 1 deletions
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index b4926c2afa..9ea68ec07d 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -854,6 +854,97 @@ void IntrinsicCodeGeneratorX86_64::VisitStringCompareTo(HInvoke* invoke) { __ Bind(slow_path->GetExitLabel()); } +void IntrinsicLocationsBuilderX86_64::VisitStringEquals(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + + // Request temporary registers, RCX and RDI needed for repe_cmpsq instruction. + locations->AddTemp(Location::RegisterLocation(RCX)); + locations->AddTemp(Location::RegisterLocation(RDI)); + + // Set output, RSI needed for repe_cmpsq instruction anyways. + locations->SetOut(Location::RegisterLocation(RSI), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorX86_64::VisitStringEquals(HInvoke* invoke) { + X86_64Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + CpuRegister str = locations->InAt(0).AsRegister<CpuRegister>(); + CpuRegister arg = locations->InAt(1).AsRegister<CpuRegister>(); + CpuRegister rcx = locations->GetTemp(0).AsRegister<CpuRegister>(); + CpuRegister rdi = locations->GetTemp(1).AsRegister<CpuRegister>(); + CpuRegister rsi = locations->Out().AsRegister<CpuRegister>(); + + Label end; + Label return_true; + Label return_false; + + // Get offsets of count, value, and class fields within a string object. + const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); + const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value(); + + // Note that the null check must have been done earlier. + DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); + + // Check if input is null, return false if it is. + __ testl(arg, arg); + __ j(kEqual, &return_false); + + // Instanceof check for the argument by comparing class fields. + // All string objects must have the same type since String cannot be subclassed. + // Receiver must be a string object, so its class field is equal to all strings' class fields. + // If the argument is a string object, its class field must be equal to receiver's class field. + __ movl(rcx, Address(str, class_offset)); + __ cmpl(rcx, Address(arg, class_offset)); + __ j(kNotEqual, &return_false); + + // Reference equality check, return true if same reference. + __ cmpl(str, arg); + __ j(kEqual, &return_true); + + // Load length of receiver string. + __ movl(rcx, Address(str, count_offset)); + // Check if lengths are equal, return false if they're not. + __ cmpl(rcx, Address(arg, count_offset)); + __ j(kNotEqual, &return_false); + // Return true if both strings are empty. + __ testl(rcx, rcx); + __ j(kEqual, &return_true); + + // Load starting addresses of string values into RSI/RDI as required for repe_cmpsq instruction. + __ leal(rsi, Address(str, value_offset)); + __ leal(rdi, Address(arg, value_offset)); + + // Divide string length by 4 and adjust for lengths not divisible by 4. + __ addl(rcx, Immediate(3)); + __ shrl(rcx, Immediate(2)); + + // Assertions that must hold in order to compare strings 4 characters at a time. + DCHECK_ALIGNED(value_offset, 8); + static_assert(IsAligned<8>(kObjectAlignment), "String is not zero padded"); + + // Loop to compare strings four characters at a time starting at the beginning of the string. + __ repe_cmpsq(); + // If strings are not equal, zero flag will be cleared. + __ j(kNotEqual, &return_false); + + // Return true and exit the function. + // If loop does not result in returning false, we return true. + __ Bind(&return_true); + __ movl(rsi, Immediate(1)); + __ jmp(&end); + + // Return false and exit the function. + __ Bind(&return_false); + __ xorl(rsi, rsi); + __ Bind(&end); +} + static void CreateStringIndexOfLocations(HInvoke* invoke, ArenaAllocator* allocator, bool start_at_zero) { @@ -1607,7 +1698,6 @@ UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros) UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros) -UNIMPLEMENTED_INTRINSIC(StringEquals) #undef UNIMPLEMENTED_INTRINSIC |