| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 descriptor->deoptimization_handler_ = NULL; | 63 descriptor->deoptimization_handler_ = NULL; |
| 64 } | 64 } |
| 65 | 65 |
| 66 | 66 |
| 67 void NumberToStringStub::InitializeInterfaceDescriptor( | 67 void NumberToStringStub::InitializeInterfaceDescriptor( |
| 68 Isolate* isolate, | 68 Isolate* isolate, |
| 69 CodeStubInterfaceDescriptor* descriptor) { | 69 CodeStubInterfaceDescriptor* descriptor) { |
| 70 static Register registers[] = { eax }; | 70 static Register registers[] = { eax }; |
| 71 descriptor->register_param_count_ = 1; | 71 descriptor->register_param_count_ = 1; |
| 72 descriptor->register_params_ = registers; | 72 descriptor->register_params_ = registers; |
| 73 descriptor->deoptimization_handler_ = NULL; | 73 descriptor->deoptimization_handler_ = |
| 74 Runtime::FunctionForId(Runtime::kNumberToString)->entry; |
| 74 } | 75 } |
| 75 | 76 |
| 76 | 77 |
| 77 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( | 78 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
| 78 Isolate* isolate, | 79 Isolate* isolate, |
| 79 CodeStubInterfaceDescriptor* descriptor) { | 80 CodeStubInterfaceDescriptor* descriptor) { |
| 80 static Register registers[] = { eax, ebx, ecx }; | 81 static Register registers[] = { eax, ebx, ecx }; |
| 81 descriptor->register_param_count_ = 3; | 82 descriptor->register_param_count_ = 3; |
| 82 descriptor->register_params_ = registers; | 83 descriptor->register_params_ = registers; |
| 83 descriptor->deoptimization_handler_ = | 84 descriptor->deoptimization_handler_ = |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 int constant_stack_parameter_count) { | 166 int constant_stack_parameter_count) { |
| 166 // register state | 167 // register state |
| 167 // eax -- number of arguments | 168 // eax -- number of arguments |
| 168 // edi -- function | 169 // edi -- function |
| 169 // ebx -- type info cell with elements kind | 170 // ebx -- type info cell with elements kind |
| 170 static Register registers[] = { edi, ebx }; | 171 static Register registers[] = { edi, ebx }; |
| 171 descriptor->register_param_count_ = 2; | 172 descriptor->register_param_count_ = 2; |
| 172 | 173 |
| 173 if (constant_stack_parameter_count != 0) { | 174 if (constant_stack_parameter_count != 0) { |
| 174 // stack param count needs (constructor pointer, and single argument) | 175 // stack param count needs (constructor pointer, and single argument) |
| 175 descriptor->stack_parameter_count_ = &eax; | 176 descriptor->stack_parameter_count_ = eax; |
| 176 } | 177 } |
| 177 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; | 178 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; |
| 178 descriptor->register_params_ = registers; | 179 descriptor->register_params_ = registers; |
| 179 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; | 180 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; |
| 180 descriptor->deoptimization_handler_ = | 181 descriptor->deoptimization_handler_ = |
| 181 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry; | 182 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry; |
| 182 } | 183 } |
| 183 | 184 |
| 184 | 185 |
| 185 static void InitializeInternalArrayConstructorDescriptor( | 186 static void InitializeInternalArrayConstructorDescriptor( |
| 186 Isolate* isolate, | 187 Isolate* isolate, |
| 187 CodeStubInterfaceDescriptor* descriptor, | 188 CodeStubInterfaceDescriptor* descriptor, |
| 188 int constant_stack_parameter_count) { | 189 int constant_stack_parameter_count) { |
| 189 // register state | 190 // register state |
| 190 // eax -- number of arguments | 191 // eax -- number of arguments |
| 191 // edi -- constructor function | 192 // edi -- constructor function |
| 192 static Register registers[] = { edi }; | 193 static Register registers[] = { edi }; |
| 193 descriptor->register_param_count_ = 1; | 194 descriptor->register_param_count_ = 1; |
| 194 | 195 |
| 195 if (constant_stack_parameter_count != 0) { | 196 if (constant_stack_parameter_count != 0) { |
| 196 // stack param count needs (constructor pointer, and single argument) | 197 // stack param count needs (constructor pointer, and single argument) |
| 197 descriptor->stack_parameter_count_ = &eax; | 198 descriptor->stack_parameter_count_ = eax; |
| 198 } | 199 } |
| 199 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; | 200 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; |
| 200 descriptor->register_params_ = registers; | 201 descriptor->register_params_ = registers; |
| 201 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; | 202 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; |
| 202 descriptor->deoptimization_handler_ = | 203 descriptor->deoptimization_handler_ = |
| 203 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry; | 204 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry; |
| 204 } | 205 } |
| 205 | 206 |
| 206 | 207 |
| 207 void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( | 208 void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 448 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 448 // We don't allow a GC during a store buffer overflow so there is no need to | 449 // We don't allow a GC during a store buffer overflow so there is no need to |
| 449 // store the registers in any particular way, but we do have to store and | 450 // store the registers in any particular way, but we do have to store and |
| 450 // restore them. | 451 // restore them. |
| 451 __ pushad(); | 452 __ pushad(); |
| 452 if (save_doubles_ == kSaveFPRegs) { | 453 if (save_doubles_ == kSaveFPRegs) { |
| 453 CpuFeatureScope scope(masm, SSE2); | 454 CpuFeatureScope scope(masm, SSE2); |
| 454 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 455 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 455 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 456 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 456 XMMRegister reg = XMMRegister::from_code(i); | 457 XMMRegister reg = XMMRegister::from_code(i); |
| 457 __ movdbl(Operand(esp, i * kDoubleSize), reg); | 458 __ movsd(Operand(esp, i * kDoubleSize), reg); |
| 458 } | 459 } |
| 459 } | 460 } |
| 460 const int argument_count = 1; | 461 const int argument_count = 1; |
| 461 | 462 |
| 462 AllowExternalCallThatCantCauseGC scope(masm); | 463 AllowExternalCallThatCantCauseGC scope(masm); |
| 463 __ PrepareCallCFunction(argument_count, ecx); | 464 __ PrepareCallCFunction(argument_count, ecx); |
| 464 __ mov(Operand(esp, 0 * kPointerSize), | 465 __ mov(Operand(esp, 0 * kPointerSize), |
| 465 Immediate(ExternalReference::isolate_address(masm->isolate()))); | 466 Immediate(ExternalReference::isolate_address(masm->isolate()))); |
| 466 __ CallCFunction( | 467 __ CallCFunction( |
| 467 ExternalReference::store_buffer_overflow_function(masm->isolate()), | 468 ExternalReference::store_buffer_overflow_function(masm->isolate()), |
| 468 argument_count); | 469 argument_count); |
| 469 if (save_doubles_ == kSaveFPRegs) { | 470 if (save_doubles_ == kSaveFPRegs) { |
| 470 CpuFeatureScope scope(masm, SSE2); | 471 CpuFeatureScope scope(masm, SSE2); |
| 471 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 472 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 472 XMMRegister reg = XMMRegister::from_code(i); | 473 XMMRegister reg = XMMRegister::from_code(i); |
| 473 __ movdbl(reg, Operand(esp, i * kDoubleSize)); | 474 __ movsd(reg, Operand(esp, i * kDoubleSize)); |
| 474 } | 475 } |
| 475 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 476 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 476 } | 477 } |
| 477 __ popad(); | 478 __ popad(); |
| 478 __ ret(0); | 479 __ ret(0); |
| 479 } | 480 } |
| 480 | 481 |
| 481 | 482 |
| 482 class FloatingPointHelper : public AllStatic { | 483 class FloatingPointHelper : public AllStatic { |
| 483 public: | 484 public: |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 __ j(not_equal, &cache_miss, Label::kNear); | 764 __ j(not_equal, &cache_miss, Label::kNear); |
| 764 // Cache hit! | 765 // Cache hit! |
| 765 Counters* counters = masm->isolate()->counters(); | 766 Counters* counters = masm->isolate()->counters(); |
| 766 __ IncrementCounter(counters->transcendental_cache_hit(), 1); | 767 __ IncrementCounter(counters->transcendental_cache_hit(), 1); |
| 767 __ mov(eax, Operand(ecx, 2 * kIntSize)); | 768 __ mov(eax, Operand(ecx, 2 * kIntSize)); |
| 768 if (tagged) { | 769 if (tagged) { |
| 769 __ fstp(0); | 770 __ fstp(0); |
| 770 __ ret(kPointerSize); | 771 __ ret(kPointerSize); |
| 771 } else { // UNTAGGED. | 772 } else { // UNTAGGED. |
| 772 CpuFeatureScope scope(masm, SSE2); | 773 CpuFeatureScope scope(masm, SSE2); |
| 773 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 774 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 774 __ Ret(); | 775 __ Ret(); |
| 775 } | 776 } |
| 776 | 777 |
| 777 __ bind(&cache_miss); | 778 __ bind(&cache_miss); |
| 778 __ IncrementCounter(counters->transcendental_cache_miss(), 1); | 779 __ IncrementCounter(counters->transcendental_cache_miss(), 1); |
| 779 // Update cache with new value. | 780 // Update cache with new value. |
| 780 // We are short on registers, so use no_reg as scratch. | 781 // We are short on registers, so use no_reg as scratch. |
| 781 // This gives slightly larger code. | 782 // This gives slightly larger code. |
| 782 if (tagged) { | 783 if (tagged) { |
| 783 __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); | 784 __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); |
| 784 } else { // UNTAGGED. | 785 } else { // UNTAGGED. |
| 785 CpuFeatureScope scope(masm, SSE2); | 786 CpuFeatureScope scope(masm, SSE2); |
| 786 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); | 787 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); |
| 787 __ sub(esp, Immediate(kDoubleSize)); | 788 __ sub(esp, Immediate(kDoubleSize)); |
| 788 __ movdbl(Operand(esp, 0), xmm1); | 789 __ movsd(Operand(esp, 0), xmm1); |
| 789 __ fld_d(Operand(esp, 0)); | 790 __ fld_d(Operand(esp, 0)); |
| 790 __ add(esp, Immediate(kDoubleSize)); | 791 __ add(esp, Immediate(kDoubleSize)); |
| 791 } | 792 } |
| 792 GenerateOperation(masm, type_); | 793 GenerateOperation(masm, type_); |
| 793 __ mov(Operand(ecx, 0), ebx); | 794 __ mov(Operand(ecx, 0), ebx); |
| 794 __ mov(Operand(ecx, kIntSize), edx); | 795 __ mov(Operand(ecx, kIntSize), edx); |
| 795 __ mov(Operand(ecx, 2 * kIntSize), eax); | 796 __ mov(Operand(ecx, 2 * kIntSize), eax); |
| 796 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 797 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 797 if (tagged) { | 798 if (tagged) { |
| 798 __ ret(kPointerSize); | 799 __ ret(kPointerSize); |
| 799 } else { // UNTAGGED. | 800 } else { // UNTAGGED. |
| 800 CpuFeatureScope scope(masm, SSE2); | 801 CpuFeatureScope scope(masm, SSE2); |
| 801 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 802 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 802 __ Ret(); | 803 __ Ret(); |
| 803 | 804 |
| 804 // Skip cache and return answer directly, only in untagged case. | 805 // Skip cache and return answer directly, only in untagged case. |
| 805 __ bind(&skip_cache); | 806 __ bind(&skip_cache); |
| 806 __ sub(esp, Immediate(kDoubleSize)); | 807 __ sub(esp, Immediate(kDoubleSize)); |
| 807 __ movdbl(Operand(esp, 0), xmm1); | 808 __ movsd(Operand(esp, 0), xmm1); |
| 808 __ fld_d(Operand(esp, 0)); | 809 __ fld_d(Operand(esp, 0)); |
| 809 GenerateOperation(masm, type_); | 810 GenerateOperation(masm, type_); |
| 810 __ fstp_d(Operand(esp, 0)); | 811 __ fstp_d(Operand(esp, 0)); |
| 811 __ movdbl(xmm1, Operand(esp, 0)); | 812 __ movsd(xmm1, Operand(esp, 0)); |
| 812 __ add(esp, Immediate(kDoubleSize)); | 813 __ add(esp, Immediate(kDoubleSize)); |
| 813 // We return the value in xmm1 without adding it to the cache, but | 814 // We return the value in xmm1 without adding it to the cache, but |
| 814 // we cause a scavenging GC so that future allocations will succeed. | 815 // we cause a scavenging GC so that future allocations will succeed. |
| 815 { | 816 { |
| 816 FrameScope scope(masm, StackFrame::INTERNAL); | 817 FrameScope scope(masm, StackFrame::INTERNAL); |
| 817 // Allocate an unused object bigger than a HeapNumber. | 818 // Allocate an unused object bigger than a HeapNumber. |
| 818 __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); | 819 __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); |
| 819 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | 820 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); |
| 820 } | 821 } |
| 821 __ Ret(); | 822 __ Ret(); |
| 822 } | 823 } |
| 823 | 824 |
| 824 // Call runtime, doing whatever allocation and cleanup is necessary. | 825 // Call runtime, doing whatever allocation and cleanup is necessary. |
| 825 if (tagged) { | 826 if (tagged) { |
| 826 __ bind(&runtime_call_clear_stack); | 827 __ bind(&runtime_call_clear_stack); |
| 827 __ fstp(0); | 828 __ fstp(0); |
| 828 __ bind(&runtime_call); | 829 __ bind(&runtime_call); |
| 829 ExternalReference runtime = | 830 ExternalReference runtime = |
| 830 ExternalReference(RuntimeFunction(), masm->isolate()); | 831 ExternalReference(RuntimeFunction(), masm->isolate()); |
| 831 __ TailCallExternalReference(runtime, 1, 1); | 832 __ TailCallExternalReference(runtime, 1, 1); |
| 832 } else { // UNTAGGED. | 833 } else { // UNTAGGED. |
| 833 CpuFeatureScope scope(masm, SSE2); | 834 CpuFeatureScope scope(masm, SSE2); |
| 834 __ bind(&runtime_call_clear_stack); | 835 __ bind(&runtime_call_clear_stack); |
| 835 __ bind(&runtime_call); | 836 __ bind(&runtime_call); |
| 836 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); | 837 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); |
| 837 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); | 838 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); |
| 838 { | 839 { |
| 839 FrameScope scope(masm, StackFrame::INTERNAL); | 840 FrameScope scope(masm, StackFrame::INTERNAL); |
| 840 __ push(eax); | 841 __ push(eax); |
| 841 __ CallRuntime(RuntimeFunction(), 1); | 842 __ CallRuntime(RuntimeFunction(), 1); |
| 842 } | 843 } |
| 843 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 844 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 844 __ Ret(); | 845 __ Ret(); |
| 845 } | 846 } |
| 846 } | 847 } |
| 847 | 848 |
| 848 | 849 |
| 849 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 850 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
| 850 switch (type_) { | 851 switch (type_) { |
| 851 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 852 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
| 852 case TranscendentalCache::COS: return Runtime::kMath_cos; | 853 case TranscendentalCache::COS: return Runtime::kMath_cos; |
| 853 case TranscendentalCache::TAN: return Runtime::kMath_tan; | 854 case TranscendentalCache::TAN: return Runtime::kMath_tan; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 | 977 |
| 977 | 978 |
| 978 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, | 979 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, |
| 979 Label* not_numbers) { | 980 Label* not_numbers) { |
| 980 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | 981 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; |
| 981 // Load operand in edx into xmm0, or branch to not_numbers. | 982 // Load operand in edx into xmm0, or branch to not_numbers. |
| 982 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); | 983 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); |
| 983 Factory* factory = masm->isolate()->factory(); | 984 Factory* factory = masm->isolate()->factory(); |
| 984 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); | 985 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); |
| 985 __ j(not_equal, not_numbers); // Argument in edx is not a number. | 986 __ j(not_equal, not_numbers); // Argument in edx is not a number. |
| 986 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 987 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 987 __ bind(&load_eax); | 988 __ bind(&load_eax); |
| 988 // Load operand in eax into xmm1, or branch to not_numbers. | 989 // Load operand in eax into xmm1, or branch to not_numbers. |
| 989 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); | 990 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); |
| 990 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); | 991 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); |
| 991 __ j(equal, &load_float_eax, Label::kNear); | 992 __ j(equal, &load_float_eax, Label::kNear); |
| 992 __ jmp(not_numbers); // Argument in eax is not a number. | 993 __ jmp(not_numbers); // Argument in eax is not a number. |
| 993 __ bind(&load_smi_edx); | 994 __ bind(&load_smi_edx); |
| 994 __ SmiUntag(edx); // Untag smi before converting to float. | 995 __ SmiUntag(edx); // Untag smi before converting to float. |
| 995 __ Cvtsi2sd(xmm0, edx); | 996 __ Cvtsi2sd(xmm0, edx); |
| 996 __ SmiTag(edx); // Retag smi for heap number overwriting test. | 997 __ SmiTag(edx); // Retag smi for heap number overwriting test. |
| 997 __ jmp(&load_eax); | 998 __ jmp(&load_eax); |
| 998 __ bind(&load_smi_eax); | 999 __ bind(&load_smi_eax); |
| 999 __ SmiUntag(eax); // Untag smi before converting to float. | 1000 __ SmiUntag(eax); // Untag smi before converting to float. |
| 1000 __ Cvtsi2sd(xmm1, eax); | 1001 __ Cvtsi2sd(xmm1, eax); |
| 1001 __ SmiTag(eax); // Retag smi for heap number overwriting test. | 1002 __ SmiTag(eax); // Retag smi for heap number overwriting test. |
| 1002 __ jmp(&done, Label::kNear); | 1003 __ jmp(&done, Label::kNear); |
| 1003 __ bind(&load_float_eax); | 1004 __ bind(&load_float_eax); |
| 1004 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 1005 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1005 __ bind(&done); | 1006 __ bind(&done); |
| 1006 } | 1007 } |
| 1007 | 1008 |
| 1008 | 1009 |
| 1009 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, | 1010 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
| 1010 Label* non_float, | 1011 Label* non_float, |
| 1011 Register scratch) { | 1012 Register scratch) { |
| 1012 Label test_other, done; | 1013 Label test_other, done; |
| 1013 // Test if both operands are floats or smi -> scratch=k_is_float; | 1014 // Test if both operands are floats or smi -> scratch=k_is_float; |
| 1014 // Otherwise scratch = k_not_float. | 1015 // Otherwise scratch = k_not_float. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1052 // This can only happen if the stub is called from non-optimized code. | 1053 // This can only happen if the stub is called from non-optimized code. |
| 1053 // Load input parameters from stack. | 1054 // Load input parameters from stack. |
| 1054 __ mov(base, Operand(esp, 2 * kPointerSize)); | 1055 __ mov(base, Operand(esp, 2 * kPointerSize)); |
| 1055 __ mov(exponent, Operand(esp, 1 * kPointerSize)); | 1056 __ mov(exponent, Operand(esp, 1 * kPointerSize)); |
| 1056 | 1057 |
| 1057 __ JumpIfSmi(base, &base_is_smi, Label::kNear); | 1058 __ JumpIfSmi(base, &base_is_smi, Label::kNear); |
| 1058 __ cmp(FieldOperand(base, HeapObject::kMapOffset), | 1059 __ cmp(FieldOperand(base, HeapObject::kMapOffset), |
| 1059 factory->heap_number_map()); | 1060 factory->heap_number_map()); |
| 1060 __ j(not_equal, &call_runtime); | 1061 __ j(not_equal, &call_runtime); |
| 1061 | 1062 |
| 1062 __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset)); | 1063 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); |
| 1063 __ jmp(&unpack_exponent, Label::kNear); | 1064 __ jmp(&unpack_exponent, Label::kNear); |
| 1064 | 1065 |
| 1065 __ bind(&base_is_smi); | 1066 __ bind(&base_is_smi); |
| 1066 __ SmiUntag(base); | 1067 __ SmiUntag(base); |
| 1067 __ Cvtsi2sd(double_base, base); | 1068 __ Cvtsi2sd(double_base, base); |
| 1068 | 1069 |
| 1069 __ bind(&unpack_exponent); | 1070 __ bind(&unpack_exponent); |
| 1070 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | 1071 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); |
| 1071 __ SmiUntag(exponent); | 1072 __ SmiUntag(exponent); |
| 1072 __ jmp(&int_exponent); | 1073 __ jmp(&int_exponent); |
| 1073 | 1074 |
| 1074 __ bind(&exponent_not_smi); | 1075 __ bind(&exponent_not_smi); |
| 1075 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), | 1076 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), |
| 1076 factory->heap_number_map()); | 1077 factory->heap_number_map()); |
| 1077 __ j(not_equal, &call_runtime); | 1078 __ j(not_equal, &call_runtime); |
| 1078 __ movdbl(double_exponent, | 1079 __ movsd(double_exponent, |
| 1079 FieldOperand(exponent, HeapNumber::kValueOffset)); | 1080 FieldOperand(exponent, HeapNumber::kValueOffset)); |
| 1080 } else if (exponent_type_ == TAGGED) { | 1081 } else if (exponent_type_ == TAGGED) { |
| 1081 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | 1082 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); |
| 1082 __ SmiUntag(exponent); | 1083 __ SmiUntag(exponent); |
| 1083 __ jmp(&int_exponent); | 1084 __ jmp(&int_exponent); |
| 1084 | 1085 |
| 1085 __ bind(&exponent_not_smi); | 1086 __ bind(&exponent_not_smi); |
| 1086 __ movdbl(double_exponent, | 1087 __ movsd(double_exponent, |
| 1087 FieldOperand(exponent, HeapNumber::kValueOffset)); | 1088 FieldOperand(exponent, HeapNumber::kValueOffset)); |
| 1088 } | 1089 } |
| 1089 | 1090 |
| 1090 if (exponent_type_ != INTEGER) { | 1091 if (exponent_type_ != INTEGER) { |
| 1091 Label fast_power, try_arithmetic_simplification; | 1092 Label fast_power, try_arithmetic_simplification; |
| 1092 __ DoubleToI(exponent, double_exponent, double_scratch, | 1093 __ DoubleToI(exponent, double_exponent, double_scratch, |
| 1093 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification); | 1094 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification); |
| 1094 __ jmp(&int_exponent); | 1095 __ jmp(&int_exponent); |
| 1095 | 1096 |
| 1096 __ bind(&try_arithmetic_simplification); | 1097 __ bind(&try_arithmetic_simplification); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1171 __ divsd(double_result, double_exponent); | 1172 __ divsd(double_result, double_exponent); |
| 1172 __ jmp(&done); | 1173 __ jmp(&done); |
| 1173 } | 1174 } |
| 1174 | 1175 |
| 1175 // Using FPU instructions to calculate power. | 1176 // Using FPU instructions to calculate power. |
| 1176 Label fast_power_failed; | 1177 Label fast_power_failed; |
| 1177 __ bind(&fast_power); | 1178 __ bind(&fast_power); |
| 1178 __ fnclex(); // Clear flags to catch exceptions later. | 1179 __ fnclex(); // Clear flags to catch exceptions later. |
| 1179 // Transfer (B)ase and (E)xponent onto the FPU register stack. | 1180 // Transfer (B)ase and (E)xponent onto the FPU register stack. |
| 1180 __ sub(esp, Immediate(kDoubleSize)); | 1181 __ sub(esp, Immediate(kDoubleSize)); |
| 1181 __ movdbl(Operand(esp, 0), double_exponent); | 1182 __ movsd(Operand(esp, 0), double_exponent); |
| 1182 __ fld_d(Operand(esp, 0)); // E | 1183 __ fld_d(Operand(esp, 0)); // E |
| 1183 __ movdbl(Operand(esp, 0), double_base); | 1184 __ movsd(Operand(esp, 0), double_base); |
| 1184 __ fld_d(Operand(esp, 0)); // B, E | 1185 __ fld_d(Operand(esp, 0)); // B, E |
| 1185 | 1186 |
| 1186 // Exponent is in st(1) and base is in st(0) | 1187 // Exponent is in st(1) and base is in st(0) |
| 1187 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) | 1188 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) |
| 1188 // FYL2X calculates st(1) * log2(st(0)) | 1189 // FYL2X calculates st(1) * log2(st(0)) |
| 1189 __ fyl2x(); // X | 1190 __ fyl2x(); // X |
| 1190 __ fld(0); // X, X | 1191 __ fld(0); // X, X |
| 1191 __ frndint(); // rnd(X), X | 1192 __ frndint(); // rnd(X), X |
| 1192 __ fsub(1); // rnd(X), X-rnd(X) | 1193 __ fsub(1); // rnd(X), X-rnd(X) |
| 1193 __ fxch(1); // X - rnd(X), rnd(X) | 1194 __ fxch(1); // X - rnd(X), rnd(X) |
| 1194 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 | 1195 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 |
| 1195 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) | 1196 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) |
| 1196 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) | 1197 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) |
| 1197 __ faddp(1); // 2^(X-rnd(X)), rnd(X) | 1198 __ faddp(1); // 2^(X-rnd(X)), rnd(X) |
| 1198 // FSCALE calculates st(0) * 2^st(1) | 1199 // FSCALE calculates st(0) * 2^st(1) |
| 1199 __ fscale(); // 2^X, rnd(X) | 1200 __ fscale(); // 2^X, rnd(X) |
| 1200 __ fstp(1); // 2^X | 1201 __ fstp(1); // 2^X |
| 1201 // Bail out to runtime in case of exceptions in the status word. | 1202 // Bail out to runtime in case of exceptions in the status word. |
| 1202 __ fnstsw_ax(); | 1203 __ fnstsw_ax(); |
| 1203 __ test_b(eax, 0x5F); // We check for all but precision exception. | 1204 __ test_b(eax, 0x5F); // We check for all but precision exception. |
| 1204 __ j(not_zero, &fast_power_failed, Label::kNear); | 1205 __ j(not_zero, &fast_power_failed, Label::kNear); |
| 1205 __ fstp_d(Operand(esp, 0)); | 1206 __ fstp_d(Operand(esp, 0)); |
| 1206 __ movdbl(double_result, Operand(esp, 0)); | 1207 __ movsd(double_result, Operand(esp, 0)); |
| 1207 __ add(esp, Immediate(kDoubleSize)); | 1208 __ add(esp, Immediate(kDoubleSize)); |
| 1208 __ jmp(&done); | 1209 __ jmp(&done); |
| 1209 | 1210 |
| 1210 __ bind(&fast_power_failed); | 1211 __ bind(&fast_power_failed); |
| 1211 __ fninit(); | 1212 __ fninit(); |
| 1212 __ add(esp, Immediate(kDoubleSize)); | 1213 __ add(esp, Immediate(kDoubleSize)); |
| 1213 __ jmp(&call_runtime); | 1214 __ jmp(&call_runtime); |
| 1214 } | 1215 } |
| 1215 | 1216 |
| 1216 // Calculate power with integer exponent. | 1217 // Calculate power with integer exponent. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1263 Counters* counters = masm->isolate()->counters(); | 1264 Counters* counters = masm->isolate()->counters(); |
| 1264 if (exponent_type_ == ON_STACK) { | 1265 if (exponent_type_ == ON_STACK) { |
| 1265 // The arguments are still on the stack. | 1266 // The arguments are still on the stack. |
| 1266 __ bind(&call_runtime); | 1267 __ bind(&call_runtime); |
| 1267 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); | 1268 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); |
| 1268 | 1269 |
| 1269 // The stub is called from non-optimized code, which expects the result | 1270 // The stub is called from non-optimized code, which expects the result |
| 1270 // as heap number in exponent. | 1271 // as heap number in exponent. |
| 1271 __ bind(&done); | 1272 __ bind(&done); |
| 1272 __ AllocateHeapNumber(eax, scratch, base, &call_runtime); | 1273 __ AllocateHeapNumber(eax, scratch, base, &call_runtime); |
| 1273 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result); | 1274 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), double_result); |
| 1274 __ IncrementCounter(counters->math_pow(), 1); | 1275 __ IncrementCounter(counters->math_pow(), 1); |
| 1275 __ ret(2 * kPointerSize); | 1276 __ ret(2 * kPointerSize); |
| 1276 } else { | 1277 } else { |
| 1277 __ bind(&call_runtime); | 1278 __ bind(&call_runtime); |
| 1278 { | 1279 { |
| 1279 AllowExternalCallThatCantCauseGC scope(masm); | 1280 AllowExternalCallThatCantCauseGC scope(masm); |
| 1280 __ PrepareCallCFunction(4, scratch); | 1281 __ PrepareCallCFunction(4, scratch); |
| 1281 __ movdbl(Operand(esp, 0 * kDoubleSize), double_base); | 1282 __ movsd(Operand(esp, 0 * kDoubleSize), double_base); |
| 1282 __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent); | 1283 __ movsd(Operand(esp, 1 * kDoubleSize), double_exponent); |
| 1283 __ CallCFunction( | 1284 __ CallCFunction( |
| 1284 ExternalReference::power_double_double_function(masm->isolate()), 4); | 1285 ExternalReference::power_double_double_function(masm->isolate()), 4); |
| 1285 } | 1286 } |
| 1286 // Return value is in st(0) on ia32. | 1287 // Return value is in st(0) on ia32. |
| 1287 // Store it into the (fixed) result register. | 1288 // Store it into the (fixed) result register. |
| 1288 __ sub(esp, Immediate(kDoubleSize)); | 1289 __ sub(esp, Immediate(kDoubleSize)); |
| 1289 __ fstp_d(Operand(esp, 0)); | 1290 __ fstp_d(Operand(esp, 0)); |
| 1290 __ movdbl(double_result, Operand(esp, 0)); | 1291 __ movsd(double_result, Operand(esp, 0)); |
| 1291 __ add(esp, Immediate(kDoubleSize)); | 1292 __ add(esp, Immediate(kDoubleSize)); |
| 1292 | 1293 |
| 1293 __ bind(&done); | 1294 __ bind(&done); |
| 1294 __ IncrementCounter(counters->math_pow(), 1); | 1295 __ IncrementCounter(counters->math_pow(), 1); |
| 1295 __ ret(0); | 1296 __ ret(0); |
| 1296 } | 1297 } |
| 1297 } | 1298 } |
| 1298 | 1299 |
| 1299 | 1300 |
| 1300 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { | 1301 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { |
| (...skipping 2629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3930 // edi: length of second argument | 3931 // edi: length of second argument |
| 3931 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 3932 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
| 3932 __ IncrementCounter(counters->string_add_native(), 1); | 3933 __ IncrementCounter(counters->string_add_native(), 1); |
| 3933 __ ret(2 * kPointerSize); | 3934 __ ret(2 * kPointerSize); |
| 3934 | 3935 |
| 3935 // Recover stack pointer before jumping to runtime. | 3936 // Recover stack pointer before jumping to runtime. |
| 3936 __ bind(&call_runtime_drop_two); | 3937 __ bind(&call_runtime_drop_two); |
| 3937 __ Drop(2); | 3938 __ Drop(2); |
| 3938 // Just jump to runtime to add the two strings. | 3939 // Just jump to runtime to add the two strings. |
| 3939 __ bind(&call_runtime); | 3940 __ bind(&call_runtime); |
| 3940 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { | 3941 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 3941 GenerateRegisterArgsPop(masm, ecx); | |
| 3942 // Build a frame | |
| 3943 { | |
| 3944 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 3945 GenerateRegisterArgsPush(masm); | |
| 3946 __ CallRuntime(Runtime::kStringAdd, 2); | |
| 3947 } | |
| 3948 __ ret(0); | |
| 3949 } else { | |
| 3950 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
| 3951 } | |
| 3952 | 3942 |
| 3953 if (call_builtin.is_linked()) { | 3943 if (call_builtin.is_linked()) { |
| 3954 __ bind(&call_builtin); | 3944 __ bind(&call_builtin); |
| 3955 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { | 3945 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
| 3956 GenerateRegisterArgsPop(masm, ecx); | |
| 3957 // Build a frame | |
| 3958 { | |
| 3959 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 3960 GenerateRegisterArgsPush(masm); | |
| 3961 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); | |
| 3962 } | |
| 3963 __ ret(0); | |
| 3964 } else { | |
| 3965 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
| 3966 } | |
| 3967 } | 3946 } |
| 3968 } | 3947 } |
| 3969 | 3948 |
| 3970 | 3949 |
| 3971 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 3950 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| 3972 __ push(eax); | 3951 __ push(eax); |
| 3973 __ push(edx); | 3952 __ push(edx); |
| 3974 } | 3953 } |
| 3975 | 3954 |
| 3976 | 3955 |
| (...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4723 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { | 4702 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { |
| 4724 CpuFeatureScope scope1(masm, SSE2); | 4703 CpuFeatureScope scope1(masm, SSE2); |
| 4725 CpuFeatureScope scope2(masm, CMOV); | 4704 CpuFeatureScope scope2(masm, CMOV); |
| 4726 | 4705 |
| 4727 // Load left and right operand. | 4706 // Load left and right operand. |
| 4728 Label done, left, left_smi, right_smi; | 4707 Label done, left, left_smi, right_smi; |
| 4729 __ JumpIfSmi(eax, &right_smi, Label::kNear); | 4708 __ JumpIfSmi(eax, &right_smi, Label::kNear); |
| 4730 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 4709 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 4731 masm->isolate()->factory()->heap_number_map()); | 4710 masm->isolate()->factory()->heap_number_map()); |
| 4732 __ j(not_equal, &maybe_undefined1, Label::kNear); | 4711 __ j(not_equal, &maybe_undefined1, Label::kNear); |
| 4733 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 4712 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 4734 __ jmp(&left, Label::kNear); | 4713 __ jmp(&left, Label::kNear); |
| 4735 __ bind(&right_smi); | 4714 __ bind(&right_smi); |
| 4736 __ mov(ecx, eax); // Can't clobber eax because we can still jump away. | 4715 __ mov(ecx, eax); // Can't clobber eax because we can still jump away. |
| 4737 __ SmiUntag(ecx); | 4716 __ SmiUntag(ecx); |
| 4738 __ Cvtsi2sd(xmm1, ecx); | 4717 __ Cvtsi2sd(xmm1, ecx); |
| 4739 | 4718 |
| 4740 __ bind(&left); | 4719 __ bind(&left); |
| 4741 __ JumpIfSmi(edx, &left_smi, Label::kNear); | 4720 __ JumpIfSmi(edx, &left_smi, Label::kNear); |
| 4742 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 4721 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 4743 masm->isolate()->factory()->heap_number_map()); | 4722 masm->isolate()->factory()->heap_number_map()); |
| 4744 __ j(not_equal, &maybe_undefined2, Label::kNear); | 4723 __ j(not_equal, &maybe_undefined2, Label::kNear); |
| 4745 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 4724 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 4746 __ jmp(&done); | 4725 __ jmp(&done); |
| 4747 __ bind(&left_smi); | 4726 __ bind(&left_smi); |
| 4748 __ mov(ecx, edx); // Can't clobber edx because we can still jump away. | 4727 __ mov(ecx, edx); // Can't clobber edx because we can still jump away. |
| 4749 __ SmiUntag(ecx); | 4728 __ SmiUntag(ecx); |
| 4750 __ Cvtsi2sd(xmm0, ecx); | 4729 __ Cvtsi2sd(xmm0, ecx); |
| 4751 | 4730 |
| 4752 __ bind(&done); | 4731 __ bind(&done); |
| 4753 // Compare operands. | 4732 // Compare operands. |
| 4754 __ ucomisd(xmm0, xmm1); | 4733 __ ucomisd(xmm0, xmm1); |
| 4755 | 4734 |
| (...skipping 1266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6022 __ bind(&fast_elements_case); | 6001 __ bind(&fast_elements_case); |
| 6023 GenerateCase(masm, FAST_ELEMENTS); | 6002 GenerateCase(masm, FAST_ELEMENTS); |
| 6024 } | 6003 } |
| 6025 | 6004 |
| 6026 | 6005 |
| 6027 #undef __ | 6006 #undef __ |
| 6028 | 6007 |
| 6029 } } // namespace v8::internal | 6008 } } // namespace v8::internal |
| 6030 | 6009 |
| 6031 #endif // V8_TARGET_ARCH_IA32 | 6010 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |