Port string keyed load IC improvements (r4444) to ARM.

Review URL: http://codereview.chromium.org/1769014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4573 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5affd79e
......@@ -3763,9 +3763,12 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
}
// This should generate code that performs a charCodeAt() call or returns
// This generates code that performs a charCodeAt() call or returns
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
// It is not yet implemented on ARM, so it always goes to the slow case.
// It can handle flat, 8 and 16 bit characters and cons strings where the
// answer is found in the left hand branch of the cons. The slow case will
// flatten the string, which will ensure that the answer is in the left hand
// side the next time around.
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope(frame_);
ASSERT(args->length() == 2);
......@@ -3773,75 +3776,28 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
LoadAndSpill(args->at(0));
LoadAndSpill(args->at(1));
frame_->EmitPop(r0); // Index.
frame_->EmitPop(r1); // String.
frame_->EmitPop(r1); // Index.
frame_->EmitPop(r2); // String.
Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string;
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &slow); // The 'string' was a Smi.
ASSERT(kSmiTag == 0);
__ tst(r0, Operand(kSmiTagMask | 0x80000000u));
__ b(ne, &slow); // The index was negative or not a Smi.
__ bind(&try_again_with_new_string);
__ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &slow);
// Now r2 has the string type.
__ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
// Now r3 has the length of the string. Compare with the index.
__ cmp(r3, Operand(r0, LSR, kSmiTagSize));
__ b(le, &slow);
// Here we know the index is in range. Check that string is sequential.
ASSERT_EQ(0, kSeqStringTag);
__ tst(r2, Operand(kStringRepresentationMask));
__ b(ne, &not_a_flat_string);
// Check whether it is an ASCII string.
ASSERT_EQ(0, kTwoByteStringTag);
__ tst(r2, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
// 2-byte string. We can add without shifting since the Smi tag size is the
// log2 of the number of bytes in a two-byte character.
ASSERT_EQ(1, kSmiTagSize);
ASSERT_EQ(0, kSmiShiftSize);
__ add(r1, r1, Operand(r0));
__ ldrh(r0, FieldMemOperand(r1, SeqTwoByteString::kHeaderSize));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ jmp(&end);
__ bind(&ascii_string);
__ add(r1, r1, Operand(r0, LSR, kSmiTagSize));
__ ldrb(r0, FieldMemOperand(r1, SeqAsciiString::kHeaderSize));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ jmp(&end);
__ bind(&not_a_flat_string);
__ and_(r2, r2, Operand(kStringRepresentationMask));
__ cmp(r2, Operand(kConsStringTag));
__ b(ne, &slow);
// ConsString.
// Check that the right hand side is the empty string (ie 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.
__ ldr(r2, FieldMemOperand(r1, ConsString::kSecondOffset));
__ LoadRoot(r3, Heap::kEmptyStringRootIndex);
__ cmp(r2, Operand(r3));
__ b(ne, &slow);
// Get the first of the two strings.
__ ldr(r1, FieldMemOperand(r1, ConsString::kFirstOffset));
__ jmp(&try_again_with_new_string);
Label slow_case;
Label exit;
StringHelper::GenerateFastCharCodeAt(masm_,
r2,
r1,
r3,
r0,
&slow_case,
&slow_case,
&slow_case,
&slow_case);
__ jmp(&exit);
__ bind(&slow);
__ bind(&slow_case);
// Move the undefined value into the result register, which will
// trigger the slow case.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ bind(&end);
__ bind(&exit);
frame_->EmitPush(r0);
}
......@@ -3850,37 +3806,19 @@ void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
Comment(masm_, "[ GenerateCharFromCode");
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0));
frame_->EmitPop(r0);
JumpTarget slow_case;
JumpTarget exit;
// Fast case of Heap::LookupSingleCharacterStringFromCode.
ASSERT(kSmiTag == 0);
ASSERT(kSmiShiftSize == 0);
ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
__ tst(r0, Operand(kSmiTagMask |
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
slow_case.Branch(nz);
ASSERT(kSmiTag == 0);
__ mov(r1, Operand(Factory::single_character_string_cache()));
__ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag));
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r1, ip);
slow_case.Branch(eq);
frame_->EmitPush(r1);
exit.Jump();
Register code = r1;
Register scratch = ip;
Register result = r0;
slow_case.Bind();
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kCharFromCode, 1);
frame_->EmitPush(r0);
LoadAndSpill(args->at(0));
frame_->EmitPop(code);
exit.Bind();
StringHelper::GenerateCharFromCode(masm_,
code,
scratch,
result,
CALL_FUNCTION);
frame_->EmitPush(result);
}
......@@ -8576,7 +8514,146 @@ int CompareStub::MinorKey() {
}
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
void StringHelper::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) {
Label not_a_flat_string;
Label try_again_with_new_string;
Label ascii_string;
Label got_char_code;
// If the receiver is a smi trigger the non-string case.
__ BranchOnSmi(object, receiver_not_string);
// Fetch the instance type of the receiver into result register.
__ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset));
__ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
// If the receiver is not a string trigger the non-string case.
__ tst(result, Operand(kIsNotStringMask));
__ b(ne, receiver_not_string);
// If the index is non-smi trigger the non-smi case.
__ BranchOnNotSmi(index, index_not_smi);
// Check for index out of range.
__ ldr(scratch, FieldMemOperand(object, String::kLengthOffset));
// Now scratch has the length of the string. Compare with the index.
__ cmp(scratch, Operand(index, LSR, kSmiTagSize));
__ b(ls, 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 : non-negative index < length
// -----------------------------------
// We need special handling for non-flat strings.
ASSERT_EQ(0, kSeqStringTag);
__ tst(result, Operand(kStringRepresentationMask));
__ b(ne, &not_a_flat_string);
// Check for 1-byte or 2-byte string.
ASSERT_EQ(0, kTwoByteStringTag);
__ tst(result, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
// 2-byte string. We can add without shifting since the Smi tag size is the
// log2 of the number of bytes in a two-byte character.
ASSERT_EQ(1, kSmiTagSize);
ASSERT_EQ(0, kSmiShiftSize);
__ add(scratch, object, Operand(index));
__ ldrh(result, FieldMemOperand(scratch, SeqTwoByteString::kHeaderSize));
__ jmp(&got_char_code);
// Handle non-flat strings.
__ bind(&not_a_flat_string);
__ and_(result, result, Operand(kStringRepresentationMask));
__ cmp(result, Operand(kConsStringTag));
__ b(ne, slow_case);
// 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.
__ ldr(result, FieldMemOperand(object, ConsString::kSecondOffset));
__ LoadRoot(scratch, Heap::kEmptyStringRootIndex);
__ cmp(result, Operand(scratch));
__ b(ne, slow_case);
// Get the first of the two strings and load its instance type.
__ ldr(object, FieldMemOperand(object, ConsString::kFirstOffset));
__ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset));
__ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
__ jmp(&try_again_with_new_string);
// ASCII string.
__ bind(&ascii_string);
__ add(scratch, object, Operand(index, LSR, kSmiTagSize));
__ ldrb(result, FieldMemOperand(scratch, SeqAsciiString::kHeaderSize));
__ bind(&got_char_code);
__ mov(result, Operand(result, LSL, kSmiTagSize));
}
void StringHelper::GenerateCharFromCode(MacroAssembler* masm,
Register code,
Register scratch,
Register result,
InvokeFlag flag) {
ASSERT(!code.is(result));
Label slow_case;
Label exit;
// Fast case of Heap::LookupSingleCharacterStringFromCode.
ASSERT(kSmiTag == 0);
ASSERT(kSmiShiftSize == 0);
ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
__ tst(code, Operand(kSmiTagMask |
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
__ b(nz, &slow_case);
ASSERT(kSmiTag == 0);
__ mov(result, Operand(Factory::single_character_string_cache()));
__ add(result, result, Operand(code, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(result, MemOperand(result, FixedArray::kHeaderSize - kHeapObjectTag));
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
__ cmp(result, scratch);
__ b(eq, &slow_case);
__ b(&exit);
__ bind(&slow_case);
if (flag == CALL_FUNCTION) {
__ push(code);
__ CallRuntime(Runtime::kCharFromCode, 1);
if (!result.is(r0)) {
__ mov(result, r0);
}
} else {
ASSERT(flag == JUMP_FUNCTION);
ASSERT(result.is(r0));
__ push(code);
__ TailCallRuntime(Runtime::kCharFromCode, 1, 1);
}
__ bind(&exit);
if (flag == JUMP_FUNCTION) {
ASSERT(result.is(r0));
__ Ret();
}
}
void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
......@@ -8612,7 +8689,7 @@ enum CopyCharactersFlags {
};
void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm,
void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest,
Register src,
Register count,
......@@ -8755,7 +8832,7 @@ void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm,
}
void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
......@@ -8785,9 +8862,9 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
__ bind(&not_array_index);
// Calculate the two character string hash.
Register hash = scratch1;
GenerateHashInit(masm, hash, c1);
GenerateHashAddCharacter(masm, hash, c2);
GenerateHashGetHash(masm, hash);
StringHelper::GenerateHashInit(masm, hash, c1);
StringHelper::GenerateHashAddCharacter(masm, hash, c2);
StringHelper::GenerateHashGetHash(masm, hash);
// Collect the two characters in a register.
Register chars = c1;
......@@ -8881,7 +8958,7 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
}
void StringStubBase::GenerateHashInit(MacroAssembler* masm,
void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character) {
// hash = character + (character << 10);
......@@ -8891,7 +8968,7 @@ void StringStubBase::GenerateHashInit(MacroAssembler* masm,
}
void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
Register hash,
Register character) {
// hash += character;
......@@ -8903,7 +8980,7 @@ void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
}
void StringStubBase::GenerateHashGetHash(MacroAssembler* masm,
void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
Register hash) {
// hash += hash << 3;
__ add(hash, hash, Operand(hash, LSL, 3));
......@@ -9031,8 +9108,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Try to lookup two character string in symbol table.
Label make_two_character_string;
GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9,
&make_two_character_string);
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
......@@ -9066,7 +9143,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r2: result string length.
// r5: first character of sub string to copy.
ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask);
GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
......@@ -9097,7 +9174,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r2: result length.
// r5: first character of string to copy.
ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask);
GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
DEST_ALWAYS_ALIGNED);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
......@@ -9282,8 +9359,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// Try to lookup two character string in symbol table. If it is not found
// just allocate a new one.
Label make_two_character_string;
GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9,
&make_two_character_string);
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string);
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
......@@ -9392,7 +9469,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string.
// r6: first character of result.
// r7: result string.
GenerateCopyCharacters(masm, r6, r0, r2, r4, true);
StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, true);
// Load second argument and locate first character.
__ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
......@@ -9400,7 +9477,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string.
// r6: next character of result.
// r7: result string.
GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
__ mov(r0, Operand(r7));
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
......@@ -9431,7 +9508,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string.
// r6: first character of result.
// r7: result string.
GenerateCopyCharacters(masm, r6, r0, r2, r4, false);
StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false);
// Locate first character of second argument.
__ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
......@@ -9440,7 +9517,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string.
// r6: next character of result (after copy of first string).
// r7: result string.
GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
__ mov(r0, Operand(r7));
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
......
......@@ -665,14 +665,46 @@ 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 r0 register.
static void GenerateCharFromCode(MacroAssembler* masm,
Register code,
Register scratch,
Register result,
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 GenerateCopyCharactersLong adds too much
// overhead. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written.
void GenerateCopyCharacters(MacroAssembler* masm,
static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
......@@ -683,7 +715,7 @@ class StringStubBase: public CodeStub {
// is allowed to spend extra time setting up conditions to make copying
// faster. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written.
void GenerateCopyCharactersLong(MacroAssembler* masm,
static void GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest,
Register src,
Register count,
......@@ -702,7 +734,7 @@ class StringStubBase: public CodeStub {
// Contents of both c1 and c2 registers are modified. At the exit c1 is
// guaranteed to contain halfword with low and high bytes equal to
// initial contents of c1 and c2 respectively.
void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
......@@ -713,16 +745,19 @@ class StringStubBase: public CodeStub {
Label* not_found);
// Generate string hash.
void GenerateHashInit(MacroAssembler* masm,
static void GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character);
void GenerateHashAddCharacter(MacroAssembler* masm,
static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash,
Register character);
void GenerateHashGetHash(MacroAssembler* masm,
static void GenerateHashGetHash(MacroAssembler* masm,
Register hash);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
};
......@@ -733,7 +768,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);
......@@ -750,7 +785,7 @@ class StringAddStub: public StringStubBase {
};
class SubStringStub: public StringStubBase {
class SubStringStub: public CodeStub {
public:
SubStringStub() {}
......
......@@ -800,28 +800,67 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- sp[0] : key
// -- sp[4] : receiver
// -----------------------------------
Label miss, index_ok;
Label miss;
Label index_not_smi;
Label index_out_of_range;
Label slow_char_code;
Label got_char_code;
// Get the key and receiver object from the stack.
__ ldm(ia, sp, r0.bit() | r1.bit());
// Check that the receiver isn't a smi.
__ BranchOnSmi(r1, &miss);
// Check that the receiver is a string.
Condition is_string = masm->IsObjectStringType(r1, r2);
__ b(NegateCondition(is_string), &miss);
Register object = r1;
Register index = r0;
Register code = r2;
Register scratch = r3;
// Check if key is a smi or a heap number.
__ BranchOnSmi(r0, &index_ok);
__ CheckMap(r0, r2, Factory::heap_number_map(), &miss, false);
StringHelper::GenerateFastCharCodeAt(masm,
object,
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, scratch, r0, 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);
__ CheckMap(index, scratch, 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.
__ bind(&slow_char_code);
__ EnterInternalFrame();
__ Push(object, index);
__ CallRuntime(Runtime::kStringCharCodeAt, 2);
ASSERT(!code.is(r0));
__ mov(code, r0);
__ LeaveInternalFrame();
__ bind(&index_ok);
// Duplicate receiver and key since they are expected on the stack after
// the KeyedLoadIC call.
__ Push(r1, r0);
__ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_JS);
// Check if the runtime call returned NaN char code. If yes, return
// undefined. Otherwise, we can continue.
if (FLAG_debug_code) {
__ BranchOnSmi(code, &got_char_code);
__ ldr(scratch, FieldMemOperand(code, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(scratch, ip);
__ Assert(eq, "StringCharCodeAt must return smi or heap number");
}
__ LoadRoot(scratch, Heap::kNanValueRootIndex);
__ cmp(code, scratch);
__ b(ne, &got_char_code);
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ Ret();
__ bind(&miss);
GenerateGeneric(masm);
......
......@@ -164,8 +164,7 @@ enum BuiltinExtraArguments {
V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1) \
V(STRING_CHAR_AT, 1)
V(APPLY_OVERFLOW, 1)
class ObjectVisitor;
......
......@@ -471,17 +471,6 @@ function TO_STRING() {
}
// Specialized version of String.charAt. It assumes string as
// the receiver type and that the index is a number.
function STRING_CHAR_AT(pos) {
var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) {
return %StringCharAt(this, pos);
}
return %_CharFromCode(char_code);
}
/* -------------------------------------
- - - C o n v e r s i o n s - - -
-------------------------------------
......
......@@ -913,6 +913,7 @@ class StringHelper : public AllStatic {
static void GenerateHashGetHash(MacroAssembler* masm,
Register hash,
Register scratch);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
};
......
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