| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 3134)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -5057,10 +5057,8 @@
|
|
|
|
|
| void DeferredInlineBinaryOperation::Generate() {
|
| - __ push(left_);
|
| - __ push(right_);
|
| - GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED);
|
| - __ CallStub(&stub);
|
| + GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB);
|
| + stub.GenerateCall(masm_, left_, right_);
|
| if (!dst_.is(rax)) __ movq(dst_, rax);
|
| }
|
|
|
| @@ -5089,16 +5087,16 @@
|
| // Bit operations always assume they likely operate on Smis. Still only
|
| // generate the inline Smi check code if this operation is part of a loop.
|
| flags = (loop_nesting() > 0)
|
| - ? SMI_CODE_INLINED
|
| - : SMI_CODE_IN_STUB;
|
| + ? NO_SMI_CODE_IN_STUB
|
| + : NO_GENERIC_BINARY_FLAGS;
|
| break;
|
|
|
| default:
|
| // By default only inline the Smi check code for likely smis if this
|
| // operation is part of a loop.
|
| flags = ((loop_nesting() > 0) && type->IsLikelySmi())
|
| - ? SMI_CODE_INLINED
|
| - : SMI_CODE_IN_STUB;
|
| + ? NO_SMI_CODE_IN_STUB
|
| + : NO_GENERIC_BINARY_FLAGS;
|
| break;
|
| }
|
|
|
| @@ -5157,7 +5155,7 @@
|
| return;
|
| }
|
|
|
| - if (flags == SMI_CODE_INLINED && !generate_no_smi_code) {
|
| + if ((flags & NO_SMI_CODE_IN_STUB) != 0 && !generate_no_smi_code) {
|
| LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
|
| } else {
|
| frame_->Push(&left);
|
| @@ -5166,7 +5164,7 @@
|
| // that does not check for the fast smi case.
|
| // The same stub is used for NO_SMI_CODE and SMI_CODE_INLINED.
|
| if (generate_no_smi_code) {
|
| - flags = SMI_CODE_INLINED;
|
| + flags = NO_SMI_CODE_IN_STUB;
|
| }
|
| GenericBinaryOpStub stub(op, overwrite_mode, flags);
|
| Result answer = frame_->CallStub(&stub, 2);
|
| @@ -5221,41 +5219,32 @@
|
|
|
|
|
| void DeferredInlineSmiAdd::Generate() {
|
| - __ push(dst_);
|
| - __ Push(value_);
|
| - GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
|
| - __ CallStub(&igostub);
|
| + GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
|
| + igostub.GenerateCall(masm_, dst_, value_);
|
| if (!dst_.is(rax)) __ movq(dst_, rax);
|
| }
|
|
|
|
|
| void DeferredInlineSmiAddReversed::Generate() {
|
| - __ Push(value_);
|
| - __ push(dst_);
|
| - GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
|
| - __ CallStub(&igostub);
|
| + GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
|
| + igostub.GenerateCall(masm_, value_, dst_);
|
| if (!dst_.is(rax)) __ movq(dst_, rax);
|
| }
|
|
|
|
|
| void DeferredInlineSmiSub::Generate() {
|
| - __ push(dst_);
|
| - __ Push(value_);
|
| - GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
|
| - __ CallStub(&igostub);
|
| - if (!dst_.is(rax)) __ movq(dst_, rax);
|
| + GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB);
|
| + igostub.GenerateCall(masm_, dst_, value_);
|
| }
|
|
|
|
|
| void DeferredInlineSmiOperation::Generate() {
|
| - __ push(src_);
|
| - __ Push(value_);
|
| // For mod we don't generate all the Smi code inline.
|
| GenericBinaryOpStub stub(
|
| op_,
|
| overwrite_mode_,
|
| - (op_ == Token::MOD) ? SMI_CODE_IN_STUB : SMI_CODE_INLINED);
|
| - __ CallStub(&stub);
|
| + (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB);
|
| + stub.GenerateCall(masm_, src_, value_);
|
| if (!dst_.is(rax)) __ movq(dst_, rax);
|
| }
|
|
|
| @@ -7340,6 +7329,127 @@
|
| }
|
|
|
|
|
| +void GenericBinaryOpStub::GenerateCall(
|
| + MacroAssembler* masm,
|
| + Register left,
|
| + Register right) {
|
| + if (!ArgsInRegistersSupported()) {
|
| + // Pass arguments on the stack.
|
| + __ push(left);
|
| + __ push(right);
|
| + } else {
|
| + // The calling convention with registers is left in rdx and right in rax.
|
| + Register left_arg = rdx;
|
| + Register right_arg = rax;
|
| + if (!(left.is(left_arg) && right.is(right_arg))) {
|
| + if (left.is(right_arg) && right.is(left_arg)) {
|
| + if (IsOperationCommutative()) {
|
| + SetArgsReversed();
|
| + } else {
|
| + __ xchg(left, right);
|
| + }
|
| + } else if (left.is(left_arg)) {
|
| + __ movq(right_arg, right);
|
| + } else if (left.is(right_arg)) {
|
| + if (IsOperationCommutative()) {
|
| + __ movq(left_arg, right);
|
| + SetArgsReversed();
|
| + } else {
|
| + // Order of moves important to avoid destroying left argument.
|
| + __ movq(left_arg, left);
|
| + __ movq(right_arg, right);
|
| + }
|
| + } else if (right.is(left_arg)) {
|
| + if (IsOperationCommutative()) {
|
| + __ movq(right_arg, left);
|
| + SetArgsReversed();
|
| + } else {
|
| + // Order of moves important to avoid destroying right argument.
|
| + __ movq(right_arg, right);
|
| + __ movq(left_arg, left);
|
| + }
|
| + } else if (right.is(right_arg)) {
|
| + __ movq(left_arg, left);
|
| + } else {
|
| + // Order of moves is not important.
|
| + __ movq(left_arg, left);
|
| + __ movq(right_arg, right);
|
| + }
|
| + }
|
| +
|
| + // Update flags to indicate that arguments are in registers.
|
| + SetArgsInRegisters();
|
| + __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
|
| + }
|
| +
|
| + // Call the stub.
|
| + __ CallStub(this);
|
| +}
|
| +
|
| +
|
| +void GenericBinaryOpStub::GenerateCall(
|
| + MacroAssembler* masm,
|
| + Register left,
|
| + Smi* right) {
|
| + if (!ArgsInRegistersSupported()) {
|
| + // Pass arguments on the stack.
|
| + __ push(left);
|
| + __ Push(right);
|
| + } else {
|
| + // The calling convention with registers is left in rdx and right in rax.
|
| + Register left_arg = rdx;
|
| + Register right_arg = rax;
|
| + if (left.is(left_arg)) {
|
| + __ Move(right_arg, right);
|
| + } else if (left.is(right_arg) && IsOperationCommutative()) {
|
| + __ Move(left_arg, right);
|
| + SetArgsReversed();
|
| + } else {
|
| + __ movq(left_arg, left);
|
| + __ Move(right_arg, right);
|
| + }
|
| +
|
| + // Update flags to indicate that arguments are in registers.
|
| + SetArgsInRegisters();
|
| + __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
|
| + }
|
| +
|
| + // Call the stub.
|
| + __ CallStub(this);
|
| +}
|
| +
|
| +
|
| +void GenericBinaryOpStub::GenerateCall(
|
| + MacroAssembler* masm,
|
| + Smi* left,
|
| + Register right) {
|
| + if (!ArgsInRegistersSupported()) {
|
| + // Pass arguments on the stack.
|
| + __ Push(left);
|
| + __ push(right);
|
| + } else {
|
| + // The calling convention with registers is left in rdx and right in rax.
|
| + Register left_arg = rdx;
|
| + Register right_arg = rax;
|
| + if (right.is(right_arg)) {
|
| + __ Move(left_arg, left);
|
| + } else if (right.is(left_arg) && IsOperationCommutative()) {
|
| + __ Move(right_arg, left);
|
| + SetArgsReversed();
|
| + } else {
|
| + __ Move(left_arg, left);
|
| + __ movq(right_arg, right);
|
| + }
|
| + // Update flags to indicate that arguments are in registers.
|
| + SetArgsInRegisters();
|
| + __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
|
| + }
|
| +
|
| + // Call the stub.
|
| + __ CallStub(this);
|
| +}
|
| +
|
| +
|
| void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
|
| // Perform fast-case smi code for the operation (rax <op> rbx) and
|
| // leave result in register rax.
|
| @@ -7412,22 +7522,21 @@
|
|
|
| void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
|
| Label call_runtime;
|
| - if (flags_ == SMI_CODE_IN_STUB) {
|
| + if (HasSmiCodeInStub()) {
|
| // The fast case smi code wasn't inlined in the stub caller
|
| // code. Generate it here to speed up common operations.
|
| Label slow;
|
| __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // get y
|
| __ movq(rax, Operand(rsp, 2 * kPointerSize)); // get x
|
| GenerateSmiCode(masm, &slow);
|
| - __ ret(2 * kPointerSize); // remove both operands
|
| + GenerateReturn(masm);
|
|
|
| // Too bad. The fast case smi code didn't succeed.
|
| __ bind(&slow);
|
| }
|
|
|
| - // Setup registers.
|
| - __ movq(rax, Operand(rsp, 1 * kPointerSize)); // get y
|
| - __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // get x
|
| + // Make sure the arguments are in rdx and rax.
|
| + GenerateLoadArguments(masm);
|
|
|
| // Floating point case.
|
| switch (op_) {
|
| @@ -7451,7 +7560,10 @@
|
| __ JumpIfNotSmi(rax, &skip_allocation);
|
| // Fall through!
|
| case NO_OVERWRITE:
|
| - __ AllocateHeapNumber(rax, rcx, &call_runtime);
|
| + // Allocate a heap number for the result. Keep rax and rdx intact
|
| + // for the possible runtime call.
|
| + __ AllocateHeapNumber(rbx, rcx, &call_runtime);
|
| + __ movq(rax, rbx);
|
| __ bind(&skip_allocation);
|
| break;
|
| default: UNREACHABLE();
|
| @@ -7467,7 +7579,7 @@
|
| default: UNREACHABLE();
|
| }
|
| __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4);
|
| - __ ret(2 * kPointerSize);
|
| + GenerateReturn(masm);
|
| }
|
| case Token::MOD: {
|
| // For MOD we go directly to runtime in the non-smi case.
|
| @@ -7535,7 +7647,7 @@
|
| __ JumpIfNotValidSmiValue(rax, &non_smi_result);
|
| // Tag smi result, if possible, and return.
|
| __ Integer32ToSmi(rax, rax);
|
| - __ ret(2 * kPointerSize);
|
| + GenerateReturn(masm);
|
|
|
| // All ops except SHR return a signed int32 that we load in a HeapNumber.
|
| if (op_ != Token::SHR && non_smi_result.is_linked()) {
|
| @@ -7561,7 +7673,7 @@
|
| __ movq(Operand(rsp, 1 * kPointerSize), rbx);
|
| __ fild_s(Operand(rsp, 1 * kPointerSize));
|
| __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
| - __ ret(2 * kPointerSize);
|
| + GenerateReturn(masm);
|
| }
|
|
|
| // Clear the FPU exception flag and reset the stack before calling
|
| @@ -7592,8 +7704,20 @@
|
| }
|
|
|
| // If all else fails, use the runtime system to get the correct
|
| - // result.
|
| + // result. If arguments was passed in registers now place them on the
|
| + // stack in the correct order below the return address.
|
| __ bind(&call_runtime);
|
| + if (HasArgumentsInRegisters()) {
|
| + __ pop(rcx);
|
| + if (HasArgumentsReversed()) {
|
| + __ push(rax);
|
| + __ push(rdx);
|
| + } else {
|
| + __ push(rdx);
|
| + __ push(rax);
|
| + }
|
| + __ push(rcx);
|
| + }
|
| switch (op_) {
|
| case Token::ADD:
|
| __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
|
| @@ -7634,6 +7758,26 @@
|
| }
|
|
|
|
|
| +void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
|
| + // If arguments are not passed in registers read them from the stack.
|
| + if (!HasArgumentsInRegisters()) {
|
| + __ movq(rax, Operand(rsp, 1 * kPointerSize));
|
| + __ movq(rdx, Operand(rsp, 2 * kPointerSize));
|
| + }
|
| +}
|
| +
|
| +
|
| +void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
|
| + // If arguments are not passed in registers remove them from the stack before
|
| + // returning.
|
| + if (!HasArgumentsInRegisters()) {
|
| + __ ret(2 * kPointerSize); // Remove both operands
|
| + } else {
|
| + __ ret(0);
|
| + }
|
| +}
|
| +
|
| +
|
| int CompareStub::MinorKey() {
|
| // Encode the two parameters in a unique 16 bit value.
|
| ASSERT(static_cast<unsigned>(cc_) < (1 << 15));
|
|
|