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:
parent
4f087f279d
commit
76774115c0
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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,7 +8139,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
|
||||
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
|
||||
Register dest,
|
||||
Register src,
|
||||
Register count,
|
||||
@ -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,
|
||||
|
@ -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() {}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,8 +674,18 @@ void MacroAssembler::SmiSub(Register dst,
|
||||
Register src2,
|
||||
Label* on_not_smi_result) {
|
||||
ASSERT(!dst.is(src2));
|
||||
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.
|
||||
@ -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) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user