| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 3504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3515 | 3515 |
| 3516 | 3516 |
| 3517 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3517 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3518 Comment cmnt(masm_, "[ CompareOperation"); | 3518 Comment cmnt(masm_, "[ CompareOperation"); |
| 3519 | 3519 |
| 3520 // Get the expressions from the node. | 3520 // Get the expressions from the node. |
| 3521 Expression* left = node->left(); | 3521 Expression* left = node->left(); |
| 3522 Expression* right = node->right(); | 3522 Expression* right = node->right(); |
| 3523 Token::Value op = node->op(); | 3523 Token::Value op = node->op(); |
| 3524 | 3524 |
| 3525 // NOTE: To make null checks efficient, we check if either left or | 3525 // To make null checks efficient, we check if either left or right is the |
| 3526 // right is the literal 'null'. If so, we optimize the code by | 3526 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3527 // inlining a null check instead of calling the (very) general | 3527 // instead of calling the (very) general runtime routine for checking |
| 3528 // runtime routine for checking equality. | 3528 // equality. |
| 3529 | |
| 3530 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3529 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3531 bool left_is_null = | 3530 bool left_is_null = |
| 3532 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3531 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3533 bool right_is_null = | 3532 bool right_is_null = |
| 3534 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3533 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3535 // The 'null' value is only equal to 'null' or 'undefined'. | 3534 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3536 if (left_is_null || right_is_null) { | 3535 if (left_is_null || right_is_null) { |
| 3537 Load(left_is_null ? right : left); | 3536 Load(left_is_null ? right : left); |
| 3538 Label exit, undetectable; | |
| 3539 frame_->Pop(eax); | 3537 frame_->Pop(eax); |
| 3540 __ cmp(eax, Factory::null_value()); | 3538 __ cmp(eax, Factory::null_value()); |
| 3541 | 3539 |
| 3542 // The 'null' value is only equal to 'undefined' if using | 3540 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3543 // non-strict comparisons. | 3541 // comparisons. |
| 3544 if (op != Token::EQ_STRICT) { | 3542 if (op != Token::EQ_STRICT) { |
| 3545 __ j(equal, &exit); | 3543 __ j(equal, true_target()); |
| 3544 |
| 3546 __ cmp(eax, Factory::undefined_value()); | 3545 __ cmp(eax, Factory::undefined_value()); |
| 3546 __ j(equal, true_target()); |
| 3547 | 3547 |
| 3548 // NOTE: it can be an undetectable object. | |
| 3549 __ j(equal, &exit); | |
| 3550 __ test(eax, Immediate(kSmiTagMask)); | 3548 __ test(eax, Immediate(kSmiTagMask)); |
| 3549 __ j(equal, false_target()); |
| 3551 | 3550 |
| 3552 __ j(not_equal, &undetectable); | 3551 // It can be an undetectable object. |
| 3553 __ jmp(false_target()); | 3552 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3554 | 3553 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); |
| 3555 __ bind(&undetectable); | 3554 __ and_(eax, 1 << Map::kIsUndetectable); |
| 3556 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3555 __ cmp(eax, 1 << Map::kIsUndetectable); |
| 3557 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | |
| 3558 __ and_(ecx, 1 << Map::kIsUndetectable); | |
| 3559 __ cmp(ecx, 1 << Map::kIsUndetectable); | |
| 3560 } | 3556 } |
| 3561 | 3557 |
| 3562 __ bind(&exit); | |
| 3563 | |
| 3564 cc_reg_ = equal; | 3558 cc_reg_ = equal; |
| 3565 return; | 3559 return; |
| 3566 } | 3560 } |
| 3567 } | 3561 } |
| 3568 | 3562 |
| 3569 // NOTE: To make typeof testing for natives implemented in | 3563 // To make typeof testing for natives implemented in JavaScript really |
| 3570 // JavaScript really efficient, we generate special code for | 3564 // efficient, we generate special code for expressions of the form: |
| 3571 // expressions of the form: 'typeof <expression> == <string>'. | 3565 // 'typeof <expression> == <string>'. |
| 3572 | |
| 3573 UnaryOperation* operation = left->AsUnaryOperation(); | 3566 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3574 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3567 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3575 (operation != NULL && operation->op() == Token::TYPEOF) && | 3568 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3576 (right->AsLiteral() != NULL && | 3569 (right->AsLiteral() != NULL && |
| 3577 right->AsLiteral()->handle()->IsString())) { | 3570 right->AsLiteral()->handle()->IsString())) { |
| 3578 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3571 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3579 | 3572 |
| 3580 // Load the operand, move it to register edx, and restore TOS. | 3573 // Load the operand and move it to register edx. |
| 3581 LoadTypeofExpression(operation->expression()); | 3574 LoadTypeofExpression(operation->expression()); |
| 3582 frame_->Pop(edx); | 3575 frame_->Pop(edx); |
| 3583 | 3576 |
| 3584 if (check->Equals(Heap::number_symbol())) { | 3577 if (check->Equals(Heap::number_symbol())) { |
| 3585 __ test(edx, Immediate(kSmiTagMask)); | 3578 __ test(edx, Immediate(kSmiTagMask)); |
| 3586 __ j(zero, true_target()); | 3579 __ j(zero, true_target()); |
| 3587 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3580 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3588 __ cmp(edx, Factory::heap_number_map()); | 3581 __ cmp(edx, Factory::heap_number_map()); |
| 3589 cc_reg_ = equal; | 3582 cc_reg_ = equal; |
| 3590 | 3583 |
| 3591 } else if (check->Equals(Heap::string_symbol())) { | 3584 } else if (check->Equals(Heap::string_symbol())) { |
| 3592 __ test(edx, Immediate(kSmiTagMask)); | 3585 __ test(edx, Immediate(kSmiTagMask)); |
| 3593 __ j(zero, false_target()); | 3586 __ j(zero, false_target()); |
| 3594 | 3587 |
| 3595 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3588 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3596 | 3589 |
| 3597 // NOTE: it might be an undetectable string object | 3590 // It can be an undetectable string object. |
| 3598 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3591 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3599 __ and_(ecx, 1 << Map::kIsUndetectable); | 3592 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3600 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3593 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3601 __ j(equal, false_target()); | 3594 __ j(equal, false_target()); |
| 3602 | 3595 |
| 3603 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3596 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3604 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 3597 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
| 3605 cc_reg_ = less; | 3598 cc_reg_ = less; |
| 3606 | 3599 |
| 3607 } else if (check->Equals(Heap::boolean_symbol())) { | 3600 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3608 __ cmp(edx, Factory::true_value()); | 3601 __ cmp(edx, Factory::true_value()); |
| 3609 __ j(equal, true_target()); | 3602 __ j(equal, true_target()); |
| 3610 __ cmp(edx, Factory::false_value()); | 3603 __ cmp(edx, Factory::false_value()); |
| 3611 cc_reg_ = equal; | 3604 cc_reg_ = equal; |
| 3612 | 3605 |
| 3613 } else if (check->Equals(Heap::undefined_symbol())) { | 3606 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3614 __ cmp(edx, Factory::undefined_value()); | 3607 __ cmp(edx, Factory::undefined_value()); |
| 3615 __ j(equal, true_target()); | 3608 __ j(equal, true_target()); |
| 3616 | 3609 |
| 3617 __ test(edx, Immediate(kSmiTagMask)); | 3610 __ test(edx, Immediate(kSmiTagMask)); |
| 3618 __ j(zero, false_target()); | 3611 __ j(zero, false_target()); |
| 3619 | 3612 |
| 3620 // NOTE: it can be an undetectable object. | 3613 // It can be an undetectable object. |
| 3621 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3614 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3622 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3615 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3623 __ and_(ecx, 1 << Map::kIsUndetectable); | 3616 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3624 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3617 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3625 | 3618 |
| 3626 cc_reg_ = equal; | 3619 cc_reg_ = equal; |
| 3627 | 3620 |
| 3628 } else if (check->Equals(Heap::function_symbol())) { | 3621 } else if (check->Equals(Heap::function_symbol())) { |
| 3629 __ test(edx, Immediate(kSmiTagMask)); | 3622 __ test(edx, Immediate(kSmiTagMask)); |
| 3630 __ j(zero, false_target()); | 3623 __ j(zero, false_target()); |
| 3631 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3624 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3632 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3625 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3633 __ cmp(edx, JS_FUNCTION_TYPE); | 3626 __ cmp(edx, JS_FUNCTION_TYPE); |
| 3634 cc_reg_ = equal; | 3627 cc_reg_ = equal; |
| 3635 | 3628 |
| 3636 } else if (check->Equals(Heap::object_symbol())) { | 3629 } else if (check->Equals(Heap::object_symbol())) { |
| 3637 __ test(edx, Immediate(kSmiTagMask)); | 3630 __ test(edx, Immediate(kSmiTagMask)); |
| 3638 __ j(zero, false_target()); | 3631 __ j(zero, false_target()); |
| 3639 | 3632 |
| 3640 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 3633 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3641 __ cmp(edx, Factory::null_value()); | 3634 __ cmp(edx, Factory::null_value()); |
| 3642 __ j(equal, true_target()); | 3635 __ j(equal, true_target()); |
| 3643 | 3636 |
| 3644 // NOTE: it might be an undetectable object | 3637 // It can be an undetectable object. |
| 3645 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 3638 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 3646 __ and_(edx, 1 << Map::kIsUndetectable); | 3639 __ and_(edx, 1 << Map::kIsUndetectable); |
| 3647 __ cmp(edx, 1 << Map::kIsUndetectable); | 3640 __ cmp(edx, 1 << Map::kIsUndetectable); |
| 3648 __ j(equal, false_target()); | 3641 __ j(equal, false_target()); |
| 3649 | 3642 |
| 3650 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3643 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3651 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 3644 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 3652 __ j(less, false_target()); | 3645 __ j(less, false_target()); |
| 3653 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 3646 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 3654 cc_reg_ = less_equal; | 3647 cc_reg_ = less_equal; |
| 3655 | 3648 |
| 3656 } else { | 3649 } else { |
| 3657 // Uncommon case: Typeof testing against a string literal that | 3650 // Uncommon case: typeof testing against a string literal that is |
| 3658 // is never returned from the typeof operator. | 3651 // never returned from the typeof operator. |
| 3659 __ jmp(false_target()); | 3652 __ jmp(false_target()); |
| 3660 } | 3653 } |
| 3661 return; | 3654 return; |
| 3662 } | 3655 } |
| 3663 | 3656 |
| 3664 Condition cc = no_condition; | 3657 Condition cc = no_condition; |
| 3665 bool strict = false; | 3658 bool strict = false; |
| 3666 switch (op) { | 3659 switch (op) { |
| 3667 case Token::EQ_STRICT: | 3660 case Token::EQ_STRICT: |
| 3668 strict = true; | 3661 strict = true; |
| (...skipping 1480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5149 | 5142 |
| 5150 // Slow-case: Go through the JavaScript implementation. | 5143 // Slow-case: Go through the JavaScript implementation. |
| 5151 __ bind(&slow); | 5144 __ bind(&slow); |
| 5152 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5145 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5153 } | 5146 } |
| 5154 | 5147 |
| 5155 | 5148 |
| 5156 #undef __ | 5149 #undef __ |
| 5157 | 5150 |
| 5158 } } // namespace v8::internal | 5151 } } // namespace v8::internal |
| OLD | NEW |