| 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 3674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3685 | 3685 |
| 3686 | 3686 |
| 3687 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3687 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3688 Comment cmnt(masm_, "[ CompareOperation"); | 3688 Comment cmnt(masm_, "[ CompareOperation"); |
| 3689 | 3689 |
| 3690 // Get the expressions from the node. | 3690 // Get the expressions from the node. |
| 3691 Expression* left = node->left(); | 3691 Expression* left = node->left(); |
| 3692 Expression* right = node->right(); | 3692 Expression* right = node->right(); |
| 3693 Token::Value op = node->op(); | 3693 Token::Value op = node->op(); |
| 3694 | 3694 |
| 3695 // NOTE: To make null checks efficient, we check if either left or | 3695 // To make null checks efficient, we check if either left or right is the |
| 3696 // right is the literal 'null'. If so, we optimize the code by | 3696 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3697 // inlining a null check instead of calling the (very) general | 3697 // instead of calling the (very) general runtime routine for checking |
| 3698 // runtime routine for checking equality. | 3698 // equality. |
| 3699 | |
| 3700 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3699 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3701 bool left_is_null = | 3700 bool left_is_null = |
| 3702 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3701 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3703 bool right_is_null = | 3702 bool right_is_null = |
| 3704 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3703 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3705 // The 'null' value is only equal to 'null' or 'undefined'. | 3704 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3706 if (left_is_null || right_is_null) { | 3705 if (left_is_null || right_is_null) { |
| 3707 Load(left_is_null ? right : left); | 3706 Load(left_is_null ? right : left); |
| 3708 JumpTarget exit(this); | |
| 3709 JumpTarget undetectable(this); | |
| 3710 frame_->Pop(eax); | 3707 frame_->Pop(eax); |
| 3711 __ cmp(eax, Factory::null_value()); | 3708 __ cmp(eax, Factory::null_value()); |
| 3712 | 3709 |
| 3713 // The 'null' value is only equal to 'undefined' if using | 3710 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3714 // non-strict comparisons. | 3711 // comparisons. |
| 3715 if (op != Token::EQ_STRICT) { | 3712 if (op != Token::EQ_STRICT) { |
| 3716 exit.Branch(equal); | 3713 true_target()->Branch(equal); |
| 3714 |
| 3717 __ cmp(eax, Factory::undefined_value()); | 3715 __ cmp(eax, Factory::undefined_value()); |
| 3716 true_target()->Branch(equal); |
| 3718 | 3717 |
| 3719 // NOTE: it can be an undetectable object. | |
| 3720 exit.Branch(equal); | |
| 3721 __ test(eax, Immediate(kSmiTagMask)); | 3718 __ test(eax, Immediate(kSmiTagMask)); |
| 3719 false_target()->Branch(equal); |
| 3722 | 3720 |
| 3723 undetectable.Branch(not_equal); | 3721 // It can be an undetectable object. |
| 3724 false_target()->Jump(); | 3722 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3725 | 3723 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); |
| 3726 undetectable.Bind(); | 3724 __ and_(eax, 1 << Map::kIsUndetectable); |
| 3727 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3725 __ cmp(eax, 1 << Map::kIsUndetectable); |
| 3728 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | |
| 3729 __ and_(ecx, 1 << Map::kIsUndetectable); | |
| 3730 __ cmp(ecx, 1 << Map::kIsUndetectable); | |
| 3731 } | 3726 } |
| 3732 | 3727 |
| 3733 exit.Bind(); | |
| 3734 | |
| 3735 cc_reg_ = equal; | 3728 cc_reg_ = equal; |
| 3736 return; | 3729 return; |
| 3737 } | 3730 } |
| 3738 } | 3731 } |
| 3739 | 3732 |
| 3740 // NOTE: To make typeof testing for natives implemented in | 3733 // To make typeof testing for natives implemented in JavaScript really |
| 3741 // JavaScript really efficient, we generate special code for | 3734 // efficient, we generate special code for expressions of the form: |
| 3742 // expressions of the form: 'typeof <expression> == <string>'. | 3735 // 'typeof <expression> == <string>'. |
| 3743 | |
| 3744 UnaryOperation* operation = left->AsUnaryOperation(); | 3736 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3745 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3737 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3746 (operation != NULL && operation->op() == Token::TYPEOF) && | 3738 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3747 (right->AsLiteral() != NULL && | 3739 (right->AsLiteral() != NULL && |
| 3748 right->AsLiteral()->handle()->IsString())) { | 3740 right->AsLiteral()->handle()->IsString())) { |
| 3749 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3741 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3750 | 3742 |
| 3751 // Load the operand, move it to register edx, and restore TOS. | 3743 // Load the operand and move it to register edx. |
| 3752 LoadTypeofExpression(operation->expression()); | 3744 LoadTypeofExpression(operation->expression()); |
| 3753 frame_->Pop(edx); | 3745 frame_->Pop(edx); |
| 3754 | 3746 |
| 3755 if (check->Equals(Heap::number_symbol())) { | 3747 if (check->Equals(Heap::number_symbol())) { |
| 3756 __ test(edx, Immediate(kSmiTagMask)); | 3748 __ test(edx, Immediate(kSmiTagMask)); |
| 3757 true_target()->Branch(zero); | 3749 true_target()->Branch(zero); |
| 3758 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3750 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3759 __ cmp(edx, Factory::heap_number_map()); | 3751 __ cmp(edx, Factory::heap_number_map()); |
| 3760 cc_reg_ = equal; | 3752 cc_reg_ = equal; |
| 3761 | 3753 |
| 3762 } else if (check->Equals(Heap::string_symbol())) { | 3754 } else if (check->Equals(Heap::string_symbol())) { |
| 3763 __ test(edx, Immediate(kSmiTagMask)); | 3755 __ test(edx, Immediate(kSmiTagMask)); |
| 3764 false_target()->Branch(zero); | 3756 false_target()->Branch(zero); |
| 3765 | 3757 |
| 3766 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3758 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3767 | 3759 |
| 3768 // NOTE: it might be an undetectable string object | 3760 // It can be an undetectable string object. |
| 3769 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3761 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3770 __ and_(ecx, 1 << Map::kIsUndetectable); | 3762 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3771 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3763 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3772 false_target()->Branch(equal); | 3764 false_target()->Branch(equal); |
| 3773 | 3765 |
| 3774 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3766 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3775 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 3767 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
| 3776 cc_reg_ = less; | 3768 cc_reg_ = less; |
| 3777 | 3769 |
| 3778 } else if (check->Equals(Heap::boolean_symbol())) { | 3770 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3779 __ cmp(edx, Factory::true_value()); | 3771 __ cmp(edx, Factory::true_value()); |
| 3780 true_target()->Branch(equal); | 3772 true_target()->Branch(equal); |
| 3781 __ cmp(edx, Factory::false_value()); | 3773 __ cmp(edx, Factory::false_value()); |
| 3782 cc_reg_ = equal; | 3774 cc_reg_ = equal; |
| 3783 | 3775 |
| 3784 } else if (check->Equals(Heap::undefined_symbol())) { | 3776 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3785 __ cmp(edx, Factory::undefined_value()); | 3777 __ cmp(edx, Factory::undefined_value()); |
| 3786 true_target()->Branch(equal); | 3778 true_target()->Branch(equal); |
| 3787 | 3779 |
| 3788 __ test(edx, Immediate(kSmiTagMask)); | 3780 __ test(edx, Immediate(kSmiTagMask)); |
| 3789 false_target()->Branch(zero); | 3781 false_target()->Branch(zero); |
| 3790 | 3782 |
| 3791 // NOTE: it can be an undetectable object. | 3783 // It can be an undetectable object. |
| 3792 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3784 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3793 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3785 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3794 __ and_(ecx, 1 << Map::kIsUndetectable); | 3786 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3795 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3787 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3796 | 3788 |
| 3797 cc_reg_ = equal; | 3789 cc_reg_ = equal; |
| 3798 | 3790 |
| 3799 } else if (check->Equals(Heap::function_symbol())) { | 3791 } else if (check->Equals(Heap::function_symbol())) { |
| 3800 __ test(edx, Immediate(kSmiTagMask)); | 3792 __ test(edx, Immediate(kSmiTagMask)); |
| 3801 false_target()->Branch(zero); | 3793 false_target()->Branch(zero); |
| 3802 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3794 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3803 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3795 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3804 __ cmp(edx, JS_FUNCTION_TYPE); | 3796 __ cmp(edx, JS_FUNCTION_TYPE); |
| 3805 cc_reg_ = equal; | 3797 cc_reg_ = equal; |
| 3806 | 3798 |
| 3807 } else if (check->Equals(Heap::object_symbol())) { | 3799 } else if (check->Equals(Heap::object_symbol())) { |
| 3808 __ test(edx, Immediate(kSmiTagMask)); | 3800 __ test(edx, Immediate(kSmiTagMask)); |
| 3809 false_target()->Branch(zero); | 3801 false_target()->Branch(zero); |
| 3810 | 3802 |
| 3811 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 3803 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3812 __ cmp(edx, Factory::null_value()); | 3804 __ cmp(edx, Factory::null_value()); |
| 3813 true_target()->Branch(equal); | 3805 true_target()->Branch(equal); |
| 3814 | 3806 |
| 3815 // NOTE: it might be an undetectable object | 3807 // It can be an undetectable object. |
| 3816 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 3808 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 3817 __ and_(edx, 1 << Map::kIsUndetectable); | 3809 __ and_(edx, 1 << Map::kIsUndetectable); |
| 3818 __ cmp(edx, 1 << Map::kIsUndetectable); | 3810 __ cmp(edx, 1 << Map::kIsUndetectable); |
| 3819 false_target()->Branch(equal); | 3811 false_target()->Branch(equal); |
| 3820 | 3812 |
| 3821 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3813 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3822 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 3814 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 3823 false_target()->Branch(less); | 3815 false_target()->Branch(less); |
| 3824 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 3816 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 3825 cc_reg_ = less_equal; | 3817 cc_reg_ = less_equal; |
| 3826 | 3818 |
| 3827 } else { | 3819 } else { |
| 3828 // Uncommon case: Typeof testing against a string literal that | 3820 // Uncommon case: typeof testing against a string literal that is |
| 3829 // is never returned from the typeof operator. | 3821 // never returned from the typeof operator. |
| 3830 false_target()->Jump(); | 3822 false_target()->Jump(); |
| 3831 // TODO(): Can this cause a problem because it is an expression that | 3823 // TODO(): Can this cause a problem because it is an expression that |
| 3832 // exits without a virtual frame in place? | 3824 // exits without a virtual frame in place? |
| 3833 } | 3825 } |
| 3834 return; | 3826 return; |
| 3835 } | 3827 } |
| 3836 | 3828 |
| 3837 Condition cc = no_condition; | 3829 Condition cc = no_condition; |
| 3838 bool strict = false; | 3830 bool strict = false; |
| 3839 switch (op) { | 3831 switch (op) { |
| (...skipping 1489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5329 | 5321 |
| 5330 // Slow-case: Go through the JavaScript implementation. | 5322 // Slow-case: Go through the JavaScript implementation. |
| 5331 __ bind(&slow); | 5323 __ bind(&slow); |
| 5332 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5324 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5333 } | 5325 } |
| 5334 | 5326 |
| 5335 | 5327 |
| 5336 #undef __ | 5328 #undef __ |
| 5337 | 5329 |
| 5338 } } // namespace v8::internal | 5330 } } // namespace v8::internal |
| OLD | NEW |