diff options
| -rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 58 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 62 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 55 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 49 | ||||
| -rw-r--r-- | runtime/arch/mips/quick_entrypoints_mips.S | 181 | ||||
| -rw-r--r-- | runtime/arch/mips64/quick_entrypoints_mips64.S | 178 |
6 files changed, 468 insertions, 115 deletions
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 0677dad078..c9dde7cc55 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1914,6 +1914,8 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) { auto null_checker = GetImplicitNullChecker(instruction); Primitive::Type type = instruction->GetType(); + const bool maybe_compressed_char_at = mirror::kUseStringCompression && + instruction->IsStringCharAt(); switch (type) { case Primitive::kPrimBoolean: { Register out = locations->Out().AsRegister<Register>(); @@ -1957,14 +1959,54 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) { case Primitive::kPrimChar: { Register out = locations->Out().AsRegister<Register>(); + if (maybe_compressed_char_at) { + uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker); + __ Sll(TMP, TMP, 31); // Extract compression flag into the most significant bit of TMP. + static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, + "Expecting 0=compressed, 1=uncompressed"); + } if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset, null_checker); + int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue(); + if (maybe_compressed_char_at) { + MipsLabel uncompressed_load, done; + __ Bnez(TMP, &uncompressed_load); + __ LoadFromOffset(kLoadUnsignedByte, + out, + obj, + data_offset + (const_index << TIMES_1)); + __ B(&done); + __ Bind(&uncompressed_load); + __ LoadFromOffset(kLoadUnsignedHalfword, + out, + obj, + data_offset + (const_index << TIMES_2)); + __ Bind(&done); + } else { + __ LoadFromOffset(kLoadUnsignedHalfword, + out, + obj, + data_offset + (const_index << TIMES_2), + null_checker); + } } else { - __ Sll(TMP, index.AsRegister<Register>(), TIMES_2); - __ Addu(TMP, obj, TMP); - __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker); + Register index_reg = index.AsRegister<Register>(); + if (maybe_compressed_char_at) { + MipsLabel uncompressed_load, done; + __ Bnez(TMP, &uncompressed_load); + __ Addu(TMP, obj, index_reg); + __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset); + __ B(&done); + __ Bind(&uncompressed_load); + __ Sll(TMP, index_reg, TIMES_2); + __ Addu(TMP, obj, TMP); + __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset); + __ Bind(&done); + } else { + __ Sll(TMP, index_reg, TIMES_2); + __ Addu(TMP, obj, TMP); + __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker); + } } break; } @@ -2046,6 +2088,10 @@ void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) { Register out = locations->Out().AsRegister<Register>(); __ LoadFromOffset(kLoadWord, out, obj, offset); codegen_->MaybeRecordImplicitNullCheck(instruction); + // Mask out compression flag from String's array length. + if (mirror::kUseStringCompression && instruction->IsStringLength()) { + __ Srl(out, out, 1u); + } } Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) { diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 4c8dabfede..5be0da4011 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1490,6 +1490,8 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) { uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction); Primitive::Type type = instruction->GetType(); + const bool maybe_compressed_char_at = mirror::kUseStringCompression && + instruction->IsStringCharAt(); switch (type) { case Primitive::kPrimBoolean: { GpuRegister out = locations->Out().AsRegister<GpuRegister>(); @@ -1533,14 +1535,54 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) { case Primitive::kPrimChar: { GpuRegister out = locations->Out().AsRegister<GpuRegister>(); + if (maybe_compressed_char_at) { + uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + __ LoadFromOffset(kLoadWord, TMP, obj, count_offset); + codegen_->MaybeRecordImplicitNullCheck(instruction); + __ Dext(TMP, TMP, 0, 1); + static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, + "Expecting 0=compressed, 1=uncompressed"); + } if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); + int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue(); + if (maybe_compressed_char_at) { + Mips64Label uncompressed_load, done; + __ Bnezc(TMP, &uncompressed_load); + __ LoadFromOffset(kLoadUnsignedByte, + out, + obj, + data_offset + (const_index << TIMES_1)); + __ Bc(&done); + __ Bind(&uncompressed_load); + __ LoadFromOffset(kLoadUnsignedHalfword, + out, + obj, + data_offset + (const_index << TIMES_2)); + __ Bind(&done); + } else { + __ LoadFromOffset(kLoadUnsignedHalfword, + out, + obj, + data_offset + (const_index << TIMES_2)); + } } else { - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_2); - __ Daddu(TMP, obj, TMP); - __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset); + GpuRegister index_reg = index.AsRegister<GpuRegister>(); + if (maybe_compressed_char_at) { + Mips64Label uncompressed_load, done; + __ Bnezc(TMP, &uncompressed_load); + __ Daddu(TMP, obj, index_reg); + __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset); + __ Bc(&done); + __ Bind(&uncompressed_load); + __ Dsll(TMP, index_reg, TIMES_2); + __ Daddu(TMP, obj, TMP); + __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset); + __ Bind(&done); + } else { + __ Dsll(TMP, index_reg, TIMES_2); + __ Daddu(TMP, obj, TMP); + __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset); + } } break; } @@ -1608,7 +1650,9 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) { LOG(FATAL) << "Unreachable type " << instruction->GetType(); UNREACHABLE(); } - codegen_->MaybeRecordImplicitNullCheck(instruction); + if (!maybe_compressed_char_at) { + codegen_->MaybeRecordImplicitNullCheck(instruction); + } } void LocationsBuilderMIPS64::VisitArrayLength(HArrayLength* instruction) { @@ -1624,6 +1668,10 @@ void InstructionCodeGeneratorMIPS64::VisitArrayLength(HArrayLength* instruction) GpuRegister out = locations->Out().AsRegister<GpuRegister>(); __ LoadFromOffset(kLoadWord, out, obj, offset); codegen_->MaybeRecordImplicitNullCheck(instruction); + // Mask out compression flag from String's array length. + if (mirror::kUseStringCompression && instruction->IsStringLength()) { + __ Srl(out, out, 1u); + } } void LocationsBuilderMIPS64::VisitArraySet(HArraySet* instruction) { diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 6cf9b83d44..64a68403e9 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -2004,31 +2004,48 @@ void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) { __ Lw(temp2, arg, class_offset); __ Bne(temp1, temp2, &return_false); - // Load lengths of this and argument strings. + // Load `count` fields of this and argument strings. __ Lw(temp1, str, count_offset); __ Lw(temp2, arg, count_offset); - // Check if lengths are equal, return false if they're not. + // Check if `count` fields are equal, return false if they're not. + // Also compares the compression style, if differs return false. __ Bne(temp1, temp2, &return_false); - // Return true if both strings are empty. + // Return true if both strings are empty. Even with string compression `count == 0` means empty. + static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, + "Expecting 0=compressed, 1=uncompressed"); __ Beqz(temp1, &return_true); // Don't overwrite input registers __ Move(TMP, str); __ Move(temp3, arg); - // Assertions that must hold in order to compare strings 2 characters at a time. + // Assertions that must hold in order to compare strings 4 bytes at a time. DCHECK_ALIGNED(value_offset, 4); static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded"); - // Loop to compare strings 2 characters at a time starting at the beginning of the string. - // Ok to do this because strings are zero-padded. + // For string compression, calculate the number of bytes to compare (not chars). + if (mirror::kUseStringCompression) { + // Extract compression flag. + if (IsR2OrNewer()) { + __ Ext(temp2, temp1, 0, 1); + } else { + __ Sll(temp2, temp1, 31); + __ Srl(temp2, temp2, 31); + } + __ Srl(temp1, temp1, 1); // Extract length. + __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed. + } + + // Loop to compare strings 4 bytes at a time starting at the beginning of the string. + // Ok to do this because strings are zero-padded to kObjectAlignment. __ Bind(&loop); __ Lw(out, TMP, value_offset); __ Lw(temp2, temp3, value_offset); __ Bne(out, temp2, &return_false); __ Addiu(TMP, TMP, 4); __ Addiu(temp3, temp3, 4); - __ Addiu(temp1, temp1, -2); + // With string compression, we have compared 4 bytes, otherwise 2 chars. + __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -4 : -2); __ Bgtz(temp1, &loop); // Return true and exit the function. @@ -2578,6 +2595,30 @@ void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) { __ Addu(dstPtr, dstPtr, AT); } + if (mirror::kUseStringCompression) { + MipsLabel uncompressed_copy, compressed_loop; + const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + // Load count field and extract compression flag. + __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset); + __ Sll(TMP, TMP, 31); + + // If string is uncompressed, use memcpy() path. + __ Bnez(TMP, &uncompressed_copy); + + // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time. + __ Addu(srcPtr, srcObj, srcBegin); + __ Bind(&compressed_loop); + __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset); + __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0); + __ Addiu(numChrs, numChrs, -1); + __ Addiu(srcPtr, srcPtr, 1); + __ Addiu(dstPtr, dstPtr, 2); + __ Bnez(numChrs, &compressed_loop); + + __ B(&done); + __ Bind(&uncompressed_copy); + } + // Calculate source address. __ Addiu(srcPtr, srcObj, value_offset); if (IsR6()) { diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 00a1fa11bb..3888828722 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1607,31 +1607,42 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringEquals(HInvoke* invoke) { __ Lw(temp2, arg, class_offset); __ Bnec(temp1, temp2, &return_false); - // Load lengths of this and argument strings. + // Load `count` fields of this and argument strings. __ Lw(temp1, str, count_offset); __ Lw(temp2, arg, count_offset); - // Check if lengths are equal, return false if they're not. + // Check if `count` fields are equal, return false if they're not. + // Also compares the compression style, if differs return false. __ Bnec(temp1, temp2, &return_false); - // Return true if both strings are empty. + // Return true if both strings are empty. Even with string compression `count == 0` means empty. + static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, + "Expecting 0=compressed, 1=uncompressed"); __ Beqzc(temp1, &return_true); // Don't overwrite input registers __ Move(TMP, str); __ Move(temp3, arg); - // Assertions that must hold in order to compare strings 4 characters at a time. + // Assertions that must hold in order to compare strings 8 bytes at a time. DCHECK_ALIGNED(value_offset, 8); static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded"); - // Loop to compare strings 4 characters at a time starting at the beginning of the string. - // Ok to do this because strings are zero-padded to be 8-byte aligned. + if (mirror::kUseStringCompression) { + // For string compression, calculate the number of bytes to compare (not chars). + __ Dext(temp2, temp1, 0, 1); // Extract compression flag. + __ Srl(temp1, temp1, 1); // Extract length. + __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed. + } + + // Loop to compare strings 8 bytes at a time starting at the beginning of the string. + // Ok to do this because strings are zero-padded to kObjectAlignment. __ Bind(&loop); __ Ld(out, TMP, value_offset); __ Ld(temp2, temp3, value_offset); __ Bnec(out, temp2, &return_false); __ Daddiu(TMP, TMP, 8); __ Daddiu(temp3, temp3, 8); - __ Addiu(temp1, temp1, -4); + // With string compression, we have compared 8 bytes, otherwise 4 chars. + __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -8 : -4); __ Bgtzc(temp1, &loop); // Return true and exit the function. @@ -1912,6 +1923,30 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) { __ Daddiu(dstPtr, dstObj, data_offset); __ Dlsa(dstPtr, dstBegin, dstPtr, char_shift); + if (mirror::kUseStringCompression) { + Mips64Label uncompressed_copy, compressed_loop; + const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + // Load count field and extract compression flag. + __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset); + __ Dext(TMP, TMP, 0, 1); + + // If string is uncompressed, use memcpy() path. + __ Bnezc(TMP, &uncompressed_copy); + + // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time. + __ Daddu(srcPtr, srcObj, srcBegin); + __ Bind(&compressed_loop); + __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset); + __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0); + __ Daddiu(numChrs, numChrs, -1); + __ Daddiu(srcPtr, srcPtr, 1); + __ Daddiu(dstPtr, dstPtr, 2); + __ Bnezc(numChrs, &compressed_loop); + + __ Bc(&done); + __ Bind(&uncompressed_copy); + } + // Calculate source address. __ Daddiu(srcPtr, srcObj, value_offset); __ Dlsa(srcPtr, srcBegin, srcPtr, char_shift); diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 10b690ac4a..ec8ae85722 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -2042,67 +2042,158 @@ ENTRY_NO_GP art_quick_indexof /* $a0 holds address of "this" */ /* $a1 holds "ch" */ /* $a2 holds "fromIndex" */ - lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() - slt $t1, $a2, $zero # if fromIndex < 0 +#if (STRING_COMPRESSION_FEATURE) + lw $a3, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this +#else + lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() +#endif + slt $t1, $a2, $zero # if fromIndex < 0 #if defined(_MIPS_ARCH_MIPS32R6) || defined(_MIPS_ARCH_MIPS64R6) - seleqz $a2, $a2, $t1 # fromIndex = 0; + seleqz $a2, $a2, $t1 # fromIndex = 0; #else - movn $a2, $zero, $t1 # fromIndex = 0; + movn $a2, $zero, $t1 # fromIndex = 0; #endif - subu $t0, $t0, $a2 # this.length() - fromIndex - blez $t0, 6f # if this.length()-fromIndex <= 0 - li $v0, -1 # return -1; - - sll $v0, $a2, 1 # $a0 += $a2 * 2 - addu $a0, $a0, $v0 # " ditto " - move $v0, $a2 # Set i to fromIndex. +#if (STRING_COMPRESSION_FEATURE) + srl $t0, $a3, 1 # $a3 holds count (with flag) and $t0 holds actual length +#endif + subu $t0, $t0, $a2 # this.length() - fromIndex + blez $t0, 6f # if this.length()-fromIndex <= 0 + li $v0, -1 # return -1; + +#if (STRING_COMPRESSION_FEATURE) + sll $a3, $a3, 31 # Extract compression flag. + beqz $a3, .Lstring_indexof_compressed + move $t2, $a0 # Save a copy in $t2 to later compute result (in branch delay slot). +#endif + sll $v0, $a2, 1 # $a0 += $a2 * 2 + addu $a0, $a0, $v0 # " ditto " + move $v0, $a2 # Set i to fromIndex. 1: - lhu $t3, MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch - beq $t3, $a1, 6f # return i; - addu $a0, $a0, 2 # i++ - subu $t0, $t0, 1 # this.length() - i - bnez $t0, 1b # while this.length() - i > 0 - addu $v0, $v0, 1 # i++ + lhu $t3, MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch + beq $t3, $a1, 6f # return i; + addu $a0, $a0, 2 # i++ + subu $t0, $t0, 1 # this.length() - i + bnez $t0, 1b # while this.length() - i > 0 + addu $v0, $v0, 1 # i++ - li $v0, -1 # if this.length() - i <= 0 - # return -1; + li $v0, -1 # if this.length() - i <= 0 + # return -1; 6: - j $ra - nop + j $ra + nop + +#if (STRING_COMPRESSION_FEATURE) +.Lstring_indexof_compressed: + addu $a0, $a0, $a2 # $a0 += $a2 + +.Lstring_indexof_compressed_loop: + lbu $t3, MIRROR_STRING_VALUE_OFFSET($a0) + beq $t3, $a1, .Lstring_indexof_compressed_matched + subu $t0, $t0, 1 + bgtz $t0, .Lstring_indexof_compressed_loop + addu $a0, $a0, 1 + +.Lstring_indexof_nomatch: + jalr $zero, $ra + li $v0, -1 # return -1; + +.Lstring_indexof_compressed_matched: + jalr $zero, $ra + subu $v0, $a0, $t2 # return (current - start); +#endif END art_quick_indexof /* java.lang.String.compareTo(String anotherString) */ ENTRY_NO_GP art_quick_string_compareto /* $a0 holds address of "this" */ /* $a1 holds address of "anotherString" */ - beq $a0, $a1, 9f # this and anotherString are the same object - move $v0, $zero + beq $a0, $a1, .Lstring_compareto_length_diff # this and anotherString are the same object + move $a3, $a2 # trick to return 0 (it returns a2 - a3) + +#if (STRING_COMPRESSION_FEATURE) + lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this + lw $t1, MIRROR_STRING_COUNT_OFFSET($a1) # 'count' field of anotherString + sra $a2, $t0, 1 # this.length() + sra $a3, $t1, 1 # anotherString.length() +#else + lw $a2, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() + lw $a3, MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length() +#endif - lw $a2, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() - lw $a3, MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length() - MINu $t2, $a2, $a3 -# $t2 now holds min(this.length(),anotherString.length()) + MINu $t2, $a2, $a3 + # $t2 now holds min(this.length(),anotherString.length()) - beqz $t2, 9f # while min(this.length(),anotherString.length())-i != 0 - subu $v0, $a2, $a3 # if $t2==0 return - # (this.length() - anotherString.length()) -1: - lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i) - lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1) - bne $t0, $t1, 9f # if this.charAt(i) != anotherString.charAt(i) - subu $v0, $t0, $t1 # return (this.charAt(i) - anotherString.charAt(i)) - addiu $a0, $a0, 2 # point at this.charAt(i++) - subu $t2, $t2, 1 # new value of - # min(this.length(),anotherString.length())-i - bnez $t2, 1b - addiu $a1, $a1, 2 # point at anotherString.charAt(i++) - subu $v0, $a2, $a3 - -9: - j $ra - nop + # while min(this.length(),anotherString.length())-i != 0 + beqz $t2, .Lstring_compareto_length_diff # if $t2==0 + nop # return (this.length() - anotherString.length()) + +#if (STRING_COMPRESSION_FEATURE) + # Differ cases: + sll $t3, $t0, 31 + beqz $t3, .Lstring_compareto_this_is_compressed + sll $t3, $t1, 31 # In branch delay slot. + beqz $t3, .Lstring_compareto_that_is_compressed + nop + b .Lstring_compareto_both_not_compressed + nop + +.Lstring_compareto_this_is_compressed: + beqz $t3, .Lstring_compareto_both_compressed + nop + /* If (this->IsCompressed() && that->IsCompressed() == false) */ +.Lstring_compareto_loop_comparison_this_compressed: + lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bne $t0, $t1, .Lstring_compareto_char_diff + addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_loop_comparison_this_compressed + addiu $a1, $a1, 2 # point at anotherString.charAt(i++) - uncompressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_that_is_compressed: + lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bne $t0, $t1, .Lstring_compareto_char_diff + addiu $a0, $a0, 2 # point at this.charAt(i++) - uncompressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_that_is_compressed + addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_both_compressed: + lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bne $t0, $t1, .Lstring_compareto_char_diff + addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_both_compressed + addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) +#endif + +.Lstring_compareto_both_not_compressed: + lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i) + lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bne $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i) + # return (this.charAt(i) - anotherString.charAt(i)) + addiu $a0, $a0, 2 # point at this.charAt(i++) + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_both_not_compressed + addiu $a1, $a1, 2 # point at anotherString.charAt(i++) + +.Lstring_compareto_length_diff: + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_char_diff: + jalr $zero, $ra + subu $v0, $t0, $t1 # return (this.charAt(i) - anotherString.charAt(i)) END art_quick_string_compareto .extern artInvokePolymorphic diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S index fff6d256b1..28d7c77938 100644 --- a/runtime/arch/mips64/quick_entrypoints_mips64.S +++ b/runtime/arch/mips64/quick_entrypoints_mips64.S @@ -1900,32 +1900,91 @@ END art_quick_deoptimize_from_compiled_code ENTRY_NO_GP art_quick_string_compareto /* $a0 holds address of "this" */ /* $a1 holds address of "anotherString" */ - beq $a0,$a1,9f # this and anotherString are the same object - move $v0,$zero + move $a2, $zero + beq $a0, $a1, .Lstring_compareto_length_diff # this and anotherString are the same object + move $a3, $zero # return 0 (it returns a2 - a3) + +#if (STRING_COMPRESSION_FEATURE) + lw $a4, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this + lw $a5, MIRROR_STRING_COUNT_OFFSET($a1) # 'count' field of anotherString + sra $a2, $a4, 1 # this.length() + sra $a3, $a5, 1 # anotherString.length() +#else + lw $a2, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() + lw $a3, MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length() +#endif - lw $a2,MIRROR_STRING_COUNT_OFFSET($a0) # this.length() - lw $a3,MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length() - MINu $t2, $a2, $a3 -# $t2 now holds min(this.length(),anotherString.length()) + MINu $t2, $a2, $a3 + # $t2 now holds min(this.length(),anotherString.length()) - beqz $t2,9f # while min(this.length(),anotherString.length())-i != 0 - subu $v0,$a2,$a3 # if $t2==0 return - # (this.length() - anotherString.length()) -1: - lhu $t0,MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i) - lhu $t1,MIRROR_STRING_VALUE_OFFSET($a1) - bne $t0,$t1,9f # if this.charAt(i) != anotherString.charAt(i) - subu $v0,$t0,$t1 # return (this.charAt(i) - anotherString.charAt(i)) - daddiu $a0,$a0,2 # point at this.charAt(i++) - subu $t2,$t2,1 # new value of - # min(this.length(),anotherString.length())-i - bnez $t2,1b - daddiu $a1,$a1,2 # point at anotherString.charAt(i++) - subu $v0,$a2,$a3 - -9: - j $ra - nop + # while min(this.length(),anotherString.length())-i != 0 + beqzc $t2, .Lstring_compareto_length_diff # if $t2==0 + # return (this.length() - anotherString.length()) + +#if (STRING_COMPRESSION_FEATURE) + # Differ cases: + dext $a6, $a4, 0, 1 + beqz $a6, .Lstring_compareto_this_is_compressed + dext $a6, $a5, 0, 1 # In branch delay slot. + beqz $a6, .Lstring_compareto_that_is_compressed + nop + b .Lstring_compareto_both_not_compressed + nop + +.Lstring_compareto_this_is_compressed: + beqzc $a6, .Lstring_compareto_both_compressed + /* If (this->IsCompressed() && that->IsCompressed() == false) */ +.Lstring_compareto_loop_comparison_this_compressed: + lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bnec $t0, $t1, .Lstring_compareto_char_diff + daddiu $a0, $a0, 1 # point at this.charAt(i++) - compressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_loop_comparison_this_compressed + daddiu $a1, $a1, 2 # point at anotherString.charAt(i++) - uncompressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_that_is_compressed: + lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bnec $t0, $t1, .Lstring_compareto_char_diff + daddiu $a0, $a0, 2 # point at this.charAt(i++) - uncompressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_that_is_compressed + daddiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_both_compressed: + lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0) + lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bnec $t0, $t1, .Lstring_compareto_char_diff + daddiu $a0, $a0, 1 # point at this.charAt(i++) - compressed + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_both_compressed + daddiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) +#endif + +.Lstring_compareto_both_not_compressed: + lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i) + lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1) + bnec $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i) + # return (this.charAt(i) - anotherString.charAt(i)) + daddiu $a0, $a0, 2 # point at this.charAt(i++) + subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i + bnez $t2, .Lstring_compareto_both_not_compressed + daddiu $a1, $a1, 2 # point at anotherString.charAt(i++) + +.Lstring_compareto_length_diff: + jalr $zero, $ra + subu $v0, $a2, $a3 # return (this.length() - anotherString.length()) + +.Lstring_compareto_char_diff: + jalr $zero, $ra + subu $v0, $t0, $t1 # return (this.charAt(i) - anotherString.charAt(i)) END art_quick_string_compareto /* java.lang.String.indexOf(int ch, int fromIndex=0) */ @@ -1933,31 +1992,64 @@ ENTRY_NO_GP art_quick_indexof /* $a0 holds address of "this" */ /* $a1 holds "ch" */ /* $a2 holds "fromIndex" */ - lw $t0,MIRROR_STRING_COUNT_OFFSET($a0) # this.length() - slt $at, $a2, $zero # if fromIndex < 0 - seleqz $a2, $a2, $at # fromIndex = 0; - subu $t0,$t0,$a2 # this.length() - fromIndex - blez $t0,6f # if this.length()-fromIndex <= 0 - li $v0,-1 # return -1; +#if (STRING_COMPRESSION_FEATURE) + lw $a3, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this +#else + lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # this.length() +#endif + slt $at, $a2, $zero # if fromIndex < 0 + seleqz $a2, $a2, $at # fromIndex = 0; +#if (STRING_COMPRESSION_FEATURE) + srl $t0, $a3, 1 # $a3 holds count (with flag) and $t0 holds actual length +#endif + subu $t0, $t0, $a2 # this.length() - fromIndex + blez $t0, 6f # if this.length()-fromIndex <= 0 + li $v0, -1 # return -1; - sll $v0,$a2,1 # $a0 += $a2 * 2 - daddu $a0,$a0,$v0 # " ditto " - move $v0,$a2 # Set i to fromIndex. +#if (STRING_COMPRESSION_FEATURE) + dext $a3, $a3, 0, 1 # Extract compression flag. + beqzc $a3, .Lstring_indexof_compressed +#endif + + sll $v0, $a2, 1 # $a0 += $a2 * 2 + daddu $a0, $a0, $v0 # " ditto " + move $v0, $a2 # Set i to fromIndex. 1: - lhu $t3,MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch - beq $t3,$a1,6f # return i; - daddu $a0,$a0,2 # i++ - subu $t0,$t0,1 # this.length() - i - bnez $t0,1b # while this.length() - i > 0 - addu $v0,$v0,1 # i++ + lhu $t3, MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch + beq $t3, $a1, 6f # return i; + daddu $a0, $a0, 2 # i++ + subu $t0, $t0, 1 # this.length() - i + bnez $t0, 1b # while this.length() - i > 0 + addu $v0, $v0, 1 # i++ - li $v0,-1 # if this.length() - i <= 0 - # return -1; + li $v0, -1 # if this.length() - i <= 0 + # return -1; 6: - j $ra - nop + j $ra + nop + +#if (STRING_COMPRESSION_FEATURE) +.Lstring_indexof_compressed: + move $a4, $a0 # Save a copy in $a4 to later compute result. + daddu $a0, $a0, $a2 # $a0 += $a2 + +.Lstring_indexof_compressed_loop: + lbu $t3, MIRROR_STRING_VALUE_OFFSET($a0) + beq $t3, $a1, .Lstring_indexof_compressed_matched + subu $t0, $t0, 1 + bgtz $t0, .Lstring_indexof_compressed_loop + daddu $a0, $a0, 1 + +.Lstring_indexof_nomatch: + jalr $zero, $ra + li $v0, -1 # return -1; + +.Lstring_indexof_compressed_matched: + jalr $zero, $ra + dsubu $v0, $a0, $a4 # return (current - start); +#endif END art_quick_indexof .extern artInvokePolymorphic |