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 3355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3366 expression->AsLiteral()->IsNull())) { | 3366 expression->AsLiteral()->IsNull())) { |
3367 // Omit evaluating the value of the primitive literal. | 3367 // Omit evaluating the value of the primitive literal. |
3368 // It will be discarded anyway, and can have no side effect. | 3368 // It will be discarded anyway, and can have no side effect. |
3369 frame_->Push(Factory::undefined_value()); | 3369 frame_->Push(Factory::undefined_value()); |
3370 } else { | 3370 } else { |
3371 Load(node->expression()); | 3371 Load(node->expression()); |
3372 frame_->SetElementAt(0, Factory::undefined_value()); | 3372 frame_->SetElementAt(0, Factory::undefined_value()); |
3373 } | 3373 } |
3374 | 3374 |
3375 } else { | 3375 } else { |
3376 bool overwrite = | 3376 bool can_overwrite = |
3377 (node->expression()->AsBinaryOperation() != NULL && | 3377 (node->expression()->AsBinaryOperation() != NULL && |
3378 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3378 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 3379 UnaryOverwriteMode overwrite = |
| 3380 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 3381 bool no_negative_zero = node->expression()->no_negative_zero(); |
3379 Load(node->expression()); | 3382 Load(node->expression()); |
3380 switch (op) { | 3383 switch (op) { |
3381 case Token::NOT: | 3384 case Token::NOT: |
3382 case Token::DELETE: | 3385 case Token::DELETE: |
3383 case Token::TYPEOF: | 3386 case Token::TYPEOF: |
3384 UNREACHABLE(); // handled above | 3387 UNREACHABLE(); // handled above |
3385 break; | 3388 break; |
3386 | 3389 |
3387 case Token::SUB: { | 3390 case Token::SUB: { |
3388 GenericUnaryOpStub stub(Token::SUB, overwrite); | 3391 GenericUnaryOpStub stub( |
| 3392 Token::SUB, |
| 3393 overwrite, |
| 3394 no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero); |
3389 Result operand = frame_->Pop(); | 3395 Result operand = frame_->Pop(); |
3390 Result answer = frame_->CallStub(&stub, &operand); | 3396 Result answer = frame_->CallStub(&stub, &operand); |
3391 answer.set_type_info(TypeInfo::Number()); | 3397 answer.set_type_info(TypeInfo::Number()); |
3392 frame_->Push(&answer); | 3398 frame_->Push(&answer); |
3393 break; | 3399 break; |
3394 } | 3400 } |
3395 | 3401 |
3396 case Token::BIT_NOT: { | 3402 case Token::BIT_NOT: { |
3397 // Smi check. | 3403 // Smi check. |
3398 JumpTarget smi_label; | 3404 JumpTarget smi_label; |
(...skipping 5100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8499 | 8505 |
8500 | 8506 |
8501 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { | 8507 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { |
8502 Label slow, done; | 8508 Label slow, done; |
8503 | 8509 |
8504 if (op_ == Token::SUB) { | 8510 if (op_ == Token::SUB) { |
8505 // Check whether the value is a smi. | 8511 // Check whether the value is a smi. |
8506 Label try_float; | 8512 Label try_float; |
8507 __ JumpIfNotSmi(rax, &try_float); | 8513 __ JumpIfNotSmi(rax, &try_float); |
8508 | 8514 |
| 8515 if (negative_zero_ == kIgnoreNegativeZero) { |
| 8516 __ SmiCompare(rax, Smi::FromInt(0)); |
| 8517 __ j(equal, &done); |
| 8518 } |
| 8519 |
8509 // Enter runtime system if the value of the smi is zero | 8520 // Enter runtime system if the value of the smi is zero |
8510 // to make sure that we switch between 0 and -0. | 8521 // to make sure that we switch between 0 and -0. |
8511 // Also enter it if the value of the smi is Smi::kMinValue. | 8522 // Also enter it if the value of the smi is Smi::kMinValue. |
8512 __ SmiNeg(rax, rax, &done); | 8523 __ SmiNeg(rax, rax, &done); |
8513 | 8524 |
8514 // Either zero or Smi::kMinValue, neither of which become a smi when | 8525 // Either zero or Smi::kMinValue, neither of which become a smi when |
8515 // negated. | 8526 // negated. |
8516 __ SmiCompare(rax, Smi::FromInt(0)); | 8527 if (negative_zero_ == kStrictNegativeZero) { |
8517 __ j(not_equal, &slow); | 8528 __ SmiCompare(rax, Smi::FromInt(0)); |
8518 __ Move(rax, Factory::minus_zero_value()); | 8529 __ j(not_equal, &slow); |
8519 __ jmp(&done); | 8530 __ Move(rax, Factory::minus_zero_value()); |
| 8531 __ jmp(&done); |
| 8532 } else { |
| 8533 __ jmp(&slow); |
| 8534 } |
8520 | 8535 |
8521 // Try floating point case. | 8536 // Try floating point case. |
8522 __ bind(&try_float); | 8537 __ bind(&try_float); |
8523 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 8538 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
8524 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); | 8539 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); |
8525 __ j(not_equal, &slow); | 8540 __ j(not_equal, &slow); |
8526 // Operand is a float, negate its value by flipping sign bit. | 8541 // Operand is a float, negate its value by flipping sign bit. |
8527 __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset)); | 8542 __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset)); |
8528 __ movq(kScratchRegister, Immediate(0x01)); | 8543 __ movq(kScratchRegister, Immediate(0x01)); |
8529 __ shl(kScratchRegister, Immediate(63)); | 8544 __ shl(kScratchRegister, Immediate(63)); |
8530 __ xor_(rdx, kScratchRegister); // Flip sign. | 8545 __ xor_(rdx, kScratchRegister); // Flip sign. |
8531 // rdx is value to store. | 8546 // rdx is value to store. |
8532 if (overwrite_) { | 8547 if (overwrite_ == UNARY_OVERWRITE) { |
8533 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx); | 8548 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx); |
8534 } else { | 8549 } else { |
8535 __ AllocateHeapNumber(rcx, rbx, &slow); | 8550 __ AllocateHeapNumber(rcx, rbx, &slow); |
8536 // rcx: allocated 'empty' number | 8551 // rcx: allocated 'empty' number |
8537 __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx); | 8552 __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx); |
8538 __ movq(rax, rcx); | 8553 __ movq(rax, rcx); |
8539 } | 8554 } |
8540 } else if (op_ == Token::BIT_NOT) { | 8555 } else if (op_ == Token::BIT_NOT) { |
8541 // Check if the operand is a heap number. | 8556 // Check if the operand is a heap number. |
8542 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 8557 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
(...skipping 2046 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10589 case Token::MUL: | 10604 case Token::MUL: |
10590 case Token::DIV: { | 10605 case Token::DIV: { |
10591 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | 10606 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
10592 HasSmiCodeInStub()) { | 10607 HasSmiCodeInStub()) { |
10593 // Execution reaches this point when the first non-smi argument occurs | 10608 // Execution reaches this point when the first non-smi argument occurs |
10594 // (and only if smi code is generated). This is the right moment to | 10609 // (and only if smi code is generated). This is the right moment to |
10595 // patch to HEAP_NUMBERS state. The transition is attempted only for | 10610 // patch to HEAP_NUMBERS state. The transition is attempted only for |
10596 // the four basic operations. The stub stays in the DEFAULT state | 10611 // the four basic operations. The stub stays in the DEFAULT state |
10597 // forever for all other operations (also if smi code is skipped). | 10612 // forever for all other operations (also if smi code is skipped). |
10598 GenerateTypeTransition(masm); | 10613 GenerateTypeTransition(masm); |
| 10614 break; |
10599 } | 10615 } |
10600 | 10616 |
10601 Label not_floats; | 10617 Label not_floats; |
10602 // rax: y | 10618 // rax: y |
10603 // rdx: x | 10619 // rdx: x |
10604 if (static_operands_type_.IsNumber()) { | 10620 if (static_operands_type_.IsNumber()) { |
10605 if (FLAG_debug_code) { | 10621 if (FLAG_debug_code) { |
10606 // Assert at runtime that inputs are only numbers. | 10622 // Assert at runtime that inputs are only numbers. |
10607 __ AbortIfNotNumber(rdx); | 10623 __ AbortIfNotNumber(rdx); |
10608 __ AbortIfNotNumber(rax); | 10624 __ AbortIfNotNumber(rax); |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10906 __ push(rdx); | 10922 __ push(rdx); |
10907 __ push(rax); | 10923 __ push(rax); |
10908 } | 10924 } |
10909 __ push(rcx); | 10925 __ push(rcx); |
10910 } | 10926 } |
10911 | 10927 |
10912 | 10928 |
10913 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 10929 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
10914 Label get_result; | 10930 Label get_result; |
10915 | 10931 |
10916 // Keep a copy of operands on the stack and make sure they are also in | 10932 // Ensure the operands are on the stack. |
10917 // rdx, rax. | |
10918 if (HasArgsInRegisters()) { | 10933 if (HasArgsInRegisters()) { |
10919 GenerateRegisterArgsPush(masm); | 10934 GenerateRegisterArgsPush(masm); |
10920 } else { | |
10921 GenerateLoadArguments(masm); | |
10922 } | 10935 } |
10923 | 10936 |
10924 // Internal frame is necessary to handle exceptions properly. | |
10925 __ EnterInternalFrame(); | |
10926 | |
10927 // Push arguments on stack if the stub expects them there. | |
10928 if (!HasArgsInRegisters()) { | |
10929 __ push(rdx); | |
10930 __ push(rax); | |
10931 } | |
10932 // Call the stub proper to get the result in rax. | |
10933 __ call(&get_result); | |
10934 __ LeaveInternalFrame(); | |
10935 | |
10936 // Left and right arguments are already on stack. | 10937 // Left and right arguments are already on stack. |
10937 __ pop(rcx); | 10938 __ pop(rcx); // Save the return address. |
10938 // Push the operation result. The tail call to BinaryOp_Patch will | |
10939 // return it to the original caller.. | |
10940 __ push(rax); | |
10941 | 10939 |
10942 // Push this stub's key. | 10940 // Push this stub's key. |
10943 __ Push(Smi::FromInt(MinorKey())); | 10941 __ Push(Smi::FromInt(MinorKey())); |
10944 | 10942 |
10945 // Although the operation and the type info are encoded into the key, | 10943 // Although the operation and the type info are encoded into the key, |
10946 // the encoding is opaque, so push them too. | 10944 // the encoding is opaque, so push them too. |
10947 __ Push(Smi::FromInt(op_)); | 10945 __ Push(Smi::FromInt(op_)); |
10948 | 10946 |
10949 __ Push(Smi::FromInt(runtime_operands_type_)); | 10947 __ Push(Smi::FromInt(runtime_operands_type_)); |
10950 | 10948 |
10951 __ push(rcx); | 10949 __ push(rcx); // The return address. |
10952 | 10950 |
10953 // Perform patching to an appropriate fast case and return the result. | 10951 // Perform patching to an appropriate fast case and return the result. |
10954 __ TailCallExternalReference( | 10952 __ TailCallExternalReference( |
10955 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), | 10953 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
10956 6, | 10954 5, |
10957 1); | 10955 1); |
10958 | |
10959 // The entry point for the result calculation is assumed to be immediately | |
10960 // after this sequence. | |
10961 __ bind(&get_result); | |
10962 } | 10956 } |
10963 | 10957 |
10964 | 10958 |
10965 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { | 10959 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
10966 GenericBinaryOpStub stub(key, type_info); | 10960 GenericBinaryOpStub stub(key, type_info); |
10967 return stub.GetCode(); | 10961 return stub.GetCode(); |
10968 } | 10962 } |
10969 | 10963 |
10970 | 10964 |
10971 int CompareStub::MinorKey() { | 10965 int CompareStub::MinorKey() { |
(...skipping 1097 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12069 } | 12063 } |
12070 | 12064 |
12071 #endif | 12065 #endif |
12072 | 12066 |
12073 | 12067 |
12074 #undef __ | 12068 #undef __ |
12075 | 12069 |
12076 } } // namespace v8::internal | 12070 } } // namespace v8::internal |
12077 | 12071 |
12078 #endif // V8_TARGET_ARCH_X64 | 12072 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |