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) {
|
void Assembler::mul(Register src) {
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
last_pc_ = pc_;
|
last_pc_ = pc_;
|
||||||
|
@ -574,6 +574,13 @@ class Assembler : public Malloced {
|
|||||||
void movzxwq(Register dst, const Operand& src);
|
void movzxwq(Register dst, const Operand& src);
|
||||||
void movzxwl(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.
|
// New x64 instruction to load from an immediate 64-bit pointer into RAX.
|
||||||
void load_rax(void* ptr, RelocInfo::Mode rmode);
|
void load_rax(void* ptr, RelocInfo::Mode rmode);
|
||||||
void load_rax(ExternalReference ext);
|
void load_rax(ExternalReference ext);
|
||||||
|
@ -3942,7 +3942,8 @@ void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) {
|
|||||||
Load(args->at(1));
|
Load(args->at(1));
|
||||||
Load(args->at(2));
|
Load(args->at(2));
|
||||||
|
|
||||||
Result answer = frame_->CallRuntime(Runtime::kSubString, 3);
|
SubStringStub stub;
|
||||||
|
Result answer = frame_->CallStub(&stub, 3);
|
||||||
frame_->Push(&answer);
|
frame_->Push(&answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8138,11 +8139,11 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
|
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
|
||||||
Register dest,
|
Register dest,
|
||||||
Register src,
|
Register src,
|
||||||
Register count,
|
Register count,
|
||||||
bool ascii) {
|
bool ascii) {
|
||||||
Label loop;
|
Label loop;
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
// This loop just copies one character at a time, as it is only used for very
|
// 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,
|
void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
||||||
Register left,
|
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.
|
// Flag that indicates how to generate code for the stub StringAddStub.
|
||||||
enum StringAddFlags {
|
enum StringAddFlags {
|
||||||
NO_STRING_ADD_FLAGS = 0,
|
NO_STRING_ADD_FLAGS = 0,
|
||||||
@ -720,7 +743,7 @@ enum StringAddFlags {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class StringAddStub: public CodeStub {
|
class StringAddStub: public StringStubBase {
|
||||||
public:
|
public:
|
||||||
explicit StringAddStub(StringAddFlags flags) {
|
explicit StringAddStub(StringAddFlags flags) {
|
||||||
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
|
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
|
||||||
@ -732,17 +755,23 @@ class StringAddStub: public CodeStub {
|
|||||||
|
|
||||||
void Generate(MacroAssembler* masm);
|
void Generate(MacroAssembler* masm);
|
||||||
|
|
||||||
void GenerateCopyCharacters(MacroAssembler* masm,
|
|
||||||
Register desc,
|
|
||||||
Register src,
|
|
||||||
Register count,
|
|
||||||
bool ascii);
|
|
||||||
|
|
||||||
// Should the stub check whether arguments are strings?
|
// Should the stub check whether arguments are strings?
|
||||||
bool string_check_;
|
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 {
|
class StringCompareStub: public CodeStub {
|
||||||
public:
|
public:
|
||||||
explicit StringCompareStub() {}
|
explicit StringCompareStub() {}
|
||||||
|
@ -114,6 +114,10 @@ static ByteMnemonic zero_operands_instr[] = {
|
|||||||
{ 0x9E, UNSET_OP_ORDER, "sahf" },
|
{ 0x9E, UNSET_OP_ORDER, "sahf" },
|
||||||
{ 0x99, UNSET_OP_ORDER, "cdq" },
|
{ 0x99, UNSET_OP_ORDER, "cdq" },
|
||||||
{ 0x9B, UNSET_OP_ORDER, "fwait" },
|
{ 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, "" }
|
{ -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 {
|
struct InstructionDesc {
|
||||||
const char* mnem;
|
const char* mnem;
|
||||||
InstructionType type;
|
InstructionType type;
|
||||||
@ -1128,12 +1142,12 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
|||||||
// Scan for prefixes.
|
// Scan for prefixes.
|
||||||
while (true) {
|
while (true) {
|
||||||
current = *data;
|
current = *data;
|
||||||
if (current == 0x66) { // Group 3 prefix.
|
if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
|
||||||
operand_size_ = current;
|
operand_size_ = current;
|
||||||
} else if ((current & 0xF0) == 0x40) { // REX prefix.
|
} else if ((current & 0xF0) == 0x40) { // REX prefix.
|
||||||
setRex(current);
|
setRex(current);
|
||||||
if (rex_w()) AppendToBuffer("REX.W ");
|
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;
|
group_1_prefix_ = current;
|
||||||
} else { // Not a prefix - an opcode.
|
} else { // Not a prefix - an opcode.
|
||||||
break;
|
break;
|
||||||
@ -1145,7 +1159,17 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
|||||||
byte_size_operand_ = idesc.byte_size_operation;
|
byte_size_operand_ = idesc.byte_size_operation;
|
||||||
switch (idesc.type) {
|
switch (idesc.type) {
|
||||||
case ZERO_OPERANDS_INSTR:
|
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++;
|
data++;
|
||||||
break;
|
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) {
|
Condition MacroAssembler::CheckEitherSmi(Register first, Register second) {
|
||||||
if (first.is(second)) {
|
if (first.is(second)) {
|
||||||
return CheckSmi(first);
|
return CheckSmi(first);
|
||||||
@ -660,7 +674,17 @@ void MacroAssembler::SmiSub(Register dst,
|
|||||||
Register src2,
|
Register src2,
|
||||||
Label* on_not_smi_result) {
|
Label* on_not_smi_result) {
|
||||||
ASSERT(!dst.is(src2));
|
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);
|
subq(dst, src2);
|
||||||
Label smi_result;
|
Label smi_result;
|
||||||
j(no_overflow, &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,
|
void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
|
||||||
Register second_object,
|
Register second_object,
|
||||||
Register scratch1,
|
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,
|
void MacroAssembler::TryGetFunctionPrototype(Register function,
|
||||||
Register result,
|
Register result,
|
||||||
Label* miss) {
|
Label* miss) {
|
||||||
|
@ -207,6 +207,9 @@ class MacroAssembler: public Assembler {
|
|||||||
// Are both values tagged smis.
|
// Are both values tagged smis.
|
||||||
Condition CheckBothSmi(Register first, Register second);
|
Condition CheckBothSmi(Register first, Register second);
|
||||||
|
|
||||||
|
// Are both values tagged smis.
|
||||||
|
Condition CheckBothPositiveSmi(Register first, Register second);
|
||||||
|
|
||||||
// Are either value a tagged smi.
|
// Are either value a tagged smi.
|
||||||
Condition CheckEitherSmi(Register first, Register second);
|
Condition CheckEitherSmi(Register first, Register second);
|
||||||
|
|
||||||
@ -248,6 +251,10 @@ class MacroAssembler: public Assembler {
|
|||||||
// Jump if either or both register are not smi values.
|
// Jump if either or both register are not smi values.
|
||||||
void JumpIfNotBothSmi(Register src1, Register src2, Label* on_not_both_smi);
|
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.
|
// Operations on tagged smi values.
|
||||||
|
|
||||||
// Smis represent a subset of integers. The subset is always equivalent to
|
// 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.
|
// Always use unsigned comparisons: above and below, not less and greater.
|
||||||
void CmpInstanceType(Register map, InstanceType type);
|
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
|
// FCmp is similar to integer cmp, but requires unsigned
|
||||||
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
|
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
|
||||||
void FCmp();
|
void FCmp();
|
||||||
|
Loading…
Reference in New Issue
Block a user