Commit 16d3811d authored by serya@chromium.org's avatar serya@chromium.org

Changing string length field type from int to SMI. It will make it be a...

Changing string length field  type from int to SMI. It will make it be a regular field. Code generated in EmitNamedLoad could be patched for faster access to string.length.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4581 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3e54b5cb
......@@ -3014,7 +3014,7 @@ template <> struct InternalConstants<4> {
// Internal constants for 64-bit systems.
template <> struct InternalConstants<8> {
static const int kStringResourceOffset = 2 * sizeof(void*);
static const int kStringResourceOffset = 3 * sizeof(void*);
};
/**
......
......@@ -8498,14 +8498,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ ldr(r3, FieldMemOperand(subject, String::kLengthOffset));
// r2: Number of capture registers
// r3: Length of subject string
// r3: Length of subject string as a smi
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
// Check that the third argument is a positive smi less than the subject
// string length. A negative value will be greater (unsigned comparison).
__ ldr(r0, MemOperand(sp, kPreviousIndexOffset));
__ cmp(r3, Operand(r0, ASR, kSmiTagSize + kSmiShiftSize));
__ b(ls, &runtime);
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &runtime);
__ cmp(r3, Operand(r0));
__ b(le, &runtime);
// r2: Number of capture registers
// subject: Subject string
......@@ -8631,6 +8633,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// For arguments 4 and 3 get string length, calculate start of string data and
// calculate the shift of the index (0 for ASCII and 1 for two byte).
__ ldr(r0, FieldMemOperand(subject, String::kLengthOffset));
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
ASSERT_EQ(SeqAsciiString::kHeaderSize, SeqTwoByteString::kHeaderSize);
__ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
__ eor(r3, r3, Operand(1));
......@@ -8890,7 +8893,7 @@ void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
// 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));
__ cmp(scratch, Operand(index));
__ b(ls, index_out_of_range);
__ bind(&try_again_with_new_string);
......@@ -9277,7 +9280,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
// If length is not 2 the string is not a candidate.
__ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
__ cmp(scratch, Operand(2));
__ cmp(scratch, Operand(Smi::FromInt(2)));
__ b(ne, &next_probe[i]);
// Check that the candidate is a non-external ascii string.
......@@ -9428,7 +9431,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r6: from (smi)
// r7: to (smi)
__ ldr(r4, FieldMemOperand(r5, String::kLengthOffset));
__ cmp(r4, Operand(r7, ASR, 1));
__ cmp(r4, Operand(r7));
__ b(lt, &runtime); // Fail if to > length.
// r1: instance type.
......@@ -9547,9 +9550,13 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
Register length_delta = scratch3;
__ mov(scratch1, scratch2, LeaveCC, gt);
Register min_length = scratch1;
ASSERT(kSmiTag == 0);
__ tst(min_length, Operand(min_length));
__ b(eq, &compare_lengths);
// Untag smi.
__ mov(min_length, Operand(min_length, ASR, kSmiTagSize));
// Setup registers so that we only need to increment one register
// in the loop.
__ add(scratch2, min_length,
......@@ -9659,9 +9666,12 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// Check if either of the strings are empty. In that case return the other.
__ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
__ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
__ cmp(r2, Operand(0)); // Test if first string is empty.
ASSERT(kSmiTag == 0);
__ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty.
__ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
__ cmp(r3, Operand(0), ne); // Else test if second string is empty.
ASSERT(kSmiTag == 0);
// Else test if second string is empty.
__ cmp(r3, Operand(Smi::FromInt(0)), ne);
__ b(ne, &strings_not_empty); // If either string was empty, return r0.
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
......@@ -9671,6 +9681,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ bind(&strings_not_empty);
}
__ mov(r2, Operand(r2, ASR, kSmiTagSize));
__ mov(r3, Operand(r3, ASR, kSmiTagSize));
// Both strings are non-empty.
// r0: first string
// r1: second string
......
......@@ -424,6 +424,20 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
}
void MacroAssembler::InitializeNewString(Register string,
Register length,
Heap::RootListIndex map_index,
Register scratch1,
Register scratch2) {
mov(scratch1, Operand(length, LSL, kSmiTagSize));
LoadRoot(scratch2, map_index);
str(scratch1, FieldMemOperand(string, String::kLengthOffset));
mov(scratch1, Operand(String::kEmptyHashField));
str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
str(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
}
int MacroAssembler::ActivationFrameAlignment() {
#if defined(V8_HOST_ARCH_ARM)
// Running on the real platform. Use the alignment as mandated by the local
......@@ -1054,11 +1068,11 @@ void MacroAssembler::AllocateTwoByteString(Register result,
TAG_OBJECT);
// Set the map, length and hash field.
LoadRoot(scratch1, Heap::kStringMapRootIndex);
str(length, FieldMemOperand(result, String::kLengthOffset));
str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
mov(scratch2, Operand(String::kEmptyHashField));
str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
InitializeNewString(result,
length,
Heap::kStringMapRootIndex,
scratch1,
scratch2);
}
......@@ -1088,12 +1102,11 @@ void MacroAssembler::AllocateAsciiString(Register result,
TAG_OBJECT);
// Set the map, length and hash field.
LoadRoot(scratch1, Heap::kAsciiStringMapRootIndex);
mov(scratch1, Operand(Factory::ascii_string_map()));
str(length, FieldMemOperand(result, String::kLengthOffset));
str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
mov(scratch2, Operand(String::kEmptyHashField));
str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
InitializeNewString(result,
length,
Heap::kAsciiStringMapRootIndex,
scratch1,
scratch2);
}
......@@ -1108,11 +1121,12 @@ void MacroAssembler::AllocateTwoByteConsString(Register result,
scratch2,
gc_required,
TAG_OBJECT);
LoadRoot(scratch1, Heap::kConsStringMapRootIndex);
mov(scratch2, Operand(String::kEmptyHashField));
str(length, FieldMemOperand(result, String::kLengthOffset));
str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
InitializeNewString(result,
length,
Heap::kConsStringMapRootIndex,
scratch1,
scratch2);
}
......@@ -1127,11 +1141,12 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
scratch2,
gc_required,
TAG_OBJECT);
LoadRoot(scratch1, Heap::kConsAsciiStringMapRootIndex);
mov(scratch2, Operand(String::kEmptyHashField));
str(length, FieldMemOperand(result, String::kLengthOffset));
str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
InitializeNewString(result,
length,
Heap::kConsAsciiStringMapRootIndex,
scratch1,
scratch2);
}
......
......@@ -572,6 +572,12 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
void InitializeNewString(Register string,
Register length,
Heap::RootListIndex map_index,
Register scratch1,
Register scratch2);
bool generating_stub_;
bool allow_stub_calls_;
// This handle will be patched with the code object on installation.
......
......@@ -229,7 +229,6 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ Ret();
// Check if the object is a JSValue wrapper.
......@@ -241,7 +240,6 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
__ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
__ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ Ret();
}
......
This diff is collapsed.
......@@ -910,7 +910,9 @@ void MacroAssembler::AllocateTwoByteString(Register result,
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::string_map()));
mov(FieldOperand(result, String::kLengthOffset), length);
mov(scratch1, length);
SmiTag(scratch1);
mov(FieldOperand(result, String::kLengthOffset), scratch1);
mov(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
......@@ -943,7 +945,9 @@ void MacroAssembler::AllocateAsciiString(Register result,
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::ascii_string_map()));
mov(FieldOperand(result, String::kLengthOffset), length);
mov(scratch1, length);
SmiTag(scratch1);
mov(FieldOperand(result, String::kLengthOffset), scratch1);
mov(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
......
......@@ -221,7 +221,6 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// Load length from the string and convert to a smi.
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
__ SmiTag(eax);
__ ret(0);
// Check if the object is a JSValue wrapper.
......@@ -234,7 +233,6 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
__ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
__ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
__ SmiTag(eax);
__ ret(0);
}
......
......@@ -1651,7 +1651,7 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
INT_ACCESSORS(Array, length, kLengthOffset)
INT_ACCESSORS(String, length, kLengthOffset)
SMI_ACCESSORS(String, length, kLengthOffset)
uint32_t String::hash_field() {
......@@ -1773,14 +1773,12 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
return SizeFor(length);
return SizeFor(length());
}
int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
return SizeFor(length);
return SizeFor(length());
}
......
......@@ -4077,7 +4077,7 @@ class String: public HeapObject {
// Layout description.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kHashFieldOffset = kLengthOffset + kIntSize;
static const int kHashFieldOffset = kLengthOffset + kPointerSize;
static const int kSize = kHashFieldOffset + kIntSize;
// Notice: kSize is not pointer-size aligned if pointers are 64-bit.
......
This diff is collapsed.
......@@ -596,6 +596,11 @@ void MacroAssembler::SmiCompare(Register dst, Smi* src) {
}
void MacroAssembler::SmiCompare(Register dst, const Operand& src) {
cmpq(dst, src);
}
void MacroAssembler::SmiCompare(const Operand& dst, Register src) {
cmpq(dst, src);
}
......@@ -731,7 +736,17 @@ void MacroAssembler::SmiAdd(Register dst,
Register src2,
Label* on_not_smi_result) {
ASSERT(!dst.is(src2));
if (dst.is(src1)) {
if (on_not_smi_result == NULL) {
// No overflow checking. Use only when it's known that
// overflowing is impossible.
if (dst.is(src1)) {
addq(dst, src2);
} else {
movq(dst, src1);
addq(dst, src2);
}
Assert(no_overflow, "Smi addition onverflow");
} else if (dst.is(src1)) {
addq(dst, src2);
Label smi_result;
j(no_overflow, &smi_result);
......@@ -778,6 +793,35 @@ void MacroAssembler::SmiSub(Register dst,
}
void MacroAssembler::SmiSub(Register dst,
Register src1,
Operand const& src2,
Label* on_not_smi_result) {
if (on_not_smi_result == NULL) {
// No overflow checking. Use only when it's known that
// overflowing is impossible (e.g., subtracting two positive smis).
if (dst.is(src1)) {
subq(dst, src2);
} else {
movq(dst, src1);
subq(dst, src2);
}
Assert(no_overflow, "Smi substraction onverflow");
} else if (dst.is(src1)) {
subq(dst, src2);
Label smi_result;
j(no_overflow, &smi_result);
// Restore src1.
addq(src1, src2);
jmp(on_not_smi_result);
bind(&smi_result);
} else {
movq(dst, src1);
subq(dst, src2);
j(overflow, on_not_smi_result);
}
}
void MacroAssembler::SmiMul(Register dst,
Register src1,
Register src2,
......@@ -2526,11 +2570,16 @@ void MacroAssembler::AllocateTwoByteString(Register result,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
const int kHeaderAlignment = SeqTwoByteString::kHeaderSize &
kObjectAlignmentMask;
ASSERT(kShortSize == 2);
// scratch1 = length * 2 + kObjectAlignmentMask.
lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask +
kHeaderAlignment));
and_(scratch1, Immediate(~kObjectAlignmentMask));
if (kHeaderAlignment > 0) {
subq(scratch1, Immediate(kHeaderAlignment));
}
// Allocate two byte string in new space.
AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
......@@ -2545,7 +2594,8 @@ void MacroAssembler::AllocateTwoByteString(Register result,
// Set the map, length and hash field.
LoadRoot(kScratchRegister, Heap::kStringMapRootIndex);
movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
movl(FieldOperand(result, String::kLengthOffset), length);
Integer32ToSmi(scratch1, length);
movq(FieldOperand(result, String::kLengthOffset), scratch1);
movl(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
......@@ -2559,11 +2609,15 @@ void MacroAssembler::AllocateAsciiString(Register result,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
const int kHeaderAlignment = SeqAsciiString::kHeaderSize &
kObjectAlignmentMask;
movl(scratch1, length);
ASSERT(kCharSize == 1);
addq(scratch1, Immediate(kObjectAlignmentMask));
addq(scratch1, Immediate(kObjectAlignmentMask + kHeaderAlignment));
and_(scratch1, Immediate(~kObjectAlignmentMask));
if (kHeaderAlignment > 0) {
subq(scratch1, Immediate(kHeaderAlignment));
}
// Allocate ascii string in new space.
AllocateInNewSpace(SeqAsciiString::kHeaderSize,
......@@ -2578,7 +2632,8 @@ void MacroAssembler::AllocateAsciiString(Register result,
// Set the map, length and hash field.
LoadRoot(kScratchRegister, Heap::kAsciiStringMapRootIndex);
movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
movl(FieldOperand(result, String::kLengthOffset), length);
Integer32ToSmi(scratch1, length);
movq(FieldOperand(result, String::kLengthOffset), scratch1);
movl(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
......
......@@ -211,6 +211,7 @@ class MacroAssembler: public Assembler {
// Simple comparison of smis.
void SmiCompare(Register dst, Register src);
void SmiCompare(Register dst, Smi* src);
void SmiCompare(Register dst, const Operand& src);
void SmiCompare(const Operand& dst, Register src);
void SmiCompare(const Operand& dst, Smi* src);
// Sets sign and zero flags depending on value of smi in register.
......@@ -301,7 +302,8 @@ class MacroAssembler: public Assembler {
Label* on_not_smi_result);
// Subtract an integer constant from a tagged smi, giving a tagged smi as
// result. No testing on the result is done.
// result. No testing on the result is done. Sets the N and Z flags
// based on the value of the resulting integer.
void SmiSubConstant(Register dst, Register src, Smi* constant);
// Subtract an integer constant from a tagged smi, giving a tagged smi as
......@@ -333,6 +335,11 @@ class MacroAssembler: public Assembler {
Register src2,
Label* on_not_smi_result);
void SmiSub(Register dst,
Register src1,
Operand const& src2,
Label* on_not_smi_result);
// Multiplies smi values and return the result as a smi,
// if possible.
// If dst is src1, then src1 will be destroyed, even if
......
......@@ -327,8 +327,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length directly from the string.
__ movl(rax, FieldOperand(receiver, String::kLengthOffset));
__ Integer32ToSmi(rax, rax);
__ movq(rax, FieldOperand(receiver, String::kLengthOffset));
__ ret(0);
// Check if the object is a JSValue wrapper.
......@@ -340,8 +339,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// directly if it is.
__ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
__ movl(rax, FieldOperand(scratch2, String::kLengthOffset));
__ Integer32ToSmi(rax, rax);
__ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
__ ret(0);
}
......
......@@ -573,7 +573,8 @@ TEST(LinearAllocation) {
FixedArray::kHeaderSize + kSmallFixedArrayLength * kPointerSize;
const int kSmallStringLength = 16;
const int kSmallStringSize =
SeqAsciiString::kHeaderSize + kSmallStringLength;
(SeqAsciiString::kHeaderSize + kSmallStringLength +
kObjectAlignmentMask) & ~kObjectAlignmentMask;
const int kMapSize = Map::kSize;
Object* new_last = NULL;
......
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