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 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 // Returns operands as floating point numbers on fp stack. | 307 // Returns operands as floating point numbers on fp stack. |
308 static void LoadFloatOperands(MacroAssembler* masm, | 308 static void LoadFloatOperands(MacroAssembler* masm, |
309 Register lhs, | 309 Register lhs, |
310 Register rhs); | 310 Register rhs); |
311 | 311 |
312 // Test if operands are smi or number objects (fp). Requirements: | 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 | 313 // operand_1 in rax, operand_2 in rdx; falls through on float or smi |
314 // operands, jumps to the non_float label otherwise. | 314 // operands, jumps to the non_float label otherwise. |
315 static void CheckNumberOperands(MacroAssembler* masm, | 315 static void CheckNumberOperands(MacroAssembler* masm, |
316 Label* non_float); | 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); |
317 | 322 |
318 // Takes the operands in rdx and rax and loads them as integers in rax | 323 // Takes the operands in rdx and rax and loads them as integers in rax |
319 // and rcx. | 324 // and rcx. |
320 static void LoadAsIntegers(MacroAssembler* masm, | 325 static void LoadAsIntegers(MacroAssembler* masm, |
321 Label* operand_conversion_failure); | 326 Label* operand_conversion_failure, |
| 327 Register heap_number_map); |
322 }; | 328 }; |
323 | 329 |
324 | 330 |
325 // ----------------------------------------------------------------------------- | 331 // ----------------------------------------------------------------------------- |
326 // CodeGenerator implementation. | 332 // CodeGenerator implementation. |
327 | 333 |
328 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 334 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
329 : deferred_(8), | 335 : deferred_(8), |
330 masm_(masm), | 336 masm_(masm), |
331 info_(NULL), | 337 info_(NULL), |
(...skipping 9649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9981 __ fild_s(Operand(rsp, 0)); | 9987 __ fild_s(Operand(rsp, 0)); |
9982 __ pop(number); | 9988 __ pop(number); |
9983 | 9989 |
9984 __ bind(&done); | 9990 __ bind(&done); |
9985 } | 9991 } |
9986 | 9992 |
9987 | 9993 |
9988 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9994 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
9989 Register src, | 9995 Register src, |
9990 XMMRegister dst) { | 9996 XMMRegister dst) { |
| 9997 ASSERT(!src.is(kScratchRegister)); |
9991 Label load_smi, done; | 9998 Label load_smi, done; |
9992 | 9999 |
9993 __ JumpIfSmi(src, &load_smi); | 10000 __ JumpIfSmi(src, &load_smi); |
9994 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); | 10001 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
9995 __ jmp(&done); | 10002 __ jmp(&done); |
9996 | 10003 |
9997 __ bind(&load_smi); | 10004 __ bind(&load_smi); |
9998 __ SmiToInteger32(src, src); | 10005 __ SmiToInteger32(kScratchRegister, src); |
9999 __ cvtlsi2sd(dst, src); | 10006 __ cvtlsi2sd(dst, kScratchRegister); |
10000 | 10007 |
10001 __ bind(&done); | 10008 __ bind(&done); |
10002 } | 10009 } |
10003 | 10010 |
10004 | 10011 |
10005 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 10012 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
10006 Register src, | 10013 Register src, |
10007 XMMRegister dst, | 10014 XMMRegister dst, |
10008 Label* not_number) { | 10015 Label* not_number) { |
10009 Label load_smi, done; | 10016 Label load_smi, done; |
10010 ASSERT(!src.is(kScratchRegister)); | 10017 ASSERT(!src.is(kScratchRegister)); |
10011 __ JumpIfSmi(src, &load_smi); | 10018 __ JumpIfSmi(src, &load_smi); |
10012 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); | 10019 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); |
10013 __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister); | 10020 __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister); |
10014 __ j(not_equal, not_number); | 10021 __ j(not_equal, not_number); |
10015 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); | 10022 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
10016 __ jmp(&done); | 10023 __ jmp(&done); |
10017 | 10024 |
10018 __ bind(&load_smi); | 10025 __ bind(&load_smi); |
10019 __ SmiToInteger32(kScratchRegister, src); | 10026 __ SmiToInteger32(kScratchRegister, src); |
10020 __ cvtlsi2sd(dst, kScratchRegister); | 10027 __ cvtlsi2sd(dst, kScratchRegister); |
10021 | 10028 |
10022 __ bind(&done); | 10029 __ bind(&done); |
10023 } | 10030 } |
10024 | 10031 |
10025 | 10032 |
10026 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 10033 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
10027 XMMRegister dst1, | 10034 XMMRegister dst1, |
10028 XMMRegister dst2) { | 10035 XMMRegister dst2) { |
10029 __ movq(kScratchRegister, rdx); | 10036 LoadFloatOperand(masm, rdx, dst1); |
10030 LoadFloatOperand(masm, kScratchRegister, dst1); | 10037 LoadFloatOperand(masm, rax, dst2); |
10031 __ movq(kScratchRegister, rax); | |
10032 LoadFloatOperand(masm, kScratchRegister, dst2); | |
10033 } | 10038 } |
10034 | 10039 |
10035 | 10040 |
10036 void FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm, | 10041 void FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm, |
10037 XMMRegister dst1, | 10042 XMMRegister dst1, |
10038 XMMRegister dst2) { | 10043 XMMRegister dst2) { |
10039 __ SmiToInteger32(kScratchRegister, rdx); | 10044 __ SmiToInteger32(kScratchRegister, rdx); |
10040 __ cvtlsi2sd(dst1, kScratchRegister); | 10045 __ cvtlsi2sd(dst1, kScratchRegister); |
10041 __ SmiToInteger32(kScratchRegister, rax); | 10046 __ SmiToInteger32(kScratchRegister, rax); |
10042 __ cvtlsi2sd(dst2, kScratchRegister); | 10047 __ cvtlsi2sd(dst2, kScratchRegister); |
10043 } | 10048 } |
10044 | 10049 |
10045 | 10050 |
10046 // Input: rdx, rax are the left and right objects of a bit op. | 10051 // Input: rdx, rax are the left and right objects of a bit op. |
10047 // Output: rax, rcx are left and right integers for a bit op. | 10052 // Output: rax, rcx are left and right integers for a bit op. |
10048 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 10053 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
10049 Label* conversion_failure) { | 10054 Label* conversion_failure, |
| 10055 Register heap_number_map) { |
10050 // Check float operands. | 10056 // Check float operands. |
10051 Label arg1_is_object, check_undefined_arg1; | 10057 Label arg1_is_object, check_undefined_arg1; |
10052 Label arg2_is_object, check_undefined_arg2; | 10058 Label arg2_is_object, check_undefined_arg2; |
10053 Label load_arg2, done; | 10059 Label load_arg2, done; |
10054 | 10060 |
10055 __ JumpIfNotSmi(rdx, &arg1_is_object); | 10061 __ JumpIfNotSmi(rdx, &arg1_is_object); |
10056 __ SmiToInteger32(rdx, rdx); | 10062 __ SmiToInteger32(rdx, rdx); |
10057 __ jmp(&load_arg2); | 10063 __ jmp(&load_arg2); |
10058 | 10064 |
10059 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 10065 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
10060 __ bind(&check_undefined_arg1); | 10066 __ bind(&check_undefined_arg1); |
10061 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 10067 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
10062 __ j(not_equal, conversion_failure); | 10068 __ j(not_equal, conversion_failure); |
10063 __ movl(rdx, Immediate(0)); | 10069 __ movl(rdx, Immediate(0)); |
10064 __ jmp(&load_arg2); | 10070 __ jmp(&load_arg2); |
10065 | 10071 |
10066 __ bind(&arg1_is_object); | 10072 __ bind(&arg1_is_object); |
10067 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 10073 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); |
10068 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); | |
10069 __ j(not_equal, &check_undefined_arg1); | 10074 __ j(not_equal, &check_undefined_arg1); |
10070 // Get the untagged integer version of the edx heap number in rcx. | 10075 // Get the untagged integer version of the edx heap number in rcx. |
10071 IntegerConvert(masm, rdx, rdx); | 10076 IntegerConvert(masm, rdx, rdx); |
10072 | 10077 |
10073 // Here rdx has the untagged integer, rax has a Smi or a heap number. | 10078 // Here rdx has the untagged integer, rax has a Smi or a heap number. |
10074 __ bind(&load_arg2); | 10079 __ bind(&load_arg2); |
10075 // Test if arg2 is a Smi. | 10080 // Test if arg2 is a Smi. |
10076 __ JumpIfNotSmi(rax, &arg2_is_object); | 10081 __ JumpIfNotSmi(rax, &arg2_is_object); |
10077 __ SmiToInteger32(rax, rax); | 10082 __ SmiToInteger32(rax, rax); |
10078 __ movl(rcx, rax); | 10083 __ movl(rcx, rax); |
10079 __ jmp(&done); | 10084 __ jmp(&done); |
10080 | 10085 |
10081 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 10086 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
10082 __ bind(&check_undefined_arg2); | 10087 __ bind(&check_undefined_arg2); |
10083 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 10088 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
10084 __ j(not_equal, conversion_failure); | 10089 __ j(not_equal, conversion_failure); |
10085 __ movl(rcx, Immediate(0)); | 10090 __ movl(rcx, Immediate(0)); |
10086 __ jmp(&done); | 10091 __ jmp(&done); |
10087 | 10092 |
10088 __ bind(&arg2_is_object); | 10093 __ bind(&arg2_is_object); |
10089 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 10094 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
10090 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); | |
10091 __ j(not_equal, &check_undefined_arg2); | 10095 __ j(not_equal, &check_undefined_arg2); |
10092 // Get the untagged integer version of the eax heap number in ecx. | 10096 // Get the untagged integer version of the eax heap number in ecx. |
10093 IntegerConvert(masm, rcx, rax); | 10097 IntegerConvert(masm, rcx, rax); |
10094 __ bind(&done); | 10098 __ bind(&done); |
10095 __ movl(rax, rdx); | 10099 __ movl(rax, rdx); |
10096 } | 10100 } |
10097 | 10101 |
10098 | 10102 |
10099 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 10103 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
10100 Register lhs, | 10104 Register lhs, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10137 __ bind(&test_other); | 10141 __ bind(&test_other); |
10138 __ JumpIfSmi(rax, &done); // argument in rax is OK | 10142 __ JumpIfSmi(rax, &done); // argument in rax is OK |
10139 __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); | 10143 __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); |
10140 __ j(not_equal, non_float); // The argument in rax is not a number. | 10144 __ j(not_equal, non_float); // The argument in rax is not a number. |
10141 | 10145 |
10142 // Fall-through: Both operands are numbers. | 10146 // Fall-through: Both operands are numbers. |
10143 __ bind(&done); | 10147 __ bind(&done); |
10144 } | 10148 } |
10145 | 10149 |
10146 | 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 |
10147 const char* GenericBinaryOpStub::GetName() { | 10171 const char* GenericBinaryOpStub::GetName() { |
10148 if (name_ != NULL) return name_; | 10172 if (name_ != NULL) return name_; |
10149 const int len = 100; | 10173 const int len = 100; |
10150 name_ = Bootstrapper::AllocateAutoDeletedArray(len); | 10174 name_ = Bootstrapper::AllocateAutoDeletedArray(len); |
10151 if (name_ == NULL) return "OOM"; | 10175 if (name_ == NULL) return "OOM"; |
10152 const char* op_name = Token::Name(op_); | 10176 const char* op_name = Token::Name(op_); |
10153 const char* overwrite_name; | 10177 const char* overwrite_name; |
10154 switch (mode_) { | 10178 switch (mode_) { |
10155 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 10179 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
10156 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 10180 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10496 | 10520 |
10497 if (ShouldGenerateSmiCode()) { | 10521 if (ShouldGenerateSmiCode()) { |
10498 GenerateSmiCode(masm, &call_runtime); | 10522 GenerateSmiCode(masm, &call_runtime); |
10499 } else if (op_ != Token::MOD) { | 10523 } else if (op_ != Token::MOD) { |
10500 if (!HasArgsInRegisters()) { | 10524 if (!HasArgsInRegisters()) { |
10501 GenerateLoadArguments(masm); | 10525 GenerateLoadArguments(masm); |
10502 } | 10526 } |
10503 } | 10527 } |
10504 // Floating point case. | 10528 // Floating point case. |
10505 if (ShouldGenerateFPCode()) { | 10529 if (ShouldGenerateFPCode()) { |
| 10530 // Load the HeapNumber map here and use it throughout the FP code. |
| 10531 Register heap_number_map = r9; |
10506 switch (op_) { | 10532 switch (op_) { |
10507 case Token::ADD: | 10533 case Token::ADD: |
10508 case Token::SUB: | 10534 case Token::SUB: |
10509 case Token::MUL: | 10535 case Token::MUL: |
10510 case Token::DIV: { | 10536 case Token::DIV: { |
10511 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | 10537 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
10512 HasSmiCodeInStub()) { | 10538 HasSmiCodeInStub()) { |
10513 // Execution reaches this point when the first non-smi argument occurs | 10539 // Execution reaches this point when the first non-smi argument occurs |
10514 // (and only if smi code is generated). This is the right moment to | 10540 // (and only if smi code is generated). This is the right moment to |
10515 // patch to HEAP_NUMBERS state. The transition is attempted only for | 10541 // patch to HEAP_NUMBERS state. The transition is attempted only for |
10516 // the four basic operations. The stub stays in the DEFAULT state | 10542 // the four basic operations. The stub stays in the DEFAULT state |
10517 // forever for all other operations (also if smi code is skipped). | 10543 // forever for all other operations (also if smi code is skipped). |
10518 GenerateTypeTransition(masm); | 10544 GenerateTypeTransition(masm); |
10519 } | 10545 } |
| 10546 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
10520 | 10547 |
10521 Label not_floats; | 10548 Label not_floats; |
10522 // rax: y | 10549 // rax: y |
10523 // rdx: x | 10550 // rdx: x |
10524 if (static_operands_type_.IsNumber() && FLAG_debug_code) { | 10551 if (static_operands_type_.IsNumber() && FLAG_debug_code) { |
10525 // Assert at runtime that inputs are only numbers. | 10552 // Assert at runtime that inputs are only numbers. |
10526 __ AbortIfNotNumber(rdx); | 10553 __ AbortIfNotNumber(rdx); |
10527 __ AbortIfNotNumber(rax); | 10554 __ AbortIfNotNumber(rax); |
10528 } else { | 10555 } else { |
10529 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 10556 if (FLAG_debug_code) { |
10530 } | 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 } |
10531 // Fast-case: Both operands are numbers. | 10565 // Fast-case: Both operands are numbers. |
10532 // xmm4 and xmm5 are volatile XMM registers. | 10566 // xmm4 and xmm5 are volatile XMM registers. |
10533 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | 10567 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
10534 | 10568 |
10535 switch (op_) { | 10569 switch (op_) { |
10536 case Token::ADD: __ addsd(xmm4, xmm5); break; | 10570 case Token::ADD: __ addsd(xmm4, xmm5); break; |
10537 case Token::SUB: __ subsd(xmm4, xmm5); break; | 10571 case Token::SUB: __ subsd(xmm4, xmm5); break; |
10538 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 10572 case Token::MUL: __ mulsd(xmm4, xmm5); break; |
10539 case Token::DIV: __ divsd(xmm4, xmm5); break; | 10573 case Token::DIV: __ divsd(xmm4, xmm5); break; |
10540 default: UNREACHABLE(); | 10574 default: UNREACHABLE(); |
10541 } | 10575 } |
10542 // Allocate a heap number, if needed. | 10576 // Allocate a heap number, if needed. |
10543 Label skip_allocation; | 10577 Label skip_allocation; |
10544 OverwriteMode mode = mode_; | 10578 OverwriteMode mode = mode_; |
10545 if (HasArgsReversed()) { | 10579 if (HasArgsReversed()) { |
10546 if (mode == OVERWRITE_RIGHT) { | 10580 if (mode == OVERWRITE_RIGHT) { |
10547 mode = OVERWRITE_LEFT; | 10581 mode = OVERWRITE_LEFT; |
10548 } else if (mode == OVERWRITE_LEFT) { | 10582 } else if (mode == OVERWRITE_LEFT) { |
10549 mode = OVERWRITE_RIGHT; | 10583 mode = OVERWRITE_RIGHT; |
10550 } | 10584 } |
10551 } | 10585 } |
10552 switch (mode) { | 10586 switch (mode) { |
| 10587 // TODO(lrn): Allocate this when we first see that the |
| 10588 // left register is a smi (and load it into xmm4). |
10553 case OVERWRITE_LEFT: | 10589 case OVERWRITE_LEFT: |
10554 __ JumpIfNotSmi(rdx, &skip_allocation); | 10590 __ JumpIfNotSmi(rdx, &skip_allocation); |
10555 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | 10591 // Allocate heap number in new space. |
| 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); |
10556 __ movq(rdx, rbx); | 10605 __ movq(rdx, rbx); |
10557 __ bind(&skip_allocation); | 10606 __ bind(&skip_allocation); |
10558 __ movq(rax, rdx); | 10607 __ movq(rax, rdx); |
10559 break; | 10608 break; |
10560 case OVERWRITE_RIGHT: | 10609 case OVERWRITE_RIGHT: |
10561 // If the argument in rax is already an object, we skip the | 10610 // If the argument in rax is already an object, we skip the |
10562 // allocation of a heap number. | 10611 // 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). |
10563 __ JumpIfNotSmi(rax, &skip_allocation); | 10614 __ JumpIfNotSmi(rax, &skip_allocation); |
10564 // Fall through! | 10615 // Fall through! |
10565 case NO_OVERWRITE: | 10616 case NO_OVERWRITE: |
10566 // Allocate a heap number for the result. Keep rax and rdx intact | 10617 // Allocate a heap number for the result. Keep rax and rdx intact |
10567 // for the possible runtime call. | 10618 // for the possible runtime call. |
10568 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | 10619 __ AllocateInNewSpace(HeapNumber::kSize, |
| 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); |
10569 __ movq(rax, rbx); | 10632 __ movq(rax, rbx); |
10570 __ bind(&skip_allocation); | 10633 __ bind(&skip_allocation); |
10571 break; | 10634 break; |
10572 default: UNREACHABLE(); | 10635 default: UNREACHABLE(); |
10573 } | 10636 } |
10574 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); | 10637 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); |
10575 GenerateReturn(masm); | 10638 GenerateReturn(masm); |
10576 __ bind(¬_floats); | 10639 __ bind(¬_floats); |
10577 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | 10640 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
10578 !HasSmiCodeInStub()) { | 10641 !HasSmiCodeInStub()) { |
(...skipping 10 matching lines...) Expand all Loading... |
10589 case Token::MOD: { | 10652 case Token::MOD: { |
10590 // For MOD we go directly to runtime in the non-smi case. | 10653 // For MOD we go directly to runtime in the non-smi case. |
10591 break; | 10654 break; |
10592 } | 10655 } |
10593 case Token::BIT_OR: | 10656 case Token::BIT_OR: |
10594 case Token::BIT_AND: | 10657 case Token::BIT_AND: |
10595 case Token::BIT_XOR: | 10658 case Token::BIT_XOR: |
10596 case Token::SAR: | 10659 case Token::SAR: |
10597 case Token::SHL: | 10660 case Token::SHL: |
10598 case Token::SHR: { | 10661 case Token::SHR: { |
10599 Label skip_allocation, non_smi_result; | 10662 Label skip_allocation, non_smi_shr_result; |
10600 FloatingPointHelper::LoadAsIntegers(masm, &call_runtime); | 10663 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 10664 FloatingPointHelper::LoadAsIntegers(masm, |
| 10665 &call_runtime, |
| 10666 heap_number_map); |
10601 switch (op_) { | 10667 switch (op_) { |
10602 case Token::BIT_OR: __ orl(rax, rcx); break; | 10668 case Token::BIT_OR: __ orl(rax, rcx); break; |
10603 case Token::BIT_AND: __ andl(rax, rcx); break; | 10669 case Token::BIT_AND: __ andl(rax, rcx); break; |
10604 case Token::BIT_XOR: __ xorl(rax, rcx); break; | 10670 case Token::BIT_XOR: __ xorl(rax, rcx); break; |
10605 case Token::SAR: __ sarl_cl(rax); break; | 10671 case Token::SAR: __ sarl_cl(rax); break; |
10606 case Token::SHL: __ shll_cl(rax); break; | 10672 case Token::SHL: __ shll_cl(rax); break; |
10607 case Token::SHR: __ shrl_cl(rax); break; | 10673 case Token::SHR: __ shrl_cl(rax); break; |
10608 default: UNREACHABLE(); | 10674 default: UNREACHABLE(); |
10609 } | 10675 } |
10610 if (op_ == Token::SHR) { | 10676 if (op_ == Token::SHR) { |
10611 // Check if result is negative. This can only happen for a shift | 10677 // Check if result is negative. This can only happen for a shift |
10612 // by zero, which also doesn't update the sign flag. | 10678 // by zero. |
10613 __ testl(rax, rax); | 10679 __ testl(rax, rax); |
10614 __ j(negative, &non_smi_result); | 10680 __ j(negative, &non_smi_shr_result); |
10615 } | 10681 } |
10616 __ JumpIfNotValidSmiValue(rax, &non_smi_result); | 10682 STATIC_ASSERT(kSmiValueSize == 32); |
10617 // Tag smi result, if possible, and return. | 10683 // Tag smi result and return. |
10618 __ Integer32ToSmi(rax, rax); | 10684 __ Integer32ToSmi(rax, rax); |
10619 GenerateReturn(masm); | 10685 GenerateReturn(masm); |
10620 | 10686 |
10621 // All ops except SHR return a signed int32 that we load in | 10687 // All bit-ops except SHR return a signed int32 that can be |
10622 // a HeapNumber. | 10688 // returned immediately as a smi. |
10623 if (op_ != Token::SHR && non_smi_result.is_linked()) { | 10689 if (op_ == Token::SHR) { |
10624 __ bind(&non_smi_result); | 10690 ASSERT(non_smi_shr_result.is_linked()); |
| 10691 __ bind(&non_smi_shr_result); |
10625 // Allocate a heap number if needed. | 10692 // Allocate a heap number if needed. |
10626 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result | 10693 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). |
10627 switch (mode_) { | 10694 switch (mode_) { |
10628 case OVERWRITE_LEFT: | 10695 case OVERWRITE_LEFT: |
10629 case OVERWRITE_RIGHT: | 10696 case OVERWRITE_RIGHT: |
10630 // If the operand was an object, we skip the | 10697 // If the operand was an object, we skip the |
10631 // allocation of a heap number. | 10698 // allocation of a heap number. |
10632 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? | 10699 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? |
10633 1 * kPointerSize : 2 * kPointerSize)); | 10700 1 * kPointerSize : 2 * kPointerSize)); |
10634 __ JumpIfNotSmi(rax, &skip_allocation); | 10701 __ JumpIfNotSmi(rax, &skip_allocation); |
10635 // Fall through! | 10702 // Fall through! |
10636 case NO_OVERWRITE: | 10703 case NO_OVERWRITE: |
10637 __ AllocateHeapNumber(rax, rcx, &call_runtime); | 10704 // Allocate heap number in new space. |
| 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); |
10638 __ bind(&skip_allocation); | 10719 __ bind(&skip_allocation); |
10639 break; | 10720 break; |
10640 default: UNREACHABLE(); | 10721 default: UNREACHABLE(); |
10641 } | 10722 } |
10642 // Store the result in the HeapNumber and return. | 10723 // Store the result in the HeapNumber and return. |
10643 __ movq(Operand(rsp, 1 * kPointerSize), rbx); | 10724 __ cvtqsi2sd(xmm0, rbx); |
10644 __ fild_s(Operand(rsp, 1 * kPointerSize)); | 10725 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
10645 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | |
10646 GenerateReturn(masm); | 10726 GenerateReturn(masm); |
10647 } | 10727 } |
10648 | 10728 |
10649 // SHR should return uint32 - go to runtime for non-smi/negative result. | |
10650 if (op_ == Token::SHR) { | |
10651 __ bind(&non_smi_result); | |
10652 } | |
10653 break; | 10729 break; |
10654 } | 10730 } |
10655 default: UNREACHABLE(); break; | 10731 default: UNREACHABLE(); break; |
10656 } | 10732 } |
10657 } | 10733 } |
10658 | 10734 |
10659 // If all else fails, use the runtime system to get the correct | 10735 // If all else fails, use the runtime system to get the correct |
10660 // result. If arguments was passed in registers now place them on the | 10736 // result. If arguments was passed in registers now place them on the |
10661 // stack in the correct order below the return address. | 10737 // stack in the correct order below the return address. |
10662 __ bind(&call_runtime); | 10738 __ bind(&call_runtime); |
(...skipping 12 matching lines...) Expand all Loading... |
10675 rhs = rdx; | 10751 rhs = rdx; |
10676 } else { | 10752 } else { |
10677 lhs = rdx; | 10753 lhs = rdx; |
10678 rhs = rax; | 10754 rhs = rax; |
10679 } | 10755 } |
10680 | 10756 |
10681 // Test for string arguments before calling runtime. | 10757 // Test for string arguments before calling runtime. |
10682 Label not_strings, both_strings, not_string1, string1, string1_smi2; | 10758 Label not_strings, both_strings, not_string1, string1, string1_smi2; |
10683 | 10759 |
10684 // If this stub has already generated FP-specific code then the arguments | 10760 // If this stub has already generated FP-specific code then the arguments |
10685 // are already in rdx, rax | 10761 // are already in rdx, rax. |
10686 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { | 10762 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
10687 GenerateLoadArguments(masm); | 10763 GenerateLoadArguments(masm); |
10688 } | 10764 } |
10689 | 10765 |
10690 Condition is_smi; | 10766 Condition is_smi; |
10691 is_smi = masm->CheckSmi(lhs); | 10767 is_smi = masm->CheckSmi(lhs); |
10692 __ j(is_smi, ¬_string1); | 10768 __ j(is_smi, ¬_string1); |
10693 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); | 10769 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); |
10694 __ j(above_equal, ¬_string1); | 10770 __ j(above_equal, ¬_string1); |
10695 | 10771 |
(...skipping 1260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11956 } | 12032 } |
11957 | 12033 |
11958 #endif | 12034 #endif |
11959 | 12035 |
11960 | 12036 |
11961 #undef __ | 12037 #undef __ |
11962 | 12038 |
11963 } } // namespace v8::internal | 12039 } } // namespace v8::internal |
11964 | 12040 |
11965 #endif // V8_TARGET_ARCH_X64 | 12041 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |