| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { | 549 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { |
| 550 ASSERT(value->is_untagged_int32()); | 550 ASSERT(value->is_untagged_int32()); |
| 551 if (value->is_register()) { | 551 if (value->is_register()) { |
| 552 Register val = value->reg(); | 552 Register val = value->reg(); |
| 553 JumpTarget done; | 553 JumpTarget done; |
| 554 __ add(val, Operand(val)); | 554 __ add(val, Operand(val)); |
| 555 done.Branch(no_overflow, value); | 555 done.Branch(no_overflow, value); |
| 556 __ sar(val, 1); | 556 __ sar(val, 1); |
| 557 // If there was an overflow, bits 30 and 31 of the original number disagree. | 557 // If there was an overflow, bits 30 and 31 of the original number disagree. |
| 558 __ xor_(val, 0x80000000u); | 558 __ xor_(val, 0x80000000u); |
| 559 if (CpuFeatures::IsSupported(SSE2)) { | 559 if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 560 CpuFeatures::Scope fscope(SSE2); | 560 CpuFeatures::Scope fscope(SSE2); |
| 561 __ cvtsi2sd(xmm0, Operand(val)); | 561 __ cvtsi2sd(xmm0, Operand(val)); |
| 562 } else { | 562 } else { |
| 563 // Move val to ST[0] in the FPU | 563 // Move val to ST[0] in the FPU |
| 564 // Push and pop are safe with respect to the virtual frame because | 564 // Push and pop are safe with respect to the virtual frame because |
| 565 // all synced elements are below the actual stack pointer. | 565 // all synced elements are below the actual stack pointer. |
| 566 __ push(val); | 566 __ push(val); |
| 567 __ fild_s(Operand(esp, 0)); | 567 __ fild_s(Operand(esp, 0)); |
| 568 __ pop(val); | 568 __ pop(val); |
| 569 } | 569 } |
| 570 Result scratch = allocator_->Allocate(); | 570 Result scratch = allocator_->Allocate(); |
| 571 ASSERT(scratch.is_register()); | 571 ASSERT(scratch.is_register()); |
| 572 Label allocation_failed; | 572 Label allocation_failed; |
| 573 __ AllocateHeapNumber(val, scratch.reg(), | 573 __ AllocateHeapNumber(val, scratch.reg(), |
| 574 no_reg, &allocation_failed); | 574 no_reg, &allocation_failed); |
| 575 VirtualFrame* clone = new VirtualFrame(frame_); | 575 VirtualFrame* clone = new VirtualFrame(frame_); |
| 576 scratch.Unuse(); | 576 scratch.Unuse(); |
| 577 if (CpuFeatures::IsSupported(SSE2)) { | 577 if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 578 CpuFeatures::Scope fscope(SSE2); | 578 CpuFeatures::Scope fscope(SSE2); |
| 579 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); | 579 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); |
| 580 } else { | 580 } else { |
| 581 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); | 581 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); |
| 582 } | 582 } |
| 583 done.Jump(value); | 583 done.Jump(value); |
| 584 | 584 |
| 585 // Establish the virtual frame, cloned from where AllocateHeapNumber | 585 // Establish the virtual frame, cloned from where AllocateHeapNumber |
| 586 // jumped to allocation_failed. | 586 // jumped to allocation_failed. |
| 587 RegisterFile empty_regs; | 587 RegisterFile empty_regs; |
| 588 SetFrame(clone, &empty_regs); | 588 SetFrame(clone, &empty_regs); |
| 589 __ bind(&allocation_failed); | 589 __ bind(&allocation_failed); |
| 590 if (!CpuFeatures::IsSupported(SSE2)) { | 590 if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 591 // Pop the value from the floating point stack. | 591 // Pop the value from the floating point stack. |
| 592 __ fstp(0); | 592 __ fstp(0); |
| 593 } | 593 } |
| 594 unsafe_bailout_->Jump(); | 594 unsafe_bailout_->Jump(); |
| 595 | 595 |
| 596 done.Bind(value); | 596 done.Bind(value); |
| 597 } else { | 597 } else { |
| 598 ASSERT(value->is_constant()); | 598 ASSERT(value->is_constant()); |
| 599 } | 599 } |
| 600 value->set_untagged_int32(false); | 600 value->set_untagged_int32(false); |
| 601 value->set_type_info(TypeInfo::Integer32()); | 601 value->set_type_info(TypeInfo::Integer32()); |
| 602 } | 602 } |
| 603 | 603 |
| 604 | 604 |
| 605 void CodeGenerator::Load(Expression* expr) { | 605 void CodeGenerator::Load(Expression* expr) { |
| 606 #ifdef DEBUG | 606 #ifdef DEBUG |
| 607 int original_height = frame_->height(); | 607 int original_height = frame_->height(); |
| 608 #endif | 608 #endif |
| 609 ASSERT(!in_spilled_code()); | 609 ASSERT(!in_spilled_code()); |
| 610 | 610 |
| 611 // If the expression should be a side-effect-free 32-bit int computation, | 611 // If the expression should be a side-effect-free 32-bit int computation, |
| 612 // compile that SafeInt32 path, and a bailout path. | 612 // compile that SafeInt32 path, and a bailout path. |
| 613 if (!in_safe_int32_mode() && | 613 if (!in_safe_int32_mode() && |
| 614 safe_int32_mode_enabled() && | 614 safe_int32_mode_enabled() && |
| 615 expr->side_effect_free() && | 615 expr->side_effect_free() && |
| 616 expr->num_bit_ops() > 2 && | 616 expr->num_bit_ops() > 2 && |
| 617 CpuFeatures::IsSupported(SSE2)) { | 617 masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 618 BreakTarget unsafe_bailout; | 618 BreakTarget unsafe_bailout; |
| 619 JumpTarget done; | 619 JumpTarget done; |
| 620 unsafe_bailout.set_expected_height(frame_->height()); | 620 unsafe_bailout.set_expected_height(frame_->height()); |
| 621 LoadInSafeInt32Mode(expr, &unsafe_bailout); | 621 LoadInSafeInt32Mode(expr, &unsafe_bailout); |
| 622 done.Jump(); | 622 done.Jump(); |
| 623 | 623 |
| 624 if (unsafe_bailout.is_linked()) { | 624 if (unsafe_bailout.is_linked()) { |
| 625 unsafe_bailout.Bind(); | 625 unsafe_bailout.Bind(); |
| 626 LoadWithSafeInt32ModeDisabled(expr); | 626 LoadWithSafeInt32ModeDisabled(expr); |
| 627 } | 627 } |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 OverwriteMode mode_; | 978 OverwriteMode mode_; |
| 979 Label answer_out_of_range_; | 979 Label answer_out_of_range_; |
| 980 Label non_smi_input_; | 980 Label non_smi_input_; |
| 981 Label constant_rhs_; | 981 Label constant_rhs_; |
| 982 Smi* smi_value_; | 982 Smi* smi_value_; |
| 983 }; | 983 }; |
| 984 | 984 |
| 985 | 985 |
| 986 Label* DeferredInlineBinaryOperation::NonSmiInputLabel() { | 986 Label* DeferredInlineBinaryOperation::NonSmiInputLabel() { |
| 987 if (Token::IsBitOp(op_) && | 987 if (Token::IsBitOp(op_) && |
| 988 CpuFeatures::IsSupported(SSE2)) { | 988 masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 989 return &non_smi_input_; | 989 return &non_smi_input_; |
| 990 } else { | 990 } else { |
| 991 return entry_label(); | 991 return entry_label(); |
| 992 } | 992 } |
| 993 } | 993 } |
| 994 | 994 |
| 995 | 995 |
| 996 void DeferredInlineBinaryOperation::JumpToAnswerOutOfRange(Condition cond) { | 996 void DeferredInlineBinaryOperation::JumpToAnswerOutOfRange(Condition cond) { |
| 997 __ j(cond, &answer_out_of_range_); | 997 __ j(cond, &answer_out_of_range_); |
| 998 } | 998 } |
| 999 | 999 |
| 1000 | 1000 |
| 1001 void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond, | 1001 void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond, |
| 1002 Smi* smi_value) { | 1002 Smi* smi_value) { |
| 1003 smi_value_ = smi_value; | 1003 smi_value_ = smi_value; |
| 1004 __ j(cond, &constant_rhs_); | 1004 __ j(cond, &constant_rhs_); |
| 1005 } | 1005 } |
| 1006 | 1006 |
| 1007 | 1007 |
| 1008 void DeferredInlineBinaryOperation::Generate() { | 1008 void DeferredInlineBinaryOperation::Generate() { |
| 1009 // Registers are not saved implicitly for this stub, so we should not | 1009 // Registers are not saved implicitly for this stub, so we should not |
| 1010 // tread on the registers that were not passed to us. | 1010 // tread on the registers that were not passed to us. |
| 1011 if (CpuFeatures::IsSupported(SSE2) && | 1011 if (masm()->isolate()->cpu_features()->IsSupported(SSE2) && |
| 1012 ((op_ == Token::ADD) || | 1012 ((op_ == Token::ADD) || |
| 1013 (op_ == Token::SUB) || | 1013 (op_ == Token::SUB) || |
| 1014 (op_ == Token::MUL) || | 1014 (op_ == Token::MUL) || |
| 1015 (op_ == Token::DIV))) { | 1015 (op_ == Token::DIV))) { |
| 1016 CpuFeatures::Scope use_sse2(SSE2); | 1016 CpuFeatures::Scope use_sse2(SSE2); |
| 1017 Label call_runtime, after_alloc_failure; | 1017 Label call_runtime, after_alloc_failure; |
| 1018 Label left_smi, right_smi, load_right, do_op; | 1018 Label left_smi, right_smi, load_right, do_op; |
| 1019 if (!left_info_.IsSmi()) { | 1019 if (!left_info_.IsSmi()) { |
| 1020 __ test(left_, Immediate(kSmiTagMask)); | 1020 __ test(left_, Immediate(kSmiTagMask)); |
| 1021 __ j(zero, &left_smi); | 1021 __ j(zero, &left_smi); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 } | 1137 } |
| 1138 | 1138 |
| 1139 __ bind(&non_smi_input_); | 1139 __ bind(&non_smi_input_); |
| 1140 | 1140 |
| 1141 if (rhs_is_constant) { | 1141 if (rhs_is_constant) { |
| 1142 __ bind(&constant_rhs_); | 1142 __ bind(&constant_rhs_); |
| 1143 // In this case the input is a heap object and it is in the dst_ register. | 1143 // In this case the input is a heap object and it is in the dst_ register. |
| 1144 // The left_ and right_ registers have not been initialized yet. | 1144 // The left_ and right_ registers have not been initialized yet. |
| 1145 __ mov(right_, Immediate(smi_value_)); | 1145 __ mov(right_, Immediate(smi_value_)); |
| 1146 __ mov(left_, Operand(dst_)); | 1146 __ mov(left_, Operand(dst_)); |
| 1147 if (!CpuFeatures::IsSupported(SSE2)) { | 1147 if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 1148 __ jmp(entry_label()); | 1148 __ jmp(entry_label()); |
| 1149 return; | 1149 return; |
| 1150 } else { | 1150 } else { |
| 1151 CpuFeatures::Scope use_sse2(SSE2); | 1151 CpuFeatures::Scope use_sse2(SSE2); |
| 1152 __ JumpIfNotNumber(dst_, left_info_, entry_label()); | 1152 __ JumpIfNotNumber(dst_, left_info_, entry_label()); |
| 1153 __ ConvertToInt32(dst_, left_, dst_, left_info_, entry_label()); | 1153 __ ConvertToInt32(dst_, left_, dst_, left_info_, entry_label()); |
| 1154 __ SmiUntag(right_); | 1154 __ SmiUntag(right_); |
| 1155 } | 1155 } |
| 1156 } else { | 1156 } else { |
| 1157 // We know we have SSE2 here because otherwise the label is not linked (see | 1157 // We know we have SSE2 here because otherwise the label is not linked (see |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 // Put a heap number pointer in left_. | 1250 // Put a heap number pointer in left_. |
| 1251 __ bind(&answer_out_of_range_); | 1251 __ bind(&answer_out_of_range_); |
| 1252 SaveRegisters(); | 1252 SaveRegisters(); |
| 1253 if (mode_ == OVERWRITE_LEFT) { | 1253 if (mode_ == OVERWRITE_LEFT) { |
| 1254 __ test(left_, Immediate(kSmiTagMask)); | 1254 __ test(left_, Immediate(kSmiTagMask)); |
| 1255 __ j(not_zero, &allocation_ok); | 1255 __ j(not_zero, &allocation_ok); |
| 1256 } | 1256 } |
| 1257 // This trashes right_. | 1257 // This trashes right_. |
| 1258 __ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2); | 1258 __ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2); |
| 1259 __ bind(&allocation_ok); | 1259 __ bind(&allocation_ok); |
| 1260 if (CpuFeatures::IsSupported(SSE2) && | 1260 if (masm()->isolate()->cpu_features()->IsSupported(SSE2) && |
| 1261 op_ != Token::SHR) { | 1261 op_ != Token::SHR) { |
| 1262 CpuFeatures::Scope use_sse2(SSE2); | 1262 CpuFeatures::Scope use_sse2(SSE2); |
| 1263 ASSERT(Token::IsBitOp(op_)); | 1263 ASSERT(Token::IsBitOp(op_)); |
| 1264 // Signed conversion. | 1264 // Signed conversion. |
| 1265 __ cvtsi2sd(xmm0, Operand(dst_)); | 1265 __ cvtsi2sd(xmm0, Operand(dst_)); |
| 1266 __ movdbl(FieldOperand(left_, HeapNumber::kValueOffset), xmm0); | 1266 __ movdbl(FieldOperand(left_, HeapNumber::kValueOffset), xmm0); |
| 1267 } else { | 1267 } else { |
| 1268 if (op_ == Token::SHR) { | 1268 if (op_ == Token::SHR) { |
| 1269 __ push(Immediate(0)); // High word of unsigned value. | 1269 __ push(Immediate(0)); // High word of unsigned value. |
| 1270 __ push(dst_); | 1270 __ push(dst_); |
| (...skipping 1744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3015 } else { | 3015 } else { |
| 3016 // Do the smi check, then the comparison. | 3016 // Do the smi check, then the comparison. |
| 3017 __ test(left_reg, Immediate(kSmiTagMask)); | 3017 __ test(left_reg, Immediate(kSmiTagMask)); |
| 3018 is_smi.Branch(zero, left_side, right_side); | 3018 is_smi.Branch(zero, left_side, right_side); |
| 3019 } | 3019 } |
| 3020 | 3020 |
| 3021 // Jump or fall through to here if we are comparing a non-smi to a | 3021 // Jump or fall through to here if we are comparing a non-smi to a |
| 3022 // constant smi. If the non-smi is a heap number and this is not | 3022 // constant smi. If the non-smi is a heap number and this is not |
| 3023 // a loop condition, inline the floating point code. | 3023 // a loop condition, inline the floating point code. |
| 3024 if (!is_loop_condition && | 3024 if (!is_loop_condition && |
| 3025 CpuFeatures::IsSupported(SSE2)) { | 3025 masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 3026 // Right side is a constant smi and left side has been checked | 3026 // Right side is a constant smi and left side has been checked |
| 3027 // not to be a smi. | 3027 // not to be a smi. |
| 3028 CpuFeatures::Scope use_sse2(SSE2); | 3028 CpuFeatures::Scope use_sse2(SSE2); |
| 3029 JumpTarget not_number; | 3029 JumpTarget not_number; |
| 3030 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | 3030 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 3031 Immediate(FACTORY->heap_number_map())); | 3031 Immediate(FACTORY->heap_number_map())); |
| 3032 not_number.Branch(not_equal, left_side); | 3032 not_number.Branch(not_equal, left_side); |
| 3033 __ movdbl(xmm1, | 3033 __ movdbl(xmm1, |
| 3034 FieldOperand(left_reg, HeapNumber::kValueOffset)); | 3034 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 3035 int value = Smi::cast(*right_val)->value(); | 3035 int value = Smi::cast(*right_val)->value(); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3179 | 3179 |
| 3180 | 3180 |
| 3181 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | 3181 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
| 3182 Result* right_side, | 3182 Result* right_side, |
| 3183 Condition cc, | 3183 Condition cc, |
| 3184 ControlDestination* dest) { | 3184 ControlDestination* dest) { |
| 3185 ASSERT(left_side->is_register()); | 3185 ASSERT(left_side->is_register()); |
| 3186 ASSERT(right_side->is_register()); | 3186 ASSERT(right_side->is_register()); |
| 3187 | 3187 |
| 3188 JumpTarget not_numbers; | 3188 JumpTarget not_numbers; |
| 3189 if (CpuFeatures::IsSupported(SSE2)) { | 3189 if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 3190 CpuFeatures::Scope use_sse2(SSE2); | 3190 CpuFeatures::Scope use_sse2(SSE2); |
| 3191 | 3191 |
| 3192 // Load left and right operand into registers xmm0 and xmm1 and compare. | 3192 // Load left and right operand into registers xmm0 and xmm1 and compare. |
| 3193 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, | 3193 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, |
| 3194 ¬_numbers); | 3194 ¬_numbers); |
| 3195 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, | 3195 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, |
| 3196 ¬_numbers); | 3196 ¬_numbers); |
| 3197 __ ucomisd(xmm0, xmm1); | 3197 __ ucomisd(xmm0, xmm1); |
| 3198 } else { | 3198 } else { |
| 3199 Label check_right, compare; | 3199 Label check_right, compare; |
| (...skipping 4221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7421 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); | 7421 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); |
| 7422 __ jmp(&heapnumber_allocated); | 7422 __ jmp(&heapnumber_allocated); |
| 7423 | 7423 |
| 7424 __ bind(&slow_allocate_heapnumber); | 7424 __ bind(&slow_allocate_heapnumber); |
| 7425 // Allocate a heap number. | 7425 // Allocate a heap number. |
| 7426 __ CallRuntime(Runtime::kNumberAlloc, 0); | 7426 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 7427 __ mov(edi, eax); | 7427 __ mov(edi, eax); |
| 7428 | 7428 |
| 7429 __ bind(&heapnumber_allocated); | 7429 __ bind(&heapnumber_allocated); |
| 7430 | 7430 |
| 7431 __ PrepareCallCFunction(1, ebx); | 7431 __ PrepareCallCFunction(0, ebx); |
| 7432 __ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address())); | |
| 7433 __ CallCFunction(ExternalReference::random_uint32_function(masm()->isolate()), | 7432 __ CallCFunction(ExternalReference::random_uint32_function(masm()->isolate()), |
| 7434 1); | 7433 0); |
| 7435 | 7434 |
| 7436 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 7435 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
| 7437 // by computing: | 7436 // by computing: |
| 7438 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 7437 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 7439 // This is implemented on both SSE2 and FPU. | 7438 // This is implemented on both SSE2 and FPU. |
| 7440 if (CpuFeatures::IsSupported(SSE2)) { | 7439 if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 7441 CpuFeatures::Scope fscope(SSE2); | 7440 CpuFeatures::Scope fscope(SSE2); |
| 7442 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 7441 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 7443 __ movd(xmm1, Operand(ebx)); | 7442 __ movd(xmm1, Operand(ebx)); |
| 7444 __ movd(xmm0, Operand(eax)); | 7443 __ movd(xmm0, Operand(eax)); |
| 7445 __ cvtss2sd(xmm1, xmm1); | 7444 __ cvtss2sd(xmm1, xmm1); |
| 7446 __ pxor(xmm0, xmm1); | 7445 __ pxor(xmm0, xmm1); |
| 7447 __ subsd(xmm0, xmm1); | 7446 __ subsd(xmm0, xmm1); |
| 7448 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); | 7447 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
| 7449 } else { | 7448 } else { |
| 7450 // 0x4130000000000000 is 1.0 x 2^20 as a double. | 7449 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7836 | 7835 |
| 7837 | 7836 |
| 7838 // Generates the Math.pow method. Only handles special cases and | 7837 // Generates the Math.pow method. Only handles special cases and |
| 7839 // branches to the runtime system for everything else. Please note | 7838 // branches to the runtime system for everything else. Please note |
| 7840 // that this function assumes that the callsite has executed ToNumber | 7839 // that this function assumes that the callsite has executed ToNumber |
| 7841 // on both arguments. | 7840 // on both arguments. |
| 7842 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { | 7841 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| 7843 ASSERT(args->length() == 2); | 7842 ASSERT(args->length() == 2); |
| 7844 Load(args->at(0)); | 7843 Load(args->at(0)); |
| 7845 Load(args->at(1)); | 7844 Load(args->at(1)); |
| 7846 if (!CpuFeatures::IsSupported(SSE2)) { | 7845 if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 7847 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); | 7846 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
| 7848 frame_->Push(&res); | 7847 frame_->Push(&res); |
| 7849 } else { | 7848 } else { |
| 7850 CpuFeatures::Scope use_sse2(SSE2); | 7849 CpuFeatures::Scope use_sse2(SSE2); |
| 7851 Label allocate_return; | 7850 Label allocate_return; |
| 7852 // Load the two operands while leaving the values on the frame. | 7851 // Load the two operands while leaving the values on the frame. |
| 7853 frame()->Dup(); | 7852 frame()->Dup(); |
| 7854 Result exponent = frame()->Pop(); | 7853 Result exponent = frame()->Pop(); |
| 7855 exponent.ToRegister(); | 7854 exponent.ToRegister(); |
| 7856 frame()->Spill(exponent.reg()); | 7855 frame()->Spill(exponent.reg()); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8053 frame_->Push(&result); | 8052 frame_->Push(&result); |
| 8054 } | 8053 } |
| 8055 | 8054 |
| 8056 | 8055 |
| 8057 // Generates the Math.sqrt method. Please note - this function assumes that | 8056 // Generates the Math.sqrt method. Please note - this function assumes that |
| 8058 // the callsite has executed ToNumber on the argument. | 8057 // the callsite has executed ToNumber on the argument. |
| 8059 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { | 8058 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 8060 ASSERT_EQ(args->length(), 1); | 8059 ASSERT_EQ(args->length(), 1); |
| 8061 Load(args->at(0)); | 8060 Load(args->at(0)); |
| 8062 | 8061 |
| 8063 if (!CpuFeatures::IsSupported(SSE2)) { | 8062 if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) { |
| 8064 Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); | 8063 Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| 8065 frame()->Push(&result); | 8064 frame()->Push(&result); |
| 8066 } else { | 8065 } else { |
| 8067 CpuFeatures::Scope use_sse2(SSE2); | 8066 CpuFeatures::Scope use_sse2(SSE2); |
| 8068 // Leave original value on the frame if we need to call runtime. | 8067 // Leave original value on the frame if we need to call runtime. |
| 8069 frame()->Dup(); | 8068 frame()->Dup(); |
| 8070 Result result = frame()->Pop(); | 8069 Result result = frame()->Pop(); |
| 8071 result.ToRegister(); | 8070 result.ToRegister(); |
| 8072 frame()->Spill(result.reg()); | 8071 frame()->Spill(result.reg()); |
| 8073 Label runtime; | 8072 Label runtime; |
| (...skipping 2075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10149 | 10148 |
| 10150 #define __ masm. | 10149 #define __ masm. |
| 10151 | 10150 |
| 10152 | 10151 |
| 10153 static void MemCopyWrapper(void* dest, const void* src, size_t size) { | 10152 static void MemCopyWrapper(void* dest, const void* src, size_t size) { |
| 10154 memcpy(dest, src, size); | 10153 memcpy(dest, src, size); |
| 10155 } | 10154 } |
| 10156 | 10155 |
| 10157 | 10156 |
| 10158 OS::MemCopyFunction CreateMemCopyFunction() { | 10157 OS::MemCopyFunction CreateMemCopyFunction() { |
| 10159 size_t actual_size; | 10158 HandleScope scope; |
| 10160 // Allocate buffer in executable space. | 10159 MacroAssembler masm(NULL, 1 * KB); |
| 10161 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, | |
| 10162 &actual_size, | |
| 10163 true)); | |
| 10164 if (buffer == NULL) return &MemCopyWrapper; | |
| 10165 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); | |
| 10166 | 10160 |
| 10167 // Generated code is put into a fixed, unmovable, buffer, and not into | 10161 // Generated code is put into a fixed, unmovable, buffer, and not into |
| 10168 // the V8 heap. We can't, and don't, refer to any relocatable addresses | 10162 // the V8 heap. We can't, and don't, refer to any relocatable addresses |
| 10169 // (e.g. the JavaScript nan-object). | 10163 // (e.g. the JavaScript nan-object). |
| 10170 | 10164 |
| 10171 // 32-bit C declaration function calls pass arguments on stack. | 10165 // 32-bit C declaration function calls pass arguments on stack. |
| 10172 | 10166 |
| 10173 // Stack layout: | 10167 // Stack layout: |
| 10174 // esp[12]: Third argument, size. | 10168 // esp[12]: Third argument, size. |
| 10175 // esp[8]: Second argument, source pointer. | 10169 // esp[8]: Second argument, source pointer. |
| 10176 // esp[4]: First argument, destination pointer. | 10170 // esp[4]: First argument, destination pointer. |
| 10177 // esp[0]: return address | 10171 // esp[0]: return address |
| 10178 | 10172 |
| 10179 const int kDestinationOffset = 1 * kPointerSize; | 10173 const int kDestinationOffset = 1 * kPointerSize; |
| 10180 const int kSourceOffset = 2 * kPointerSize; | 10174 const int kSourceOffset = 2 * kPointerSize; |
| 10181 const int kSizeOffset = 3 * kPointerSize; | 10175 const int kSizeOffset = 3 * kPointerSize; |
| 10182 | 10176 |
| 10183 int stack_offset = 0; // Update if we change the stack height. | 10177 int stack_offset = 0; // Update if we change the stack height. |
| 10184 | 10178 |
| 10185 if (FLAG_debug_code) { | 10179 if (FLAG_debug_code) { |
| 10186 __ cmp(Operand(esp, kSizeOffset + stack_offset), | 10180 __ cmp(Operand(esp, kSizeOffset + stack_offset), |
| 10187 Immediate(OS::kMinComplexMemCopy)); | 10181 Immediate(OS::kMinComplexMemCopy)); |
| 10188 Label ok; | 10182 Label ok; |
| 10189 __ j(greater_equal, &ok); | 10183 __ j(greater_equal, &ok); |
| 10190 __ int3(); | 10184 __ int3(); |
| 10191 __ bind(&ok); | 10185 __ bind(&ok); |
| 10192 } | 10186 } |
| 10193 if (CpuFeatures::IsSupported(SSE2)) { | 10187 if (masm.isolate()->cpu_features()->IsSupported(SSE2)) { |
| 10194 CpuFeatures::Scope enable(SSE2); | 10188 CpuFeatures::Scope enable(SSE2); |
| 10195 __ push(edi); | 10189 __ push(edi); |
| 10196 __ push(esi); | 10190 __ push(esi); |
| 10197 stack_offset += 2 * kPointerSize; | 10191 stack_offset += 2 * kPointerSize; |
| 10198 Register dst = edi; | 10192 Register dst = edi; |
| 10199 Register src = esi; | 10193 Register src = esi; |
| 10200 Register count = ecx; | 10194 Register count = ecx; |
| 10201 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); | 10195 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); |
| 10202 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); | 10196 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); |
| 10203 __ mov(count, Operand(esp, stack_offset + kSizeOffset)); | 10197 __ mov(count, Operand(esp, stack_offset + kSizeOffset)); |
| 10204 | 10198 |
| 10205 | 10199 |
| 10206 __ movdqu(xmm0, Operand(src, 0)); | 10200 __ movdqu(xmm0, Operand(src, 0)); |
| 10207 __ movdqu(Operand(dst, 0), xmm0); | 10201 __ movdqu(Operand(dst, 0), xmm0); |
| 10208 __ mov(edx, dst); | 10202 __ mov(edx, dst); |
| 10209 __ and_(edx, 0xF); | 10203 __ and_(edx, 0xF); |
| 10210 __ neg(edx); | 10204 __ neg(edx); |
| 10211 __ add(Operand(edx), Immediate(16)); | 10205 __ add(Operand(edx), Immediate(16)); |
| 10212 __ add(dst, Operand(edx)); | 10206 __ add(dst, Operand(edx)); |
| 10213 __ add(src, Operand(edx)); | 10207 __ add(src, Operand(edx)); |
| 10214 __ sub(Operand(count), edx); | 10208 __ sub(Operand(count), edx); |
| 10215 | 10209 |
| 10216 // edi is now aligned. Check if esi is also aligned. | 10210 // edi is now aligned. Check if esi is also aligned. |
| 10217 Label unaligned_source; | 10211 Label unaligned_source; |
| 10218 __ test(Operand(src), Immediate(0x0F)); | 10212 __ test(Operand(src), Immediate(0x0F)); |
| 10219 __ j(not_zero, &unaligned_source); | 10213 __ j(not_zero, &unaligned_source); |
| 10220 { | 10214 { |
| 10215 __ IncrementCounter(masm.isolate()->counters()->memcopy_aligned(), 1); |
| 10221 // Copy loop for aligned source and destination. | 10216 // Copy loop for aligned source and destination. |
| 10222 __ mov(edx, count); | 10217 __ mov(edx, count); |
| 10223 Register loop_count = ecx; | 10218 Register loop_count = ecx; |
| 10224 Register count = edx; | 10219 Register count = edx; |
| 10225 __ shr(loop_count, 5); | 10220 __ shr(loop_count, 5); |
| 10226 { | 10221 { |
| 10227 // Main copy loop. | 10222 // Main copy loop. |
| 10228 Label loop; | 10223 Label loop; |
| 10229 __ bind(&loop); | 10224 __ bind(&loop); |
| 10230 __ prefetch(Operand(src, 0x20), 1); | 10225 __ prefetch(Operand(src, 0x20), 1); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 10258 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); | 10253 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); |
| 10259 __ pop(esi); | 10254 __ pop(esi); |
| 10260 __ pop(edi); | 10255 __ pop(edi); |
| 10261 __ ret(0); | 10256 __ ret(0); |
| 10262 } | 10257 } |
| 10263 __ Align(16); | 10258 __ Align(16); |
| 10264 { | 10259 { |
| 10265 // Copy loop for unaligned source and aligned destination. | 10260 // Copy loop for unaligned source and aligned destination. |
| 10266 // If source is not aligned, we can't read it as efficiently. | 10261 // If source is not aligned, we can't read it as efficiently. |
| 10267 __ bind(&unaligned_source); | 10262 __ bind(&unaligned_source); |
| 10263 __ IncrementCounter(masm.isolate()->counters()->memcopy_unaligned(), 1); |
| 10268 __ mov(edx, ecx); | 10264 __ mov(edx, ecx); |
| 10269 Register loop_count = ecx; | 10265 Register loop_count = ecx; |
| 10270 Register count = edx; | 10266 Register count = edx; |
| 10271 __ shr(loop_count, 5); | 10267 __ shr(loop_count, 5); |
| 10272 { | 10268 { |
| 10273 // Main copy loop | 10269 // Main copy loop |
| 10274 Label loop; | 10270 Label loop; |
| 10275 __ bind(&loop); | 10271 __ bind(&loop); |
| 10276 __ prefetch(Operand(src, 0x20), 1); | 10272 __ prefetch(Operand(src, 0x20), 1); |
| 10277 __ movdqu(xmm0, Operand(src, 0x00)); | 10273 __ movdqu(xmm0, Operand(src, 0x00)); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 10301 __ movdqu(xmm0, Operand(src, count, times_1, -0x10)); | 10297 __ movdqu(xmm0, Operand(src, count, times_1, -0x10)); |
| 10302 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0); | 10298 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0); |
| 10303 | 10299 |
| 10304 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); | 10300 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); |
| 10305 __ pop(esi); | 10301 __ pop(esi); |
| 10306 __ pop(edi); | 10302 __ pop(edi); |
| 10307 __ ret(0); | 10303 __ ret(0); |
| 10308 } | 10304 } |
| 10309 | 10305 |
| 10310 } else { | 10306 } else { |
| 10307 __ IncrementCounter(masm.isolate()->counters()->memcopy_noxmm(), 1); |
| 10311 // SSE2 not supported. Unlikely to happen in practice. | 10308 // SSE2 not supported. Unlikely to happen in practice. |
| 10312 __ push(edi); | 10309 __ push(edi); |
| 10313 __ push(esi); | 10310 __ push(esi); |
| 10314 stack_offset += 2 * kPointerSize; | 10311 stack_offset += 2 * kPointerSize; |
| 10315 __ cld(); | 10312 __ cld(); |
| 10316 Register dst = edi; | 10313 Register dst = edi; |
| 10317 Register src = esi; | 10314 Register src = esi; |
| 10318 Register count = ecx; | 10315 Register count = ecx; |
| 10319 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); | 10316 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); |
| 10320 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); | 10317 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 10347 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); | 10344 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); |
| 10348 __ pop(esi); | 10345 __ pop(esi); |
| 10349 __ pop(edi); | 10346 __ pop(edi); |
| 10350 __ ret(0); | 10347 __ ret(0); |
| 10351 } | 10348 } |
| 10352 | 10349 |
| 10353 CodeDesc desc; | 10350 CodeDesc desc; |
| 10354 masm.GetCode(&desc); | 10351 masm.GetCode(&desc); |
| 10355 ASSERT(desc.reloc_size == 0); | 10352 ASSERT(desc.reloc_size == 0); |
| 10356 | 10353 |
| 10357 CPU::FlushICache(buffer, actual_size); | 10354 // Copy the generated code into an executable chunk and return a pointer |
| 10358 return FUNCTION_CAST<OS::MemCopyFunction>(buffer); | 10355 // to the first instruction in it as a C++ function pointer. |
| 10356 LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE); |
| 10357 if (chunk == NULL) return &MemCopyWrapper; |
| 10358 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size); |
| 10359 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size); |
| 10360 return FUNCTION_CAST<OS::MemCopyFunction>(chunk->GetStartAddress()); |
| 10359 } | 10361 } |
| 10360 | 10362 |
| 10361 #undef __ | 10363 #undef __ |
| 10362 | 10364 |
| 10363 } } // namespace v8::internal | 10365 } } // namespace v8::internal |
| 10364 | 10366 |
| 10365 #endif // V8_TARGET_ARCH_IA32 | 10367 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |