parent 62e8d5a7
...@@ -5950,6 +5950,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { ...@@ -5950,6 +5950,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
result.reg(), result.reg(),
&slow_case, &slow_case,
&slow_case, &slow_case,
&slow_case,
&slow_case); &slow_case);
__ jmp(&exit); __ jmp(&exit);
...@@ -12048,7 +12049,8 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, ...@@ -12048,7 +12049,8 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
Register scratch, Register scratch,
Register result, Register result,
Label* receiver_not_string, Label* receiver_not_string,
Label* index_not_positive_smi, Label* index_not_smi,
Label* index_out_of_range,
Label* slow_case) { Label* slow_case) {
Label not_a_flat_string; Label not_a_flat_string;
Label try_again_with_new_string; Label try_again_with_new_string;
...@@ -12067,11 +12069,10 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, ...@@ -12067,11 +12069,10 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
__ test(result, Immediate(kIsNotStringMask)); __ test(result, Immediate(kIsNotStringMask));
__ j(not_zero, receiver_not_string); __ j(not_zero, receiver_not_string);
// If the index is negative or non-smi trigger the non-positive-smi // If the index is non-smi trigger the non-smi case.
// case.
ASSERT(kSmiTag == 0); ASSERT(kSmiTag == 0);
__ test(index, Immediate(kSmiTagMask | kSmiSignMask)); __ test(index, Immediate(kSmiTagMask));
__ j(not_zero, index_not_positive_smi); __ j(not_zero, index_not_smi);
// Put untagged index into scratch register. // Put untagged index into scratch register.
__ mov(scratch, index); __ mov(scratch, index);
...@@ -12079,13 +12080,13 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, ...@@ -12079,13 +12080,13 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
// Check for index out of range. // Check for index out of range.
__ cmp(scratch, FieldOperand(object, String::kLengthOffset)); __ cmp(scratch, FieldOperand(object, String::kLengthOffset));
__ j(greater_equal, slow_case); __ j(above_equal, index_out_of_range);
__ bind(&try_again_with_new_string); __ bind(&try_again_with_new_string);
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- object : string to access // -- object : string to access
// -- result : instance type of the string // -- result : instance type of the string
// -- scratch : positive smi index < length // -- scratch : non-negative index < length
// ----------------------------------- // -----------------------------------
// We need special handling for non-flat strings. // We need special handling for non-flat strings.
...@@ -12099,7 +12100,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, ...@@ -12099,7 +12100,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
__ j(not_zero, &ascii_string); __ j(not_zero, &ascii_string);
// 2-byte string. // 2-byte string.
// Load the 2-byte character code into the temp register. // Load the 2-byte character code into the result register.
__ movzx_w(result, FieldOperand(object, __ movzx_w(result, FieldOperand(object,
scratch, times_2, scratch, times_2,
SeqTwoByteString::kHeaderSize)); SeqTwoByteString::kHeaderSize));
...@@ -12127,7 +12128,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, ...@@ -12127,7 +12128,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
// ASCII string. // ASCII string.
__ bind(&ascii_string); __ bind(&ascii_string);
// Load the byte into the temp register. // Load the byte into the result register.
__ movzx_b(result, FieldOperand(object, __ movzx_b(result, FieldOperand(object,
scratch, times_1, scratch, times_1,
SeqAsciiString::kHeaderSize)); SeqAsciiString::kHeaderSize));
......
...@@ -886,14 +886,15 @@ class GenericBinaryOpStub: public CodeStub { ...@@ -886,14 +886,15 @@ class GenericBinaryOpStub: public CodeStub {
class StringHelper : public AllStatic { class StringHelper : public AllStatic {
public: public:
// Generates fast code for getting a char code out of a string // Generates fast code for getting a char code out of a string
// object at the given index. May bail out for three reasons (in the // object at the given index. May bail out for four reasons (in the
// listed order): // listed order):
// * Receiver is not a string (receiver_not_string label). // * Receiver is not a string (receiver_not_string label).
// * Index is not a positive smi (index_not_positive_smi label). // * Index is not a smi (index_not_smi label).
// * Index is out of range (index_out_of_range).
// * Some other reason (slow_case label). In this case it's // * Some other reason (slow_case label). In this case it's
// guaranteed that the above conditions are not violated, // guaranteed that the above conditions are not violated,
// e.g. it's safe to assume the receiver is a string and the // e.g. it's safe to assume the receiver is a string and the
// index is a positive smi. // index is a non-negative smi < length.
// When successful, object, index, and scratch are clobbered. // When successful, object, index, and scratch are clobbered.
// Otherwise, scratch and result are clobbered. // Otherwise, scratch and result are clobbered.
static void GenerateFastCharCodeAt(MacroAssembler* masm, static void GenerateFastCharCodeAt(MacroAssembler* masm,
...@@ -902,7 +903,8 @@ class StringHelper : public AllStatic { ...@@ -902,7 +903,8 @@ class StringHelper : public AllStatic {
Register scratch, Register scratch,
Register result, Register result,
Label* receiver_not_string, Label* receiver_not_string,
Label* index_not_positive_smi, Label* index_not_smi,
Label* index_out_of_range,
Label* slow_case); Label* slow_case);
// Generates code for creating a one-char string from the given char // Generates code for creating a one-char string from the given char
......
...@@ -496,7 +496,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -496,7 +496,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- esp[0] : return address // -- esp[0] : return address
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
Label not_positive_smi; Label index_not_smi;
Label index_out_of_range;
Label slow_char_code; Label slow_char_code;
Label got_char_code; Label got_char_code;
...@@ -511,7 +512,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -511,7 +512,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
scratch, scratch,
code, code,
&miss, // When not a string. &miss, // When not a string.
&not_positive_smi, &index_not_smi,
&index_out_of_range,
&slow_char_code); &slow_char_code);
// If we didn't bail out, code register contains smi tagged char // If we didn't bail out, code register contains smi tagged char
// code. // code.
...@@ -521,14 +523,9 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -521,14 +523,9 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
__ Abort("Unexpected fall-through from char from code tail call"); __ Abort("Unexpected fall-through from char from code tail call");
#endif #endif
// Check if key is a smi or a heap number. // Check if key is a heap number.
__ bind(&not_positive_smi); __ bind(&index_not_smi);
ASSERT(kSmiTag == 0); __ CheckMap(index, Factory::heap_number_map(), &miss, true);
__ test(index, Immediate(kSmiTagMask));
__ j(zero, &slow_char_code);
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(ecx, Factory::heap_number_map());
__ j(not_equal, &miss);
// Push receiver and key on the stack (now that we know they are a // Push receiver and key on the stack (now that we know they are a
// string and a number), and call runtime. // string and a number), and call runtime.
...@@ -553,6 +550,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -553,6 +550,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
} }
__ cmp(code, Factory::nan_value()); __ cmp(code, Factory::nan_value());
__ j(not_equal, &got_char_code); __ j(not_equal, &got_char_code);
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::undefined_value())); __ Set(eax, Immediate(Factory::undefined_value()));
__ ret(0); __ ret(0);
......
This diff is collapsed.
...@@ -816,14 +816,45 @@ class GenericBinaryOpStub: public CodeStub { ...@@ -816,14 +816,45 @@ class GenericBinaryOpStub: public CodeStub {
} }
}; };
class StringHelper : public AllStatic {
class StringStubBase: public CodeStub {
public: public:
// Generates fast code for getting a char code out of a string
// object at the given index. May bail out for four reasons (in the
// listed order):
// * Receiver is not a string (receiver_not_string label).
// * Index is not a smi (index_not_smi label).
// * Index is out of range (index_out_of_range).
// * Some other reason (slow_case label). In this case it's
// guaranteed that the above conditions are not violated,
// e.g. it's safe to assume the receiver is a string and the
// index is a non-negative smi < length.
// When successful, object, index, and scratch are clobbered.
// Otherwise, scratch and result are clobbered.
static void GenerateFastCharCodeAt(MacroAssembler* masm,
Register object,
Register index,
Register scratch,
Register result,
Label* receiver_not_string,
Label* index_not_smi,
Label* index_out_of_range,
Label* slow_case);
// Generates code for creating a one-char string from the given char
// code. May do a runtime call, so any register can be clobbered
// and, if the given invoke flag specifies a call, an internal frame
// is required. In tail call mode the result must be rax register.
static void GenerateCharFromCode(MacroAssembler* masm,
Register code,
Register result,
Register scratch,
InvokeFlag flag);
// Generate code for copying characters using a simple loop. This should only // Generate code for copying characters using a simple loop. This should only
// be used in places where the number of characters is small and the // be used in places where the number of characters is small and the
// additional setup and checking in GenerateCopyCharactersREP adds too much // additional setup and checking in GenerateCopyCharactersREP adds too much
// overhead. Copying of overlapping regions is not supported. // overhead. Copying of overlapping regions is not supported.
void GenerateCopyCharacters(MacroAssembler* masm, static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
...@@ -832,7 +863,7 @@ class StringStubBase: public CodeStub { ...@@ -832,7 +863,7 @@ class StringStubBase: public CodeStub {
// Generate code for copying characters using the rep movs instruction. // Generate code for copying characters using the rep movs instruction.
// Copies rcx characters from rsi to rdi. Copying of overlapping regions is // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
// not supported. // not supported.
void GenerateCopyCharactersREP(MacroAssembler* masm, static void GenerateCopyCharactersREP(MacroAssembler* masm,
Register dest, // Must be rdi. Register dest, // Must be rdi.
Register src, // Must be rsi. Register src, // Must be rsi.
Register count, // Must be rcx. Register count, // Must be rcx.
...@@ -843,7 +874,7 @@ class StringStubBase: public CodeStub { ...@@ -843,7 +874,7 @@ class StringStubBase: public CodeStub {
// not found by probing a jump to the label not_found is performed. This jump // not found by probing a jump to the label not_found is performed. This jump
// does not guarantee that the string is not in the symbol table. If the // does not guarantee that the string is not in the symbol table. If the
// string is found the code falls through with the string in register rax. // string is found the code falls through with the string in register rax.
void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1, Register c1,
Register c2, Register c2,
Register scratch1, Register scratch1,
...@@ -853,17 +884,19 @@ class StringStubBase: public CodeStub { ...@@ -853,17 +884,19 @@ class StringStubBase: public CodeStub {
Label* not_found); Label* not_found);
// Generate string hash. // Generate string hash.
void GenerateHashInit(MacroAssembler* masm, static void GenerateHashInit(MacroAssembler* masm,
Register hash, Register hash,
Register character, Register character,
Register scratch); Register scratch);
void GenerateHashAddCharacter(MacroAssembler* masm, static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash, Register hash,
Register character, Register character,
Register scratch); Register scratch);
void GenerateHashGetHash(MacroAssembler* masm, static void GenerateHashGetHash(MacroAssembler* masm,
Register hash, Register hash,
Register scratch); Register scratch);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
}; };
...@@ -874,7 +907,7 @@ enum StringAddFlags { ...@@ -874,7 +907,7 @@ enum StringAddFlags {
}; };
class StringAddStub: public StringStubBase { class StringAddStub: public CodeStub {
public: public:
explicit StringAddStub(StringAddFlags flags) { explicit StringAddStub(StringAddFlags flags) {
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
...@@ -891,7 +924,7 @@ class StringAddStub: public StringStubBase { ...@@ -891,7 +924,7 @@ class StringAddStub: public StringStubBase {
}; };
class SubStringStub: public StringStubBase { class SubStringStub: public CodeStub {
public: public:
SubStringStub() {} SubStringStub() {}
......
...@@ -523,30 +523,69 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -523,30 +523,69 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- rsp[8] : name // -- rsp[8] : name
// -- rsp[16] : receiver // -- rsp[16] : receiver
// ----------------------------------- // -----------------------------------
Label miss;
Label index_not_smi;
Label index_out_of_range;
Label slow_char_code;
Label got_char_code;
Label miss, index_ok; Register receiver = rdx;
Register index = rax;
// Check that the receiver isn't a smi. Register code = rbx;
__ movq(rcx, Operand(rsp, 2 * kPointerSize)); Register scratch = rcx;
__ JumpIfSmi(rcx, &miss);
__ movq(index, Operand(rsp, 1 * kPointerSize));
__ movq(receiver, Operand(rsp, 2 * kPointerSize));
StringHelper::GenerateFastCharCodeAt(masm,
receiver,
index,
scratch,
code,
&miss, // When not a string.
&index_not_smi,
&index_out_of_range,
&slow_char_code);
// If we didn't bail out, code register contains smi tagged char
// code.
__ bind(&got_char_code);
StringHelper::GenerateCharFromCode(masm, code, rax, scratch, JUMP_FUNCTION);
#ifdef DEBUG
__ Abort("Unexpected fall-through from char from code tail call");
#endif
// Check if key is a heap number.
__ bind(&index_not_smi);
__ CompareRoot(FieldOperand(index, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &miss);
// Check that the receiver is a string. // Push receiver and key on the stack (now that we know they are a
Condition is_string = masm->IsObjectStringType(rcx, rax, rbx); // string and a number), and call runtime.
__ j(NegateCondition(is_string), &miss); __ bind(&slow_char_code);
__ EnterInternalFrame();
__ push(receiver);
__ push(index);
__ CallRuntime(Runtime::kStringCharCodeAt, 2);
ASSERT(!code.is(rax));
__ movq(code, rax);
__ LeaveInternalFrame();
// Check if key is a smi or a heap number. // Check if the runtime call returned NaN char code. If yes, return
__ movq(rax, Operand(rsp, kPointerSize)); // undefined. Otherwise, we can continue.
__ JumpIfSmi(rax, &index_ok); if (FLAG_debug_code) {
__ CheckMap(rax, Factory::heap_number_map(), &miss, false); ASSERT(kSmiTag == 0);
__ JumpIfSmi(code, &got_char_code);
__ CompareRoot(FieldOperand(code, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ Assert(equal, "StringCharCodeAt must return smi or heap number");
}
__ CompareRoot(code, Heap::kNanValueRootIndex);
__ j(not_equal, &got_char_code);
__ bind(&index_ok); __ bind(&index_out_of_range);
// Duplicate receiver and key since they are expected on the stack after __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
// the KeyedLoadIC call. __ ret(0);
__ pop(rbx); // return address
__ push(rcx); // receiver
__ push(rax); // key
__ push(rbx); // return address
__ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
__ bind(&miss); __ bind(&miss);
GenerateMiss(masm); GenerateMiss(masm);
......
...@@ -195,3 +195,43 @@ for (var i = 0; i < 300; ++i) { ...@@ -195,3 +195,43 @@ for (var i = 0; i < 300; ++i) {
var actual = str[key]; var actual = str[key];
assertEquals(expected, actual); assertEquals(expected, actual);
} }
// Test heap number case.
var keys = [0, Math.floor(2) * 0.5];
var str = 'ab', arr = ['a', 'b'];
for (var i = 0; i < 100; ++i) {
var index = Math.floor(i / 50);
var key = keys[index];
var expected = arr[index];
var actual = str[key];
assertEquals(expected, actual);
}
// Test out of range case.
var keys = [0, -1];
var str = 'ab', arr = ['a', undefined];
for (var i = 0; i < 100; ++i) {
var index = Math.floor(i / 50);
var key = keys[index];
var expected = arr[index];
var actual = str[key];
assertEquals(expected, actual);
}
var keys = [0, 10];
var str = 'ab', arr = ['a', undefined];
for (var i = 0; i < 100; ++i) {
var index = Math.floor(i / 50);
var key = keys[index];
var expected = arr[index];
var actual = str[key];
assertEquals(expected, actual);
}
// Test two byte string.
var str = '\u0427', arr = ['\u0427'];
for (var i = 0; i < 50; ++i) {
var expected = arr[0];
var actual = str[0];
assertEquals(expected, actual);
}
\ No newline at end of file
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