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 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 Token::Value op_; | 255 Token::Value op_; |
256 Register dst_; | 256 Register dst_; |
257 Smi* value_; | 257 Smi* value_; |
258 Register src_; | 258 Register src_; |
259 OverwriteMode overwrite_mode_; | 259 OverwriteMode overwrite_mode_; |
260 }; | 260 }; |
261 | 261 |
262 | 262 |
263 class FloatingPointHelper : public AllStatic { | 263 class FloatingPointHelper : public AllStatic { |
264 public: | 264 public: |
265 // Code pattern for loading a floating point value. Input value must | 265 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. |
266 // be either a smi or a heap number object (fp value). Requirements: | 266 // If the operands are not both numbers, jump to not_numbers. |
267 // operand on TOS+1. Returns operand as floating point number on FPU | 267 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
268 // stack. | 268 // NumberOperands assumes both are smis or heap numbers. |
269 static void LoadFloatOperand(MacroAssembler* masm, Register scratch); | 269 static void LoadSSE2SmiOperands(MacroAssembler* masm); |
270 | 270 static void LoadSSE2NumberOperands(MacroAssembler* masm); |
271 // Code pattern for loading a floating point value. Input value must | 271 static void LoadSSE2UnknownOperands(MacroAssembler* masm, |
272 // be either a smi or a heap number object (fp value). Requirements: | 272 Label* not_numbers); |
273 // operand in src register. Returns operand as floating point number | |
274 // in XMM register. May destroy src register. | |
275 static void LoadFloatOperand(MacroAssembler* masm, | |
276 Register src, | |
277 XMMRegister dst); | |
278 | |
279 // Code pattern for loading a possible number into a XMM register. | |
280 // If the contents of src is not a number, control branches to | |
281 // the Label not_number. If contents of src is a smi or a heap number | |
282 // object (fp value), it is loaded into the XMM register as a double. | |
283 // The register src is not changed, and src may not be kScratchRegister. | |
284 static void LoadFloatOperand(MacroAssembler* masm, | |
285 Register src, | |
286 XMMRegister dst, | |
287 Label *not_number); | |
288 | |
289 // Code pattern for loading floating point values. Input values must | |
290 // be either smi or heap number objects (fp values). Requirements: | |
291 // operand_1 in rdx, operand_2 in rax; Returns operands as | |
292 // floating point numbers in XMM registers. | |
293 static void LoadFloatOperands(MacroAssembler* masm, | |
294 XMMRegister dst1, | |
295 XMMRegister dst2); | |
296 | |
297 // Similar to LoadFloatOperands, assumes that the operands are smis. | |
298 static void LoadFloatOperandsFromSmis(MacroAssembler* masm, | |
299 XMMRegister dst1, | |
300 XMMRegister dst2); | |
301 | |
302 // Code pattern for loading floating point values onto the fp stack. | |
303 // Input values must be either smi or heap number objects (fp values). | |
304 // Requirements: | |
305 // Register version: operands in registers lhs and rhs. | |
306 // Stack version: operands on TOS+1 and TOS+2. | |
307 // Returns operands as floating point numbers on fp stack. | |
308 static void LoadFloatOperands(MacroAssembler* masm, | |
309 Register lhs, | |
310 Register rhs); | |
311 | |
312 // Test if operands are smi or number objects (fp). Requirements: | |
313 // operand_1 in rax, operand_2 in rdx; falls through on float or smi | |
314 // operands, jumps to the non_float label otherwise. | |
315 static void CheckNumberOperands(MacroAssembler* masm, | |
316 Label* non_float); | |
317 // As CheckNumberOperands above, but expects the HeapNumber map in | |
318 // a register. | |
319 static void CheckNumberOperands(MacroAssembler* masm, | |
320 Label* non_float, | |
321 Register heap_number_map); | |
322 | 273 |
323 // Takes the operands in rdx and rax and loads them as integers in rax | 274 // Takes the operands in rdx and rax and loads them as integers in rax |
324 // and rcx. | 275 // and rcx. |
325 static void LoadAsIntegers(MacroAssembler* masm, | 276 static void LoadAsIntegers(MacroAssembler* masm, |
326 Label* operand_conversion_failure, | 277 Label* operand_conversion_failure); |
327 Register heap_number_map); | |
328 }; | 278 }; |
329 | 279 |
330 | 280 |
331 // ----------------------------------------------------------------------------- | 281 // ----------------------------------------------------------------------------- |
332 // CodeGenerator implementation. | 282 // CodeGenerator implementation. |
333 | 283 |
334 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 284 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
335 : deferred_(8), | 285 : deferred_(8), |
336 masm_(masm), | 286 masm_(masm), |
337 info_(NULL), | 287 info_(NULL), |
(...skipping 8767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9105 // Push arguments below the return address to prepare jump to builtin. | 9055 // Push arguments below the return address to prepare jump to builtin. |
9106 __ pop(rcx); | 9056 __ pop(rcx); |
9107 __ push(rax); | 9057 __ push(rax); |
9108 __ push(rdx); | 9058 __ push(rdx); |
9109 __ push(rcx); | 9059 __ push(rcx); |
9110 | 9060 |
9111 // Generate the number comparison code. | 9061 // Generate the number comparison code. |
9112 if (include_number_compare_) { | 9062 if (include_number_compare_) { |
9113 Label non_number_comparison; | 9063 Label non_number_comparison; |
9114 Label unordered; | 9064 Label unordered; |
9115 FloatingPointHelper::LoadFloatOperand(masm, rdx, xmm0, | 9065 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); |
9116 &non_number_comparison); | |
9117 FloatingPointHelper::LoadFloatOperand(masm, rax, xmm1, | |
9118 &non_number_comparison); | |
9119 | |
9120 __ ucomisd(xmm0, xmm1); | 9066 __ ucomisd(xmm0, xmm1); |
9121 | 9067 |
9122 // Don't base result on EFLAGS when a NaN is involved. | 9068 // Don't base result on EFLAGS when a NaN is involved. |
9123 __ j(parity_even, &unordered); | 9069 __ j(parity_even, &unordered); |
9124 // Return a result of -1, 0, or 1, based on EFLAGS. | 9070 // Return a result of -1, 0, or 1, based on EFLAGS. |
9125 __ movq(rax, Immediate(0)); // equal | 9071 __ movq(rax, Immediate(0)); // equal |
9126 __ movq(rcx, Immediate(1)); | 9072 __ movq(rcx, Immediate(1)); |
9127 __ cmovq(above, rax, rcx); | 9073 __ cmovq(above, rax, rcx); |
9128 __ movq(rcx, Immediate(-1)); | 9074 __ movq(rcx, Immediate(-1)); |
9129 __ cmovq(below, rax, rcx); | 9075 __ cmovq(below, rax, rcx); |
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9966 // temporarily store that in a register. | 9912 // temporarily store that in a register. |
9967 __ pop(rax); | 9913 __ pop(rax); |
9968 __ Push(Smi::FromInt(0)); | 9914 __ Push(Smi::FromInt(0)); |
9969 __ push(rax); | 9915 __ push(rax); |
9970 | 9916 |
9971 // Do tail-call to runtime routine. | 9917 // Do tail-call to runtime routine. |
9972 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); | 9918 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
9973 } | 9919 } |
9974 | 9920 |
9975 | 9921 |
9976 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9922 void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) { |
9977 Register number) { | 9923 __ SmiToInteger32(kScratchRegister, rdx); |
9978 Label load_smi, done; | 9924 __ cvtlsi2sd(xmm0, kScratchRegister); |
| 9925 __ SmiToInteger32(kScratchRegister, rax); |
| 9926 __ cvtlsi2sd(xmm1, kScratchRegister); |
| 9927 } |
9979 | 9928 |
9980 __ JumpIfSmi(number, &load_smi); | 9929 |
9981 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); | 9930 void FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) { |
| 9931 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done; |
| 9932 // Load operand in rdx into xmm0. |
| 9933 __ JumpIfSmi(rdx, &load_smi_rdx); |
| 9934 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
| 9935 // Load operand in rax into xmm1. |
| 9936 __ JumpIfSmi(rax, &load_smi_rax); |
| 9937 __ bind(&load_nonsmi_rax); |
| 9938 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
9982 __ jmp(&done); | 9939 __ jmp(&done); |
9983 | 9940 |
9984 __ bind(&load_smi); | 9941 __ bind(&load_smi_rdx); |
9985 __ SmiToInteger32(number, number); | 9942 __ SmiToInteger32(kScratchRegister, rdx); |
9986 __ push(number); | 9943 __ cvtlsi2sd(xmm0, kScratchRegister); |
9987 __ fild_s(Operand(rsp, 0)); | 9944 __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
9988 __ pop(number); | 9945 |
| 9946 __ bind(&load_smi_rax); |
| 9947 __ SmiToInteger32(kScratchRegister, rax); |
| 9948 __ cvtlsi2sd(xmm1, kScratchRegister); |
9989 | 9949 |
9990 __ bind(&done); | 9950 __ bind(&done); |
9991 } | 9951 } |
9992 | 9952 |
9993 | 9953 |
9994 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9954 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, |
9995 Register src, | 9955 Label* not_numbers) { |
9996 XMMRegister dst) { | 9956 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done; |
9997 ASSERT(!src.is(kScratchRegister)); | 9957 // Load operand in rdx into xmm0, or branch to not_numbers. |
9998 Label load_smi, done; | 9958 __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex); |
| 9959 __ JumpIfSmi(rdx, &load_smi_rdx); |
| 9960 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx); |
| 9961 __ j(not_equal, not_numbers); // Argument in rdx is not a number. |
| 9962 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
| 9963 // Load operand in rax into xmm1, or branch to not_numbers. |
| 9964 __ JumpIfSmi(rax, &load_smi_rax); |
9999 | 9965 |
10000 __ JumpIfSmi(src, &load_smi); | 9966 __ bind(&load_nonsmi_rax); |
10001 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); | 9967 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx); |
| 9968 __ j(not_equal, not_numbers); |
| 9969 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
10002 __ jmp(&done); | 9970 __ jmp(&done); |
10003 | 9971 |
10004 __ bind(&load_smi); | 9972 __ bind(&load_smi_rdx); |
10005 __ SmiToInteger32(kScratchRegister, src); | 9973 __ SmiToInteger32(kScratchRegister, rdx); |
10006 __ cvtlsi2sd(dst, kScratchRegister); | 9974 __ cvtlsi2sd(xmm0, kScratchRegister); |
| 9975 __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
10007 | 9976 |
| 9977 __ bind(&load_smi_rax); |
| 9978 __ SmiToInteger32(kScratchRegister, rax); |
| 9979 __ cvtlsi2sd(xmm1, kScratchRegister); |
10008 __ bind(&done); | 9980 __ bind(&done); |
10009 } | 9981 } |
10010 | 9982 |
10011 | 9983 |
10012 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | |
10013 Register src, | |
10014 XMMRegister dst, | |
10015 Label* not_number) { | |
10016 Label load_smi, done; | |
10017 ASSERT(!src.is(kScratchRegister)); | |
10018 __ JumpIfSmi(src, &load_smi); | |
10019 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); | |
10020 __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister); | |
10021 __ j(not_equal, not_number); | |
10022 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); | |
10023 __ jmp(&done); | |
10024 | |
10025 __ bind(&load_smi); | |
10026 __ SmiToInteger32(kScratchRegister, src); | |
10027 __ cvtlsi2sd(dst, kScratchRegister); | |
10028 | |
10029 __ bind(&done); | |
10030 } | |
10031 | |
10032 | |
10033 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | |
10034 XMMRegister dst1, | |
10035 XMMRegister dst2) { | |
10036 LoadFloatOperand(masm, rdx, dst1); | |
10037 LoadFloatOperand(masm, rax, dst2); | |
10038 } | |
10039 | |
10040 | |
10041 void FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm, | |
10042 XMMRegister dst1, | |
10043 XMMRegister dst2) { | |
10044 __ SmiToInteger32(kScratchRegister, rdx); | |
10045 __ cvtlsi2sd(dst1, kScratchRegister); | |
10046 __ SmiToInteger32(kScratchRegister, rax); | |
10047 __ cvtlsi2sd(dst2, kScratchRegister); | |
10048 } | |
10049 | |
10050 | |
10051 // Input: rdx, rax are the left and right objects of a bit op. | 9984 // Input: rdx, rax are the left and right objects of a bit op. |
10052 // Output: rax, rcx are left and right integers for a bit op. | 9985 // Output: rax, rcx are left and right integers for a bit op. |
10053 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 9986 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
10054 Label* conversion_failure, | 9987 Label* conversion_failure) { |
10055 Register heap_number_map) { | |
10056 // Check float operands. | 9988 // Check float operands. |
10057 Label arg1_is_object, check_undefined_arg1; | 9989 Label arg1_is_object, check_undefined_arg1; |
10058 Label arg2_is_object, check_undefined_arg2; | 9990 Label arg2_is_object, check_undefined_arg2; |
10059 Label load_arg2, done; | 9991 Label load_arg2, done; |
10060 | 9992 |
10061 __ JumpIfNotSmi(rdx, &arg1_is_object); | 9993 __ JumpIfNotSmi(rdx, &arg1_is_object); |
10062 __ SmiToInteger32(rdx, rdx); | 9994 __ SmiToInteger32(rdx, rdx); |
10063 __ jmp(&load_arg2); | 9995 __ jmp(&load_arg2); |
10064 | 9996 |
10065 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 9997 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
10066 __ bind(&check_undefined_arg1); | 9998 __ bind(&check_undefined_arg1); |
10067 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 9999 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
10068 __ j(not_equal, conversion_failure); | 10000 __ j(not_equal, conversion_failure); |
10069 __ movl(rdx, Immediate(0)); | 10001 __ movl(rdx, Immediate(0)); |
10070 __ jmp(&load_arg2); | 10002 __ jmp(&load_arg2); |
10071 | 10003 |
10072 __ bind(&arg1_is_object); | 10004 __ bind(&arg1_is_object); |
10073 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); | 10005 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 10006 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
10074 __ j(not_equal, &check_undefined_arg1); | 10007 __ j(not_equal, &check_undefined_arg1); |
10075 // Get the untagged integer version of the edx heap number in rcx. | 10008 // Get the untagged integer version of the edx heap number in rcx. |
10076 IntegerConvert(masm, rdx, rdx); | 10009 IntegerConvert(masm, rdx, rdx); |
10077 | 10010 |
10078 // Here rdx has the untagged integer, rax has a Smi or a heap number. | 10011 // Here rdx has the untagged integer, rax has a Smi or a heap number. |
10079 __ bind(&load_arg2); | 10012 __ bind(&load_arg2); |
10080 // Test if arg2 is a Smi. | 10013 // Test if arg2 is a Smi. |
10081 __ JumpIfNotSmi(rax, &arg2_is_object); | 10014 __ JumpIfNotSmi(rax, &arg2_is_object); |
10082 __ SmiToInteger32(rax, rax); | 10015 __ SmiToInteger32(rax, rax); |
10083 __ movl(rcx, rax); | 10016 __ movl(rcx, rax); |
10084 __ jmp(&done); | 10017 __ jmp(&done); |
10085 | 10018 |
10086 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 10019 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
10087 __ bind(&check_undefined_arg2); | 10020 __ bind(&check_undefined_arg2); |
10088 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 10021 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
10089 __ j(not_equal, conversion_failure); | 10022 __ j(not_equal, conversion_failure); |
10090 __ movl(rcx, Immediate(0)); | 10023 __ movl(rcx, Immediate(0)); |
10091 __ jmp(&done); | 10024 __ jmp(&done); |
10092 | 10025 |
10093 __ bind(&arg2_is_object); | 10026 __ bind(&arg2_is_object); |
10094 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); | 10027 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 10028 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
10095 __ j(not_equal, &check_undefined_arg2); | 10029 __ j(not_equal, &check_undefined_arg2); |
10096 // Get the untagged integer version of the eax heap number in ecx. | 10030 // Get the untagged integer version of the eax heap number in ecx. |
10097 IntegerConvert(masm, rcx, rax); | 10031 IntegerConvert(masm, rcx, rax); |
10098 __ bind(&done); | 10032 __ bind(&done); |
10099 __ movl(rax, rdx); | 10033 __ movl(rax, rdx); |
10100 } | 10034 } |
10101 | 10035 |
10102 | 10036 |
10103 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | |
10104 Register lhs, | |
10105 Register rhs) { | |
10106 Label load_smi_lhs, load_smi_rhs, done_load_lhs, done; | |
10107 __ JumpIfSmi(lhs, &load_smi_lhs); | |
10108 __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset)); | |
10109 __ bind(&done_load_lhs); | |
10110 | |
10111 __ JumpIfSmi(rhs, &load_smi_rhs); | |
10112 __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); | |
10113 __ jmp(&done); | |
10114 | |
10115 __ bind(&load_smi_lhs); | |
10116 __ SmiToInteger64(kScratchRegister, lhs); | |
10117 __ push(kScratchRegister); | |
10118 __ fild_d(Operand(rsp, 0)); | |
10119 __ pop(kScratchRegister); | |
10120 __ jmp(&done_load_lhs); | |
10121 | |
10122 __ bind(&load_smi_rhs); | |
10123 __ SmiToInteger64(kScratchRegister, rhs); | |
10124 __ push(kScratchRegister); | |
10125 __ fild_d(Operand(rsp, 0)); | |
10126 __ pop(kScratchRegister); | |
10127 | |
10128 __ bind(&done); | |
10129 } | |
10130 | |
10131 | |
10132 void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm, | |
10133 Label* non_float) { | |
10134 Label test_other, done; | |
10135 // Test if both operands are numbers (heap_numbers or smis). | |
10136 // If not, jump to label non_float. | |
10137 __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK | |
10138 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map()); | |
10139 __ j(not_equal, non_float); // The argument in rdx is not a number. | |
10140 | |
10141 __ bind(&test_other); | |
10142 __ JumpIfSmi(rax, &done); // argument in rax is OK | |
10143 __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); | |
10144 __ j(not_equal, non_float); // The argument in rax is not a number. | |
10145 | |
10146 // Fall-through: Both operands are numbers. | |
10147 __ bind(&done); | |
10148 } | |
10149 | |
10150 | |
10151 void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm, | |
10152 Label* non_float, | |
10153 Register heap_number_map) { | |
10154 Label test_other, done; | |
10155 // Test if both operands are numbers (heap_numbers or smis). | |
10156 // If not, jump to label non_float. | |
10157 __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK | |
10158 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); | |
10159 __ j(not_equal, non_float); // The argument in rdx is not a number. | |
10160 | |
10161 __ bind(&test_other); | |
10162 __ JumpIfSmi(rax, &done); // argument in rax is OK | |
10163 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); | |
10164 __ j(not_equal, non_float); // The argument in rax is not a number. | |
10165 | |
10166 // Fall-through: Both operands are numbers. | |
10167 __ bind(&done); | |
10168 } | |
10169 | |
10170 | |
10171 const char* GenericBinaryOpStub::GetName() { | 10037 const char* GenericBinaryOpStub::GetName() { |
10172 if (name_ != NULL) return name_; | 10038 if (name_ != NULL) return name_; |
10173 const int len = 100; | 10039 const int len = 100; |
10174 name_ = Bootstrapper::AllocateAutoDeletedArray(len); | 10040 name_ = Bootstrapper::AllocateAutoDeletedArray(len); |
10175 if (name_ == NULL) return "OOM"; | 10041 if (name_ == NULL) return "OOM"; |
10176 const char* op_name = Token::Name(op_); | 10042 const char* op_name = Token::Name(op_); |
10177 const char* overwrite_name; | 10043 const char* overwrite_name; |
10178 switch (mode_) { | 10044 switch (mode_) { |
10179 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 10045 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
10180 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 10046 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10467 case Token::MUL: | 10333 case Token::MUL: |
10468 case Token::DIV: { | 10334 case Token::DIV: { |
10469 ASSERT(use_fp_on_smis.is_linked()); | 10335 ASSERT(use_fp_on_smis.is_linked()); |
10470 __ bind(&use_fp_on_smis); | 10336 __ bind(&use_fp_on_smis); |
10471 if (op_ == Token::DIV) { | 10337 if (op_ == Token::DIV) { |
10472 __ movq(rdx, rax); | 10338 __ movq(rdx, rax); |
10473 __ movq(rax, rbx); | 10339 __ movq(rax, rbx); |
10474 } | 10340 } |
10475 // left is rdx, right is rax. | 10341 // left is rdx, right is rax. |
10476 __ AllocateHeapNumber(rbx, rcx, slow); | 10342 __ AllocateHeapNumber(rbx, rcx, slow); |
10477 FloatingPointHelper::LoadFloatOperandsFromSmis(masm, xmm4, xmm5); | 10343 FloatingPointHelper::LoadSSE2SmiOperands(masm); |
10478 switch (op_) { | 10344 switch (op_) { |
10479 case Token::ADD: __ addsd(xmm4, xmm5); break; | 10345 case Token::ADD: __ addsd(xmm0, xmm1); break; |
10480 case Token::SUB: __ subsd(xmm4, xmm5); break; | 10346 case Token::SUB: __ subsd(xmm0, xmm1); break; |
10481 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 10347 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
10482 case Token::DIV: __ divsd(xmm4, xmm5); break; | 10348 case Token::DIV: __ divsd(xmm0, xmm1); break; |
10483 default: UNREACHABLE(); | 10349 default: UNREACHABLE(); |
10484 } | 10350 } |
10485 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm4); | 10351 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); |
10486 __ movq(rax, rbx); | 10352 __ movq(rax, rbx); |
10487 GenerateReturn(masm); | 10353 GenerateReturn(masm); |
10488 } | 10354 } |
10489 default: | 10355 default: |
10490 break; | 10356 break; |
10491 } | 10357 } |
10492 | 10358 |
10493 // 6. Non-smi operands, fall out to the non-smi code with the operands in | 10359 // 6. Non-smi operands, fall out to the non-smi code with the operands in |
10494 // rdx and rax. | 10360 // rdx and rax. |
10495 Comment done_comment(masm, "-- Enter non-smi code"); | 10361 Comment done_comment(masm, "-- Enter non-smi code"); |
(...skipping 24 matching lines...) Expand all Loading... |
10520 | 10386 |
10521 if (ShouldGenerateSmiCode()) { | 10387 if (ShouldGenerateSmiCode()) { |
10522 GenerateSmiCode(masm, &call_runtime); | 10388 GenerateSmiCode(masm, &call_runtime); |
10523 } else if (op_ != Token::MOD) { | 10389 } else if (op_ != Token::MOD) { |
10524 if (!HasArgsInRegisters()) { | 10390 if (!HasArgsInRegisters()) { |
10525 GenerateLoadArguments(masm); | 10391 GenerateLoadArguments(masm); |
10526 } | 10392 } |
10527 } | 10393 } |
10528 // Floating point case. | 10394 // Floating point case. |
10529 if (ShouldGenerateFPCode()) { | 10395 if (ShouldGenerateFPCode()) { |
10530 // Load the HeapNumber map here and use it throughout the FP code. | |
10531 Register heap_number_map = r9; | |
10532 switch (op_) { | 10396 switch (op_) { |
10533 case Token::ADD: | 10397 case Token::ADD: |
10534 case Token::SUB: | 10398 case Token::SUB: |
10535 case Token::MUL: | 10399 case Token::MUL: |
10536 case Token::DIV: { | 10400 case Token::DIV: { |
10537 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | 10401 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
10538 HasSmiCodeInStub()) { | 10402 HasSmiCodeInStub()) { |
10539 // Execution reaches this point when the first non-smi argument occurs | 10403 // Execution reaches this point when the first non-smi argument occurs |
10540 // (and only if smi code is generated). This is the right moment to | 10404 // (and only if smi code is generated). This is the right moment to |
10541 // patch to HEAP_NUMBERS state. The transition is attempted only for | 10405 // patch to HEAP_NUMBERS state. The transition is attempted only for |
10542 // the four basic operations. The stub stays in the DEFAULT state | 10406 // the four basic operations. The stub stays in the DEFAULT state |
10543 // forever for all other operations (also if smi code is skipped). | 10407 // forever for all other operations (also if smi code is skipped). |
10544 GenerateTypeTransition(masm); | 10408 GenerateTypeTransition(masm); |
10545 } | 10409 } |
10546 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
10547 | 10410 |
10548 Label not_floats; | 10411 Label not_floats; |
10549 // rax: y | 10412 // rax: y |
10550 // rdx: x | 10413 // rdx: x |
10551 if (static_operands_type_.IsNumber() && FLAG_debug_code) { | 10414 ASSERT(!static_operands_type_.IsSmi()); |
10552 // Assert at runtime that inputs are only numbers. | 10415 if (static_operands_type_.IsNumber()) { |
10553 __ AbortIfNotNumber(rdx); | 10416 if (FLAG_debug_code) { |
10554 __ AbortIfNotNumber(rax); | 10417 // Assert at runtime that inputs are only numbers. |
| 10418 __ AbortIfNotNumber(rdx); |
| 10419 __ AbortIfNotNumber(rax); |
| 10420 } |
| 10421 FloatingPointHelper::LoadSSE2NumberOperands(masm); |
10555 } else { | 10422 } else { |
10556 if (FLAG_debug_code) { | 10423 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &call_runtime); |
10557 __ AbortIfNotRootValue(heap_number_map, | |
10558 Heap::kHeapNumberMapRootIndex, | |
10559 "HeapNumberMap register clobbered."); | |
10560 } | |
10561 FloatingPointHelper::CheckNumberOperands(masm, | |
10562 &call_runtime, | |
10563 heap_number_map); | |
10564 } | 10424 } |
10565 // Fast-case: Both operands are numbers. | |
10566 // xmm4 and xmm5 are volatile XMM registers. | |
10567 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | |
10568 | 10425 |
10569 switch (op_) { | 10426 switch (op_) { |
10570 case Token::ADD: __ addsd(xmm4, xmm5); break; | 10427 case Token::ADD: __ addsd(xmm0, xmm1); break; |
10571 case Token::SUB: __ subsd(xmm4, xmm5); break; | 10428 case Token::SUB: __ subsd(xmm0, xmm1); break; |
10572 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 10429 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
10573 case Token::DIV: __ divsd(xmm4, xmm5); break; | 10430 case Token::DIV: __ divsd(xmm0, xmm1); break; |
10574 default: UNREACHABLE(); | 10431 default: UNREACHABLE(); |
10575 } | 10432 } |
10576 // Allocate a heap number, if needed. | 10433 // Allocate a heap number, if needed. |
10577 Label skip_allocation; | 10434 Label skip_allocation; |
10578 OverwriteMode mode = mode_; | 10435 OverwriteMode mode = mode_; |
10579 if (HasArgsReversed()) { | 10436 if (HasArgsReversed()) { |
10580 if (mode == OVERWRITE_RIGHT) { | 10437 if (mode == OVERWRITE_RIGHT) { |
10581 mode = OVERWRITE_LEFT; | 10438 mode = OVERWRITE_LEFT; |
10582 } else if (mode == OVERWRITE_LEFT) { | 10439 } else if (mode == OVERWRITE_LEFT) { |
10583 mode = OVERWRITE_RIGHT; | 10440 mode = OVERWRITE_RIGHT; |
10584 } | 10441 } |
10585 } | 10442 } |
10586 switch (mode) { | 10443 switch (mode) { |
10587 // TODO(lrn): Allocate this when we first see that the | |
10588 // left register is a smi (and load it into xmm4). | |
10589 case OVERWRITE_LEFT: | 10444 case OVERWRITE_LEFT: |
10590 __ JumpIfNotSmi(rdx, &skip_allocation); | 10445 __ JumpIfNotSmi(rdx, &skip_allocation); |
10591 // Allocate heap number in new space. | 10446 __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
10592 __ AllocateInNewSpace(HeapNumber::kSize, | |
10593 rbx, | |
10594 rcx, | |
10595 no_reg, | |
10596 &call_runtime, | |
10597 TAG_OBJECT); | |
10598 if (FLAG_debug_code) { | |
10599 __ AbortIfNotRootValue(heap_number_map, | |
10600 Heap::kHeapNumberMapRootIndex, | |
10601 "HeapNumberMap register clobbered."); | |
10602 } | |
10603 __ movq(FieldOperand(rbx, HeapObject::kMapOffset), | |
10604 heap_number_map); | |
10605 __ movq(rdx, rbx); | 10447 __ movq(rdx, rbx); |
10606 __ bind(&skip_allocation); | 10448 __ bind(&skip_allocation); |
10607 __ movq(rax, rdx); | 10449 __ movq(rax, rdx); |
10608 break; | 10450 break; |
10609 case OVERWRITE_RIGHT: | 10451 case OVERWRITE_RIGHT: |
10610 // If the argument in rax is already an object, we skip the | 10452 // If the argument in rax is already an object, we skip the |
10611 // allocation of a heap number. | 10453 // allocation of a heap number. |
10612 // TODO(lrn): Allocate the heap number when we first see that the | |
10613 // right register is a smi (and load it into xmm5). | |
10614 __ JumpIfNotSmi(rax, &skip_allocation); | 10454 __ JumpIfNotSmi(rax, &skip_allocation); |
10615 // Fall through! | 10455 // Fall through! |
10616 case NO_OVERWRITE: | 10456 case NO_OVERWRITE: |
10617 // Allocate a heap number for the result. Keep rax and rdx intact | 10457 // Allocate a heap number for the result. Keep rax and rdx intact |
10618 // for the possible runtime call. | 10458 // for the possible runtime call. |
10619 __ AllocateInNewSpace(HeapNumber::kSize, | 10459 __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
10620 rbx, | |
10621 rcx, | |
10622 no_reg, | |
10623 &call_runtime, | |
10624 TAG_OBJECT); | |
10625 if (FLAG_debug_code) { | |
10626 __ AbortIfNotRootValue(heap_number_map, | |
10627 Heap::kHeapNumberMapRootIndex, | |
10628 "HeapNumberMap register clobbered."); | |
10629 } | |
10630 __ movq(FieldOperand(rbx, HeapObject::kMapOffset), | |
10631 heap_number_map); | |
10632 __ movq(rax, rbx); | 10460 __ movq(rax, rbx); |
10633 __ bind(&skip_allocation); | 10461 __ bind(&skip_allocation); |
10634 break; | 10462 break; |
10635 default: UNREACHABLE(); | 10463 default: UNREACHABLE(); |
10636 } | 10464 } |
10637 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); | 10465 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
10638 GenerateReturn(masm); | 10466 GenerateReturn(masm); |
10639 __ bind(¬_floats); | 10467 __ bind(¬_floats); |
10640 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | 10468 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
10641 !HasSmiCodeInStub()) { | 10469 !HasSmiCodeInStub()) { |
10642 // Execution reaches this point when the first non-number argument | 10470 // Execution reaches this point when the first non-number argument |
10643 // occurs (and only if smi code is skipped from the stub, otherwise | 10471 // occurs (and only if smi code is skipped from the stub, otherwise |
10644 // the patching has already been done earlier in this case branch). | 10472 // the patching has already been done earlier in this case branch). |
10645 // A perfect moment to try patching to STRINGS for ADD operation. | 10473 // A perfect moment to try patching to STRINGS for ADD operation. |
10646 if (op_ == Token::ADD) { | 10474 if (op_ == Token::ADD) { |
10647 GenerateTypeTransition(masm); | 10475 GenerateTypeTransition(masm); |
10648 } | 10476 } |
10649 } | 10477 } |
10650 break; | 10478 break; |
10651 } | 10479 } |
10652 case Token::MOD: { | 10480 case Token::MOD: { |
10653 // For MOD we go directly to runtime in the non-smi case. | 10481 // For MOD we go directly to runtime in the non-smi case. |
10654 break; | 10482 break; |
10655 } | 10483 } |
10656 case Token::BIT_OR: | 10484 case Token::BIT_OR: |
10657 case Token::BIT_AND: | 10485 case Token::BIT_AND: |
10658 case Token::BIT_XOR: | 10486 case Token::BIT_XOR: |
10659 case Token::SAR: | 10487 case Token::SAR: |
10660 case Token::SHL: | 10488 case Token::SHL: |
10661 case Token::SHR: { | 10489 case Token::SHR: { |
10662 Label skip_allocation, non_smi_shr_result; | 10490 Label skip_allocation, non_smi_result; |
10663 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 10491 FloatingPointHelper::LoadAsIntegers(masm, &call_runtime); |
10664 FloatingPointHelper::LoadAsIntegers(masm, | |
10665 &call_runtime, | |
10666 heap_number_map); | |
10667 switch (op_) { | 10492 switch (op_) { |
10668 case Token::BIT_OR: __ orl(rax, rcx); break; | 10493 case Token::BIT_OR: __ orl(rax, rcx); break; |
10669 case Token::BIT_AND: __ andl(rax, rcx); break; | 10494 case Token::BIT_AND: __ andl(rax, rcx); break; |
10670 case Token::BIT_XOR: __ xorl(rax, rcx); break; | 10495 case Token::BIT_XOR: __ xorl(rax, rcx); break; |
10671 case Token::SAR: __ sarl_cl(rax); break; | 10496 case Token::SAR: __ sarl_cl(rax); break; |
10672 case Token::SHL: __ shll_cl(rax); break; | 10497 case Token::SHL: __ shll_cl(rax); break; |
10673 case Token::SHR: __ shrl_cl(rax); break; | 10498 case Token::SHR: __ shrl_cl(rax); break; |
10674 default: UNREACHABLE(); | 10499 default: UNREACHABLE(); |
10675 } | 10500 } |
10676 if (op_ == Token::SHR) { | 10501 if (op_ == Token::SHR) { |
10677 // Check if result is negative. This can only happen for a shift | 10502 // Check if result is negative. This can only happen for a shift |
10678 // by zero. | 10503 // by zero, which also doesn't update the sign flag. |
10679 __ testl(rax, rax); | 10504 __ testl(rax, rax); |
10680 __ j(negative, &non_smi_shr_result); | 10505 __ j(negative, &non_smi_result); |
10681 } | 10506 } |
10682 STATIC_ASSERT(kSmiValueSize == 32); | 10507 __ JumpIfNotValidSmiValue(rax, &non_smi_result); |
10683 // Tag smi result and return. | 10508 // Tag smi result, if possible, and return. |
10684 __ Integer32ToSmi(rax, rax); | 10509 __ Integer32ToSmi(rax, rax); |
10685 GenerateReturn(masm); | 10510 GenerateReturn(masm); |
10686 | 10511 |
10687 // All bit-ops except SHR return a signed int32 that can be | 10512 // All ops except SHR return a signed int32 that we load in |
10688 // returned immediately as a smi. | 10513 // a HeapNumber. |
10689 if (op_ == Token::SHR) { | 10514 if (op_ != Token::SHR && non_smi_result.is_linked()) { |
10690 ASSERT(non_smi_shr_result.is_linked()); | 10515 __ bind(&non_smi_result); |
10691 __ bind(&non_smi_shr_result); | |
10692 // Allocate a heap number if needed. | 10516 // Allocate a heap number if needed. |
10693 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). | 10517 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result |
10694 switch (mode_) { | 10518 switch (mode_) { |
10695 case OVERWRITE_LEFT: | 10519 case OVERWRITE_LEFT: |
10696 case OVERWRITE_RIGHT: | 10520 case OVERWRITE_RIGHT: |
10697 // If the operand was an object, we skip the | 10521 // If the operand was an object, we skip the |
10698 // allocation of a heap number. | 10522 // allocation of a heap number. |
10699 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? | 10523 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? |
10700 1 * kPointerSize : 2 * kPointerSize)); | 10524 1 * kPointerSize : 2 * kPointerSize)); |
10701 __ JumpIfNotSmi(rax, &skip_allocation); | 10525 __ JumpIfNotSmi(rax, &skip_allocation); |
10702 // Fall through! | 10526 // Fall through! |
10703 case NO_OVERWRITE: | 10527 case NO_OVERWRITE: |
10704 // Allocate heap number in new space. | 10528 __ AllocateHeapNumber(rax, rcx, &call_runtime); |
10705 __ AllocateInNewSpace(HeapNumber::kSize, | |
10706 rax, | |
10707 rcx, | |
10708 no_reg, | |
10709 &call_runtime, | |
10710 TAG_OBJECT); | |
10711 // Set the map. | |
10712 if (FLAG_debug_code) { | |
10713 __ AbortIfNotRootValue(heap_number_map, | |
10714 Heap::kHeapNumberMapRootIndex, | |
10715 "HeapNumberMap register clobbered."); | |
10716 } | |
10717 __ movq(FieldOperand(rax, HeapObject::kMapOffset), | |
10718 heap_number_map); | |
10719 __ bind(&skip_allocation); | 10529 __ bind(&skip_allocation); |
10720 break; | 10530 break; |
10721 default: UNREACHABLE(); | 10531 default: UNREACHABLE(); |
10722 } | 10532 } |
10723 // Store the result in the HeapNumber and return. | 10533 // Store the result in the HeapNumber and return. |
10724 __ cvtqsi2sd(xmm0, rbx); | 10534 __ movq(Operand(rsp, 1 * kPointerSize), rbx); |
10725 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); | 10535 __ fild_s(Operand(rsp, 1 * kPointerSize)); |
| 10536 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
10726 GenerateReturn(masm); | 10537 GenerateReturn(masm); |
10727 } | 10538 } |
10728 | 10539 |
| 10540 // SHR should return uint32 - go to runtime for non-smi/negative result. |
| 10541 if (op_ == Token::SHR) { |
| 10542 __ bind(&non_smi_result); |
| 10543 } |
10729 break; | 10544 break; |
10730 } | 10545 } |
10731 default: UNREACHABLE(); break; | 10546 default: UNREACHABLE(); break; |
10732 } | 10547 } |
10733 } | 10548 } |
10734 | 10549 |
10735 // If all else fails, use the runtime system to get the correct | 10550 // If all else fails, use the runtime system to get the correct |
10736 // result. If arguments was passed in registers now place them on the | 10551 // result. If arguments was passed in registers now place them on the |
10737 // stack in the correct order below the return address. | 10552 // stack in the correct order below the return address. |
10738 __ bind(&call_runtime); | 10553 __ bind(&call_runtime); |
(...skipping 12 matching lines...) Expand all Loading... |
10751 rhs = rdx; | 10566 rhs = rdx; |
10752 } else { | 10567 } else { |
10753 lhs = rdx; | 10568 lhs = rdx; |
10754 rhs = rax; | 10569 rhs = rax; |
10755 } | 10570 } |
10756 | 10571 |
10757 // Test for string arguments before calling runtime. | 10572 // Test for string arguments before calling runtime. |
10758 Label not_strings, both_strings, not_string1, string1, string1_smi2; | 10573 Label not_strings, both_strings, not_string1, string1, string1_smi2; |
10759 | 10574 |
10760 // If this stub has already generated FP-specific code then the arguments | 10575 // If this stub has already generated FP-specific code then the arguments |
10761 // are already in rdx, rax. | 10576 // are already in rdx, rax |
10762 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { | 10577 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
10763 GenerateLoadArguments(masm); | 10578 GenerateLoadArguments(masm); |
10764 } | 10579 } |
10765 | 10580 |
10766 Condition is_smi; | 10581 Condition is_smi; |
10767 is_smi = masm->CheckSmi(lhs); | 10582 is_smi = masm->CheckSmi(lhs); |
10768 __ j(is_smi, ¬_string1); | 10583 __ j(is_smi, ¬_string1); |
10769 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); | 10584 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); |
10770 __ j(above_equal, ¬_string1); | 10585 __ j(above_equal, ¬_string1); |
10771 | 10586 |
(...skipping 1260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12032 } | 11847 } |
12033 | 11848 |
12034 #endif | 11849 #endif |
12035 | 11850 |
12036 | 11851 |
12037 #undef __ | 11852 #undef __ |
12038 | 11853 |
12039 } } // namespace v8::internal | 11854 } } // namespace v8::internal |
12040 | 11855 |
12041 #endif // V8_TARGET_ARCH_X64 | 11856 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |