Ported SubStringStub to X64.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3683 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2010-01-25 08:55:08 +00:00
parent 4f087f279d
commit 76774115c0
7 changed files with 339 additions and 17 deletions

View File

@ -1537,6 +1537,40 @@ void Assembler::movzxwl(Register dst, const Operand& src) {
}
void Assembler::repmovsb() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0xF3);
emit(0xA4);
}
void Assembler::repmovsw() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66); // Operand size override.
emit(0xF3);
emit(0xA4);
}
void Assembler::repmovsl() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0xF3);
emit(0xA5);
}
void Assembler::repmovsq() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0xF3);
emit_rex_64();
emit(0xA5);
}
void Assembler::mul(Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;

View File

@ -574,6 +574,13 @@ class Assembler : public Malloced {
void movzxwq(Register dst, const Operand& src);
void movzxwl(Register dst, const Operand& src);
// Repeated moves.
void repmovsb();
void repmovsw();
void repmovsl();
void repmovsq();
// New x64 instruction to load from an immediate 64-bit pointer into RAX.
void load_rax(void* ptr, RelocInfo::Mode rmode);
void load_rax(ExternalReference ext);

View File

@ -3942,7 +3942,8 @@ void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) {
Load(args->at(1));
Load(args->at(2));
Result answer = frame_->CallRuntime(Runtime::kSubString, 3);
SubStringStub stub;
Result answer = frame_->CallStub(&stub, 3);
frame_->Push(&answer);
}
@ -8138,11 +8139,11 @@ void StringAddStub::Generate(MacroAssembler* masm) {
}
void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
bool ascii) {
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
bool ascii) {
Label loop;
__ bind(&loop);
// This loop just copies one character at a time, as it is only used for very
@ -8163,6 +8164,174 @@ void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
}
void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm,
Register dest,
Register src,
Register count,
bool ascii) {
// Copy characters using rep movs of doublewords. Align destination on 4 byte
// boundary before starting rep movs. Copy remaining characters after running
// rep movs.
ASSERT(dest.is(rdi)); // rep movs destination
ASSERT(src.is(rsi)); // rep movs source
ASSERT(count.is(rcx)); // rep movs count
// Nothing to do for zero characters.
Label done;
__ testq(count, count);
__ j(zero, &done);
// Make count the number of bytes to copy.
if (!ascii) {
ASSERT_EQ(2, sizeof(uc16)); // NOLINT
__ addq(count, count);
}
// Don't enter the rep movs if there are less than 4 bytes to copy.
Label last_bytes;
__ testq(count, Immediate(~7));
__ j(zero, &last_bytes);
// Copy from edi to esi using rep movs instruction.
__ movq(kScratchRegister, count);
__ sar(count, Immediate(3)); // Number of doublewords to copy.
__ repmovsq();
// Find number of bytes left.
__ movq(count, kScratchRegister);
__ and_(count, Immediate(7));
// Check if there are more bytes to copy.
__ bind(&last_bytes);
__ testq(count, count);
__ j(zero, &done);
// Copy remaining characters.
Label loop;
__ bind(&loop);
__ movb(kScratchRegister, Operand(src, 0));
__ movb(Operand(dest, 0), kScratchRegister);
__ addq(src, Immediate(1));
__ addq(dest, Immediate(1));
__ subq(count, Immediate(1));
__ j(not_zero, &loop);
__ bind(&done);
}
void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime;
// Stack frame on entry.
// rsp[0]: return address
// rsp[8]: to
// rsp[16]: from
// rsp[24]: string
const int kToOffset = 1 * kPointerSize;
const int kFromOffset = kToOffset + kPointerSize;
const int kStringOffset = kFromOffset + kPointerSize;
const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset;
// Make sure first argument is a string.
__ movq(rax, Operand(rsp, kStringOffset));
ASSERT_EQ(0, kSmiTag);
__ testl(rax, Immediate(kSmiTagMask));
__ j(zero, &runtime);
Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
__ j(NegateCondition(is_string), &runtime);
// rax: string
// rbx: instance type
// Calculate length of sub string using the smi values.
__ movq(rcx, Operand(rsp, kToOffset));
__ movq(rdx, Operand(rsp, kFromOffset));
__ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime);
__ SmiSub(rcx, rcx, rdx, NULL); // Overflow doesn't happen.
__ j(negative, &runtime);
// Handle sub-strings of length 2 and less in the runtime system.
__ SmiToInteger32(rcx, rcx);
__ cmpl(rcx, Immediate(2));
__ j(below_equal, &runtime);
// rax: string
// rbx: instance type
// rcx: result string length
// Check for flat ascii string
Label non_ascii_flat;
__ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask));
__ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag));
__ j(not_equal, &non_ascii_flat);
// Allocate the result.
__ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
// rax: result string
// rcx: result string length
__ movq(rdx, rsi); // esi used by following code.
// Locate first character of result.
__ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize));
// Load string argument and locate character of sub string start.
__ movq(rsi, Operand(rsp, kStringOffset));
__ movq(rbx, Operand(rsp, kFromOffset));
{
SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1);
__ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
SeqAsciiString::kHeaderSize - kHeapObjectTag));
}
// rax: result string
// rcx: result length
// rdx: original value of rsi
// rdi: first character of result
// rsi: character of sub string start
GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true);
__ movq(rsi, rdx); // Restore rsi.
__ IncrementCounter(&Counters::sub_string_native, 1);
__ ret(kArgumentsSize);
__ bind(&non_ascii_flat);
// rax: string
// rbx: instance type & kStringRepresentationMask | kStringEncodingMask
// rcx: result string length
// Check for sequential two byte string
__ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag));
__ j(not_equal, &runtime);
// Allocate the result.
__ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime);
// rax: result string
// rcx: result string length
__ movq(rdx, rsi); // esi used by following code.
// Locate first character of result.
__ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
// Load string argument and locate character of sub string start.
__ movq(rsi, Operand(rsp, kStringOffset));
__ movq(rbx, Operand(rsp, kFromOffset));
{
SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2);
__ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
SeqAsciiString::kHeaderSize - kHeapObjectTag));
}
// rax: result string
// rcx: result length
// rdx: original value of rsi
// rdi: first character of result
// rsi: character of sub string start
GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false);
__ movq(rsi, rdx); // Restore esi.
__ IncrementCounter(&Counters::sub_string_native, 1);
__ ret(kArgumentsSize);
// Just jump to runtime to create the sub string.
__ bind(&runtime);
__ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
}
void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
Register left,

