Commit 3077e8aa authored by yangguo@chromium.org's avatar yangguo@chromium.org

Generated code for substring slices in ia32.

Review URL: http://codereview.chromium.org/7744052

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9064 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4084e698
...@@ -3473,8 +3473,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { ...@@ -3473,8 +3473,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the indirect string shape: slice or cons. // Dispatch on the indirect string shape: slice or cons.
Label cons_string; Label cons_string;
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
__ tst(result, Operand(kSlicedNotConsMask)); __ tst(result, Operand(kSlicedNotConsMask));
__ b(eq, &cons_string); __ b(eq, &cons_string);
......
...@@ -5642,9 +5642,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, ...@@ -5642,9 +5642,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
void SubStringStub::Generate(MacroAssembler* masm) { void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime; Label runtime;
if (FLAG_string_slices) {
__ jmp(&runtime);
}
// Stack frame on entry. // Stack frame on entry.
// esp[0]: return address // esp[0]: return address
// esp[4]: to // esp[4]: to
...@@ -5706,7 +5703,83 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -5706,7 +5703,83 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ Set(ecx, Immediate(2)); __ Set(ecx, Immediate(2));
if (FLAG_string_slices) {
Label copy_rountine;
// If coming from the make_two_character_string path, the string
// is too short to be sliced anyways.
STATIC_ASSERT(2 < SlicedString::kMinLength);
__ jmp(&copy_routine);
__ bind(&result_longer_than_two);
// eax: string
// ebx: instance type
// ecx: sub string length
// edx: from index (smi)
Label allocate_slice, sliced_string, seq_string;
__ cmp(ecx, SlicedString::kMinLength);
// Short slice. Copy instead of slicing.
__ j(less, &copy_routine);
STATIC_ASSERT(kSeqStringTag == 0);
__ test(ebx, Immediate(kStringRepresentationMask));
__ j(zero, &seq_string, Label::kNear);
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
STATIC_ASSERT(kIsIndirectStringMask != 0);
__ test(ebx, Immediate(kIsIndirectStringMask));
// External string. Jump to runtime.
__ j(zero, &runtime);
Factory* factory = masm->isolate()->factory();
__ test(ebx, Immediate(kSlicedNotConsMask));
__ j(not_zero, &sliced_string, Label::kNear);
// Cons string. Check whether it is flat, then fetch first part.
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
factory->empty_string());
__ j(not_equal, &runtime);
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
__ jmp(&allocate_slice, Label::kNear);
__ bind(&sliced_string);
// Sliced string. Fetch parent and correct start index by offset.
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
__ jmp(&allocate_slice, Label::kNear);
__ bind(&seq_string);
// Sequential string. Just move string to the right register.
__ mov(edi, eax);
__ bind(&allocate_slice);
// edi: underlying subject string
// ebx: instance type of original subject string
// edx: offset
// ecx: length
// 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(kAsciiStringTag != 0);
__ test(ebx, Immediate(kAsciiStringTag));
__ j(zero, &two_byte_slice, Label::kNear);
__ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
__ jmp(&set_slice_header, Label::kNear);
__ bind(&two_byte_slice);
__ AllocateSlicedString(eax, ebx, no_reg, &runtime);
__ bind(&set_slice_header);
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
__ SmiTag(ecx);
__ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
__ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
__ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
Immediate(String::kEmptyHashField));
__ jmp(&return_eax);
__ bind(&copy_routine);
} else {
__ bind(&result_longer_than_two); __ bind(&result_longer_than_two);
}
// eax: string // eax: string
// ebx: instance type // ebx: instance type
// ecx: result string length // ecx: result string length
......
...@@ -3234,8 +3234,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { ...@@ -3234,8 +3234,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the indirect string shape: slice or cons. // Dispatch on the indirect string shape: slice or cons.
Label cons_string; Label cons_string;
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
__ test(result, Immediate(kSlicedNotConsMask)); __ test(result, Immediate(kSlicedNotConsMask));
__ j(zero, &cons_string, Label::kNear); __ j(zero, &cons_string, Label::kNear);
......
...@@ -1208,6 +1208,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result, ...@@ -1208,6 +1208,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
} }
void MacroAssembler::AllocateSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
// Allocate heap number in new space.
AllocateInNewSpace(SlicedString::kSize,
result,
scratch1,
scratch2,
gc_required,
TAG_OBJECT);
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(isolate()->factory()->sliced_string_map()));
}
void MacroAssembler::AllocateAsciiSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
// Allocate heap number in new space.
AllocateInNewSpace(SlicedString::kSize,
result,
scratch1,
scratch2,
gc_required,
TAG_OBJECT);
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(isolate()->factory()->sliced_ascii_string_map()));
}
// Copy memory, byte-by-byte, from source to destination. Not optimized for // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed. // long or aligned copies. The contents of scratch and length are destroyed.
// Source and destination are incremented by length. // Source and destination are incremented by length.
......
...@@ -446,6 +446,17 @@ class MacroAssembler: public Assembler { ...@@ -446,6 +446,17 @@ class MacroAssembler: public Assembler {
Register scratch2, Register scratch2,
Label* gc_required); Label* gc_required);
// Allocate a raw sliced string object. Only the map field of the result is
// initialized.
void AllocateSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
void AllocateAsciiSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
// Copy memory, byte-by-byte, from source to destination. Not optimized for // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. // long or aligned copies.
// The contents of index and scratch are destroyed. // The contents of index and scratch are destroyed.
......
...@@ -496,6 +496,11 @@ STATIC_ASSERT( ...@@ -496,6 +496,11 @@ STATIC_ASSERT(
STATIC_ASSERT( STATIC_ASSERT(
(kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); (kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
// Use this mask to distinguish between cons and slice only after making
// sure that the string is one of the two (an indirect string).
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
// If bit 7 is clear, then bit 3 indicates whether this two-byte // If bit 7 is clear, then bit 3 indicates whether this two-byte
// string actually contains ascii data. // string actually contains ascii data.
const uint32_t kAsciiDataHintMask = 0x08; const uint32_t kAsciiDataHintMask = 0x08;
......
...@@ -3217,8 +3217,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { ...@@ -3217,8 +3217,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the indirect string shape: slice or cons. // Dispatch on the indirect string shape: slice or cons.
Label cons_string; Label cons_string;
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
__ testb(result, Immediate(kSlicedNotConsMask)); __ testb(result, Immediate(kSlicedNotConsMask));
__ j(zero, &cons_string, Label::kNear); __ j(zero, &cons_string, Label::kNear);
......
...@@ -72,7 +72,7 @@ for (var i = 0; i < 25; i++) { ...@@ -72,7 +72,7 @@ for (var i = 0; i < 25; i++) {
} }
/x/.exec(x); // Try to force a flatten. /x/.exec(x); // Try to force a flatten.
for (var i = 5; i < 25; i++) { for (var i = 5; i < 25; i++) {
for (var j = 12; j < 25; j++) { for (var j = 0; j < 25; j++) {
var z = x.substring(i, i+j); var z = x.substring(i, i+j);
var w = Math.random() * 42; // Allocate something new in new-space. var w = Math.random() * 42; // Allocate something new in new-space.
assertEquals(j, z.length); assertEquals(j, z.length);
...@@ -110,7 +110,7 @@ x += x; ...@@ -110,7 +110,7 @@ x += x;
x += x; x += x;
var xl = x.length; var xl = x.length;
var cache = []; var cache = [];
for (var i = 0; i < 10000; i++) { for (var i = 0; i < 1000; i++) {
var z = x.substring(i % xl); var z = x.substring(i % xl);
assertEquals(xl - (i % xl), z.length); assertEquals(xl - (i % xl), z.length);
cache.push(z); cache.push(z);
...@@ -129,7 +129,7 @@ x += x; ...@@ -129,7 +129,7 @@ x += x;
x += x; x += x;
var xl = x.length; var xl = x.length;
var cache = []; var cache = [];
for (var i = 0; i < 10000; i++) { for (var i = 0; i < 1000; i++) {
var z = x.substring(i % xl); var z = x.substring(i % xl);
assertEquals(xl - (i % xl), z.length); assertEquals(xl - (i % xl), z.length);
cache.push(z); cache.push(z);
...@@ -149,6 +149,7 @@ for (var i = 63; i >= 0; i--) { ...@@ -149,6 +149,7 @@ for (var i = 63; i >= 0; i--) {
var z = cache.pop(); var z = cache.pop();
assertTrue(/\u2028123456789ABCDEF/.test(z)); assertTrue(/\u2028123456789ABCDEF/.test(z));
assertEquals(xl - offset, z.length); assertEquals(xl - offset, z.length);
assertEquals(x.charAt(i*(i+1)/2), z.charAt(0));
offset -= i; offset -= i;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment