Commit f0ef4d7b authored by lrn@chromium.org's avatar lrn@chromium.org

ARM: Implement native substring copying.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3793 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 14a64027
......@@ -83,9 +83,9 @@ Register r4 = { 4 };
Register r5 = { 5 };
Register r6 = { 6 };
Register r7 = { 7 };
Register r8 = { 8 };
Register r8 = { 8 }; // Used as context register.
Register r9 = { 9 };
Register r10 = { 10 };
Register r10 = { 10 }; // Used as roots register.
Register fp = { 11 };
Register ip = { 12 };
Register sp = { 13 };
......
......@@ -250,7 +250,7 @@ enum Coprocessor {
};
// Condition field in instructions
// Condition field in instructions.
enum Condition {
eq = 0 << 28, // Z set equal.
ne = 1 << 28, // Z clear not equal.
......
This diff is collapsed.
......@@ -531,6 +531,55 @@ class GenericBinaryOpStub : public CodeStub {
};
class StringStubBase: public CodeStub {
public:
// 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.
void GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
Register scratch,
bool ascii);
// Generate code for copying a large number of characters. This function
// is allowed to spend extra time setting up conditions to make copying
// faster. Copying of overlapping regions is not supported.
void GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest,
Register src,
Register count,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
Register scratch5,
int flags);
};
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
NO_STRING_ADD_FLAGS = 0,
NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub.
};
class SubStringStub: public StringStubBase {
public:
SubStringStub() {}
private:
Major MajorKey() { return SubString; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
};
class StringCompareStub: public CodeStub {
public:
StringCompareStub() { }
......
......@@ -196,7 +196,7 @@ void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
void MacroAssembler::LoadRoot(Register destination,
Heap::RootListIndex index,
Condition cond) {
ldr(destination, MemOperand(r10, index << kPointerSizeLog2), cond);
ldr(destination, MemOperand(roots, index << kPointerSizeLog2), cond);
}
......@@ -940,6 +940,75 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object,
}
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
mov(scratch1, Operand(length, LSL, 1)); // Length in bytes, not chars.
add(scratch1, scratch1,
Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
// AllocateInNewSpace expects the size in words, so we can round down
// to kObjectAlignment and divide by kPointerSize in the same shift.
ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
// Allocate two-byte string in new space.
AllocateInNewSpace(scratch1,
result,
scratch2,
scratch3,
gc_required,
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));
}
void MacroAssembler::AllocateAsciiString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
ASSERT(kCharSize == 1);
add(scratch1, length,
Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize));
// AllocateInNewSpace expects the size in words, so we can round down
// to kObjectAlignment and divide by kPointerSize in the same shift.
ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
// Allocate ASCII string in new space.
AllocateInNewSpace(scratch1,
result,
scratch2,
scratch3,
gc_required,
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));
}
void MacroAssembler::CompareObjectType(Register function,
Register map,
Register type_reg,
......
......@@ -33,10 +33,18 @@
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// Static helper functions
// Generate a MemOperand for loading a field from an object.
static inline MemOperand FieldMemOperand(Register object, int offset) {
return MemOperand(object, offset - kHeapObjectTag);
}
// Give alias names to registers
const Register cp = { 8 }; // JavaScript context pointer
const Register roots = { 10 }; // Roots array pointer.
enum InvokeJSFlags {
CALL_JS,
......@@ -209,6 +217,21 @@ class MacroAssembler: public Assembler {
// allocation is undone.
void UndoAllocationInNewSpace(Register object, Register scratch);
void AllocateTwoByteString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required);
void AllocateAsciiString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required);
// ---------------------------------------------------------------------------
// Support functions.
......@@ -243,6 +266,20 @@ class MacroAssembler: public Assembler {
Register type_reg,
InstanceType type);
// Load and check the instance type of an object for being a string.
// Loads the type into the second argument register.
// Returns a condition that will be enabled if the object was a string.
Condition IsObjectStringType(Register obj,
Register type) {
ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
tst(type, Operand(kIsNotStringMask));
ASSERT_EQ(0, kStringTag);
return eq;
}
inline void BranchOnSmi(Register value, Label* smi_label) {
tst(value, Operand(kSmiTagMask));
b(eq, smi_label);
......@@ -421,12 +458,6 @@ class CodePatcher {
// -----------------------------------------------------------------------------
// Static helper functions.
// Generate a MemOperand for loading a field from an object.
static inline MemOperand FieldMemOperand(Register object, int offset) {
return MemOperand(object, offset - kHeapObjectTag);
}
#ifdef GENERATED_CODE_COVERAGE
#define CODE_COVERAGE_STRINGIFY(x) #x
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
......
......@@ -1785,7 +1785,8 @@ void Simulator::DecodeType3(Instr* instr) {
uint8_t byte = ReadB(addr);
set_register(rd, byte);
} else {
UNIMPLEMENTED();
uint8_t byte = get_register(rd);
WriteB(addr, byte);
}
} else {
if (instr->HasL()) {
......
......@@ -9959,7 +9959,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
// Load string argument and locate character of sub string start.
__ mov(esi, Operand(esp, 3 * kPointerSize));
__ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
__ add(Operand(esi),
Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
__ mov(ebx, Operand(esp, 2 * kPointerSize)); // from
// As from is a smi it is 2 times the value which matches the size of a two
// byte character.
......
......@@ -63,7 +63,10 @@ SOURCES = {
'test-utils.cc',
'test-version.cc'
],
'arch:arm': ['test-assembler-arm.cc', 'test-disasm-arm.cc'],
'arch:arm': [
'test-assembler-arm.cc',
'test-disasm-arm.cc'
],
'arch:ia32': [
'test-assembler-ia32.cc',
'test-disasm-ia32.cc',
......
......@@ -44,9 +44,6 @@ assertEquals(s1, s.substr(1.1));
assertEquals(s1, s.substr({ valueOf: function() { return 1; } }));
assertEquals(s1, s.substr({ toString: function() { return '1'; } }));
for (var i = 0; i < s.length; i++)
for (var j = i; j < s.length + 5; j++)
assertEquals(s.substring(i, j), s.substr(i, j - i));
assertEquals(s.substring(s.length - 1), s.substr(-1));
assertEquals(s.substring(s.length - 1), s.substr(-1.2));
......@@ -63,3 +60,78 @@ assertEquals('abcdefghijklmn', s.substr(0, void 0)); // kjs and v8
assertEquals('', s.substr(0, null));
assertEquals(s, s.substr(0, String(s.length)));
assertEquals('a', s.substr(0, true));
// Test substrings of different lengths and alignments.
// First ASCII.
var x = "ASCII";
for (var i = 0; i < 25; i++) {
x += (i >> 4).toString(16) + (i & 0x0f).toString(16);
}
/x/.exec(x); // Try to force a flatten.
for (var i = 5; i < 25; i++) {
for (var j = 0; j < 25; j++) {
var z = x.substring(i, i+j);
var w = Math.random() * 42; // Allocate something new in new-space.
assertEquals(j, z.length);
for (var k = 0; k < j; k++) {
assertEquals(x.charAt(i+k), z.charAt(k));
}
}
}
// Then two-byte strings.
x = "UC16\u2028"; // Non-ascii char forces two-byte string.
for (var i = 0; i < 25; i++) {
x += (i >> 4).toString(16) + (i & 0x0f).toString(16);
}
/x/.exec(x); // Try to force a flatten.
for (var i = 5; i < 25; i++) {
for (var j = 0; j < 25; j++) {
var z = x.substring(i, i + j);
var w = Math.random() * 42; // Allocate something new in new-space.
assertEquals(j, z.length);
for (var k = 0; k < j; k++) {
assertEquals(x.charAt(i+k), z.charAt(k));
}
}
}
// 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;
var xl = x.length;
var cache = [];
for (var i = 0; i < 10000; i++) {
var z = x.substring(i % xl);
assertEquals(xl - (i % xl), z.length);
cache.push(z);
}
// 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;
var xl = x.length;
var cache = [];
for (var i = 0; i < 10000; i++) {
var z = x.substring(i % xl);
assertEquals(xl - (i % xl), z.length);
cache.push(z);
}
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