Simplify StringCharCodeAt in non-crankshaft codegen.
TEST=test/mjsunit/string-slices.js Review URL: http://codereview.chromium.org/8510005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9936 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8b7bcc4e80
commit
6157562994
@ -5056,14 +5056,11 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
|
||||
// If the index is non-smi trigger the non-smi case.
|
||||
__ JumpIfNotSmi(index_, &index_not_smi_);
|
||||
|
||||
// Put smi-tagged index into scratch register.
|
||||
__ mov(scratch_, index_);
|
||||
__ bind(&got_smi_index_);
|
||||
|
||||
// Check for index out of range.
|
||||
__ ldr(ip, FieldMemOperand(object_, String::kLengthOffset));
|
||||
__ cmp(ip, Operand(scratch_));
|
||||
__ cmp(ip, Operand(index_));
|
||||
__ b(ls, index_out_of_range_);
|
||||
|
||||
// We need special handling for non-flat strings.
|
||||
@ -5089,27 +5086,27 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
__ LoadRoot(ip, Heap::kEmptyStringRootIndex);
|
||||
__ cmp(result_, Operand(ip));
|
||||
__ b(ne, &call_runtime_);
|
||||
// Get the first of the two strings and load its instance type.
|
||||
__ ldr(result_, FieldMemOperand(object_, ConsString::kFirstOffset));
|
||||
// Get the first of the two parts.
|
||||
__ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset));
|
||||
__ jmp(&assure_seq_string);
|
||||
|
||||
// SlicedString, unpack and add offset.
|
||||
__ bind(&sliced_string);
|
||||
__ ldr(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset));
|
||||
__ add(scratch_, scratch_, result_);
|
||||
__ ldr(result_, FieldMemOperand(object_, SlicedString::kParentOffset));
|
||||
__ add(index_, index_, result_);
|
||||
__ ldr(object_, FieldMemOperand(object_, SlicedString::kParentOffset));
|
||||
|
||||
// Assure that we are dealing with a sequential string. Go to runtime if not.
|
||||
__ bind(&assure_seq_string);
|
||||
__ ldr(result_, FieldMemOperand(result_, HeapObject::kMapOffset));
|
||||
__ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
|
||||
__ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
|
||||
// Check that parent is not an external string. Go to runtime otherwise.
|
||||
// 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 updated index to the runtime function.
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ tst(result_, Operand(kStringRepresentationMask));
|
||||
__ b(ne, &call_runtime_);
|
||||
// Actually fetch the parent string if it is confirmed to be sequential.
|
||||
STATIC_ASSERT(SlicedString::kParentOffset == ConsString::kFirstOffset);
|
||||
__ ldr(object_, FieldMemOperand(object_, SlicedString::kParentOffset));
|
||||
|
||||
// Check for 1-byte or 2-byte string.
|
||||
__ bind(&flat_string);
|
||||
@ -5123,15 +5120,15 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// add without shifting since the smi tag size is the log2 of the
|
||||
// number of bytes in a two-byte character.
|
||||
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0);
|
||||
__ add(scratch_, object_, Operand(scratch_));
|
||||
__ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize));
|
||||
__ add(index_, object_, Operand(index_));
|
||||
__ ldrh(result_, FieldMemOperand(index_, SeqTwoByteString::kHeaderSize));
|
||||
__ jmp(&got_char_code);
|
||||
|
||||
// ASCII string.
|
||||
// Load the byte into the result register.
|
||||
__ bind(&ascii_string);
|
||||
__ add(scratch_, object_, Operand(scratch_, LSR, kSmiTagSize));
|
||||
__ ldrb(result_, FieldMemOperand(scratch_, SeqAsciiString::kHeaderSize));
|
||||
__ add(index_, object_, Operand(index_, LSR, kSmiTagSize));
|
||||
__ ldrb(result_, FieldMemOperand(index_, SeqAsciiString::kHeaderSize));
|
||||
|
||||
__ bind(&got_char_code);
|
||||
__ mov(result_, Operand(result_, LSL, kSmiTagSize));
|
||||
@ -5148,12 +5145,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ bind(&index_not_smi_);
|
||||
// If index is a heap number, try converting it to an integer.
|
||||
__ CheckMap(index_,
|
||||
scratch_,
|
||||
result_,
|
||||
Heap::kHeapNumberMapRootIndex,
|
||||
index_not_number_,
|
||||
DONT_DO_SMI_CHECK);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ Push(object_, index_);
|
||||
__ push(object_);
|
||||
__ push(index_); // Consumed by runtime conversion function.
|
||||
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
|
||||
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
|
||||
@ -5164,15 +5161,14 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
}
|
||||
// Save the conversion result before the pop instructions below
|
||||
// have a chance to overwrite it.
|
||||
__ Move(scratch_, r0);
|
||||
__ pop(index_);
|
||||
__ Move(index_, r0);
|
||||
__ pop(object_);
|
||||
// Reload the instance type.
|
||||
__ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
|
||||
__ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
|
||||
call_helper.AfterCall(masm);
|
||||
// If index is still not a smi, it must be out of range.
|
||||
__ JumpIfNotSmi(scratch_, index_out_of_range_);
|
||||
__ JumpIfNotSmi(index_, index_out_of_range_);
|
||||
// Otherwise, return to the fast path.
|
||||
__ jmp(&got_smi_index_);
|
||||
|
||||
|
@ -3033,7 +3033,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
|
||||
Register object = r1;
|
||||
Register index = r0;
|
||||
Register scratch = r2;
|
||||
Register result = r3;
|
||||
|
||||
__ pop(object);
|
||||
@ -3043,7 +3042,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharCodeAtGenerator generator(object,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
@ -3080,8 +3078,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
|
||||
Register object = r1;
|
||||
Register index = r0;
|
||||
Register scratch1 = r2;
|
||||
Register scratch2 = r3;
|
||||
Register scratch = r3;
|
||||
Register result = r0;
|
||||
|
||||
__ pop(object);
|
||||
@ -3091,8 +3088,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharAtGenerator generator(object,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
|
@ -1109,14 +1109,12 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
|
||||
|
||||
Register receiver = r1;
|
||||
Register index = r0;
|
||||
Register scratch1 = r2;
|
||||
Register scratch2 = r3;
|
||||
Register scratch = r3;
|
||||
Register result = r0;
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -3647,6 +3647,9 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
|
||||
|
||||
// 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 updated index to the runtime function.
|
||||
__ bind(&check_sequential);
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ tst(result, Operand(kStringRepresentationMask));
|
||||
|
@ -1727,7 +1727,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
Register receiver = r1;
|
||||
Register index = r4;
|
||||
Register scratch = r3;
|
||||
Register result = r0;
|
||||
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1738,7 +1737,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
StringCharCodeAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
@ -1809,8 +1807,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
Register receiver = r0;
|
||||
Register index = r4;
|
||||
Register scratch1 = r1;
|
||||
Register scratch2 = r3;
|
||||
Register scratch = r3;
|
||||
Register result = r0;
|
||||
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1821,8 +1818,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
StringCharAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -771,7 +771,6 @@ class StringCharCodeAtGenerator {
|
||||
public:
|
||||
StringCharCodeAtGenerator(Register object,
|
||||
Register index,
|
||||
Register scratch,
|
||||
Register result,
|
||||
Label* receiver_not_string,
|
||||
Label* index_not_number,
|
||||
@ -779,7 +778,6 @@ class StringCharCodeAtGenerator {
|
||||
StringIndexFlags index_flags)
|
||||
: object_(object),
|
||||
index_(index),
|
||||
scratch_(scratch),
|
||||
result_(result),
|
||||
receiver_not_string_(receiver_not_string),
|
||||
index_not_number_(index_not_number),
|
||||
@ -805,7 +803,6 @@ class StringCharCodeAtGenerator {
|
||||
private:
|
||||
Register object_;
|
||||
Register index_;
|
||||
Register scratch_;
|
||||
Register result_;
|
||||
|
||||
Label* receiver_not_string_;
|
||||
@ -868,8 +865,7 @@ class StringCharAtGenerator {
|
||||
public:
|
||||
StringCharAtGenerator(Register object,
|
||||
Register index,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch,
|
||||
Register result,
|
||||
Label* receiver_not_string,
|
||||
Label* index_not_number,
|
||||
@ -877,13 +873,12 @@ class StringCharAtGenerator {
|
||||
StringIndexFlags index_flags)
|
||||
: char_code_at_generator_(object,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
receiver_not_string,
|
||||
index_not_number,
|
||||
index_out_of_range,
|
||||
index_flags),
|
||||
char_from_code_generator_(scratch2, result) {}
|
||||
char_from_code_generator_(scratch, result) {}
|
||||
|
||||
// Generates the fast case code. On the fallthrough path |result|
|
||||
// register contains the result.
|
||||
|
@ -5106,13 +5106,10 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// If the index is non-smi trigger the non-smi case.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ JumpIfNotSmi(index_, &index_not_smi_);
|
||||
|
||||
// Put smi-tagged index into scratch register.
|
||||
__ mov(scratch_, index_);
|
||||
__ bind(&got_smi_index_);
|
||||
|
||||
// Check for index out of range.
|
||||
__ cmp(scratch_, FieldOperand(object_, String::kLengthOffset));
|
||||
__ cmp(index_, FieldOperand(object_, String::kLengthOffset));
|
||||
__ j(above_equal, index_out_of_range_);
|
||||
|
||||
// We need special handling for non-flat strings.
|
||||
@ -5137,25 +5134,25 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
__ cmp(FieldOperand(object_, ConsString::kSecondOffset),
|
||||
Immediate(masm->isolate()->factory()->empty_string()));
|
||||
__ j(not_equal, &call_runtime_);
|
||||
// Get the first of the two strings and load its instance type.
|
||||
__ mov(result_, FieldOperand(object_, ConsString::kFirstOffset));
|
||||
// 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(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
|
||||
__ mov(result_, FieldOperand(object_, SlicedString::kParentOffset));
|
||||
__ 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 updated index to the runtime function.
|
||||
__ bind(&assure_seq_string);
|
||||
__ mov(result_, FieldOperand(result_, HeapObject::kMapOffset));
|
||||
__ 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_);
|
||||
// Actually fetch the parent string if it is confirmed to be sequential.
|
||||
STATIC_ASSERT(SlicedString::kParentOffset == ConsString::kFirstOffset);
|
||||
__ mov(object_, FieldOperand(object_, SlicedString::kParentOffset));
|
||||
|
||||
// Check for 1-byte or 2-byte string.
|
||||
__ bind(&flat_string);
|
||||
@ -5168,16 +5165,16 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Load the 2-byte character code into the result register.
|
||||
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
|
||||
__ movzx_w(result_, FieldOperand(object_,
|
||||
scratch_, times_1, // Scratch is smi-tagged.
|
||||
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(scratch_);
|
||||
__ SmiUntag(index_);
|
||||
__ movzx_b(result_, FieldOperand(object_,
|
||||
scratch_, times_1,
|
||||
index_, times_1,
|
||||
SeqAsciiString::kHeaderSize));
|
||||
__ bind(&got_char_code);
|
||||
__ SmiTag(result_);
|
||||
@ -5199,7 +5196,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
DONT_DO_SMI_CHECK);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(object_);
|
||||
__ push(index_);
|
||||
__ push(index_); // Consumed by runtime conversion function.
|
||||
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
|
||||
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
|
||||
@ -5208,12 +5204,11 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
// NumberToSmi discards numbers that are not exact integers.
|
||||
__ CallRuntime(Runtime::kNumberToSmi, 1);
|
||||
}
|
||||
if (!scratch_.is(eax)) {
|
||||
if (!index_.is(eax)) {
|
||||
// Save the conversion result before the pop instructions below
|
||||
// have a chance to overwrite it.
|
||||
__ mov(scratch_, eax);
|
||||
__ mov(index_, eax);
|
||||
}
|
||||
__ pop(index_);
|
||||
__ pop(object_);
|
||||
// Reload the instance type.
|
||||
__ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
|
||||
@ -5221,7 +5216,7 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
call_helper.AfterCall(masm);
|
||||
// If index is still not a smi, it must be out of range.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ JumpIfNotSmi(scratch_, index_out_of_range_);
|
||||
__ JumpIfNotSmi(index_, index_out_of_range_);
|
||||
// Otherwise, return to the fast path.
|
||||
__ jmp(&got_smi_index_);
|
||||
|
||||
|
@ -2936,7 +2936,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
|
||||
Register object = ebx;
|
||||
Register index = eax;
|
||||
Register scratch = ecx;
|
||||
Register result = edx;
|
||||
|
||||
__ pop(object);
|
||||
@ -2946,7 +2945,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharCodeAtGenerator generator(object,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
@ -2984,8 +2982,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
|
||||
Register object = ebx;
|
||||
Register index = eax;
|
||||
Register scratch1 = ecx;
|
||||
Register scratch2 = edx;
|
||||
Register scratch = edx;
|
||||
Register result = eax;
|
||||
|
||||
__ pop(object);
|
||||
@ -2995,8 +2992,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharAtGenerator generator(object,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
|
@ -606,14 +606,12 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
|
||||
|
||||
Register receiver = edx;
|
||||
Register index = eax;
|
||||
Register scratch1 = ebx;
|
||||
Register scratch2 = ecx;
|
||||
Register scratch = ecx;
|
||||
Register result = eax;
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -3451,6 +3451,9 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
|
||||
|
||||
// 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 updated index to the runtime function.
|
||||
__ bind(&check_sequential);
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ test(result, Immediate(kStringRepresentationMask));
|
||||
|
@ -1624,7 +1624,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
Register receiver = ebx;
|
||||
Register index = edi;
|
||||
Register scratch = edx;
|
||||
Register result = eax;
|
||||
__ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1635,7 +1634,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
StringCharCodeAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
@ -1709,8 +1707,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
Register receiver = eax;
|
||||
Register index = edi;
|
||||
Register scratch1 = ebx;
|
||||
Register scratch2 = edx;
|
||||
Register scratch = edx;
|
||||
Register result = eax;
|
||||
__ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1721,8 +1718,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
StringCharAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -4068,13 +4068,10 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
|
||||
// If the index is non-smi trigger the non-smi case.
|
||||
__ JumpIfNotSmi(index_, &index_not_smi_);
|
||||
|
||||
// Put smi-tagged index into scratch register.
|
||||
__ movq(scratch_, index_);
|
||||
__ bind(&got_smi_index_);
|
||||
|
||||
// Check for index out of range.
|
||||
__ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset));
|
||||
__ SmiCompare(index_, FieldOperand(object_, String::kLengthOffset));
|
||||
__ j(above_equal, index_out_of_range_);
|
||||
|
||||
// We need special handling for non-flat strings.
|
||||
@ -4099,46 +4096,47 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
__ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset),
|
||||
Heap::kEmptyStringRootIndex);
|
||||
__ j(not_equal, &call_runtime_);
|
||||
// Get the first of the two strings and load its instance type.
|
||||
// Get the first of the two parts.
|
||||
ASSERT(!kScratchRegister.is(scratch_));
|
||||
__ movq(kScratchRegister, FieldOperand(object_, ConsString::kFirstOffset));
|
||||
__ movq(object_, FieldOperand(object_, ConsString::kFirstOffset));
|
||||
__ jmp(&assure_seq_string, Label::kNear);
|
||||
|
||||
// SlicedString, unpack and add offset.
|
||||
__ bind(&sliced_string);
|
||||
__ addq(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
|
||||
__ movq(kScratchRegister, FieldOperand(object_, SlicedString::kParentOffset));
|
||||
__ addq(index_, FieldOperand(object_, SlicedString::kOffsetOffset));
|
||||
__ movq(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 updated index to the runtime function.
|
||||
__ bind(&assure_seq_string);
|
||||
__ movq(result_, FieldOperand(kScratchRegister, HeapObject::kMapOffset));
|
||||
__ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
|
||||
__ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
|
||||
// If the first cons component is also non-flat, then go to runtime.
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ testb(result_, Immediate(kStringRepresentationMask));
|
||||
__ j(not_zero, &call_runtime_);
|
||||
__ movq(object_, kScratchRegister);
|
||||
|
||||
// Check for 1-byte or 2-byte string.
|
||||
__ bind(&flat_string);
|
||||
STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
|
||||
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
|
||||
__ SmiToInteger32(index_, index_);
|
||||
__ testb(result_, Immediate(kStringEncodingMask));
|
||||
__ j(not_zero, &ascii_string);
|
||||
|
||||
// 2-byte string.
|
||||
// Load the 2-byte character code into the result register.
|
||||
__ SmiToInteger32(scratch_, scratch_);
|
||||
__ movzxwl(result_, FieldOperand(object_,
|
||||
scratch_, times_2,
|
||||
index_, times_2,
|
||||
SeqTwoByteString::kHeaderSize));
|
||||
__ jmp(&got_char_code);
|
||||
|
||||
// ASCII string.
|
||||
// Load the byte into the result register.
|
||||
__ bind(&ascii_string);
|
||||
__ SmiToInteger32(scratch_, scratch_);
|
||||
__ movzxbl(result_, FieldOperand(object_,
|
||||
scratch_, times_1,
|
||||
index_, times_1,
|
||||
SeqAsciiString::kHeaderSize));
|
||||
__ bind(&got_char_code);
|
||||
__ Integer32ToSmi(result_, result_);
|
||||
@ -4161,7 +4159,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
DONT_DO_SMI_CHECK);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(object_);
|
||||
__ push(index_);
|
||||
__ push(index_); // Consumed by runtime conversion function.
|
||||
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
|
||||
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
|
||||
@ -4170,19 +4167,18 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
// NumberToSmi discards numbers that are not exact integers.
|
||||
__ CallRuntime(Runtime::kNumberToSmi, 1);
|
||||
}
|
||||
if (!scratch_.is(rax)) {
|
||||
if (!index_.is(rax)) {
|
||||
// Save the conversion result before the pop instructions below
|
||||
// have a chance to overwrite it.
|
||||
__ movq(scratch_, rax);
|
||||
__ movq(index_, rax);
|
||||
}
|
||||
__ pop(index_);
|
||||
__ pop(object_);
|
||||
// Reload the instance type.
|
||||
__ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
|
||||
__ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
|
||||
call_helper.AfterCall(masm);
|
||||
// If index is still not a smi, it must be out of range.
|
||||
__ JumpIfNotSmi(scratch_, index_out_of_range_);
|
||||
__ JumpIfNotSmi(index_, index_out_of_range_);
|
||||
// Otherwise, return to the fast path.
|
||||
__ jmp(&got_smi_index_);
|
||||
|
||||
|
@ -2865,7 +2865,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
|
||||
Register object = rbx;
|
||||
Register index = rax;
|
||||
Register scratch = rcx;
|
||||
Register result = rdx;
|
||||
|
||||
__ pop(object);
|
||||
@ -2875,7 +2874,6 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharCodeAtGenerator generator(object,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
@ -2913,8 +2911,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
|
||||
Register object = rbx;
|
||||
Register index = rax;
|
||||
Register scratch1 = rcx;
|
||||
Register scratch2 = rdx;
|
||||
Register scratch = rdx;
|
||||
Register result = rax;
|
||||
|
||||
__ pop(object);
|
||||
@ -2924,8 +2921,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
||||
Label done;
|
||||
StringCharAtGenerator generator(object,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&need_conversion,
|
||||
&need_conversion,
|
||||
|
@ -531,14 +531,12 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
|
||||
|
||||
Register receiver = rdx;
|
||||
Register index = rax;
|
||||
Register scratch1 = rbx;
|
||||
Register scratch2 = rcx;
|
||||
Register scratch = rcx;
|
||||
Register result = rax;
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -3380,6 +3380,9 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
|
||||
|
||||
// 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 updated index to the runtime function.
|
||||
__ bind(&check_sequential);
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ testb(result, Immediate(kStringRepresentationMask));
|
||||
|
@ -1600,7 +1600,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
Register receiver = rbx;
|
||||
Register index = rdi;
|
||||
Register scratch = rdx;
|
||||
Register result = rax;
|
||||
__ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1611,7 +1610,6 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
|
||||
|
||||
StringCharCodeAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
@ -1680,8 +1678,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
Register receiver = rax;
|
||||
Register index = rdi;
|
||||
Register scratch1 = rbx;
|
||||
Register scratch2 = rdx;
|
||||
Register scratch = rdx;
|
||||
Register result = rax;
|
||||
__ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
|
||||
if (argc > 0) {
|
||||
@ -1692,8 +1689,7 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
|
||||
|
||||
StringCharAtGenerator generator(receiver,
|
||||
index,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch,
|
||||
result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
|
@ -24,11 +24,6 @@
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Flags: --string-slices
|
||||
|
||||
//assertEquals('345"12345 6"1234567"123',
|
||||
// '12345""12345 6""1234567""1234'.slice(2,-1).replace(/""/g, '"'));
|
||||
|
||||
var foo = "lsdfj sldkfj sdklfj læsdfjl sdkfjlsdk fjsdl fjsdljskdj flsj flsdkj flskd regexp: /foobar/\nldkfj sdlkfj sdkl";
|
||||
for(var i = 0; i < 1000; i++) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --string-slices --expose-externalize-string
|
||||
// Flags: --expose-externalize-string --allow-natives-syntax
|
||||
|
||||
var s = 'abcdefghijklmn';
|
||||
assertEquals(s, s.substr());
|
||||
@ -100,14 +100,7 @@ for (var i = 5; i < 25; i++) {
|
||||
|
||||
// Keep creating strings to to force allocation failure on substring creation.
|
||||
var x = "0123456789ABCDEF";
|
||||
x += x; // 2^5
|
||||
x += x;
|
||||
x += x;
|
||||
x += x;
|
||||
x += x;
|
||||
x += x; // 2^10
|
||||
x += x;
|
||||
x += x;
|
||||
for (var i = 0; i < 8; i++) x += x;
|
||||
var xl = x.length;
|
||||
var cache = [];
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
@ -119,14 +112,7 @@ for (var i = 0; i < 1000; i++) {
|
||||
|
||||
// Same with two-byte strings
|
||||
var x = "\u2028123456789ABCDEF";
|
||||
x += x; // 2^5
|
||||
x += x;
|
||||
x += x;
|
||||
x += x;
|
||||
x += x;
|
||||
x += x; // 2^10
|
||||
x += x;
|
||||
x += x;
|
||||
for (var i = 0; i < 8; i++) x += x;
|
||||
var xl = x.length;
|
||||
var cache = [];
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
@ -202,3 +188,21 @@ assertEquals(a.slice(1,-1), b);
|
||||
assertTrue(/3456789qwe/.test(a));
|
||||
assertEquals(5, a.indexOf("678"));
|
||||
assertEquals("12345", a.split("6")[0]);
|
||||
|
||||
// Create a slice with an external string as parent string.
|
||||
var c = a.slice(1,-1);
|
||||
|
||||
function test_crankshaft() {
|
||||
for (var i = 0; i < 20; i++) {
|
||||
assertEquals(b.charAt(i), a.charAt(i + 1));
|
||||
assertEquals(b.charAt(i), c.charAt(i));
|
||||
assertEquals(b.charAt(4), c.charAt(4));
|
||||
assertTrue(/3456789qwe/.test(c));
|
||||
assertEquals(4, c.indexOf("678"));
|
||||
assertEquals("2345", c.split("6")[0]);
|
||||
}
|
||||
}
|
||||
|
||||
test_crankshaft();
|
||||
%OptimizeFunctionOnNextCall(test_crankshaft);
|
||||
test_crankshaft();
|
Loading…
Reference in New Issue
Block a user