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)) { |