Chromium Code Reviews| Index: src/x64/codegen-x64.cc |
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc |
| index 31f55aeed6f28b0c68ebbc0144c7aa502f4ff601..a2e022bd3cf98ece65774d60e064784f5f55616a 100644 |
| --- a/src/x64/codegen-x64.cc |
| +++ b/src/x64/codegen-x64.cc |
| @@ -720,11 +720,12 @@ void CodeGenerator::CallApplyLazy(Property* apply, |
| frame_->SyncRange(0, frame_->element_count() - 1); |
| // Check that the receiver really is a JavaScript object. |
| - { frame_->PushElementAt(0); |
| + { |
| + frame_->PushElementAt(0); |
| Result receiver = frame_->Pop(); |
| receiver.ToRegister(); |
| - __ testl(receiver.reg(), Immediate(kSmiTagMask)); |
| - build_args.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(receiver.reg()); |
|
William Hesse
2009/09/10 11:13:22
This bugged me a lot at first, but now I see that
Lasse Reichstein
2009/09/10 12:28:11
I thought about inlining the CheckSmi call in the
Lasse Reichstein
2009/09/10 12:45:35
... but I'll leave that for a later change (e.g. w
|
| + build_args.Branch(is_smi); |
| // We allow all JSObjects including JSFunctions. As long as |
| // JS_FUNCTION_TYPE is the last instance type and it is right |
| // after LAST_JS_OBJECT_TYPE, we do not have to check the upper |
| @@ -736,11 +737,12 @@ void CodeGenerator::CallApplyLazy(Property* apply, |
| } |
| // Verify that we're invoking Function.prototype.apply. |
| - { frame_->PushElementAt(1); |
| + { |
| + frame_->PushElementAt(1); |
| Result apply = frame_->Pop(); |
| apply.ToRegister(); |
| - __ testl(apply.reg(), Immediate(kSmiTagMask)); |
| - build_args.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(apply.reg()); |
| + build_args.Branch(is_smi); |
| Result tmp = allocator_->Allocate(); |
| __ CmpObjectType(apply.reg(), JS_FUNCTION_TYPE, tmp.reg()); |
| build_args.Branch(not_equal); |
| @@ -755,8 +757,8 @@ void CodeGenerator::CallApplyLazy(Property* apply, |
| // Get the function receiver from the stack. Check that it |
| // really is a function. |
| __ movq(rdi, Operand(rsp, 2 * kPointerSize)); |
| - __ testl(rdi, Immediate(kSmiTagMask)); |
| - build_args.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(rdi); |
| + build_args.Branch(is_smi); |
| __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| build_args.Branch(not_equal); |
| @@ -780,7 +782,7 @@ void CodeGenerator::CallApplyLazy(Property* apply, |
| __ bind(&adapted); |
| static const uint32_t kArgumentsLimit = 1 * KB; |
| __ movq(rax, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| - __ shrl(rax, Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(rax, rax); |
| __ movq(rcx, rax); |
| __ cmpq(rax, Immediate(kArgumentsLimit)); |
| build_args.Branch(above); |
| @@ -1657,8 +1659,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| // Check if enumerable is already a JSObject |
| // rax: value to be iterated over |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - primitive.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(rax); |
| + primitive.Branch(is_smi); |
| __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| jsobject.Branch(above_equal); |
| @@ -1695,8 +1697,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| frame_->EmitPush(rax); // <- slot 3 |
| frame_->EmitPush(rdx); // <- slot 2 |
| - __ movsxlq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); |
| - __ shl(rax, Immediate(kSmiTagSize)); |
| + __ movl(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); |
| + __ Integer32ToSmi(rax, rax); |
| frame_->EmitPush(rax); // <- slot 1 |
| frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
| entry.Jump(); |
| @@ -1707,8 +1709,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| frame_->EmitPush(rax); // <- slot 2 |
| // Push the length of the array and the initial index onto the stack. |
| - __ movsxlq(rax, FieldOperand(rax, FixedArray::kLengthOffset)); |
| - __ shl(rax, Immediate(kSmiTagSize)); |
| + __ movl(rax, FieldOperand(rax, FixedArray::kLengthOffset)); |
| + __ Integer32ToSmi(rax, rax); |
| frame_->EmitPush(rax); // <- slot 1 |
| frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
| @@ -1725,6 +1727,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| // Get the i'th entry of the array. |
| __ movq(rdx, frame_->ElementAt(2)); |
| + // TODO(smi): Find a way to abstract indexing by a smi value. |
| ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| // Multiplier is times_4 since rax is already a Smi. |
| __ movq(rbx, FieldOperand(rdx, rax, times_4, FixedArray::kHeaderSize)); |
| @@ -3093,8 +3096,9 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| JumpTarget continue_label; |
| Result operand = frame_->Pop(); |
| operand.ToRegister(); |
| - __ testl(operand.reg(), Immediate(kSmiTagMask)); |
| - smi_label.Branch(zero, &operand); |
| + |
| + Condition is_smi = masm_->CheckSmi(operand.reg()); |
| + smi_label.Branch(is_smi, &operand); |
| frame_->Push(&operand); // undo popping of TOS |
| Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, |
| @@ -3103,9 +3107,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| smi_label.Bind(&answer); |
| answer.ToRegister(); |
| frame_->Spill(answer.reg()); |
| - __ not_(answer.reg()); |
| - // Remove inverted smi-tag. The mask is sign-extended to 64 bits. |
| - __ xor_(answer.reg(), Immediate(kSmiTagMask)); |
| + __ SmiNot(answer.reg(), answer.reg()); |
| continue_label.Bind(&answer); |
| frame_->Push(&answer); |
| break; |
| @@ -3116,9 +3118,8 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| JumpTarget continue_label; |
| Result operand = frame_->Pop(); |
| operand.ToRegister(); |
| - __ testl(operand.reg(), Immediate(kSmiTagMask)); |
| - continue_label.Branch(zero, &operand, taken); |
| - |
| + Condition is_smi = masm_->CheckSmi(operand.reg()); |
| + continue_label.Branch(is_smi, &operand); |
| frame_->Push(&operand); |
| Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
| CALL_FUNCTION, 1); |
| @@ -3264,8 +3265,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| } |
| // Smi test. |
| deferred->Branch(overflow); |
| - __ testl(kScratchRegister, Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(kScratchRegister, deferred->entry_label()); |
| __ movq(new_value.reg(), kScratchRegister); |
| deferred->BindExit(); |
| @@ -3470,8 +3470,8 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| answer.ToRegister(); |
| if (check->Equals(Heap::number_symbol())) { |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - destination()->true_target()->Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(answer.reg()); |
| + destination()->true_target()->Branch(is_smi); |
| frame_->Spill(answer.reg()); |
| __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex); |
| @@ -3479,8 +3479,8 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| destination()->Split(equal); |
| } else if (check->Equals(Heap::string_symbol())) { |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - destination()->false_target()->Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(answer.reg()); |
| + destination()->false_target()->Branch(is_smi); |
| // It can be an undetectable string object. |
| __ movq(kScratchRegister, |
| @@ -3503,8 +3503,8 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex); |
| destination()->true_target()->Branch(equal); |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - destination()->false_target()->Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(answer.reg()); |
| + destination()->false_target()->Branch(is_smi); |
| // It can be an undetectable object. |
| __ movq(kScratchRegister, |
| @@ -3515,16 +3515,16 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| destination()->Split(not_zero); |
| } else if (check->Equals(Heap::function_symbol())) { |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - destination()->false_target()->Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(answer.reg()); |
| + destination()->false_target()->Branch(is_smi); |
| frame_->Spill(answer.reg()); |
| __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); |
| answer.Unuse(); |
| destination()->Split(equal); |
| } else if (check->Equals(Heap::object_symbol())) { |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - destination()->false_target()->Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(answer.reg()); |
| + destination()->false_target()->Branch(is_smi); |
| __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); |
| destination()->true_target()->Branch(equal); |
| @@ -3623,8 +3623,8 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| Result value = frame_->Pop(); |
| value.ToRegister(); |
| ASSERT(value.is_valid()); |
| - __ testl(value.reg(), Immediate(kSmiTagMask)); |
| - destination()->false_target()->Branch(equal); |
| + Condition is_smi = masm_->CheckSmi(value.reg()); |
| + destination()->false_target()->Branch(is_smi); |
| // It is a heap object - get map. |
| // Check if the object is a JS array or not. |
| __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, kScratchRegister); |
| @@ -3727,17 +3727,13 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| // push. |
| // If the receiver is a smi trigger the slow case. |
| - ASSERT(kSmiTag == 0); |
| - __ testl(object.reg(), Immediate(kSmiTagMask)); |
| - __ j(zero, &slow_case); |
| + __ JumpIfSmi(object.reg(), &slow_case); |
| // If the index is negative or non-smi trigger the slow case. |
| - ASSERT(kSmiTag == 0); |
| - __ testl(index.reg(), |
| - Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U))); |
| - __ j(not_zero, &slow_case); |
| + __ JumpIfNotPositiveSmi(index.reg(), &slow_case); |
| + |
| // Untag the index. |
| - __ sarl(index.reg(), Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(index.reg(), index.reg()); |
| __ bind(&try_again_with_new_string); |
| // Fetch the instance type of the receiver into rcx. |
| @@ -3790,8 +3786,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| times_1, |
| SeqAsciiString::kHeaderSize)); |
| __ bind(&got_char_code); |
| - ASSERT(kSmiTag == 0); |
| - __ shl(temp.reg(), Immediate(kSmiTagSize)); |
| + __ Integer32ToSmi(temp.reg(), temp.reg()); |
| __ jmp(&end); |
| // Handle non-flat strings. |
| @@ -3832,10 +3827,9 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| Result value = frame_->Pop(); |
| value.ToRegister(); |
| ASSERT(value.is_valid()); |
| - __ testl(value.reg(), |
| - Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U))); |
| + Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); |
| value.Unuse(); |
| - destination()->Split(zero); |
| + destination()->Split(positive_smi); |
| } |
| @@ -3845,9 +3839,9 @@ void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| Result value = frame_->Pop(); |
| value.ToRegister(); |
| ASSERT(value.is_valid()); |
| - __ testl(value.reg(), Immediate(kSmiTagMask)); |
| + Condition is_smi = masm_->CheckSmi(value.reg()); |
| value.Unuse(); |
| - destination()->Split(zero); |
| + destination()->Split(is_smi); |
| } |
| @@ -4002,8 +3996,8 @@ void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { |
| frame_->Spill(obj.reg()); |
| // If the object is a smi, we return null. |
| - __ testl(obj.reg(), Immediate(kSmiTagMask)); |
| - null.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(obj.reg()); |
| + null.Branch(is_smi); |
| // Check that the object is a JS object but take special care of JS |
| // functions to make sure they have 'Function' as their class. |
| @@ -4064,8 +4058,8 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| object.ToRegister(); |
| // if (object->IsSmi()) return value. |
| - __ testl(object.reg(), Immediate(kSmiTagMask)); |
| - leave.Branch(zero, &value); |
| + Condition is_smi = masm_->CheckSmi(object.reg()); |
| + leave.Branch(is_smi, &value); |
| // It is a heap object - get its map. |
| Result scratch = allocator_->Allocate(); |
| @@ -4105,8 +4099,8 @@ void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| object.ToRegister(); |
| ASSERT(object.is_valid()); |
| // if (object->IsSmi()) return object. |
| - __ testl(object.reg(), Immediate(kSmiTagMask)); |
| - leave.Branch(zero); |
| + Condition is_smi = masm_->CheckSmi(object.reg()); |
| + leave.Branch(is_smi); |
| // It is a heap object - get map. |
| Result temp = allocator()->Allocate(); |
| ASSERT(temp.is_valid()); |
| @@ -4274,11 +4268,10 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) { |
| dest->false_target()->Branch(equal); |
| // Smi => false iff zero. |
| - ASSERT(kSmiTag == 0); |
| - __ testl(value.reg(), value.reg()); |
| - dest->false_target()->Branch(zero); |
| - __ testl(value.reg(), Immediate(kSmiTagMask)); |
| - dest->true_target()->Branch(zero); |
| + Condition equals = masm_->CheckSmiEqualsConstant(value.reg(), 0); |
| + dest->false_target()->Branch(equals); |
| + Condition is_smi = masm_->CheckSmi(value.reg()); |
| + dest->true_target()->Branch(is_smi); |
| // Call the stub for all other cases. |
| frame_->Push(&value); // Undo the Pop() from above. |
| @@ -4940,8 +4933,9 @@ void CodeGenerator::Comparison(Condition cc, |
| JumpTarget is_smi; |
| Register left_reg = left_side.reg(); |
| Handle<Object> right_val = right_side.handle(); |
| - __ testl(left_side.reg(), Immediate(kSmiTagMask)); |
| - is_smi.Branch(zero, taken); |
| + |
| + Condition left_is_smi = masm_->CheckSmi(left_side.reg()); |
| + is_smi.Branch(left_is_smi); |
| // Setup and call the compare stub. |
| CompareStub stub(cc, strict); |
| @@ -4982,8 +4976,8 @@ void CodeGenerator::Comparison(Condition cc, |
| dest->true_target()->Branch(equal); |
| __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex); |
| dest->true_target()->Branch(equal); |
| - __ testl(operand.reg(), Immediate(kSmiTagMask)); |
| - dest->false_target()->Branch(equal); |
| + Condition is_smi = masm_->CheckSmi(operand.reg()); |
| + dest->false_target()->Branch(is_smi); |
| // It can be an undetectable object. |
| // Use a scratch register in preference to spilling operand.reg(). |
| @@ -5023,10 +5017,8 @@ void CodeGenerator::Comparison(Condition cc, |
| Register left_reg = left_side.reg(); |
| Register right_reg = right_side.reg(); |
| - __ movq(kScratchRegister, left_reg); |
| - __ or_(kScratchRegister, right_reg); |
| - __ testl(kScratchRegister, Immediate(kSmiTagMask)); |
| - is_smi.Branch(zero, taken); |
| + Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); |
| + is_smi.Branch(both_smi); |
| // When non-smi, call out to the compare stub. |
| CompareStub stub(cc, strict); |
| Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
| @@ -5317,15 +5309,11 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| smi_value, |
| overwrite_mode); |
| } |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| - // A smi currently fits in a 32-bit Immediate. |
| - __ addl(operand->reg(), Immediate(smi_value)); |
| - Label add_success; |
| - __ j(no_overflow, &add_success); |
| - __ subl(operand->reg(), Immediate(smi_value)); |
| - deferred->Jump(); |
| - __ bind(&add_success); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| + __ SmiAddConstant(operand->reg(), |
| + operand->reg(), |
| + int_value, |
| + deferred->entry_label()); |
| deferred->BindExit(); |
| frame_->Push(operand); |
| break; |
| @@ -5342,15 +5330,12 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| // A smi currently fits in a 32-bit Immediate. |
| - __ subl(operand->reg(), Immediate(smi_value)); |
| - Label add_success; |
| - __ j(no_overflow, &add_success); |
| - __ addl(operand->reg(), Immediate(smi_value)); |
| - deferred->Jump(); |
| - __ bind(&add_success); |
| + __ SmiSubConstant(operand->reg(), |
| + operand->reg(), |
| + int_value, |
| + deferred->entry_label()); |
| deferred->BindExit(); |
| frame_->Push(operand); |
| } |
| @@ -5374,12 +5359,10 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| - if (shift_value > 0) { |
| - __ sarl(operand->reg(), Immediate(shift_value)); |
| - __ and_(operand->reg(), Immediate(~kSmiTagMask)); |
| - } |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| + __ SmiShiftArithmeticRightConstant(operand->reg(), |
| + operand->reg(), |
| + shift_value); |
| deferred->BindExit(); |
| frame_->Push(operand); |
| } |
| @@ -5403,21 +5386,13 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| - __ movl(answer.reg(), operand->reg()); |
| - __ sarl(answer.reg(), Immediate(kSmiTagSize)); |
| - __ shrl(answer.reg(), Immediate(shift_value)); |
| - // A negative Smi shifted right two is in the positive Smi range. |
| - if (shift_value < 2) { |
| - __ testl(answer.reg(), Immediate(0xc0000000)); |
| - deferred->Branch(not_zero); |
| - } |
| - operand->Unuse(); |
| - ASSERT(kSmiTag == 0); |
| - ASSERT(kSmiTagSize == 1); |
| - __ addl(answer.reg(), answer.reg()); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| + __ SmiShiftLogicRightConstant(answer.reg(), |
|
William Hesse
2009/09/10 11:13:22
ShiftLogicalRight
Lasse Reichstein
2009/09/10 12:28:11
Will rename LogicRight into LogicalRight.
|
| + operand->reg(), |
| + shift_value, |
| + deferred->entry_label()); |
| deferred->BindExit(); |
| + operand->Unuse(); |
| frame_->Push(&answer); |
| } |
| break; |
| @@ -5441,8 +5416,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| deferred->BindExit(); |
| frame_->Push(operand); |
| } else { |
| @@ -5455,18 +5429,11 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| - __ movl(answer.reg(), operand->reg()); |
| - ASSERT(kSmiTag == 0); // adjust code if not the case |
| - // We do no shifts, only the Smi conversion, if shift_value is 1. |
| - if (shift_value > 1) { |
| - __ shll(answer.reg(), Immediate(shift_value - 1)); |
| - } |
| - // Convert int result to Smi, checking that it is in int range. |
| - ASSERT(kSmiTagSize == 1); // adjust code if not the case |
| - __ addl(answer.reg(), answer.reg()); |
| - deferred->Branch(overflow); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| + __ SmiShiftLeftConstant(answer.reg(), |
| + operand->reg(), |
| + shift_value, |
| + deferred->entry_label()); |
| deferred->BindExit(); |
| operand->Unuse(); |
| frame_->Push(&answer); |
| @@ -5490,18 +5457,17 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| operand->reg(), |
| smi_value, |
| overwrite_mode); |
| - __ testl(operand->reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
| if (op == Token::BIT_AND) { |
| - __ and_(operand->reg(), Immediate(smi_value)); |
| + __ SmiAndConstant(operand->reg(), operand->reg(), int_value); |
| } else if (op == Token::BIT_XOR) { |
| if (int_value != 0) { |
| - __ xor_(operand->reg(), Immediate(smi_value)); |
| + __ SmiXorConstant(operand->reg(), operand->reg(), int_value); |
| } |
| } else { |
| ASSERT(op == Token::BIT_OR); |
| if (int_value != 0) { |
| - __ or_(operand->reg(), Immediate(smi_value)); |
| + __ SmiOrConstant(operand->reg(), operand->reg(), int_value); |
| } |
| } |
| deferred->BindExit(); |
| @@ -5522,14 +5488,12 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| smi_value, |
| overwrite_mode); |
| // Check for negative or non-Smi left hand side. |
| - __ testl(operand->reg(), |
| - Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000))); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label()); |
| if (int_value < 0) int_value = -int_value; |
| if (int_value == 1) { |
| __ movl(operand->reg(), Immediate(Smi::FromInt(0))); |
| } else { |
| - __ and_(operand->reg(), Immediate((int_value << kSmiTagSize) - 1)); |
| + __ SmiAndConstant(operand->reg(), operand->reg(), int_value - 1); |
| } |
| deferred->BindExit(); |
| frame_->Push(operand); |
| @@ -5631,67 +5595,17 @@ void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| left->reg(), |
| right->reg(), |
| overwrite_mode); |
| - if (left->reg().is(right->reg())) { |
| - __ testl(left->reg(), Immediate(kSmiTagMask)); |
| - } else { |
| - // Use the quotient register as a scratch for the tag check. |
| - if (!left_is_in_rax) __ movq(rax, left->reg()); |
| - left_is_in_rax = false; // About to destroy the value in rax. |
| - __ or_(rax, right->reg()); |
| - ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - } |
| - deferred->Branch(not_zero); |
| - |
| - // All operations on the smi values are on 32-bit registers, which are |
| - // zero-extended into 64-bits by all 32-bit operations. |
| - if (!left_is_in_rax) __ movl(rax, left->reg()); |
| - // Sign extend eax into edx:eax. |
| - __ cdq(); |
| - // Check for 0 divisor. |
| - __ testl(right->reg(), right->reg()); |
| - deferred->Branch(zero); |
| - // Divide rdx:rax by the right operand. |
| - __ idivl(right->reg()); |
| - |
| - // Complete the operation. |
| + __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); |
| + |
| if (op == Token::DIV) { |
| - // Check for negative zero result. If the result is zero, and the |
| - // divisor is negative, return a floating point negative zero. |
| - Label non_zero_result; |
| - __ testl(left->reg(), left->reg()); |
| - __ j(not_zero, &non_zero_result); |
| - __ testl(right->reg(), right->reg()); |
| - deferred->Branch(negative); |
| - // The frame is identical on all paths reaching this label. |
| - __ bind(&non_zero_result); |
| - // Check for the corner case of dividing the most negative smi by |
| - // -1. We cannot use the overflow flag, since it is not set by |
| - // idiv instruction. |
| - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| - __ cmpl(rax, Immediate(0x40000000)); |
| - deferred->Branch(equal); |
| - // Check that the remainder is zero. |
| - __ testl(rdx, rdx); |
| - deferred->Branch(not_zero); |
| - // Tag the result and store it in the quotient register. |
| - ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| + __ SmiDiv(rax, left->reg(), right->reg(), deferred->entry_label()); |
| deferred->BindExit(); |
| left->Unuse(); |
| right->Unuse(); |
| frame_->Push("ient); |
| } else { |
| ASSERT(op == Token::MOD); |
| - // Check for a negative zero result. If the result is zero, and the |
| - // dividend is negative, return a floating point negative zero. |
| - Label non_zero_result; |
| - __ testl(rdx, rdx); |
| - __ j(not_zero, &non_zero_result); |
| - __ testl(left->reg(), left->reg()); |
| - deferred->Branch(negative); |
| - // The frame is identical on all paths reaching this label. |
| - __ bind(&non_zero_result); |
| + __ SmiMod(rdx, left->reg(), right->reg(), deferred->entry_label()); |
| deferred->BindExit(); |
| left->Unuse(); |
| right->Unuse(); |
| @@ -5730,59 +5644,30 @@ void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| overwrite_mode); |
| __ movq(answer.reg(), left->reg()); |
| __ or_(answer.reg(), rcx); |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(answer.reg(), deferred->entry_label()); |
| - // Untag both operands. |
| - __ movl(answer.reg(), left->reg()); |
| - __ sarl(answer.reg(), Immediate(kSmiTagSize)); |
| - __ sarl(rcx, Immediate(kSmiTagSize)); |
| // Perform the operation. |
| switch (op) { |
| case Token::SAR: |
| - __ sarl(answer.reg()); |
| - // No checks of result necessary |
| + __ SmiShiftArithmeticRight(answer.reg(), left->reg(), rcx); |
| break; |
| case Token::SHR: { |
| - Label result_ok; |
| - __ shrl(answer.reg()); |
| - // Check that the *unsigned* result fits in a smi. Neither of |
| - // the two high-order bits can be set: |
| - // * 0x80000000: high bit would be lost when smi tagging. |
| - // * 0x40000000: this number would convert to negative when smi |
| - // tagging. |
| - // These two cases can only happen with shifts by 0 or 1 when |
| - // handed a valid smi. If the answer cannot be represented by a |
| - // smi, restore the left and right arguments, and jump to slow |
| - // case. The low bit of the left argument may be lost, but only |
| - // in a case where it is dropped anyway. |
| - __ testl(answer.reg(), Immediate(0xc0000000)); |
| - __ j(zero, &result_ok); |
| - ASSERT(kSmiTag == 0); |
| - __ shl(rcx, Immediate(kSmiTagSize)); |
| - deferred->Jump(); |
| - __ bind(&result_ok); |
| + __ SmiShiftLogicRight(answer.reg(), |
| + left->reg(), |
| + rcx, |
| + deferred->entry_label()); |
| break; |
| } |
| case Token::SHL: { |
| - Label result_ok; |
| - __ shl(answer.reg()); |
| - // Check that the *signed* result fits in a smi. |
| - __ cmpl(answer.reg(), Immediate(0xc0000000)); |
| - __ j(positive, &result_ok); |
| - ASSERT(kSmiTag == 0); |
| - __ shl(rcx, Immediate(kSmiTagSize)); |
| - deferred->Jump(); |
| - __ bind(&result_ok); |
| + __ SmiShiftLeft(answer.reg(), |
| + left->reg(), |
| + rcx, |
| + deferred->entry_label()); |
| break; |
| } |
| default: |
| UNREACHABLE(); |
| } |
| - // Smi-tag the result in answer. |
| - ASSERT(kSmiTagSize == 1); // Adjust code if not the case. |
| - __ lea(answer.reg(), |
| - Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); |
| deferred->BindExit(); |
| left->Unuse(); |
| right->Unuse(); |
| @@ -5806,63 +5691,41 @@ void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| left->reg(), |
| right->reg(), |
| overwrite_mode); |
| - if (left->reg().is(right->reg())) { |
| - __ testl(left->reg(), Immediate(kSmiTagMask)); |
| - } else { |
| - __ movq(answer.reg(), left->reg()); |
| - __ or_(answer.reg(), right->reg()); |
| - ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| - __ testl(answer.reg(), Immediate(kSmiTagMask)); |
| - } |
| - deferred->Branch(not_zero); |
| - __ movq(answer.reg(), left->reg()); |
| + __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); |
| + |
| switch (op) { |
| case Token::ADD: |
| - __ addl(answer.reg(), right->reg()); |
| - deferred->Branch(overflow); |
| + __ SmiAdd(answer.reg(), |
| + left->reg(), |
| + right->reg(), |
| + deferred->entry_label()); |
| break; |
| case Token::SUB: |
| - __ subl(answer.reg(), right->reg()); |
| - deferred->Branch(overflow); |
| + __ SmiSub(answer.reg(), |
| + left->reg(), |
| + right->reg(), |
| + deferred->entry_label()); |
| break; |
| case Token::MUL: { |
| - // If the smi tag is 0 we can just leave the tag on one operand. |
| - ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| - // Remove smi tag from the left operand (but keep sign). |
| - // Left-hand operand has been copied into answer. |
| - __ sarl(answer.reg(), Immediate(kSmiTagSize)); |
| - // Do multiplication of smis, leaving result in answer. |
| - __ imull(answer.reg(), right->reg()); |
| - // Go slow on overflows. |
| - deferred->Branch(overflow); |
| - // Check for negative zero result. If product is zero, and one |
| - // argument is negative, go to slow case. The frame is unchanged |
| - // in this block, so local control flow can use a Label rather |
| - // than a JumpTarget. |
| - Label non_zero_result; |
| - __ testl(answer.reg(), answer.reg()); |
| - __ j(not_zero, &non_zero_result); |
| - __ movq(answer.reg(), left->reg()); |
| - __ or_(answer.reg(), right->reg()); |
| - deferred->Branch(negative); |
| - __ xor_(answer.reg(), answer.reg()); // Positive 0 is correct. |
| - __ bind(&non_zero_result); |
| + __ SmiMul(answer.reg(), |
| + left->reg(), |
| + right->reg(), |
| + deferred->entry_label()); |
| break; |
| } |
| case Token::BIT_OR: |
| - __ or_(answer.reg(), right->reg()); |
| + __ SmiOr(answer.reg(), left->reg(), right->reg()); |
| break; |
| case Token::BIT_AND: |
| - __ and_(answer.reg(), right->reg()); |
| + __ SmiAnd(answer.reg(), left->reg(), right->reg()); |
| break; |
| case Token::BIT_XOR: |
| - ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| - __ xor_(answer.reg(), right->reg()); |
| + __ SmiXor(answer.reg(), left->reg(), right->reg()); |
| break; |
| default: |
| @@ -5973,8 +5836,7 @@ void Reference::GetValue(TypeofState typeof_state) { |
| GetName()); |
| // Check that the receiver is a heap object. |
| - __ testl(receiver.reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(zero); |
| + __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| __ bind(deferred->patch_site()); |
| // This is the map check instruction that will be patched (so we can't |
| @@ -6046,8 +5908,7 @@ void Reference::GetValue(TypeofState typeof_state) { |
| // is not a load from the global context) and that it has the |
| // expected map. |
| if (!is_global) { |
| - __ testl(receiver.reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(zero); |
| + __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| } |
| // Initially, use an invalid map. The map is patched in the IC |
| @@ -6062,9 +5923,7 @@ void Reference::GetValue(TypeofState typeof_state) { |
| deferred->Branch(not_equal); |
| // Check that the key is a non-negative smi. |
| - __ testl(key.reg(), |
| - Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000u))); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); |
| // Get the elements array from the receiver and check that it |
| // is not a dictionary. |
| @@ -6076,8 +5935,7 @@ void Reference::GetValue(TypeofState typeof_state) { |
| // Shift the key to get the actual index value and check that |
| // it is within bounds. |
| - __ movl(index.reg(), key.reg()); |
| - __ shrl(index.reg(), Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(index.reg(), key.reg()); |
| __ cmpl(index.reg(), |
| FieldOperand(elements.reg(), FixedArray::kLengthOffset)); |
| deferred->Branch(above_equal); |
| @@ -6228,20 +6086,16 @@ void Reference::SetValue(InitState init_state) { |
| // Check that the value is a smi if it is not a constant. |
| // We can skip the write barrier for smis and constants. |
| if (!value_is_constant) { |
| - __ testl(value.reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotSmi(value.reg(), deferred->entry_label()); |
| } |
| // Check that the key is a non-negative smi. |
| - __ testl(key.reg(), |
| - Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U))); |
| - deferred->Branch(not_zero); |
| + __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); |
| // Ensure that the smi is zero-extended. This is not guaranteed. |
| __ movl(key.reg(), key.reg()); |
| // Check that the receiver is not a smi. |
| - __ testl(receiver.reg(), Immediate(kSmiTagMask)); |
| - deferred->Branch(zero); |
| + __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| // Check that the receiver is a JSArray. |
| __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); |
| @@ -6274,6 +6128,7 @@ void Reference::SetValue(InitState init_state) { |
| // Store the value. |
| ASSERT_EQ(1, kSmiTagSize); |
| ASSERT_EQ(0, kSmiTag); |
| + // TODO(lrn) Find way to abstract indexing by smi. |
| __ movq(Operand(tmp.reg(), |
| key.reg(), |
| times_half_pointer_size, |
| @@ -6457,8 +6312,7 @@ void UnarySubStub::Generate(MacroAssembler* masm) { |
| Label try_float; |
| Label special; |
| // Check whether the value is a smi. |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &try_float); |
| + __ JumpIfNotSmi(rax, &try_float); |
| // Enter runtime system if the value of the smi is zero |
| // to make sure that we switch between 0 and -0. |
| @@ -6567,23 +6421,7 @@ void CompareStub::Generate(MacroAssembler* masm) { |
| // be equal if the other is a HeapNumber. If so, use the slow case. |
| { |
| Label not_smis; |
| - ASSERT_EQ(0, kSmiTag); |
| - ASSERT_EQ(0, Smi::FromInt(0)); |
| - __ movq(rcx, Immediate(kSmiTagMask)); |
| - __ and_(rcx, rax); |
| - __ testq(rcx, rdx); |
| - __ j(not_zero, ¬_smis); |
| - // One operand is a smi. |
| - |
| - // Check whether the non-smi is a heap number. |
| - ASSERT_EQ(1, static_cast<int>(kSmiTagMask)); |
| - // rcx still holds rax & kSmiTag, which is either zero or one. |
| - __ decq(rcx); // If rax is a smi, all 1s, else all 0s. |
| - __ movq(rbx, rdx); |
| - __ xor_(rbx, rax); |
| - __ and_(rbx, rcx); // rbx holds either 0 or rax ^ rdx. |
| - __ xor_(rbx, rax); |
| - // if rax was smi, rbx is now rdx, else rax. |
| + __ SelectNonSmi(rbx, rax, rdx, ¬_smis); |
| // Check if the non-smi operand is a heap number. |
| __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), |
| @@ -6712,8 +6550,7 @@ void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, |
| Label* label, |
| Register object, |
| Register scratch) { |
| - __ testl(object, Immediate(kSmiTagMask)); |
| - __ j(zero, label); |
| + __ JumpIfSmi(object, label); |
| __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
| __ movzxbq(scratch, |
| FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| @@ -6757,8 +6594,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { |
| // Get the object - go slow case if it's a smi. |
| Label slow; |
| __ movq(rax, Operand(rsp, 2 * kPointerSize)); |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - __ j(zero, &slow); |
| + __ JumpIfSmi(rax, &slow); |
| // Check that the left hand is a JS object. Leave its map in rax. |
| __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); |
| @@ -6771,8 +6607,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { |
| __ TryGetFunctionPrototype(rdx, rbx, &slow); |
| // Check that the function prototype is a JS object. |
| - __ testl(rbx, Immediate(kSmiTagMask)); |
| - __ j(zero, &slow); |
| + __ JumpIfSmi(rbx, &slow); |
| __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
| __ j(below, &slow); |
| __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); |
| @@ -6844,8 +6679,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| // Check that the key is a smi. |
| Label slow; |
| - __ testl(rdx, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &slow); |
| + __ JumpIfNotSmi(rdx, &slow); |
| // Check if the calling frame is an arguments adaptor frame. |
| Label adaptor; |
| @@ -6863,9 +6697,10 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| // Read the argument from the stack and return it. |
| // Shifting code depends on SmiEncoding being equivalent to left shift: |
| // we multiply by four to get pointer alignment. |
| + // TODO(smi): Find a way to abstract indexing by a smi. |
| ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| __ lea(rbx, Operand(rbp, rax, times_4, 0)); |
| - __ neg(rdx); |
| + __ neg(rdx); // TODO(smi): Abstract negative indexing too. |
| __ movq(rax, Operand(rbx, rdx, times_4, kDisplacement)); |
| __ Ret(); |
| @@ -6880,6 +6715,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| // Read the argument from the stack and return it. |
| // Shifting code depends on SmiEncoding being equivalent to left shift: |
| // we multiply by four to get pointer alignment. |
| + // TODO(smi): Find a way to abstract indexing by a smi. |
| ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| __ lea(rbx, Operand(rbx, rcx, times_4, 0)); |
| __ neg(rdx); |
| @@ -7139,8 +6975,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { |
| __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); |
| // Check that the function really is a JavaScript function. |
| - __ testl(rdi, Immediate(kSmiTagMask)); |
| - __ j(zero, &slow); |
| + __ JumpIfSmi(rdi, &slow); |
| // Goto slow case if we do not have a function. |
| __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| __ j(not_equal, &slow); |
| @@ -7390,13 +7225,12 @@ void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| Register number) { |
| Label load_smi, done; |
| - __ testl(number, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi); |
| + __ JumpIfSmi(number, &load_smi); |
| __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); |
| __ jmp(&done); |
| __ bind(&load_smi); |
| - __ sarl(number, Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(number, number); |
| __ push(number); |
| __ fild_s(Operand(rsp, 0)); |
| __ pop(number); |
| @@ -7410,13 +7244,12 @@ void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| XMMRegister dst) { |
| Label load_smi, done; |
| - __ testl(src, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi); |
| + __ JumpIfSmi(src, &load_smi); |
| __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
| __ jmp(&done); |
| __ bind(&load_smi); |
| - __ sarl(src, Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(src, src); |
| __ cvtlsi2sd(dst, src); |
| __ bind(&done); |
| @@ -7445,26 +7278,24 @@ void FloatingPointHelper::LoadInt32Operand(MacroAssembler* masm, |
| void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm) { |
| Label load_smi_1, load_smi_2, done_load_1, done; |
| __ movq(kScratchRegister, Operand(rsp, 2 * kPointerSize)); |
| - __ testl(kScratchRegister, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi_1); |
| + __ JumpIfSmi(kScratchRegister, &load_smi_1); |
| __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); |
| __ bind(&done_load_1); |
| __ movq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); |
| - __ testl(kScratchRegister, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi_2); |
| + __ JumpIfSmi(kScratchRegister, &load_smi_2); |
| __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); |
| __ jmp(&done); |
| __ bind(&load_smi_1); |
| - __ sarl(kScratchRegister, Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(kScratchRegister, kScratchRegister); |
| __ push(kScratchRegister); |
| __ fild_s(Operand(rsp, 0)); |
| __ pop(kScratchRegister); |
| __ jmp(&done_load_1); |
| __ bind(&load_smi_2); |
| - __ sarl(kScratchRegister, Immediate(kSmiTagSize)); |
| + __ SmiToInteger32(kScratchRegister, kScratchRegister); |
| __ push(kScratchRegister); |
| __ fild_s(Operand(rsp, 0)); |
| __ pop(kScratchRegister); |
| @@ -7477,29 +7308,25 @@ void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| Register lhs, |
| Register rhs) { |
| Label load_smi_lhs, load_smi_rhs, done_load_lhs, done; |
| - __ testl(lhs, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi_lhs); |
| + __ JumpIfSmi(lhs, &load_smi_lhs); |
| __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset)); |
| __ bind(&done_load_lhs); |
| - __ testl(rhs, Immediate(kSmiTagMask)); |
| - __ j(zero, &load_smi_rhs); |
| + __ JumpIfSmi(rhs, &load_smi_rhs); |
| __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); |
| __ jmp(&done); |
| __ bind(&load_smi_lhs); |
| ASSERT(kSmiTagSize == 1); |
| ASSERT(kSmiTag == 0); |
| - __ movsxlq(kScratchRegister, lhs); |
| - __ sar(kScratchRegister, Immediate(kSmiTagSize)); |
| + __ SmiToInteger64(kScratchRegister, lhs); |
| __ push(kScratchRegister); |
| __ fild_d(Operand(rsp, 0)); |
| __ pop(kScratchRegister); |
| __ jmp(&done_load_lhs); |
| __ bind(&load_smi_rhs); |
| - __ movsxlq(kScratchRegister, rhs); |
| - __ sar(kScratchRegister, Immediate(kSmiTagSize)); |
| + __ SmiToInteger64(kScratchRegister, rhs); |
| __ push(kScratchRegister); |
| __ fild_d(Operand(rsp, 0)); |
| __ pop(kScratchRegister); |
| @@ -7513,14 +7340,12 @@ void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
| Label test_other, done; |
| // Test if both operands are numbers (heap_numbers or smis). |
| // If not, jump to label non_float. |
| - __ testl(rdx, Immediate(kSmiTagMask)); |
| - __ j(zero, &test_other); // argument in rdx is OK |
| + __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK |
| __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map()); |
| __ j(not_equal, non_float); // The argument in rdx is not a number. |
| __ bind(&test_other); |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - __ j(zero, &done); // argument in rax is OK |
| + __ JumpIfSmi(rax, &done); // argument in rax is OK |
| __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); |
| __ j(not_equal, non_float); // The argument in rax is not a number. |
| @@ -7551,88 +7376,41 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
| // leave result in register rax. |
| // Smi check both operands. |
| - __ movq(rcx, rbx); |
| - __ or_(rcx, rax); // The value in ecx is used for negative zero test later. |
| - __ testl(rcx, Immediate(kSmiTagMask)); |
| - __ j(not_zero, slow); |
| + __ JumpIfNotBothSmi(rax, rbx, slow); |
| switch (op_) { |
| case Token::ADD: { |
| - __ addl(rax, rbx); |
| - __ j(overflow, slow); // The slow case rereads operands from the stack. |
| + __ SmiAdd(rax, rax, rbx, slow); |
| break; |
| } |
| case Token::SUB: { |
| - __ subl(rax, rbx); |
| - __ j(overflow, slow); // The slow case rereads operands from the stack. |
| + __ SmiSub(rax, rax, rbx, slow); |
| break; |
| } |
| case Token::MUL: |
| - // If the smi tag is 0 we can just leave the tag on one operand. |
| - ASSERT(kSmiTag == 0); // adjust code below if not the case |
| - // Remove tag from one of the operands (but keep sign). |
| - __ sarl(rax, Immediate(kSmiTagSize)); |
| - // Do multiplication. |
| - __ imull(rax, rbx); // multiplication of smis; result in eax |
| - // Go slow on overflows. |
| - __ j(overflow, slow); |
| - // Check for negative zero result. |
| - __ NegativeZeroTest(rax, rcx, slow); // ecx (not rcx) holds x | y. |
| + __ SmiMul(rax, rax, rbx, slow); |
| break; |
| case Token::DIV: |
| - // Sign extend eax into edx:eax. |
| - __ cdq(); |
| - // Check for 0 divisor. |
| - __ testl(rbx, rbx); |
| - __ j(zero, slow); |
| - // Divide edx:eax by ebx (where edx:eax is equivalent to the smi in eax). |
| - __ idivl(rbx); |
| - // Check that the remainder is zero. |
| - __ testl(rdx, rdx); |
| - __ j(not_zero, slow); |
| - // Check for the corner case of dividing the most negative smi |
| - // by -1. We cannot use the overflow flag, since it is not set |
| - // by idiv instruction. |
| - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| - // TODO(X64): TODO(Smi): Smi implementation dependent constant. |
| - // Value is Smi::fromInt(-(1<<31)) / Smi::fromInt(-1) |
| - __ cmpl(rax, Immediate(0x40000000)); |
| - __ j(equal, slow); |
| - // Check for negative zero result. |
| - __ NegativeZeroTest(rax, rcx, slow); // ecx (not rcx) holds x | y. |
| - // Tag the result and store it in register rax. |
| - ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| + __ SmiDiv(rax, rax, rbx, slow); |
| break; |
| case Token::MOD: |
| - // Sign extend eax into edx:eax |
| - __ cdq(); |
| - // Check for 0 divisor. |
| - __ testl(rbx, rbx); |
| - __ j(zero, slow); |
| - // Divide edx:eax by ebx. |
| - __ idivl(rbx); |
| - // Check for negative zero result. |
| - __ NegativeZeroTest(rdx, rcx, slow); // ecx (not rcx) holds x | y. |
| - // Move remainder to register rax. |
| - __ movl(rax, rdx); |
| + __ SmiMod(rax, rax, rbx, slow); |
| break; |
| case Token::BIT_OR: |
| - __ or_(rax, rbx); |
| + __ SmiOr(rax, rax, rbx); |
| break; |
| case Token::BIT_AND: |
| - __ and_(rax, rbx); |
| + __ SmiAnd(rax, rax, rbx); |
| break; |
| case Token::BIT_XOR: |
| - ASSERT_EQ(0, kSmiTag); |
| - __ xor_(rax, rbx); |
| + __ SmiXor(rax, rax, rbx); |
| break; |
| case Token::SHL: |
| @@ -7640,41 +7418,20 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
| case Token::SAR: |
| // Move the second operand into register ecx. |
| __ movl(rcx, rbx); |
| - // Remove tags from operands (but keep sign). |
| - __ sarl(rax, Immediate(kSmiTagSize)); |
| - __ sarl(rcx, Immediate(kSmiTagSize)); |
| // Perform the operation. |
| switch (op_) { |
| case Token::SAR: |
| - __ sarl(rax); |
| - // No checks of result necessary |
| + __ SmiShiftArithmeticRight(rax, rax, rbx); |
| break; |
| case Token::SHR: |
| - __ shrl(rax); // rcx is implicit shift register |
| - // Check that the *unsigned* result fits in a smi. |
| - // Neither of the two high-order bits can be set: |
| - // - 0x80000000: high bit would be lost when smi tagging. |
| - // - 0x40000000: this number would convert to negative when |
| - // Smi tagging these two cases can only happen with shifts |
| - // by 0 or 1 when handed a valid smi. |
| - __ testl(rax, Immediate(0xc0000000)); |
| - __ j(not_zero, slow); |
| + __ SmiShiftLogicRight(rax, rax, rbx, slow); |
| break; |
| case Token::SHL: |
| - __ shll(rax); |
| - // Check that the *signed* result fits in a smi. |
| - // It does, if the 30th and 31st bits are equal, since then |
| - // shifting the SmiTag in at the bottom doesn't change the sign. |
| - ASSERT(kSmiTagSize == 1); |
| - __ cmpl(rax, Immediate(0xc0000000)); |
| - __ j(sign, slow); |
| + __ SmiShiftLeft(rax, rax, rbx, slow); |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| - // Tag the result and store it in register eax. |
| - ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| break; |
| default: |
| @@ -7722,8 +7479,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| case OVERWRITE_RIGHT: |
| // If the argument in rax is already an object, we skip the |
| // allocation of a heap number. |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &skip_allocation); |
| + __ JumpIfNotSmi(rax, &skip_allocation); |
| // Fall through! |
| case NO_OVERWRITE: |
| FloatingPointHelper::AllocateHeapNumber(masm, |
| @@ -7829,8 +7585,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| __ j(negative, &non_smi_result); |
| } |
| // Tag smi result and return. |
| - ASSERT(kSmiTagSize == 1); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| + __ Integer32ToSmi(rax, rax); |
| __ ret(2 * kPointerSize); |
| // All ops except SHR return a signed int32 that we load in a HeapNumber. |
| @@ -7845,8 +7600,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| // allocation of a heap number. |
| __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? |
| 1 * kPointerSize : 2 * kPointerSize)); |
| - __ testl(rax, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &skip_allocation); |
| + __ JumpIfNotSmi(rax, &skip_allocation); |
| // Fall through! |
| case NO_OVERWRITE: |
| FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime, |