View File

@ -713,6 +713,29 @@ 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 GenerateCopyCharactersREP adds too much
// overhead. Copying of overlapping regions is not supported.
void GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
bool ascii);
// 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,
Register dest, // Must be rdi.
Register src, // Must be rsi.
Register count, // Must be rcx.
bool ascii);
};
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
NO_STRING_ADD_FLAGS = 0,
@ -720,7 +743,7 @@ enum StringAddFlags {
};
class StringAddStub: public CodeStub {
class StringAddStub: public StringStubBase {
public:
explicit StringAddStub(StringAddFlags flags) {
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
@ -732,17 +755,23 @@ class StringAddStub: public CodeStub {
void Generate(MacroAssembler* masm);
void GenerateCopyCharacters(MacroAssembler* masm,
Register desc,
Register src,
Register count,
bool ascii);
// Should the stub check whether arguments are strings?
bool string_check_;
};
class SubStringStub: public StringStubBase {
public:
SubStringStub() {}
private:
Major MajorKey() { return SubString; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
};
class StringCompareStub: public CodeStub {
public:
explicit StringCompareStub() {}

View File

@ -114,6 +114,10 @@ static ByteMnemonic zero_operands_instr[] = {
{ 0x9E, UNSET_OP_ORDER, "sahf" },
{ 0x99, UNSET_OP_ORDER, "cdq" },
{ 0x9B, UNSET_OP_ORDER, "fwait" },
{ 0xA4, UNSET_OP_ORDER, "movs" },
{ 0xA5, UNSET_OP_ORDER, "movs" },
{ 0xA6, UNSET_OP_ORDER, "cmps" },
{ 0xA7, UNSET_OP_ORDER, "cmps" },
{ -1, UNSET_OP_ORDER, "" }
};
@ -157,6 +161,16 @@ enum InstructionType {
};
enum Prefixes {
ESCAPE_PREFIX = 0x0F,
OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
REPNE_PREFIX = 0xF2,
REP_PREFIX = 0xF3,
REPEQ_PREFIX = REP_PREFIX
};
struct InstructionDesc {
const char* mnem;
InstructionType type;
@ -1128,12 +1142,12 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
// Scan for prefixes.
while (true) {
current = *data;
if (current == 0x66) { // Group 3 prefix.
if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
operand_size_ = current;
} else if ((current & 0xF0) == 0x40) { // REX prefix.
setRex(current);
if (rex_w()) AppendToBuffer("REX.W ");
} else if ((current & 0xFE) == 0xF2) { // Group 1 prefix.
} else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
group_1_prefix_ = current;
} else { // Not a prefix - an opcode.
break;
@ -1145,7 +1159,17 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
byte_size_operand_ = idesc.byte_size_operation;
switch (idesc.type) {
case ZERO_OPERANDS_INSTR:
AppendToBuffer(idesc.mnem);
if (current >= 0xA4 && current <= 0xA7) {
// String move or compare operations.
if (group_1_prefix_ == REP_PREFIX) {
// REP.
AppendToBuffer("rep ");
}
if (rex_w()) AppendToBuffer("REX.W ");
AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
} else {
AppendToBuffer("%s", idesc.mnem, operand_size_code());
}
data++;
break;

View File

@ -581,6 +581,20 @@ Condition MacroAssembler::CheckBothSmi(Register first, Register second) {
}
Condition MacroAssembler::CheckBothPositiveSmi(Register first,
Register second) {
if (first.is(second)) {
return CheckPositiveSmi(first);
}
movl(kScratchRegister, first);
orl(kScratchRegister, second);
rol(kScratchRegister, Immediate(1));
testl(kScratchRegister, Immediate(0x03));
return zero;
}
Condition MacroAssembler::CheckEitherSmi(Register first, Register second) {
if (first.is(second)) {
return CheckSmi(first);
@ -660,7 +674,17 @@ void MacroAssembler::SmiSub(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 (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);
@ -1292,6 +1316,14 @@ void MacroAssembler::JumpIfNotBothSmi(Register src1, Register src2,
}
void MacroAssembler::JumpIfNotBothPositiveSmi(Register src1, Register src2,
Label* on_not_both_smi) {
Condition both_smi = CheckBothPositiveSmi(src1, src2);
j(NegateCondition(both_smi), on_not_both_smi);
}
void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
Register second_object,
Register scratch1,
@ -1517,6 +1549,17 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
}
Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register map,
Register instance_type) {
movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
movzxbq(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0);
testb(instance_type, Immediate(kIsNotStringMask));
return zero;
}
void MacroAssembler::TryGetFunctionPrototype(Register function,
Register result,
Label* miss) {

View File

@ -207,6 +207,9 @@ class MacroAssembler: public Assembler {
// Are both values tagged smis.
Condition CheckBothSmi(Register first, Register second);
// Are both values tagged smis.
Condition CheckBothPositiveSmi(Register first, Register second);
// Are either value a tagged smi.
Condition CheckEitherSmi(Register first, Register second);
@ -248,6 +251,10 @@ class MacroAssembler: public Assembler {
// Jump if either or both register are not smi values.
void JumpIfNotBothSmi(Register src1, Register src2, Label* on_not_both_smi);
// Jump if either or both register are not positive smi values.
void JumpIfNotBothPositiveSmi(Register src1, Register src2,
Label* on_not_both_smi);
// Operations on tagged smi values.
// Smis represent a subset of integers. The subset is always equivalent to
@ -452,6 +459,15 @@ class MacroAssembler: public Assembler {
// Always use unsigned comparisons: above and below, not less and greater.
void CmpInstanceType(Register map, InstanceType type);
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the
// same in which case it contains the instance type afterwards. Either of the
// registers map and instance_type can be the same as heap_object.
Condition IsObjectStringType(Register heap_object,
Register map,
Register instance_type);
// FCmp is similar to integer cmp, but requires unsigned
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp();