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 4713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4724 JumpTarget slow; | 4724 JumpTarget slow; |
4725 JumpTarget done; | 4725 JumpTarget done; |
4726 | 4726 |
4727 // Generate fast-case code for variables that might be shadowed by | 4727 // Generate fast-case code for variables that might be shadowed by |
4728 // eval-introduced variables. Eval is used a lot without | 4728 // eval-introduced variables. Eval is used a lot without |
4729 // introducing variables. In those cases, we do not want to | 4729 // introducing variables. In those cases, we do not want to |
4730 // perform a runtime call for all variables in the scope | 4730 // perform a runtime call for all variables in the scope |
4731 // containing the eval. | 4731 // containing the eval. |
4732 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 4732 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
4733 result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 4733 result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); |
4734 // If there was no control flow to slow, we can exit early. | |
4735 if (!slow.is_linked()) return result; | |
4736 done.Jump(&result); | 4734 done.Jump(&result); |
4737 | 4735 |
4738 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 4736 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
4739 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); | 4737 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
4740 // Only generate the fast case for locals that rewrite to slots. | 4738 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
4741 // This rules out argument loads because eval forces arguments | |
4742 // access to be through the arguments object. | |
4743 if (potential_slot != NULL) { | 4739 if (potential_slot != NULL) { |
| 4740 // Generate fast case for locals that rewrite to slots. |
4744 // Allocate a fresh register to use as a temp in | 4741 // Allocate a fresh register to use as a temp in |
4745 // ContextSlotOperandCheckExtensions and to hold the result | 4742 // ContextSlotOperandCheckExtensions and to hold the result |
4746 // value. | 4743 // value. |
4747 result = allocator()->Allocate(); | 4744 result = allocator()->Allocate(); |
4748 ASSERT(result.is_valid()); | 4745 ASSERT(result.is_valid()); |
4749 __ mov(result.reg(), | 4746 __ mov(result.reg(), |
4750 ContextSlotOperandCheckExtensions(potential_slot, | 4747 ContextSlotOperandCheckExtensions(potential_slot, |
4751 result, | 4748 result, |
4752 &slow)); | 4749 &slow)); |
4753 if (potential_slot->var()->mode() == Variable::CONST) { | 4750 if (potential_slot->var()->mode() == Variable::CONST) { |
4754 __ cmp(result.reg(), Factory::the_hole_value()); | 4751 __ cmp(result.reg(), Factory::the_hole_value()); |
4755 done.Branch(not_equal, &result); | 4752 done.Branch(not_equal, &result); |
4756 __ mov(result.reg(), Factory::undefined_value()); | 4753 __ mov(result.reg(), Factory::undefined_value()); |
4757 } | 4754 } |
4758 // There is always control flow to slow from | |
4759 // ContextSlotOperandCheckExtensions so we have to jump around | |
4760 // it. | |
4761 done.Jump(&result); | 4755 done.Jump(&result); |
| 4756 } else if (rewrite != NULL) { |
| 4757 // Generate fast case for argument loads. |
| 4758 Property* property = rewrite->AsProperty(); |
| 4759 if (property != NULL) { |
| 4760 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 4761 Literal* key_literal = property->key()->AsLiteral(); |
| 4762 if (obj_proxy != NULL && |
| 4763 key_literal != NULL && |
| 4764 obj_proxy->IsArguments() && |
| 4765 key_literal->handle()->IsSmi()) { |
| 4766 // Load arguments object if there are no eval-introduced |
| 4767 // variables. Then load the argument from the arguments |
| 4768 // object using keyed load. |
| 4769 Result arguments = allocator()->Allocate(); |
| 4770 ASSERT(arguments.is_valid()); |
| 4771 __ mov(arguments.reg(), |
| 4772 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 4773 arguments, |
| 4774 &slow)); |
| 4775 frame_->Push(&arguments); |
| 4776 frame_->Push(key_literal->handle()); |
| 4777 result = EmitKeyedLoad(); |
| 4778 done.Jump(&result); |
| 4779 } |
| 4780 } |
4762 } | 4781 } |
4763 } | 4782 } |
4764 | 4783 |
4765 slow.Bind(); | 4784 slow.Bind(); |
4766 // A runtime call is inevitable. We eagerly sync frame elements | 4785 // A runtime call is inevitable. We eagerly sync frame elements |
4767 // to memory so that we can push the arguments directly into place | 4786 // to memory so that we can push the arguments directly into place |
4768 // on top of the frame. | 4787 // on top of the frame. |
4769 frame()->SyncRange(0, frame()->element_count() - 1); | 4788 frame()->SyncRange(0, frame()->element_count() - 1); |
4770 frame()->EmitPush(esi); | 4789 frame()->EmitPush(esi); |
4771 frame()->EmitPush(Immediate(slot->var()->name())); | 4790 frame()->EmitPush(Immediate(slot->var()->name())); |
(...skipping 986 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5758 arg_count, | 5777 arg_count, |
5759 loop_nesting()); | 5778 loop_nesting()); |
5760 frame_->RestoreContextRegister(); | 5779 frame_->RestoreContextRegister(); |
5761 frame_->Push(&result); | 5780 frame_->Push(&result); |
5762 | 5781 |
5763 } else if (var != NULL && var->slot() != NULL && | 5782 } else if (var != NULL && var->slot() != NULL && |
5764 var->slot()->type() == Slot::LOOKUP) { | 5783 var->slot()->type() == Slot::LOOKUP) { |
5765 // ---------------------------------- | 5784 // ---------------------------------- |
5766 // JavaScript examples: | 5785 // JavaScript examples: |
5767 // | 5786 // |
5768 // with (obj) foo(1, 2, 3) // foo is in obj | 5787 // with (obj) foo(1, 2, 3) // foo may be in obj. |
5769 // | 5788 // |
5770 // function f() {}; | 5789 // function f() {}; |
5771 // function g() { | 5790 // function g() { |
5772 // eval(...); | 5791 // eval(...); |
5773 // f(); // f could be in extension object | 5792 // f(); // f could be in extension object. |
5774 // } | 5793 // } |
5775 // ---------------------------------- | 5794 // ---------------------------------- |
5776 | 5795 |
5777 JumpTarget slow; | 5796 JumpTarget slow; |
5778 JumpTarget done; | 5797 JumpTarget done; |
5779 | 5798 |
5780 // Generate fast-case code for variables that might be shadowed by | 5799 // Generate fast-case code for variables that might be shadowed by |
5781 // eval-introduced variables. Eval is used a lot without | 5800 // eval-introduced variables. Eval is used a lot without |
5782 // introducing variables. In those cases, we do not want to | 5801 // introducing variables. In those cases, we do not want to |
5783 // perform a runtime call for all variables in the scope | 5802 // perform a runtime call for all variables in the scope |
5784 // containing the eval. | 5803 // containing the eval. |
5785 Result function; | |
5786 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 5804 if (var->mode() == Variable::DYNAMIC_GLOBAL) { |
5787 function = LoadFromGlobalSlotCheckExtensions(var->slot(), | 5805 Result function = LoadFromGlobalSlotCheckExtensions(var->slot(), |
5788 NOT_INSIDE_TYPEOF, | 5806 NOT_INSIDE_TYPEOF, |
5789 &slow); | 5807 &slow); |
5790 frame_->Push(&function); | 5808 frame_->Push(&function); |
5791 LoadGlobalReceiver(); | 5809 LoadGlobalReceiver(); |
5792 done.Jump(); | 5810 done.Jump(); |
5793 | 5811 |
5794 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | 5812 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { |
5795 Slot* potential_slot = var->local_if_not_shadowed()->slot(); | 5813 Slot* potential_slot = var->local_if_not_shadowed()->slot(); |
5796 // Only generate the fast case for locals that rewrite to slots. | 5814 Expression* rewrite = var->local_if_not_shadowed()->rewrite(); |
5797 // This rules out argument loads because eval forces arguments | |
5798 // access to be through the arguments object. | |
5799 if (potential_slot != NULL) { | 5815 if (potential_slot != NULL) { |
| 5816 // Generate fast case for locals that rewrite to slots. |
5800 // Allocate a fresh register to use as a temp in | 5817 // Allocate a fresh register to use as a temp in |
5801 // ContextSlotOperandCheckExtensions and to hold the result | 5818 // ContextSlotOperandCheckExtensions and to hold the result |
5802 // value. | 5819 // value. |
5803 function = allocator()->Allocate(); | 5820 Result function = allocator()->Allocate(); |
5804 ASSERT(function.is_valid()); | 5821 ASSERT(function.is_valid()); |
5805 __ mov(function.reg(), | 5822 __ mov(function.reg(), |
5806 ContextSlotOperandCheckExtensions(potential_slot, | 5823 ContextSlotOperandCheckExtensions(potential_slot, |
5807 function, | 5824 function, |
5808 &slow)); | 5825 &slow)); |
5809 JumpTarget push_function_and_receiver; | 5826 JumpTarget push_function_and_receiver; |
5810 if (potential_slot->var()->mode() == Variable::CONST) { | 5827 if (potential_slot->var()->mode() == Variable::CONST) { |
5811 __ cmp(function.reg(), Factory::the_hole_value()); | 5828 __ cmp(function.reg(), Factory::the_hole_value()); |
5812 push_function_and_receiver.Branch(not_equal, &function); | 5829 push_function_and_receiver.Branch(not_equal, &function); |
5813 __ mov(function.reg(), Factory::undefined_value()); | 5830 __ mov(function.reg(), Factory::undefined_value()); |
5814 } | 5831 } |
5815 push_function_and_receiver.Bind(&function); | 5832 push_function_and_receiver.Bind(&function); |
5816 frame_->Push(&function); | 5833 frame_->Push(&function); |
5817 LoadGlobalReceiver(); | 5834 LoadGlobalReceiver(); |
5818 done.Jump(); | 5835 done.Jump(); |
| 5836 } else if (rewrite != NULL) { |
| 5837 // Generate fast case for calls of an argument function. |
| 5838 Property* property = rewrite->AsProperty(); |
| 5839 if (property != NULL) { |
| 5840 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 5841 Literal* key_literal = property->key()->AsLiteral(); |
| 5842 if (obj_proxy != NULL && |
| 5843 key_literal != NULL && |
| 5844 obj_proxy->IsArguments() && |
| 5845 key_literal->handle()->IsSmi()) { |
| 5846 // Load arguments object if there are no eval-introduced |
| 5847 // variables. Then load the argument from the arguments |
| 5848 // object using keyed load. |
| 5849 Result arguments = allocator()->Allocate(); |
| 5850 ASSERT(arguments.is_valid()); |
| 5851 __ mov(arguments.reg(), |
| 5852 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 5853 arguments, |
| 5854 &slow)); |
| 5855 frame_->Push(&arguments); |
| 5856 frame_->Push(key_literal->handle()); |
| 5857 Result value = EmitKeyedLoad(); |
| 5858 frame_->Push(&value); |
| 5859 LoadGlobalReceiver(); |
| 5860 done.Jump(); |
| 5861 } |
| 5862 } |
5819 } | 5863 } |
5820 } | 5864 } |
5821 | 5865 |
5822 slow.Bind(); | 5866 slow.Bind(); |
5823 // Enter the runtime system to load the function from the context. | 5867 // Enter the runtime system to load the function from the context. |
5824 // Sync the frame so we can push the arguments directly into | 5868 // Sync the frame so we can push the arguments directly into |
5825 // place. | 5869 // place. |
5826 frame_->SyncRange(0, frame_->element_count() - 1); | 5870 frame_->SyncRange(0, frame_->element_count() - 1); |
5827 frame_->EmitPush(esi); | 5871 frame_->EmitPush(esi); |
5828 frame_->EmitPush(Immediate(var->name())); | 5872 frame_->EmitPush(Immediate(var->name())); |
(...skipping 7465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13294 | 13338 |
13295 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 13339 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
13296 // tagged as a small integer. | 13340 // tagged as a small integer. |
13297 __ bind(&runtime); | 13341 __ bind(&runtime); |
13298 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13342 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13299 } | 13343 } |
13300 | 13344 |
13301 #undef __ | 13345 #undef __ |
13302 | 13346 |
13303 } } // namespace v8::internal | 13347 } } // namespace v8::internal |
OLD | NEW |