Chromium Code Reviews| Index: src/ia32/code-stubs-ia32.cc |
| diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc |
| index 23bea4f8568ce2cebeccf8212be82343e75e4d29..a37c9d731e2b5218d24e7b3a725c57fd1f5e0a71 100644 |
| --- a/src/ia32/code-stubs-ia32.cc |
| +++ b/src/ia32/code-stubs-ia32.cc |
| @@ -5089,11 +5089,6 @@ void CompareStub::PrintName(StringStream* stream) { |
| // StringCharCodeAtGenerator |
| void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| - Label flat_string; |
| - Label ascii_string; |
| - Label got_char_code; |
| - Label sliced_string; |
| - |
| // If the receiver is a smi trigger the non-string case. |
| STATIC_ASSERT(kSmiTag == 0); |
| __ JumpIfSmi(object_, receiver_not_string_); |
| @@ -5114,73 +5109,118 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| __ cmp(index_, FieldOperand(object_, String::kLengthOffset)); |
| __ j(above_equal, index_out_of_range_); |
| - // We need special handling for non-flat strings. |
| - STATIC_ASSERT(kSeqStringTag == 0); |
| - __ test(result_, Immediate(kStringRepresentationMask)); |
| - __ j(zero, &flat_string); |
| + __ SmiUntag(index_); |
| - // Handle non-flat strings. |
| - __ and_(result_, kStringRepresentationMask); |
| - STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| - STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| - __ cmp(result_, kExternalStringTag); |
| - __ j(greater, &sliced_string, Label::kNear); |
| - __ j(equal, &call_runtime_); |
| + Factory* factory = masm->isolate()->factory(); |
| + GenerateCharLoad(masm, factory, object_, index_, result_, &call_runtime_); |
| - // ConsString. |
| + __ SmiTag(result_); |
| + __ bind(&exit_); |
| +} |
| + |
| + |
| +void StringCharCodeAtGenerator::GenerateCharLoad(MacroAssembler* masm, |
| + Factory* factory, |
| + Register string, |
| + Register index, |
| + Register result, |
| + Label* call_runtime) { |
| + // Fetch the instance type of the receiver into result register. |
| + __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); |
| + __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
| + |
| + // We need special handling for indirect strings. |
| + Label check_sequential; |
| + __ test(result, Immediate(kIsIndirectStringMask)); |
| + __ j(zero, &check_sequential); |
| + |
| + // Dispatch on the indirect string shape: slice or cons. |
| + Label cons_string; |
| + __ test(result, Immediate(kSlicedNotConsMask)); |
| + __ j(zero, &cons_string); |
| + |
| + // Handle slices. |
| + Label indirect_string_loaded; |
| + __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset)); |
| + __ SmiUntag(result); |
| + __ add(index, result); |
| + __ mov(string, FieldOperand(string, SlicedString::kParentOffset)); |
| + __ jmp(&indirect_string_loaded); |
| + |
| + // Handle external strings. |
| + Label external_string, ascii_external, done; |
| + __ bind(&external_string); |
| + if (FLAG_debug_code) { |
| + // Assert that we do not have a cons or slice (indirect strings) here. |
| + __ test(result, Immediate(kIsIndirectStringMask)); |
| + __ Assert(zero, "external string expected, but not found"); |
|
Lasse Reichstein
2011/11/17 13:40:18
This test checks for "indirect string" but reports
|
| + } |
| + __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset)); |
| + __ test(result, result); |
| + __ j(zero, call_runtime); |
| + __ cmp(FieldOperand(string, HeapObject::kMapOffset), |
| + Immediate(factory->external_ascii_string_map())); |
| + __ j(equal, &ascii_external, Label::kNear); |
| + __ cmp(FieldOperand(string, HeapObject::kMapOffset), |
|
Lasse Reichstein
2011/11/17 13:40:18
Comparing against the same memory location twice i
Yang
2011/11/17 17:06:23
|string| is used as a temp register, so I can use
|
| + Immediate(factory->external_ascii_symbol_map())); |
| + __ j(equal, &ascii_external, Label::kNear); |
| + // Two-byte string. |
| + __ movzx_w(result, Operand(result, index, times_2, 0)); |
| + __ jmp(&done); |
| + __ bind(&ascii_external); |
| + // Ascii string. |
| + __ movzx_b(result, Operand(result, index, times_1, 0)); |
| + __ jmp(&done); |
| + |
| + // Handle conses. |
| // Check whether the right hand side is the empty string (i.e. if |
| // this is really a flat string in a cons string). If that is not |
| // the case we would rather go to the runtime system now to flatten |
| // the string. |
| - Label assure_seq_string; |
| - __ cmp(FieldOperand(object_, ConsString::kSecondOffset), |
| - Immediate(masm->isolate()->factory()->empty_string())); |
| - __ j(not_equal, &call_runtime_); |
| - // Get the first of the two parts. |
| - __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); |
| - __ jmp(&assure_seq_string, Label::kNear); |
| - |
| - // SlicedString, unpack and add offset. |
| - __ bind(&sliced_string); |
| - __ add(index_, FieldOperand(object_, SlicedString::kOffsetOffset)); |
| - __ mov(object_, FieldOperand(object_, SlicedString::kParentOffset)); |
| - |
| - // Assure that we are dealing with a sequential string. Go to runtime if not. |
| + __ bind(&cons_string); |
| + __ cmp(FieldOperand(string, ConsString::kSecondOffset), |
| + Immediate(factory->empty_string())); |
| + __ j(not_equal, call_runtime); |
| + __ mov(string, FieldOperand(string, ConsString::kFirstOffset)); |
| + |
| + __ bind(&indirect_string_loaded); |
| + __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); |
| + __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
| + |
| + // Check whether the string is sequential. The only non-sequential |
| + // shapes we support have just been unwrapped above. |
| // Note that if the original string is a cons or slice with an external |
| // string as underlying string, we pass that unpacked underlying string with |
| // the adjusted index to the runtime function. |
| - __ bind(&assure_seq_string); |
| - __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| - __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| + __ bind(&check_sequential); |
| STATIC_ASSERT(kSeqStringTag == 0); |
| - __ test(result_, Immediate(kStringRepresentationMask)); |
| - __ j(not_zero, &call_runtime_); |
| + __ test(result, Immediate(kStringRepresentationMask)); |
| + __ j(not_zero, &external_string); |
| - // Check for 1-byte or 2-byte string. |
| - __ bind(&flat_string); |
| + // Dispatch on the encoding: ASCII or two-byte. |
| + Label ascii_string; |
| STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| - __ test(result_, Immediate(kStringEncodingMask)); |
| + __ test(result, Immediate(kStringEncodingMask)); |
| __ j(not_zero, &ascii_string, Label::kNear); |
| - // 2-byte string. |
| - // Load the 2-byte character code into the result register. |
| + // Two-byte string. |
| + // Load the two-byte character code into the result register. |
| STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| - __ movzx_w(result_, FieldOperand(object_, |
| - index_, times_1, // Scratch is smi-tagged. |
| - SeqTwoByteString::kHeaderSize)); |
| - __ jmp(&got_char_code, Label::kNear); |
| + __ movzx_w(result, FieldOperand(string, |
| + index, |
| + times_2, |
| + SeqTwoByteString::kHeaderSize)); |
| + __ jmp(&done, Label::kNear); |
| - // ASCII string. |
| + // Ascii string. |
| // Load the byte into the result register. |
| __ bind(&ascii_string); |
| - __ SmiUntag(index_); |
| - __ movzx_b(result_, FieldOperand(object_, |
| - index_, times_1, |
| - SeqAsciiString::kHeaderSize)); |
| - __ bind(&got_char_code); |
| - __ SmiTag(result_); |
| - __ bind(&exit_); |
| + __ movzx_b(result, FieldOperand(string, |
| + index, |
| + times_1, |
| + SeqAsciiString::kHeaderSize)); |
| + __ bind(&done); |
| } |
| @@ -5228,6 +5268,7 @@ void StringCharCodeAtGenerator::GenerateSlow( |
| __ bind(&call_runtime_); |
| call_helper.BeforeCall(masm); |
| __ push(object_); |
| + __ SmiTag(index_); |
| __ push(index_); |
| __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
| if (!result_.is(eax)) { |