Commit e7ef1811 authored by haitao.feng@intel.com's avatar haitao.feng@intel.com

Refine CountOperation of FullCodeGen

R=danno@chromium.org

Review URL: https://codereview.chromium.org/42973002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17547 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent eb550c6d
......@@ -4394,14 +4394,44 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
// Call ToNumber only if operand is not a smi.
Label no_conversion;
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
__ JumpIfSmi(r0, &no_conversion);
Label slow;
patch_site.EmitJumpIfNotSmi(r0, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(r0);
break;
case NAMED_PROPERTY:
__ str(r0, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ str(r0, MemOperand(sp, 2 * kPointerSize));
break;
}
}
}
__ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
__ b(vc, &done);
// Call stub. Undo operation first.
__ sub(r0, r0, Operand(Smi::FromInt(count_value)));
__ jmp(&stub_call);
__ bind(&slow);
}
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
__ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
......@@ -4424,22 +4454,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
__ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
__ b(vs, &stub_call);
// We could eliminate this smi check if we split the code at
// the first smi check before calling ToNumber.
patch_site.EmitJumpIfSmi(r0, &done);
__ bind(&stub_call);
// Call stub. Undo operation first.
__ sub(r0, r0, Operand(Smi::FromInt(count_value)));
}
__ bind(&stub_call);
__ mov(r1, r0);
__ mov(r0, Operand(Smi::FromInt(count_value)));
......
......@@ -4394,14 +4394,50 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
// Call ToNumber only if operand is not a smi.
Label no_conversion;
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
__ JumpIfSmi(eax, &no_conversion, Label::kNear);
Label slow;
patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(eax);
break;
case NAMED_PROPERTY:
__ mov(Operand(esp, kPointerSize), eax);
break;
case KEYED_PROPERTY:
__ mov(Operand(esp, 2 * kPointerSize), eax);
break;
}
}
}
if (expr->op() == Token::INC) {
__ add(eax, Immediate(Smi::FromInt(1)));
} else {
__ sub(eax, Immediate(Smi::FromInt(1)));
}
__ j(no_overflow, &done, Label::kNear);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
__ sub(eax, Immediate(Smi::FromInt(1)));
} else {
__ add(eax, Immediate(Smi::FromInt(1)));
}
__ jmp(&stub_call, Label::kNear);
__ bind(&slow);
}
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
__ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
......@@ -4423,34 +4459,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
if (expr->op() == Token::INC) {
__ add(eax, Immediate(Smi::FromInt(1)));
} else {
__ sub(eax, Immediate(Smi::FromInt(1)));
}
__ j(overflow, &stub_call, Label::kNear);
// We could eliminate this smi check if we split the code at
// the first smi check before calling ToNumber.
patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
__ bind(&stub_call);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
__ sub(eax, Immediate(Smi::FromInt(1)));
} else {
__ add(eax, Immediate(Smi::FromInt(1)));
}
}
// Record position before stub call.
SetSourcePosition(expr->position());
// Call stub for +1/-1.
__ bind(&stub_call);
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1)));
BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
......
......@@ -4377,14 +4377,47 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
PrepareForBailoutForId(prop->LoadId(), TOS_REG);
}
// Call ToNumber only if operand is not a smi.
Label no_conversion;
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
__ JumpIfSmi(rax, &no_conversion, Label::kNear);
Label slow;
patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(rax);
break;
case NAMED_PROPERTY:
__ movq(Operand(rsp, kPointerSize), rax);
break;
case KEYED_PROPERTY:
__ movq(Operand(rsp, 2 * kPointerSize), rax);
break;
}
}
}
SmiOperationExecutionMode mode;
mode.Add(PRESERVE_SOURCE_REGISTER);
mode.Add(BAILOUT_ON_NO_OVERFLOW);
if (expr->op() == Token::INC) {
__ SmiAddConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
} else {
__ SmiSubConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
}
__ jmp(&stub_call, Label::kNear);
__ bind(&slow);
}
ToNumberStub convert_stub;
__ CallStub(&convert_stub);
__ bind(&no_conversion);
// Save result for postfix expressions.
if (expr->is_postfix()) {
......@@ -4406,34 +4439,11 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
if (expr->op() == Token::INC) {
__ SmiAddConstant(rax, rax, Smi::FromInt(1));
} else {
__ SmiSubConstant(rax, rax, Smi::FromInt(1));
}
__ j(overflow, &stub_call, Label::kNear);
// We could eliminate this smi check if we split the code at
// the first smi check before calling ToNumber.
patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
__ bind(&stub_call);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
__ SmiSubConstant(rax, rax, Smi::FromInt(1));
} else {
__ SmiAddConstant(rax, rax, Smi::FromInt(1));
}
}
// Record position before stub call.
SetSourcePosition(expr->position());
// Call stub for +1/-1.
__ bind(&stub_call);
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(1));
BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
......
......@@ -1516,7 +1516,8 @@ void MacroAssembler::SmiAddConstant(const Operand& dst, Smi* constant) {
void MacroAssembler::SmiAddConstant(Register dst,
Register src,
Smi* constant,
Label* on_not_smi_result,
SmiOperationExecutionMode mode,
Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
if (!dst.is(src)) {
......@@ -1524,19 +1525,32 @@ void MacroAssembler::SmiAddConstant(Register dst,
}
} else if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
Label done;
LoadSmiConstant(kScratchRegister, constant);
addq(dst, kScratchRegister);
j(no_overflow, &done, Label::kNear);
// Restore src.
subq(dst, kScratchRegister);
jmp(on_not_smi_result, near_jump);
bind(&done);
if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
j(no_overflow, bailout_label, near_jump);
ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
subq(dst, kScratchRegister);
} else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
Label done;
j(no_overflow, &done, Label::kNear);
subq(dst, kScratchRegister);
jmp(bailout_label, near_jump);
bind(&done);
} else {
// Bailout if overflow without reserving src.
j(overflow, bailout_label, near_jump);
}
} else {
CHECK(mode.IsEmpty());
}
} else {
ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
ASSERT(mode.Contains(BAILOUT_ON_OVERFLOW));
LoadSmiConstant(dst, constant);
addq(dst, src);
j(overflow, on_not_smi_result, near_jump);
j(overflow, bailout_label, near_jump);
}
}
......@@ -1568,7 +1582,8 @@ void MacroAssembler::SmiSubConstant(Register dst, Register src, Smi* constant) {
void MacroAssembler::SmiSubConstant(Register dst,
Register src,
Smi* constant,
Label* on_not_smi_result,
SmiOperationExecutionMode mode,
Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
if (!dst.is(src)) {
......@@ -1576,35 +1591,40 @@ void MacroAssembler::SmiSubConstant(Register dst,
}
} else if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
if (constant->value() == Smi::kMinValue) {
// Subtracting min-value from any non-negative value will overflow.
// We test the non-negativeness before doing the subtraction.
testq(src, src);
j(not_sign, on_not_smi_result, near_jump);
LoadSmiConstant(kScratchRegister, constant);
subq(dst, kScratchRegister);
LoadSmiConstant(kScratchRegister, constant);
subq(dst, kScratchRegister);
if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
j(no_overflow, bailout_label, near_jump);
ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
addq(dst, kScratchRegister);
} else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
Label done;
j(no_overflow, &done, Label::kNear);
addq(dst, kScratchRegister);
jmp(bailout_label, near_jump);
bind(&done);
} else {
// Bailout if overflow without reserving src.
j(overflow, bailout_label, near_jump);
}
} else {
// Subtract by adding the negation.
LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
addq(kScratchRegister, dst);
j(overflow, on_not_smi_result, near_jump);
movq(dst, kScratchRegister);
CHECK(mode.IsEmpty());
}
} else {
ASSERT(mode.Contains(PRESERVE_SOURCE_REGISTER));
ASSERT(mode.Contains(BAILOUT_ON_OVERFLOW));
if (constant->value() == Smi::kMinValue) {
// Subtracting min-value from any non-negative value will overflow.
// We test the non-negativeness before doing the subtraction.
testq(src, src);
j(not_sign, on_not_smi_result, near_jump);
LoadSmiConstant(dst, constant);
// Adding and subtracting the min-value gives the same result, it only
// differs on the overflow bit, which we don't check here.
addq(dst, src);
ASSERT(!dst.is(kScratchRegister));
movq(dst, src);
LoadSmiConstant(kScratchRegister, constant);
subq(dst, kScratchRegister);
j(overflow, bailout_label, near_jump);
} else {
// Subtract by adding the negation.
LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
addq(dst, src);
j(overflow, on_not_smi_result, near_jump);
j(overflow, bailout_label, near_jump);
}
}
}
......
......@@ -53,6 +53,22 @@ typedef Operand MemOperand;
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
enum SmiOperationConstraint {
PRESERVE_SOURCE_REGISTER,
BAILOUT_ON_NO_OVERFLOW,
BAILOUT_ON_OVERFLOW,
NUMBER_OF_CONSTRAINTS
};
STATIC_ASSERT(NUMBER_OF_CONSTRAINTS <= 8);
class SmiOperationExecutionMode : public EnumSet<SmiOperationConstraint, byte> {
public:
SmiOperationExecutionMode() : EnumSet<SmiOperationConstraint, byte>(0) { }
explicit SmiOperationExecutionMode(byte bits)
: EnumSet<SmiOperationConstraint, byte>(bits) { }
};
bool AreAliased(Register r1, Register r2, Register r3, Register r4);
// Forward declaration.
......@@ -547,7 +563,8 @@ class MacroAssembler: public Assembler {
void SmiAddConstant(Register dst,
Register src,
Smi* constant,
Label* on_not_smi_result,
SmiOperationExecutionMode mode,
Label* bailout_label,
Label::Distance near_jump = Label::kFar);
// Subtract an integer constant from a tagged smi, giving a tagged smi as
......@@ -560,7 +577,8 @@ class MacroAssembler: public Assembler {
void SmiSubConstant(Register dst,
Register src,
Smi* constant,
Label* on_not_smi_result,
SmiOperationExecutionMode mode,
Label* bailout_label,
Label::Distance near_jump = Label::kFar);
// Negating a smi can give a negative zero or too large positive value.
......
This diff is collapsed.
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