From 25abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6b Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Tue, 19 Jan 2016 23:39:24 +0800 Subject: [PATCH] Optimizing: Add ARM and ARM64 intrinsics support for StringGetCharsNoCheck This change refers to x86 implementation of StringGetCharsNoCheck and arm implementation of SystemArrayCopy. Change-Id: I1cb86854a2a8fa8736af7726b8efacd00d416f6f --- compiler/optimizing/intrinsics_arm.cc | 64 ++++++++++++++++++++++++++++++++- compiler/optimizing/intrinsics_arm64.cc | 64 ++++++++++++++++++++++++++++++++- test/020-string/expected.txt | 6 ++++ test/020-string/src/Main.java | 45 +++++++++++++++++++++++ 4 files changed, 177 insertions(+), 2 deletions(-) diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 8cbdcbbca..8e22f8677 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1909,6 +1909,69 @@ void IntrinsicCodeGeneratorARM::VisitShortReverseBytes(HInvoke* invoke) { __ revsh(out, in); } +void IntrinsicLocationsBuilderARM::VisitStringGetCharsNoCheck(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(3, Location::RequiresRegister()); + locations->SetInAt(4, Location::RequiresRegister()); + + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM::VisitStringGetCharsNoCheck(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + // Check assumption that sizeof(Char) is 2 (used in scaling below). + const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar); + DCHECK_EQ(char_size, 2u); + + // Location of data in char array buffer. + const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value(); + + // Location of char array data in string. + const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); + + // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin); + // Since getChars() calls getCharsNoCheck() - we use registers rather than constants. + Register srcObj = locations->InAt(0).AsRegister(); + Register srcBegin = locations->InAt(1).AsRegister(); + Register srcEnd = locations->InAt(2).AsRegister(); + Register dstObj = locations->InAt(3).AsRegister(); + Register dstBegin = locations->InAt(4).AsRegister(); + + Register src_ptr = locations->GetTemp(0).AsRegister(); + Register src_ptr_end = locations->GetTemp(1).AsRegister(); + Register dst_ptr = locations->GetTemp(2).AsRegister(); + Register tmp = locations->GetTemp(3).AsRegister(); + + // src range to copy. + __ add(src_ptr, srcObj, ShifterOperand(value_offset)); + __ add(src_ptr_end, src_ptr, ShifterOperand(srcEnd, LSL, 1)); + __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1)); + + // dst to be copied. + __ add(dst_ptr, dstObj, ShifterOperand(data_offset)); + __ add(dst_ptr, dst_ptr, ShifterOperand(dstBegin, LSL, 1)); + + // Do the copy. + Label loop, done; + __ Bind(&loop); + __ cmp(src_ptr, ShifterOperand(src_ptr_end)); + __ b(&done, EQ); + __ ldrh(tmp, Address(src_ptr, char_size, Address::PostIndex)); + __ strh(tmp, Address(dst_ptr, char_size, Address::PostIndex)); + __ b(&loop); + __ Bind(&done); +} + // Unimplemented intrinsics. #define UNIMPLEMENTED_INTRINSIC(Name) \ @@ -1933,7 +1996,6 @@ UNIMPLEMENTED_INTRINSIC(MathRoundFloat) // Could be done by changing rounding UNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) -UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index b5f15fe22..19ccb3d56 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1602,6 +1602,69 @@ void IntrinsicCodeGeneratorARM64::VisitMathNextAfter(HInvoke* invoke) { GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickNextAfter); } +void IntrinsicLocationsBuilderARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(3, Location::RequiresRegister()); + locations->SetInAt(4, Location::RequiresRegister()); + + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) { + vixl::MacroAssembler* masm = GetVIXLAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + // Check assumption that sizeof(Char) is 2 (used in scaling below). + const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar); + DCHECK_EQ(char_size, 2u); + + // Location of data in char array buffer. + const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value(); + + // Location of char array data in string. + const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); + + // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin); + // Since getChars() calls getCharsNoCheck() - we use registers rather than constants. + Register srcObj = XRegisterFrom(locations->InAt(0)); + Register srcBegin = XRegisterFrom(locations->InAt(1)); + Register srcEnd = XRegisterFrom(locations->InAt(2)); + Register dstObj = XRegisterFrom(locations->InAt(3)); + Register dstBegin = XRegisterFrom(locations->InAt(4)); + + Register src_ptr = XRegisterFrom(locations->GetTemp(0)); + Register src_ptr_end = XRegisterFrom(locations->GetTemp(1)); + + UseScratchRegisterScope temps(masm); + Register dst_ptr = temps.AcquireX(); + Register tmp = temps.AcquireW(); + + // src range to copy. + __ Add(src_ptr, srcObj, Operand(value_offset)); + __ Add(src_ptr_end, src_ptr, Operand(srcEnd, LSL, 1)); + __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1)); + + // dst to be copied. + __ Add(dst_ptr, dstObj, Operand(data_offset)); + __ Add(dst_ptr, dst_ptr, Operand(dstBegin, LSL, 1)); + + // Do the copy. + vixl::Label loop, done; + __ Bind(&loop); + __ Cmp(src_ptr, src_ptr_end); + __ B(&done, eq); + __ Ldrh(tmp, MemOperand(src_ptr, char_size, vixl::PostIndex)); + __ Strh(tmp, MemOperand(dst_ptr, char_size, vixl::PostIndex)); + __ B(&loop); + __ Bind(&done); +} + // Unimplemented intrinsics. #define UNIMPLEMENTED_INTRINSIC(Name) \ @@ -1615,7 +1678,6 @@ UNIMPLEMENTED_INTRINSIC(LongBitCount) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) -UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) diff --git a/test/020-string/expected.txt b/test/020-string/expected.txt index 081fea3a4..76b8929bd 100644 --- a/test/020-string/expected.txt +++ b/test/020-string/expected.txt @@ -5,3 +5,9 @@ Compare unicode: -65302 Got expected exception subStr is 'uick brown fox jumps over the lazy ' Indexes are: 0:-1:0:43:33:-1:18:13:13:-1:18:18:-1:13:-1:-1:-1 +Got expected exception +Got expected exception +Got expected exception +Got expected exception +Got expected exception +llo And diff --git a/test/020-string/src/Main.java b/test/020-string/src/Main.java index b876e6ad2..710808255 100644 --- a/test/020-string/src/Main.java +++ b/test/020-string/src/Main.java @@ -25,6 +25,7 @@ public class Main { basicTest(); indexTest(); constructorTest(); + copyTest(); } public static void basicTest() { @@ -117,4 +118,48 @@ public class Main { String s14 = new String(codePoints, 1, 3); String s15 = new String(stringBuilder); } + + public static void copyTest() { + String src = new String("Hello Android"); + char[] dst = new char[7]; + char[] tmp = null; + + try { + src.getChars(2, 9, tmp, 0); + System.out.println("GLITCH: expected exception"); + } catch (NullPointerException npe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(-1, 9, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 19, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 1, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 10, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (ArrayIndexOutOfBoundsException aioobe) { + System.out.println("Got expected exception"); + } + + src.getChars(2, 9, dst, 0); + System.out.println(new String(dst)); + } } -- 2.11.0