From 216564af58810a379ee2dcfaaca13f38867807b2 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Thu, 15 Dec 2011 13:38:46 +0000 Subject: [PATCH] MIPS: Porting r10221 to ARM (avoid bailing out to runtime for short substrings). Port r10250 (77889cc). BUG= TEST= Review URL: http://codereview.chromium.org/8953013 Patch from Daniel Kalmar . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10264 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mips/code-stubs-mips.cc | 335 ++++++++++++++++++-------------------------- 1 file changed, 140 insertions(+), 195 deletions(-) diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 47f24a0..693b1ae 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -5972,7 +5972,7 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, void SubStringStub::Generate(MacroAssembler* masm) { - Label sub_string_runtime; + Label runtime; // Stack frame on entry. // ra: return address // sp[0]: to @@ -5990,53 +5990,35 @@ void SubStringStub::Generate(MacroAssembler* masm) { static const int kFromOffset = 1 * kPointerSize; static const int kStringOffset = 2 * kPointerSize; - Register to = t2; - Register from = t3; - - // Check bounds and smi-ness. - __ lw(to, MemOperand(sp, kToOffset)); - __ lw(from, MemOperand(sp, kFromOffset)); + __ lw(a2, MemOperand(sp, kToOffset)); + __ lw(a3, MemOperand(sp, kFromOffset)); STATIC_ASSERT(kFromOffset == kToOffset + 4); STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - __ JumpIfNotSmi(from, &sub_string_runtime); - __ JumpIfNotSmi(to, &sub_string_runtime); + // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is + // safe in this case. + __ JumpIfSmi(a2, &runtime, at, USE_DELAY_SLOT); + __ SmiUntag(a2); + __ JumpIfSmi(a3, &runtime, at, USE_DELAY_SLOT); + __ SmiUntag(a3); - __ sra(a3, from, kSmiTagSize); // Remove smi tag. - __ sra(t5, to, kSmiTagSize); // Remove smi tag. + // Both a2 and a3 are untagged integers. - // a3: from index (untagged smi) - // t5: to index (untagged smi) - - __ Branch(&sub_string_runtime, lt, a3, Operand(zero_reg)); // From < 0. + __ Branch(&runtime, lt, a3, Operand(zero_reg)); // From < 0. __ subu(a2, t5, a3); - __ Branch(&sub_string_runtime, gt, a3, Operand(t5)); // Fail if from > to. - - // Special handling of sub-strings of length 1 and 2. One character strings - // are handled in the runtime system (looked up in the single character - // cache). Two character strings are looked for in the symbol cache in - // generated code. - __ Branch(&sub_string_runtime, lt, a2, Operand(2)); - - // Both to and from are smis. - - // a2: result string length - // a3: from index (untagged smi) - // t2: (a.k.a. to): to (smi) - // t3: (a.k.a. from): from offset (smi) - // t5: to index (untagged smi) + __ Branch(&runtime, gt, a3, Operand(t5)); // Fail if from > to. - // Make sure first argument is a sequential (or flat) string. + // Make sure first argument is a string. __ lw(v0, MemOperand(sp, kStringOffset)); - __ Branch(&sub_string_runtime, eq, v0, Operand(kSmiTagMask)); + __ Branch(&runtime, eq, v0, Operand(kSmiTagMask)); __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); __ And(t4, v0, Operand(kIsNotStringMask)); - __ Branch(&sub_string_runtime, ne, t4, Operand(zero_reg)); + __ Branch(&runtime, ne, t4, Operand(zero_reg)); // Short-cut for the case of trivial substring. Label return_v0; @@ -6046,74 +6028,16 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ sra(t0, t0, 1); __ Branch(&return_v0, eq, a2, Operand(t0)); - Label create_slice; - if (FLAG_string_slices) { - __ Branch(&create_slice, ge, a2, Operand(SlicedString::kMinLength)); - } - - // v0: original string - // a1: instance type - // a2: result string length - // a3: from index (untagged smi) - // t2: (a.k.a. to): to (smi) - // t3: (a.k.a. from): from offset (smi) - // t5: to index (untagged smi) - - Label seq_string; - __ And(t0, a1, Operand(kStringRepresentationMask)); - STATIC_ASSERT(kSeqStringTag < kConsStringTag); - STATIC_ASSERT(kConsStringTag < kExternalStringTag); - STATIC_ASSERT(kConsStringTag < kSlicedStringTag); - - // Slices and external strings go to runtime. - __ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag)); - - // Sequential strings are handled directly. - __ Branch(&seq_string, lt, t0, Operand(kConsStringTag)); - - // Cons string. Try to recurse (once) on the first substring. - // (This adds a little more generality than necessary to handle flattened - // cons strings, but not much). - __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset)); - __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset)); - STATIC_ASSERT(kSeqStringTag == 0); - // Cons, slices and external strings go to runtime. - __ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask)); - - // Definitly a sequential string. - __ bind(&seq_string); - - // v0: original string - // a1: instance type - // a2: result string length - // a3: from index (untagged smi) - // t2: (a.k.a. to): to (smi) - // t3: (a.k.a. from): from offset (smi) - // t5: to index (untagged smi) - - __ lw(t0, FieldMemOperand(v0, String::kLengthOffset)); - __ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length. - to = no_reg; - - // v0: original string or left hand side of the original cons string. - // a1: instance type - // a2: result string length - // a3: from index (untagged smi) - // t3: (a.k.a. from): from offset (smi) - // t5: to index (untagged smi) - - // Check for flat ASCII string. - Label non_ascii_flat; - STATIC_ASSERT(kTwoByteStringTag == 0); - - __ And(t4, a1, Operand(kStringEncodingMask)); - __ Branch(&non_ascii_flat, eq, t4, Operand(zero_reg)); Label result_longer_than_two; - __ Branch(&result_longer_than_two, gt, a2, Operand(2)); + // Check for special case of two character ascii string, in which case + // we do a lookup in the symbol table first. + __ li(t0, 2); + __ Branch(&result_longer_than_two, gt, a2, Operand(t0)); + __ Branch(&runtime, lt, a2, Operand(t0)); + + __ JumpIfInstanceTypeIsNotSequentialAscii(a1, a1, &runtime); - // Sub string of length 2 requested. // Get the two characters forming the sub string. __ Addu(v0, v0, Operand(a3)); __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); @@ -6123,31 +6047,126 @@ void SubStringStub::Generate(MacroAssembler* masm) { Label make_two_character_string; StringHelper::GenerateTwoCharacterSymbolTableProbe( masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string); - Counters* counters = masm->isolate()->counters(); __ jmp(&return_v0); // a2: result string length. // a3: two characters combined into halfword in little endian byte order. __ bind(&make_two_character_string); - __ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime); + __ AllocateAsciiString(v0, a2, t0, t1, t4, &runtime); __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); __ jmp(&return_v0); __ bind(&result_longer_than_two); - // Locate 'from' character of string. - __ Addu(t1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - __ sra(t4, from, 1); - __ Addu(t1, t1, t4); + // Deal with different string types: update the index if necessary + // and put the underlying string into t1. + // v0: original string + // a1: instance type + // a2: length + // a3: from index (untagged) + Label underlying_unpacked, sliced_string, seq_or_external_string; + // If the string is not indirect, it can only be sequential or external. + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + __ And(t0, a1, Operand(kIsIndirectStringMask)); + __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, t0, Operand(zero_reg)); + + __ And(t0, a1, Operand(kSlicedNotConsMask)); + __ Branch(&sliced_string, ne, t0, Operand(zero_reg)); + // Cons string. Check whether it is flat, then fetch first part. + __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset)); + __ LoadRoot(t0, Heap::kEmptyStringRootIndex); + __ Branch(&runtime, ne, t1, Operand(t0)); + __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset)); + // Update instance type. + __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset)); + __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); + __ jmp(&underlying_unpacked); + + __ bind(&sliced_string); + // Sliced string. Fetch parent and correct start index by offset. + __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset)); + __ sra(t1, t1, 1); + __ Addu(a3, a3, t1); + __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); + // Update instance type. + __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset)); + __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); + __ jmp(&underlying_unpacked); - // Allocate the result. - __ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime); + __ bind(&seq_or_external_string); + // Sequential or external string. Just move string to the expected register. + __ mov(t1, v0); + + __ bind(&underlying_unpacked); + + if (FLAG_string_slices) { + Label copy_routine; + // t1: underlying subject string + // a1: instance type of underlying subject string + // a2: length + // a3: adjusted start index (untagged) + // Short slice. Copy instead of slicing. + __ Branch(©_routine, lt, a2, Operand(SlicedString::kMinLength)); + // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info + // provided by the original string. It does not matter if the original + // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings. + Label two_byte_slice, set_slice_header; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ And(t0, a1, Operand(kStringEncodingMask)); + __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg)); + __ AllocateAsciiSlicedString(v0, a2, t2, t3, &runtime); + __ jmp(&set_slice_header); + __ bind(&two_byte_slice); + __ AllocateTwoByteSlicedString(v0, a2, t2, t3, &runtime); + __ bind(&set_slice_header); + __ sll(a3, a3, 1); + __ sw(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset)); + __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); + __ jmp(&return_v0); + + __ bind(©_routine); + } + + // t1: underlying subject string + // a1: instance type of underlying subject string + // a2: length + // a3: adjusted start index (untagged) + Label two_byte_sequential, sequential_string, allocate_result; + STATIC_ASSERT(kExternalStringTag != 0); + STATIC_ASSERT(kSeqStringTag == 0); + __ And(t0, a1, Operand(kExternalStringTag)); + __ Branch(&sequential_string, eq, t0, Operand(zero_reg)); + + // Handle external string. + // Rule out short external strings. + STATIC_CHECK(kShortExternalStringTag != 0); + __ And(t0, a1, Operand(kShortExternalStringTag)); + __ Branch(&runtime, ne, t0, Operand(zero_reg)); + __ lw(t1, FieldMemOperand(t1, ExternalString::kResourceDataOffset)); + // t1 already points to the first character of underlying string. + __ jmp(&allocate_result); + + __ bind(&sequential_string); + // Locate first character of underlying subject string. + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + + __ bind(&allocate_result); + // Sequential acii string. Allocate the result. + STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + __ And(t0, a1, Operand(kStringEncodingMask)); + __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg)); + + // Allocate and copy the resulting ascii string. + __ AllocateAsciiString(v0, a2, t0, t2, t3, &runtime); + + // Locate first character of substring to copy. + __ Addu(t1, t1, a3); - // v0: result string - // a2: result string length - // a3: from index (untagged smi) - // t1: first character of substring to copy - // t3: (a.k.a. from): from offset (smi) // Locate first character of result. __ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); @@ -6160,30 +6179,17 @@ void SubStringStub::Generate(MacroAssembler* masm) { masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED); __ jmp(&return_v0); - __ bind(&non_ascii_flat); - // a2: result string length - // t1: string - // t3: (a.k.a. from): from offset (smi) - // Check for flat two byte string. - - // Locate 'from' character of string. - __ Addu(t1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // As "from" is a smi it is 2 times the value which matches the size of a two - // byte character. - STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); - __ Addu(t1, t1, Operand(from)); - - // Allocate the result. - __ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime); + // Allocate and copy the resulting two-byte string. + __ bind(&two_byte_sequential); + __ AllocateTwoByteString(v0, a2, t0, t2, t3, &runtime); - // v0: result string - // a2: result string length - // t1: first character of substring to copy + // Locate first character of substring to copy. + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + __ sll(t0, a3, 1); + __ Addu(t1, t1, t0); // Locate first character of result. __ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - from = no_reg; - // v0: result string. // a1: first character of result. // a2: result length. @@ -6191,75 +6197,14 @@ void SubStringStub::Generate(MacroAssembler* masm) { STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong( masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED); - __ jmp(&return_v0); - - if (FLAG_string_slices) { - __ bind(&create_slice); - // v0: original string - // a1: instance type - // a2: length - // a3: from index (untagged smi) - // t2 (a.k.a. to): to (smi) - // t3 (a.k.a. from): from offset (smi) - Label allocate_slice, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ And(t4, a1, Operand(kIsIndirectStringMask)); - // External string. Jump to runtime. - __ Branch(&seq_or_external_string, eq, t4, Operand(zero_reg)); - - __ And(t4, a1, Operand(kSlicedNotConsMask)); - __ Branch(&sliced_string, ne, t4, Operand(zero_reg)); - // Cons string. Check whether it is flat, then fetch first part. - __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset)); - __ LoadRoot(t5, Heap::kEmptyStringRootIndex); - __ Branch(&sub_string_runtime, ne, t1, Operand(t5)); - __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset)); - __ jmp(&allocate_slice); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ addu(t3, t3, t1); - __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); - __ jmp(&allocate_slice); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the correct register. - __ mov(t1, v0); - - __ bind(&allocate_slice); - // a1: instance type of original string - // a2: length - // t1: underlying subject string - // t3 (a.k.a. from): from offset (smi) - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ And(t4, a1, Operand(kStringEncodingMask)); - __ Branch(&two_byte_slice, eq, t4, Operand(zero_reg)); - __ AllocateAsciiSlicedString(v0, a2, a3, t0, &sub_string_runtime); - __ jmp(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(v0, a2, a3, t0, &sub_string_runtime); - __ bind(&set_slice_header); - __ sw(t3, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); - } __ bind(&return_v0); + Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); - __ Addu(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ DropAndRet(3); // Just jump to runtime to create the sub string. - __ bind(&sub_string_runtime); + __ bind(&runtime); __ TailCallRuntime(Runtime::kSubString, 3, 1); } -- 2.7.4