parent 62e8d5a7
......@@ -5950,6 +5950,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
result.reg(),
&slow_case,
&slow_case,
&slow_case,
&slow_case);
__ jmp(&exit);
......@@ -12048,7 +12049,8 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
Register scratch,
Register result,
Label* receiver_not_string,
Label* index_not_positive_smi,
Label* index_not_smi,
Label* index_out_of_range,
Label* slow_case) {
Label not_a_flat_string;
Label try_again_with_new_string;
......@@ -12067,11 +12069,10 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
__ test(result, Immediate(kIsNotStringMask));
__ j(not_zero, receiver_not_string);
// If the index is negative or non-smi trigger the non-positive-smi
// case.
// If the index is non-smi trigger the non-smi case.
ASSERT(kSmiTag == 0);
__ test(index, Immediate(kSmiTagMask | kSmiSignMask));
__ j(not_zero, index_not_positive_smi);
__ test(index, Immediate(kSmiTagMask));
__ j(not_zero, index_not_smi);
// Put untagged index into scratch register.
__ mov(scratch, index);
......@@ -12079,13 +12080,13 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
// Check for index out of range.
__ cmp(scratch, FieldOperand(object, String::kLengthOffset));
__ j(greater_equal, slow_case);
__ j(above_equal, index_out_of_range);
__ bind(&try_again_with_new_string);
// ----------- S t a t e -------------
// -- object : string to access
// -- result : instance type of the string
// -- scratch : positive smi index < length
// -- scratch : non-negative index < length
// -----------------------------------
// We need special handling for non-flat strings.
......@@ -12099,7 +12100,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
__ j(not_zero, &ascii_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,
scratch, times_2,
SeqTwoByteString::kHeaderSize));
......@@ -12127,7 +12128,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
// ASCII string.
__ bind(&ascii_string);
// Load the byte into the temp register.
// Load the byte into the result register.
__ movzx_b(result, FieldOperand(object,
scratch, times_1,
SeqAsciiString::kHeaderSize));
......
......@@ -886,14 +886,15 @@ class GenericBinaryOpStub: public CodeStub {
class StringHelper : public AllStatic {
public:
// 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):
// * 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
// 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 positive smi.
// 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,
......@@ -902,7 +903,8 @@ class StringHelper : public AllStatic {
Register scratch,
Register result,
Label* receiver_not_string,
Label* index_not_positive_smi,
Label* index_not_smi,
Label* index_out_of_range,
Label* slow_case);
// Generates code for creating a one-char string from the given char
......
......@@ -496,7 +496,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- esp[0] : return address
// -----------------------------------
Label miss;
Label not_positive_smi;
Label index_not_smi;
Label index_out_of_range;
Label slow_char_code;
Label got_char_code;
......@@ -511,7 +512,8 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
scratch,
code,
&miss, // When not a string.
&not_positive_smi,
&index_not_smi,
&index_out_of_range,
&slow_char_code);
// If we didn't bail out, code register contains smi tagged char
// code.
......@@ -521,14 +523,9 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
__ Abort("Unexpected fall-through from char from code tail call");
#endif
// Check if key is a smi or a heap number.
__ bind(&not_positive_smi);
ASSERT(kSmiTag == 0);
__ 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);
// Check if key is a heap number.
__ bind(&index_not_smi);
__ CheckMap(index, Factory::heap_number_map(), &miss, true);
// Push receiver and key on the stack (now that we know they are a
// string and a number), and call runtime.
......@@ -553,6 +550,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
}
__ cmp(code, Factory::nan_value());
__ j(not_equal, &got_char_code);
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::undefined_value()));
__ ret(0);
......
This diff is collapsed.
......@@ -816,14 +816,45 @@ class GenericBinaryOpStub: public CodeStub {
}
};
class StringStubBase: public CodeStub {
class StringHelper : public AllStatic {
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
// be used in places where the number of characters is small and the
// additional setup and checking in GenerateCopyCharactersREP adds too much
// overhead. Copying of overlapping regions is not supported.
void GenerateCopyCharacters(MacroAssembler* masm,
static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
......@@ -832,7 +863,7 @@ class StringStubBase: public CodeStub {
// Generate code for copying characters using the rep movs instruction.
// Copies rcx characters from rsi to rdi. Copying of overlapping regions is
// not supported.
void GenerateCopyCharactersREP(MacroAssembler* masm,
static void GenerateCopyCharactersREP(MacroAssembler* masm,
Register dest, // Must be rdi.
Register src, // Must be rsi.
Register count, // Must be rcx.
......@@ -843,7 +874,7 @@ class StringStubBase: public CodeStub {
// 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
// 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 c2,
Register scratch1,
......@@ -853,17 +884,19 @@ class StringStubBase: public CodeStub {
Label* not_found);
// Generate string hash.
void GenerateHashInit(MacroAssembler* masm,
static void GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character,
Register scratch);
void GenerateHashAddCharacter(MacroAssembler* masm,
static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash,
Register character,
Register scratch);
void GenerateHashGetHash(MacroAssembler* masm,
static void GenerateHashGetHash(MacroAssembler* masm,
Register hash,
Register scratch);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
};
......@@ -874,7 +907,7 @@ enum StringAddFlags {
};
class StringAddStub: public StringStubBase {
class StringAddStub: public CodeStub {
public:
explicit StringAddStub(StringAddFlags flags) {
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
......@@ -891,7 +924,7 @@ class StringAddStub: public StringStubBase {
};
class SubStringStub: public StringStubBase {
class SubStringStub: public CodeStub {
public:
SubStringStub() {}
......
......@@ -523,30 +523,69 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- rsp[8] : name
// -- 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;
// Check that the receiver isn't a smi.
__ movq(rcx, Operand(rsp, 2 * kPointerSize));
__ JumpIfSmi(rcx, &miss);
Register receiver = rdx;
Register index = rax;
Register code = rbx;
Register scratch = rcx;
__ 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.
Condition is_string = masm->IsObjectStringType(rcx, rax, rbx);
__ j(NegateCondition(is_string), &miss);
// Push receiver and key on the stack (now that we know they are a
// string and a number), and call runtime.
__ 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.
__ movq(rax, Operand(rsp, kPointerSize));
__ JumpIfSmi(rax, &index_ok);
__ CheckMap(rax, Factory::heap_number_map(), &miss, false);
// Check if the runtime call returned NaN char code. If yes, return
// undefined. Otherwise, we can continue.
if (FLAG_debug_code) {
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);
// Duplicate receiver and key since they are expected on the stack after
// the KeyedLoadIC call.
__ pop(rbx); // return address
__ push(rcx); // receiver
__ push(rax); // key
__ push(rbx); // return address
__ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
__ bind(&index_out_of_range);
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
__ ret(0);
__ bind(&miss);
GenerateMiss(masm);
......
......@@ -195,3 +195,43 @@ for (var i = 0; i < 300; ++i) {
var actual = str[key];
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