Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 761 // be either smi or heap number objects (fp values). Requirements: | 761 // be either smi or heap number objects (fp values). Requirements: |
| 762 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 762 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
| 763 // floating point numbers on FPU stack. | 763 // floating point numbers on FPU stack. |
| 764 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); | 764 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); |
| 765 // Test if operands are smi or number objects (fp). Requirements: | 765 // Test if operands are smi or number objects (fp). Requirements: |
| 766 // operand_1 in eax, operand_2 in edx; falls through on float | 766 // operand_1 in eax, operand_2 in edx; falls through on float |
| 767 // operands, jumps to the non_float label otherwise. | 767 // operands, jumps to the non_float label otherwise. |
| 768 static void CheckFloatOperands(MacroAssembler* masm, | 768 static void CheckFloatOperands(MacroAssembler* masm, |
| 769 Label* non_float, | 769 Label* non_float, |
| 770 Register scratch); | 770 Register scratch); |
| 771 // Test if operands are numbers (smi or HeapNumber objects), and load | |
| 772 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | |
| 773 // either operand is not a number. Operands are in edx and eax. | |
| 774 // Leaves operands unchanged. | |
| 775 static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); | |
| 771 // Allocate a heap number in new space with undefined value. | 776 // Allocate a heap number in new space with undefined value. |
| 772 // Returns tagged pointer in eax, or jumps to need_gc if new space is full. | 777 // Returns tagged pointer in eax, or jumps to need_gc if new space is full. |
| 773 static void AllocateHeapNumber(MacroAssembler* masm, | 778 static void AllocateHeapNumber(MacroAssembler* masm, |
| 774 Label* need_gc, | 779 Label* need_gc, |
| 775 Register scratch1, | 780 Register scratch1, |
| 776 Register scratch2, | 781 Register scratch2, |
| 777 Register result); | 782 Register result); |
| 778 }; | 783 }; |
| 779 | 784 |
| 780 | 785 |
| (...skipping 5911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6692 __ mov(edx, Operand(esp, 2 * kPointerSize)); // get x | 6697 __ mov(edx, Operand(esp, 2 * kPointerSize)); // get x |
| 6693 | 6698 |
| 6694 // Floating point case. | 6699 // Floating point case. |
| 6695 switch (op_) { | 6700 switch (op_) { |
| 6696 case Token::ADD: | 6701 case Token::ADD: |
| 6697 case Token::SUB: | 6702 case Token::SUB: |
| 6698 case Token::MUL: | 6703 case Token::MUL: |
| 6699 case Token::DIV: { | 6704 case Token::DIV: { |
| 6700 // eax: y | 6705 // eax: y |
| 6701 // edx: x | 6706 // edx: x |
| 6702 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 6707 |
| 6703 // Fast-case: Both operands are numbers. | 6708 if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) { |
| 6704 // Allocate a heap number, if needed. | 6709 CpuFeatures::Scope use_sse2(CpuFeatures::SSE2); |
| 6705 Label skip_allocation; | 6710 FloatingPointHelper::LoadSse2Operands(masm, &call_runtime); |
| 6706 switch (mode_) { | 6711 |
| 6707 case OVERWRITE_LEFT: | 6712 switch (op_) { |
| 6708 __ mov(eax, Operand(edx)); | 6713 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 6709 // Fall through! | 6714 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 6710 case OVERWRITE_RIGHT: | 6715 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 6711 // If the argument in eax is already an object, we skip the | 6716 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 6712 // allocation of a heap number. | 6717 default: UNREACHABLE(); |
| 6713 __ test(eax, Immediate(kSmiTagMask)); | 6718 } |
| 6714 __ j(not_zero, &skip_allocation, not_taken); | 6719 // Allocate a heap number, if needed. |
| 6715 // Fall through! | 6720 Label skip_allocation; |
| 6716 case NO_OVERWRITE: | 6721 switch (mode_) { |
| 6717 FloatingPointHelper::AllocateHeapNumber(masm, | 6722 case OVERWRITE_LEFT: |
| 6718 &call_runtime, | 6723 __ mov(eax, Operand(edx)); |
| 6719 ecx, | 6724 // Fall through! |
| 6720 edx, | 6725 case OVERWRITE_RIGHT: |
| 6721 eax); | 6726 // If the argument in eax is already an object, we skip the |
| 6722 __ bind(&skip_allocation); | 6727 // allocation of a heap number. |
| 6723 break; | 6728 __ test(eax, Immediate(kSmiTagMask)); |
| 6724 default: UNREACHABLE(); | 6729 __ j(not_zero, &skip_allocation, not_taken); |
| 6730 // Fall through! | |
| 6731 case NO_OVERWRITE: | |
| 6732 FloatingPointHelper::AllocateHeapNumber(masm, | |
| 6733 &call_runtime, | |
| 6734 ecx, | |
| 6735 edx, | |
| 6736 eax); | |
| 6737 __ bind(&skip_allocation); | |
| 6738 break; | |
| 6739 default: UNREACHABLE(); | |
| 6740 } | |
| 6741 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
| 6742 __ ret(2 * kPointerSize); | |
| 6743 | |
| 6744 } else { // SSE2 not available, use FPU. | |
| 6745 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | |
|
Mark Mentovai
2009/09/09 15:09:55
Shouldn't this be done for both SSE2 and x87, or s
William Hesse
2009/09/10 07:27:37
The checking and the loading are combined into one
| |
| 6746 // Allocate a heap number, if needed. | |
|
Mark Mentovai
2009/09/09 15:09:55
Is there a reason that this is done before the x87
William Hesse
2009/09/10 07:27:37
This code has to go after the check, but before th
| |
| 6747 Label skip_allocation; | |
| 6748 switch (mode_) { | |
| 6749 case OVERWRITE_LEFT: | |
| 6750 __ mov(eax, Operand(edx)); | |
| 6751 // Fall through! | |
| 6752 case OVERWRITE_RIGHT: | |
| 6753 // If the argument in eax is already an object, we skip the | |
| 6754 // allocation of a heap number. | |
| 6755 __ test(eax, Immediate(kSmiTagMask)); | |
| 6756 __ j(not_zero, &skip_allocation, not_taken); | |
| 6757 // Fall through! | |
| 6758 case NO_OVERWRITE: | |
| 6759 FloatingPointHelper::AllocateHeapNumber(masm, | |
| 6760 &call_runtime, | |
| 6761 ecx, | |
| 6762 edx, | |
| 6763 eax); | |
| 6764 __ bind(&skip_allocation); | |
| 6765 break; | |
| 6766 default: UNREACHABLE(); | |
| 6767 } | |
| 6768 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
| 6769 | |
| 6770 switch (op_) { | |
| 6771 case Token::ADD: __ faddp(1); break; | |
| 6772 case Token::SUB: __ fsubp(1); break; | |
| 6773 case Token::MUL: __ fmulp(1); break; | |
| 6774 case Token::DIV: __ fdivp(1); break; | |
| 6775 default: UNREACHABLE(); | |
| 6776 } | |
| 6777 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 6778 __ ret(2 * kPointerSize); | |
| 6725 } | 6779 } |
| 6726 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
| 6727 | |
| 6728 switch (op_) { | |
| 6729 case Token::ADD: __ faddp(1); break; | |
| 6730 case Token::SUB: __ fsubp(1); break; | |
| 6731 case Token::MUL: __ fmulp(1); break; | |
| 6732 case Token::DIV: __ fdivp(1); break; | |
| 6733 default: UNREACHABLE(); | |
| 6734 } | |
| 6735 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 6736 __ ret(2 * kPointerSize); | |
| 6737 } | 6780 } |
| 6738 case Token::MOD: { | 6781 case Token::MOD: { |
| 6739 // For MOD we go directly to runtime in the non-smi case. | 6782 // For MOD we go directly to runtime in the non-smi case. |
| 6740 break; | 6783 break; |
| 6741 } | 6784 } |
| 6742 case Token::BIT_OR: | 6785 case Token::BIT_OR: |
| 6743 case Token::BIT_AND: | 6786 case Token::BIT_AND: |
| 6744 case Token::BIT_XOR: | 6787 case Token::BIT_XOR: |
| 6745 case Token::SAR: | 6788 case Token::SAR: |
| 6746 case Token::SHL: | 6789 case Token::SHL: |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6974 __ bind(&load_smi); | 7017 __ bind(&load_smi); |
| 6975 __ sar(number, kSmiTagSize); | 7018 __ sar(number, kSmiTagSize); |
| 6976 __ push(number); | 7019 __ push(number); |
| 6977 __ fild_s(Operand(esp, 0)); | 7020 __ fild_s(Operand(esp, 0)); |
| 6978 __ pop(number); | 7021 __ pop(number); |
| 6979 | 7022 |
| 6980 __ bind(&done); | 7023 __ bind(&done); |
| 6981 } | 7024 } |
| 6982 | 7025 |
| 6983 | 7026 |
| 7027 void FloatingPointHelper::LoadSse2Operands(MacroAssembler* masm, | |
| 7028 Label* not_numbers) { | |
| 7029 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | |
| 7030 // Load operand in edx into xmm0, or branch to not_numbers. | |
| 7031 __ test(edx, Immediate(kSmiTagMask)); | |
| 7032 __ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi. | |
| 7033 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Factory::heap_number_map()); | |
| 7034 __ j(not_equal, not_numbers); // Argument in edx is not a number. | |
| 7035 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | |
| 7036 __ bind(&load_eax); | |
| 7037 // Load operand in eax into xmm1, or branch to not_numbers. | |
| 7038 __ test(eax, Immediate(kSmiTagMask)); | |
| 7039 __ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi. | |
| 7040 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::heap_number_map()); | |
| 7041 __ j(equal, &load_float_eax); | |
| 7042 __ jmp(not_numbers); // Argument in eax is not a number. | |
| 7043 __ bind(&load_smi_edx); | |
| 7044 __ sar(edx, 1); // Untag smi before converting to float. | |
| 7045 __ cvtsi2sd(xmm0, Operand(edx)); | |
| 7046 __ shl(edx, 1); // Retag smi for heap number overwriting test. | |
| 7047 __ jmp(&load_eax); | |
| 7048 __ bind(&load_smi_eax); | |
| 7049 __ sar(eax, 1); // Untag smi before converting to float. | |
| 7050 __ cvtsi2sd(xmm1, Operand(eax)); | |
| 7051 __ shl(eax, 1); // Retag smi for heap number overwriting test. | |
| 7052 __ jmp(&done); | |
| 7053 __ bind(&load_float_eax); | |
| 7054 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 7055 __ bind(&done); | |
| 7056 } | |
| 7057 | |
| 7058 | |
| 6984 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 7059 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| 6985 Register scratch) { | 7060 Register scratch) { |
| 6986 Label load_smi_1, load_smi_2, done_load_1, done; | 7061 Label load_smi_1, load_smi_2, done_load_1, done; |
| 6987 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 7062 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| 6988 __ test(scratch, Immediate(kSmiTagMask)); | 7063 __ test(scratch, Immediate(kSmiTagMask)); |
| 6989 __ j(zero, &load_smi_1, not_taken); | 7064 __ j(zero, &load_smi_1, not_taken); |
| 6990 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); | 7065 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
| 6991 __ bind(&done_load_1); | 7066 __ bind(&done_load_1); |
| 6992 | 7067 |
| 6993 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | 7068 __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7336 | 7411 |
| 7337 // Push arguments below the return address. | 7412 // Push arguments below the return address. |
| 7338 __ pop(ecx); | 7413 __ pop(ecx); |
| 7339 __ push(eax); | 7414 __ push(eax); |
| 7340 __ push(edx); | 7415 __ push(edx); |
| 7341 __ push(ecx); | 7416 __ push(ecx); |
| 7342 | 7417 |
| 7343 // Inlined floating point compare. | 7418 // Inlined floating point compare. |
| 7344 // Call builtin if operands are not floating point or smi. | 7419 // Call builtin if operands are not floating point or smi. |
| 7345 Label check_for_symbols; | 7420 Label check_for_symbols; |
| 7346 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); | 7421 Label unordered; |
| 7347 FloatingPointHelper::LoadFloatOperands(masm, ecx); | 7422 if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) { |
| 7348 __ FCmp(); | 7423 CpuFeatures::Scope use_sse2(CpuFeatures::SSE2); |
| 7424 CpuFeatures::Scope use_cmov(CpuFeatures::CMOV); | |
| 7349 | 7425 |
| 7350 // Jump to builtin for NaN. | 7426 FloatingPointHelper::LoadSse2Operands(masm, &check_for_symbols); |
| 7351 __ j(parity_even, &call_builtin, not_taken); | 7427 __ comisd(xmm0, xmm1); |
| 7352 | 7428 |
| 7353 // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up. | 7429 // Jump to builtin for NaN. |
| 7354 Label below_lbl, above_lbl; | 7430 __ j(parity_even, &unordered, not_taken); |
| 7355 // use edx, eax to convert unsigned to signed comparison | 7431 __ mov(eax, 0); // equal |
| 7356 __ j(below, &below_lbl, not_taken); | 7432 __ mov(ecx, Immediate(Smi::FromInt(1))); |
| 7357 __ j(above, &above_lbl, not_taken); | 7433 __ cmov(above, eax, Operand(ecx)); |
| 7434 __ mov(ecx, Immediate(Smi::FromInt(-1))); | |
| 7435 __ cmov(below, eax, Operand(ecx)); | |
| 7436 __ ret(2 * kPointerSize); | |
| 7437 } else { | |
| 7438 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); | |
| 7439 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
| 7440 __ FCmp(); | |
| 7358 | 7441 |
| 7359 __ xor_(eax, Operand(eax)); // equal | 7442 // Jump to builtin for NaN. |
| 7360 __ ret(2 * kPointerSize); | 7443 __ j(parity_even, &unordered, not_taken); |
| 7361 | 7444 |
| 7362 __ bind(&below_lbl); | 7445 Label below_lbl, above_lbl; |
| 7363 __ mov(eax, -1); | 7446 // Return a result of -1, 0, or 1, to indicate result of comparison. |
| 7364 __ ret(2 * kPointerSize); | 7447 __ j(below, &below_lbl, not_taken); |
| 7448 __ j(above, &above_lbl, not_taken); | |
| 7365 | 7449 |
| 7366 __ bind(&above_lbl); | 7450 __ xor_(eax, Operand(eax)); // equal |
| 7367 __ mov(eax, 1); | 7451 // Both arguments were pushed in case a runtime call was needed. |
| 7452 __ ret(2 * kPointerSize); | |
| 7453 | |
| 7454 __ bind(&below_lbl); | |
| 7455 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
| 7456 __ ret(2 * kPointerSize); | |
| 7457 | |
| 7458 __ bind(&above_lbl); | |
| 7459 __ mov(eax, Immediate(Smi::FromInt(1))); | |
| 7460 __ ret(2 * kPointerSize); // eax, edx were pushed | |
| 7461 } | |
| 7462 // If one of the numbers was NaN, then the result is always false. | |
| 7463 // The cc is never not-equal. | |
| 7464 __ bind(&unordered); | |
| 7465 ASSERT(cc_ != not_equal); | |
| 7466 if (cc_ == less || cc_ == less_equal) { | |
| 7467 __ mov(eax, Immediate(Smi::FromInt(1))); | |
| 7468 } else { | |
| 7469 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
| 7470 } | |
| 7368 __ ret(2 * kPointerSize); // eax, edx were pushed | 7471 __ ret(2 * kPointerSize); // eax, edx were pushed |
| 7369 | 7472 |
| 7370 // Fast negative check for symbol-to-symbol equality. | 7473 // Fast negative check for symbol-to-symbol equality. |
| 7371 __ bind(&check_for_symbols); | 7474 __ bind(&check_for_symbols); |
| 7372 if (cc_ == equal) { | 7475 if (cc_ == equal) { |
| 7373 BranchIfNonSymbol(masm, &call_builtin, eax, ecx); | 7476 BranchIfNonSymbol(masm, &call_builtin, eax, ecx); |
| 7374 BranchIfNonSymbol(masm, &call_builtin, edx, ecx); | 7477 BranchIfNonSymbol(masm, &call_builtin, edx, ecx); |
| 7375 | 7478 |
| 7376 // We've already checked for object identity, so if both operands | 7479 // We've already checked for object identity, so if both operands |
| 7377 // are symbols they aren't equal. Register eax already holds a | 7480 // are symbols they aren't equal. Register eax already holds a |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7876 | 7979 |
| 7877 int CompareStub::MinorKey() { | 7980 int CompareStub::MinorKey() { |
| 7878 // Encode the two parameters in a unique 16 bit value. | 7981 // Encode the two parameters in a unique 16 bit value. |
| 7879 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 7982 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
| 7880 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 7983 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
| 7881 } | 7984 } |
| 7882 | 7985 |
| 7883 #undef __ | 7986 #undef __ |
| 7884 | 7987 |
| 7885 } } // namespace v8::internal | 7988 } } // namespace v8::internal |
| OLD | NEW |