Index: src/ia32/code-stubs-ia32.cc |
=================================================================== |
--- src/ia32/code-stubs-ia32.cc (revision 10035) |
+++ src/ia32/code-stubs-ia32.cc (working copy) |
@@ -35,6 +35,7 @@ |
#include "jsregexp.h" |
#include "regexp-macro-assembler.h" |
#include "stub-cache.h" |
+#include "codegen.h" |
namespace v8 { |
namespace internal { |
@@ -231,70 +232,38 @@ |
} |
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
- // Stack layout on entry: |
+static void GenerateFastCloneShallowArrayCommon( |
+ MacroAssembler* masm, |
+ int length, |
+ FastCloneShallowArrayStub::Mode mode, |
+ Label* fail) { |
+ // Registers on entry: |
// |
- // [esp + kPointerSize]: constant elements. |
- // [esp + (2 * kPointerSize)]: literal index. |
- // [esp + (3 * kPointerSize)]: literals array. |
+ // ecx: boilerplate literal array. |
+ ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); |
// All sizes here are multiples of kPointerSize. |
int elements_size = 0; |
- if (length_ > 0) { |
- elements_size = mode_ == CLONE_DOUBLE_ELEMENTS |
- ? FixedDoubleArray::SizeFor(length_) |
- : FixedArray::SizeFor(length_); |
+ if (length > 0) { |
+ elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
+ ? FixedDoubleArray::SizeFor(length) |
+ : FixedArray::SizeFor(length); |
} |
int size = JSArray::kSize + elements_size; |
- // Load boilerplate object into ecx and check if we need to create a |
- // boilerplate. |
- Label slow_case; |
- __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
- __ mov(eax, Operand(esp, 2 * kPointerSize)); |
- STATIC_ASSERT(kPointerSize == 4); |
- STATIC_ASSERT(kSmiTagSize == 1); |
- STATIC_ASSERT(kSmiTag == 0); |
- __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, |
- FixedArray::kHeaderSize)); |
- Factory* factory = masm->isolate()->factory(); |
- __ cmp(ecx, factory->undefined_value()); |
- __ j(equal, &slow_case); |
- |
- if (FLAG_debug_code) { |
- const char* message; |
- Handle<Map> expected_map; |
- if (mode_ == CLONE_ELEMENTS) { |
- message = "Expected (writable) fixed array"; |
- expected_map = factory->fixed_array_map(); |
- } else if (mode_ == CLONE_DOUBLE_ELEMENTS) { |
- message = "Expected (writable) fixed double array"; |
- expected_map = factory->fixed_double_array_map(); |
- } else { |
- ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); |
- message = "Expected copy-on-write fixed array"; |
- expected_map = factory->fixed_cow_array_map(); |
- } |
- __ push(ecx); |
- __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
- __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); |
- __ Assert(equal, message); |
- __ pop(ecx); |
- } |
- |
// Allocate both the JS array and the elements array in one big |
// allocation. This avoids multiple limit checks. |
- __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); |
+ __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT); |
// Copy the JS array part. |
for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
- if ((i != JSArray::kElementsOffset) || (length_ == 0)) { |
+ if ((i != JSArray::kElementsOffset) || (length == 0)) { |
__ mov(ebx, FieldOperand(ecx, i)); |
__ mov(FieldOperand(eax, i), ebx); |
} |
} |
- if (length_ > 0) { |
+ if (length > 0) { |
// Get hold of the elements array of the boilerplate and setup the |
// elements pointer in the resulting object. |
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
@@ -302,13 +271,13 @@ |
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); |
// Copy the elements array. |
- if (mode_ == CLONE_ELEMENTS) { |
+ if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) { |
for (int i = 0; i < elements_size; i += kPointerSize) { |
__ mov(ebx, FieldOperand(ecx, i)); |
__ mov(FieldOperand(edx, i), ebx); |
} |
} else { |
- ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS); |
+ ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS); |
int i; |
for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) { |
__ mov(ebx, FieldOperand(ecx, i)); |
@@ -322,7 +291,75 @@ |
ASSERT(i == elements_size); |
} |
} |
+} |
+ |
+void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
+ // Stack layout on entry: |
+ // |
+ // [esp + kPointerSize]: constant elements. |
+ // [esp + (2 * kPointerSize)]: literal index. |
+ // [esp + (3 * kPointerSize)]: literals array. |
+ |
+ // Load boilerplate object into ecx and check if we need to create a |
+ // boilerplate. |
+ __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
+ __ mov(eax, Operand(esp, 2 * kPointerSize)); |
+ STATIC_ASSERT(kPointerSize == 4); |
+ STATIC_ASSERT(kSmiTagSize == 1); |
+ STATIC_ASSERT(kSmiTag == 0); |
+ __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, |
+ FixedArray::kHeaderSize)); |
+ Factory* factory = masm->isolate()->factory(); |
+ __ cmp(ecx, factory->undefined_value()); |
+ Label slow_case; |
+ __ j(equal, &slow_case); |
+ |
+ FastCloneShallowArrayStub::Mode mode = mode_; |
+ // ecx is boilerplate object. |
+ if (mode == CLONE_ANY_ELEMENTS) { |
+ Label double_elements, check_fast_elements; |
+ __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset)); |
+ __ CheckMap(ebx, factory->fixed_cow_array_map(), |
+ &check_fast_elements, DONT_DO_SMI_CHECK); |
+ GenerateFastCloneShallowArrayCommon(masm, 0, |
+ COPY_ON_WRITE_ELEMENTS, &slow_case); |
+ __ ret(3 * kPointerSize); |
+ |
+ __ bind(&check_fast_elements); |
+ __ CheckMap(ebx, factory->fixed_array_map(), |
+ &double_elements, DONT_DO_SMI_CHECK); |
+ GenerateFastCloneShallowArrayCommon(masm, length_, |
+ CLONE_ELEMENTS, &slow_case); |
+ __ ret(3 * kPointerSize); |
+ |
+ __ bind(&double_elements); |
+ mode = CLONE_DOUBLE_ELEMENTS; |
+ // Fall through to generate the code to handle double elements. |
+ } |
+ |
+ if (FLAG_debug_code) { |
+ const char* message; |
+ Handle<Map> expected_map; |
+ if (mode == CLONE_ELEMENTS) { |
+ message = "Expected (writable) fixed array"; |
+ expected_map = factory->fixed_array_map(); |
+ } else if (mode == CLONE_DOUBLE_ELEMENTS) { |
+ message = "Expected (writable) fixed double array"; |
+ expected_map = factory->fixed_double_array_map(); |
+ } else { |
+ ASSERT(mode == COPY_ON_WRITE_ELEMENTS); |
+ message = "Expected copy-on-write fixed array"; |
+ expected_map = factory->fixed_cow_array_map(); |
+ } |
+ __ push(ecx); |
+ __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
+ __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); |
+ __ Assert(equal, message); |
+ __ pop(ecx); |
+ } |
+ |
+ GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case); |
// Return and remove the on-stack parameters. |
__ ret(3 * kPointerSize); |
@@ -5089,11 +5126,6 @@ |
// 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,71 +5146,12 @@ |
__ 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(); |
+ StringCharLoadGenerator::Generate( |
+ masm, factory, object_, index_, result_, &call_runtime_); |
- // ConsString. |
- // 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. |
- // 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)); |
- STATIC_ASSERT(kSeqStringTag == 0); |
- __ test(result_, Immediate(kStringRepresentationMask)); |
- __ j(not_zero, &call_runtime_); |
- |
- // Check for 1-byte or 2-byte string. |
- __ bind(&flat_string); |
- STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
- STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
- __ test(result_, Immediate(kStringEncodingMask)); |
- __ j(not_zero, &ascii_string, Label::kNear); |
- |
- // 2-byte string. |
- // Load the 2-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); |
- |
- // 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_); |
} |
@@ -5228,6 +5201,7 @@ |
__ bind(&call_runtime_); |
call_helper.BeforeCall(masm); |
__ push(object_); |
+ __ SmiTag(index_); |
__ push(index_); |
__ CallRuntime(Runtime::kStringCharCodeAt, 2); |
if (!result_.is(eax)) { |
@@ -5973,18 +5947,15 @@ |
// ebx: instance type |
// ecx: sub string length |
// edx: from index (smi) |
- Label allocate_slice, sliced_string, seq_string; |
+ Label allocate_slice, sliced_string, seq_or_external_string; |
__ cmp(ecx, SlicedString::kMinLength); |
// Short slice. Copy instead of slicing. |
__ j(less, ©_routine); |
- STATIC_ASSERT(kSeqStringTag == 0); |
- __ test(ebx, Immediate(kStringRepresentationMask)); |
- __ j(zero, &seq_string, Label::kNear); |
+ // If the string is not indirect, it can only be sequential or external. |
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
STATIC_ASSERT(kIsIndirectStringMask != 0); |
__ test(ebx, Immediate(kIsIndirectStringMask)); |
- // External string. Jump to runtime. |
- __ j(zero, &runtime); |
+ __ j(zero, &seq_or_external_string, Label::kNear); |
Factory* factory = masm->isolate()->factory(); |
__ test(ebx, Immediate(kSlicedNotConsMask)); |
@@ -6002,8 +5973,8 @@ |
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); |
__ jmp(&allocate_slice, Label::kNear); |
- __ bind(&seq_string); |
- // Sequential string. Just move string to the right register. |
+ __ bind(&seq_or_external_string); |
+ // Sequential or external string. Just move string to the correct register. |
__ mov(edi, eax); |
__ bind(&allocate_slice); |