| 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 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 Variable* variable = x->AsVariableProxy()->AsVariable(); | 487 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 488 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 488 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 489 // NOTE: This is somewhat nasty. We force the compiler to load | 489 // NOTE: This is somewhat nasty. We force the compiler to load |
| 490 // the variable as if through '<global>.<variable>' to make sure we | 490 // the variable as if through '<global>.<variable>' to make sure we |
| 491 // do not get reference errors. | 491 // do not get reference errors. |
| 492 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 492 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
| 493 Literal key(variable->name()); | 493 Literal key(variable->name()); |
| 494 // TODO(1241834): Fetch the position from the variable instead of using | 494 // TODO(1241834): Fetch the position from the variable instead of using |
| 495 // no position. | 495 // no position. |
| 496 Property property(&global, &key, RelocInfo::kNoPosition); | 496 Property property(&global, &key, RelocInfo::kNoPosition); |
| 497 LoadAndSpill(&property); | 497 Load(&property); |
| 498 } else { | 498 } else { |
| 499 LoadAndSpill(x, INSIDE_TYPEOF); | 499 Load(x, INSIDE_TYPEOF); |
| 500 } | 500 } |
| 501 } | 501 } |
| 502 | 502 |
| 503 | 503 |
| 504 Reference::Reference(CodeGenerator* cgen, Expression* expression) | 504 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
| 505 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 505 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
| 506 cgen->LoadReference(this); | 506 cgen->LoadReference(this); |
| 507 } | 507 } |
| 508 | 508 |
| 509 | 509 |
| (...skipping 3113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3623 | 3623 |
| 3624 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3624 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3625 // Note that because of NOT and an optimization in comparison of a typeof | 3625 // Note that because of NOT and an optimization in comparison of a typeof |
| 3626 // expression to a literal string, this function can fail to leave a value | 3626 // expression to a literal string, this function can fail to leave a value |
| 3627 // on top of the frame or in the cc register. | 3627 // on top of the frame or in the cc register. |
| 3628 Comment cmnt(masm_, "[ UnaryOperation"); | 3628 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3629 | 3629 |
| 3630 Token::Value op = node->op(); | 3630 Token::Value op = node->op(); |
| 3631 | 3631 |
| 3632 if (op == Token::NOT) { | 3632 if (op == Token::NOT) { |
| 3633 VirtualFrame::SpilledScope spilled_scope(this); | 3633 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3634 LoadConditionAndSpill(node->expression(), NOT_INSIDE_TYPEOF, | 3634 false_target(), true_target(), true); |
| 3635 false_target(), true_target(), true); | |
| 3636 | 3635 |
| 3637 } else if (op == Token::DELETE) { | 3636 } else if (op == Token::DELETE) { |
| 3638 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3639 Property* property = node->expression()->AsProperty(); | 3637 Property* property = node->expression()->AsProperty(); |
| 3640 if (property != NULL) { | 3638 if (property != NULL) { |
| 3641 LoadAndSpill(property->obj()); | 3639 Load(property->obj()); |
| 3642 LoadAndSpill(property->key()); | 3640 Load(property->key()); |
| 3643 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3641 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3644 frame_->EmitPush(eax); | 3642 frame_->Push(&answer); |
| 3645 return; | 3643 return; |
| 3646 } | 3644 } |
| 3647 | 3645 |
| 3648 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3646 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 3649 if (variable != NULL) { | 3647 if (variable != NULL) { |
| 3650 Slot* slot = variable->slot(); | 3648 Slot* slot = variable->slot(); |
| 3651 if (variable->is_global()) { | 3649 if (variable->is_global()) { |
| 3652 LoadGlobal(); | 3650 LoadGlobal(); |
| 3653 frame_->EmitPush(Immediate(variable->name())); | 3651 frame_->Push(variable->name()); |
| 3654 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3652 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
| 3655 frame_->EmitPush(eax); | 3653 CALL_FUNCTION, 2); |
| 3654 frame_->Push(&answer); |
| 3656 return; | 3655 return; |
| 3657 | 3656 |
| 3658 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 3657 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 3659 // lookup the context holding the named variable | 3658 // lookup the context holding the named variable |
| 3660 frame_->EmitPush(esi); | 3659 frame_->Push(esi); |
| 3661 frame_->EmitPush(Immediate(variable->name())); | 3660 frame_->Push(variable->name()); |
| 3662 frame_->CallRuntime(Runtime::kLookupContext, 2); | 3661 Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); |
| 3663 // eax: context | 3662 frame_->Push(&context); |
| 3664 frame_->EmitPush(eax); | 3663 frame_->Push(variable->name()); |
| 3665 frame_->EmitPush(Immediate(variable->name())); | 3664 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
| 3666 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3665 CALL_FUNCTION, 2); |
| 3667 frame_->EmitPush(eax); | 3666 frame_->Push(&answer); |
| 3668 return; | 3667 return; |
| 3669 } | 3668 } |
| 3670 | 3669 |
| 3671 // Default: Result of deleting non-global, not dynamically | 3670 // Default: Result of deleting non-global, not dynamically |
| 3672 // introduced variables is false. | 3671 // introduced variables is false. |
| 3673 frame_->EmitPush(Immediate(Factory::false_value())); | 3672 frame_->Push(Factory::false_value()); |
| 3674 | 3673 |
| 3675 } else { | 3674 } else { |
| 3676 // Default: Result of deleting expressions is true. | 3675 // Default: Result of deleting expressions is true. |
| 3677 LoadAndSpill(node->expression()); // may have side-effects | 3676 Load(node->expression()); // may have side-effects |
| 3678 __ Set(frame_->Top(), Immediate(Factory::true_value())); | 3677 frame_->SetElementAt(0, Factory::true_value()); |
| 3679 } | 3678 } |
| 3680 | 3679 |
| 3681 } else if (op == Token::TYPEOF) { | 3680 } else if (op == Token::TYPEOF) { |
| 3682 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3683 // Special case for loading the typeof expression; see comment on | 3681 // Special case for loading the typeof expression; see comment on |
| 3684 // LoadTypeofExpression(). | 3682 // LoadTypeofExpression(). |
| 3685 LoadTypeofExpression(node->expression()); | 3683 LoadTypeofExpression(node->expression()); |
| 3686 frame_->CallRuntime(Runtime::kTypeof, 1); | 3684 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); |
| 3687 frame_->EmitPush(eax); | 3685 frame_->Push(&answer); |
| 3688 | 3686 |
| 3689 } else { | 3687 } else { |
| 3690 Load(node->expression()); | 3688 Load(node->expression()); |
| 3691 switch (op) { | 3689 switch (op) { |
| 3692 case Token::NOT: | 3690 case Token::NOT: |
| 3693 case Token::DELETE: | 3691 case Token::DELETE: |
| 3694 case Token::TYPEOF: | 3692 case Token::TYPEOF: |
| 3695 UNREACHABLE(); // handled above | 3693 UNREACHABLE(); // handled above |
| 3696 break; | 3694 break; |
| 3697 | 3695 |
| 3698 case Token::SUB: { | 3696 case Token::SUB: { |
| 3699 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3700 UnarySubStub stub; | 3697 UnarySubStub stub; |
| 3701 // TODO(1222589): remove dependency of TOS being cached inside stub | 3698 // TODO(1222589): remove dependency of TOS being cached inside stub |
| 3702 frame_->EmitPop(eax); | 3699 Result operand = frame_->Pop(); |
| 3703 frame_->CallStub(&stub, 0); | 3700 operand.ToRegister(eax); |
| 3704 frame_->EmitPush(eax); | 3701 Result answer = frame_->CallStub(&stub, &operand, 0); |
| 3702 frame_->Push(&answer); |
| 3705 break; | 3703 break; |
| 3706 } | 3704 } |
| 3707 | 3705 |
| 3708 case Token::BIT_NOT: { | 3706 case Token::BIT_NOT: { |
| 3709 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3710 // Smi check. | 3707 // Smi check. |
| 3711 JumpTarget smi_label(this); | 3708 JumpTarget smi_label(this); |
| 3712 JumpTarget continue_label(this); | 3709 JumpTarget continue_label(this); |
| 3713 frame_->EmitPop(eax); | 3710 Result operand = frame_->Pop(); |
| 3714 __ test(eax, Immediate(kSmiTagMask)); | 3711 operand.ToRegister(); |
| 3715 smi_label.Branch(zero, taken); | 3712 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 3713 smi_label.Branch(zero, &operand, taken); |
| 3716 | 3714 |
| 3717 frame_->EmitPush(eax); // undo popping of TOS | 3715 frame_->Push(&operand); // undo popping of TOS |
| 3718 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); | 3716 Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, |
| 3717 CALL_FUNCTION, 1); |
| 3719 | 3718 |
| 3720 continue_label.Jump(); | 3719 continue_label.Jump(&answer); |
| 3721 smi_label.Bind(); | 3720 smi_label.Bind(&answer); |
| 3722 __ not_(eax); | 3721 answer.ToRegister(); |
| 3723 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. | 3722 frame_->Spill(answer.reg()); |
| 3724 continue_label.Bind(); | 3723 __ not_(answer.reg()); |
| 3725 frame_->EmitPush(eax); | 3724 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. |
| 3725 continue_label.Bind(&answer); |
| 3726 frame_->Push(&answer); |
| 3726 break; | 3727 break; |
| 3727 } | 3728 } |
| 3728 | 3729 |
| 3729 case Token::VOID: { | 3730 case Token::VOID: { |
| 3730 VirtualFrame::SpilledScope spilled_scope(this); | 3731 frame_->SetElementAt(0, Factory::undefined_value()); |
| 3731 __ mov(frame_->Top(), Factory::undefined_value()); | |
| 3732 break; | 3732 break; |
| 3733 } | 3733 } |
| 3734 | 3734 |
| 3735 case Token::ADD: { | 3735 case Token::ADD: { |
| 3736 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3737 // Smi check. | 3736 // Smi check. |
| 3738 JumpTarget continue_label(this); | 3737 JumpTarget continue_label(this); |
| 3739 frame_->EmitPop(eax); | 3738 Result operand = frame_->Pop(); |
| 3740 __ test(eax, Immediate(kSmiTagMask)); | 3739 operand.ToRegister(); |
| 3741 continue_label.Branch(zero); | 3740 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 3741 continue_label.Branch(zero, &operand, taken); |
| 3742 | 3742 |
| 3743 frame_->EmitPush(eax); | 3743 frame_->Push(&operand); |
| 3744 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); | 3744 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
| 3745 CALL_FUNCTION, 1); |
| 3745 | 3746 |
| 3746 continue_label.Bind(); | 3747 continue_label.Bind(&answer); |
| 3747 frame_->EmitPush(eax); | 3748 frame_->Push(&answer); |
| 3748 break; | 3749 break; |
| 3749 } | 3750 } |
| 3750 | 3751 |
| 3751 default: | 3752 default: |
| 3752 UNREACHABLE(); | 3753 UNREACHABLE(); |
| 3753 } | 3754 } |
| 3754 } | 3755 } |
| 3755 } | 3756 } |
| 3756 | 3757 |
| 3757 | 3758 |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4137 // To make typeof testing for natives implemented in JavaScript really | 4138 // To make typeof testing for natives implemented in JavaScript really |
| 4138 // efficient, we generate special code for expressions of the form: | 4139 // efficient, we generate special code for expressions of the form: |
| 4139 // 'typeof <expression> == <string>'. | 4140 // 'typeof <expression> == <string>'. |
| 4140 UnaryOperation* operation = left->AsUnaryOperation(); | 4141 UnaryOperation* operation = left->AsUnaryOperation(); |
| 4141 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 4142 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 4142 (operation != NULL && operation->op() == Token::TYPEOF) && | 4143 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 4143 (right->AsLiteral() != NULL && | 4144 (right->AsLiteral() != NULL && |
| 4144 right->AsLiteral()->handle()->IsString())) { | 4145 right->AsLiteral()->handle()->IsString())) { |
| 4145 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 4146 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 4146 | 4147 |
| 4147 VirtualFrame::SpilledScope spilled_scope(this); | |
| 4148 // Load the operand and move it to register edx. | 4148 // Load the operand and move it to register edx. |
| 4149 LoadTypeofExpression(operation->expression()); | 4149 LoadTypeofExpression(operation->expression()); |
| 4150 frame_->EmitPop(edx); | 4150 Result type_returned = frame_->Pop(); |
| 4151 type_returned.ToRegister(edx); |
| 4152 |
| 4153 VirtualFrame::SpilledScope spilled_scope(this); |
| 4154 type_returned.Unuse(); |
| 4151 | 4155 |
| 4152 if (check->Equals(Heap::number_symbol())) { | 4156 if (check->Equals(Heap::number_symbol())) { |
| 4153 __ test(edx, Immediate(kSmiTagMask)); | 4157 __ test(edx, Immediate(kSmiTagMask)); |
| 4154 true_target()->Branch(zero); | 4158 true_target()->Branch(zero); |
| 4155 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4159 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4156 __ cmp(edx, Factory::heap_number_map()); | 4160 __ cmp(edx, Factory::heap_number_map()); |
| 4157 true_target()->Branch(equal); | 4161 true_target()->Branch(equal); |
| 4158 false_target()->Jump(); | 4162 false_target()->Jump(); |
| 4159 | 4163 |
| 4160 } else if (check->Equals(Heap::string_symbol())) { | 4164 } else if (check->Equals(Heap::string_symbol())) { |
| (...skipping 1923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6084 | 6088 |
| 6085 // Slow-case: Go through the JavaScript implementation. | 6089 // Slow-case: Go through the JavaScript implementation. |
| 6086 __ bind(&slow); | 6090 __ bind(&slow); |
| 6087 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6091 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6088 } | 6092 } |
| 6089 | 6093 |
| 6090 | 6094 |
| 6091 #undef __ | 6095 #undef __ |
| 6092 | 6096 |
| 6093 } } // namespace v8::internal | 6097 } } // namespace v8::internal |
| OLD | NEW |