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 4705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4716 } | 4716 } |
4717 | 4717 |
4718 | 4718 |
4719 Result CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 4719 Result CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
4720 Result result; | 4720 Result result; |
4721 if (slot->type() == Slot::LOOKUP) { | 4721 if (slot->type() == Slot::LOOKUP) { |
4722 ASSERT(slot->var()->is_dynamic()); | 4722 ASSERT(slot->var()->is_dynamic()); |
4723 JumpTarget slow; | 4723 JumpTarget slow; |
4724 JumpTarget done; | 4724 JumpTarget done; |
4725 | 4725 |
4726 // Generate fast-case code for variables that might be shadowed by | 4726 // Generate fast case for loading from slots that correspond to |
4727 // eval-introduced variables. Eval is used a lot without | 4727 // local/global variables or arguments unless they are shadowed by |
4728 // introducing variables. In those cases, we do not want to | 4728 // eval-introduced bindings. |
4729 // perform a runtime call for all variables in the scope | 4729 EmitDynamicLoadFromSlotFastCase(slot, |
4730 // containing the eval. | 4730 typeof_state, |
4731 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 4731 &result, |
4732 result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 4732 &slow, |
4733 done.Jump(&result); | 4733 &done); |
4734 | |
4735 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | |
4736 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); | |
4737 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
4738 if (potential_slot != NULL) { | |
4739 // Generate fast case for locals that rewrite to slots. | |
4740 // Allocate a fresh register to use as a temp in | |
4741 // ContextSlotOperandCheckExtensions and to hold the result | |
4742 // value. | |
4743 result = allocator()->Allocate(); | |
4744 ASSERT(result.is_valid()); | |
4745 __ mov(result.reg(), | |
4746 ContextSlotOperandCheckExtensions(potential_slot, | |
4747 result, | |
4748 &slow)); | |
4749 if (potential_slot->var()->mode() == Variable::CONST) { | |
4750 __ cmp(result.reg(), Factory::the_hole_value()); | |
4751 done.Branch(not_equal, &result); | |
4752 __ mov(result.reg(), Factory::undefined_value()); | |
4753 } | |
4754 done.Jump(&result); | |
4755 } else if (rewrite != NULL) { | |
4756 // Generate fast case for argument loads. | |
4757 Property* property = rewrite->AsProperty(); | |
4758 if (property != NULL) { | |
4759 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
4760 Literal* key_literal = property->key()->AsLiteral(); | |
4761 if (obj_proxy != NULL && | |
4762 key_literal != NULL && | |
4763 obj_proxy->IsArguments() && | |
4764 key_literal->handle()->IsSmi()) { | |
4765 // Load arguments object if there are no eval-introduced | |
4766 // variables. Then load the argument from the arguments | |
4767 // object using keyed load. | |
4768 Result arguments = allocator()->Allocate(); | |
4769 ASSERT(arguments.is_valid()); | |
4770 __ mov(arguments.reg(), | |
4771 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
4772 arguments, | |
4773 &slow)); | |
4774 frame_->Push(&arguments); | |
4775 frame_->Push(key_literal->handle()); | |
4776 result = EmitKeyedLoad(); | |
4777 done.Jump(&result); | |
4778 } | |
4779 } | |
4780 } | |
4781 } | |
4782 | 4734 |
4783 slow.Bind(); | 4735 slow.Bind(); |
4784 // A runtime call is inevitable. We eagerly sync frame elements | 4736 // A runtime call is inevitable. We eagerly sync frame elements |
4785 // to memory so that we can push the arguments directly into place | 4737 // to memory so that we can push the arguments directly into place |
4786 // on top of the frame. | 4738 // on top of the frame. |
4787 frame()->SyncRange(0, frame()->element_count() - 1); | 4739 frame()->SyncRange(0, frame()->element_count() - 1); |
4788 frame()->EmitPush(esi); | 4740 frame()->EmitPush(esi); |
4789 frame()->EmitPush(Immediate(slot->var()->name())); | 4741 frame()->EmitPush(Immediate(slot->var()->name())); |
4790 if (typeof_state == INSIDE_TYPEOF) { | 4742 if (typeof_state == INSIDE_TYPEOF) { |
4791 result = | 4743 result = |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4940 : RelocInfo::CODE_TARGET_CONTEXT; | 4892 : RelocInfo::CODE_TARGET_CONTEXT; |
4941 Result answer = frame_->CallLoadIC(mode); | 4893 Result answer = frame_->CallLoadIC(mode); |
4942 // A test eax instruction following the call signals that the inobject | 4894 // A test eax instruction following the call signals that the inobject |
4943 // property case was inlined. Ensure that there is not a test eax | 4895 // property case was inlined. Ensure that there is not a test eax |
4944 // instruction here. | 4896 // instruction here. |
4945 __ nop(); | 4897 __ nop(); |
4946 return answer; | 4898 return answer; |
4947 } | 4899 } |
4948 | 4900 |
4949 | 4901 |
| 4902 void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, |
| 4903 TypeofState typeof_state, |
| 4904 Result* result, |
| 4905 JumpTarget* slow, |
| 4906 JumpTarget* done) { |
| 4907 // Generate fast-case code for variables that might be shadowed by |
| 4908 // eval-introduced variables. Eval is used a lot without |
| 4909 // introducing variables. In those cases, we do not want to |
| 4910 // perform a runtime call for all variables in the scope |
| 4911 // containing the eval. |
| 4912 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 4913 *result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 4914 done->Jump(result); |
| 4915 |
| 4916 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 4917 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 4918 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 4919 if (potential_slot != NULL) { |
| 4920 // Generate fast case for locals that rewrite to slots. |
| 4921 // Allocate a fresh register to use as a temp in |
| 4922 // ContextSlotOperandCheckExtensions and to hold the result |
| 4923 // value. |
| 4924 *result = allocator()->Allocate(); |
| 4925 ASSERT(result->is_valid()); |
| 4926 __ mov(result->reg(), |
| 4927 ContextSlotOperandCheckExtensions(potential_slot, *result, slow)); |
| 4928 if (potential_slot->var()->mode() == Variable::CONST) { |
| 4929 __ cmp(result->reg(), Factory::the_hole_value()); |
| 4930 done->Branch(not_equal, result); |
| 4931 __ mov(result->reg(), Factory::undefined_value()); |
| 4932 } |
| 4933 done->Jump(result); |
| 4934 } else if (rewrite != NULL) { |
| 4935 // Generate fast case for calls of an argument function. |
| 4936 Property* property = rewrite->AsProperty(); |
| 4937 if (property != NULL) { |
| 4938 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 4939 Literal* key_literal = property->key()->AsLiteral(); |
| 4940 if (obj_proxy != NULL && |
| 4941 key_literal != NULL && |
| 4942 obj_proxy->IsArguments() && |
| 4943 key_literal->handle()->IsSmi()) { |
| 4944 // Load arguments object if there are no eval-introduced |
| 4945 // variables. Then load the argument from the arguments |
| 4946 // object using keyed load. |
| 4947 Result arguments = allocator()->Allocate(); |
| 4948 ASSERT(arguments.is_valid()); |
| 4949 __ mov(arguments.reg(), |
| 4950 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 4951 arguments, |
| 4952 slow)); |
| 4953 frame_->Push(&arguments); |
| 4954 frame_->Push(key_literal->handle()); |
| 4955 *result = EmitKeyedLoad(); |
| 4956 done->Jump(result); |
| 4957 } |
| 4958 } |
| 4959 } |
| 4960 } |
| 4961 } |
| 4962 |
| 4963 |
4950 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 4964 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
4951 if (slot->type() == Slot::LOOKUP) { | 4965 if (slot->type() == Slot::LOOKUP) { |
4952 ASSERT(slot->var()->is_dynamic()); | 4966 ASSERT(slot->var()->is_dynamic()); |
4953 | 4967 |
4954 // For now, just do a runtime call. Since the call is inevitable, | 4968 // For now, just do a runtime call. Since the call is inevitable, |
4955 // we eagerly sync the virtual frame so we can directly push the | 4969 // we eagerly sync the virtual frame so we can directly push the |
4956 // arguments into place. | 4970 // arguments into place. |
4957 frame_->SyncRange(0, frame_->element_count() - 1); | 4971 frame_->SyncRange(0, frame_->element_count() - 1); |
4958 | 4972 |
4959 frame_->EmitPush(esi); | 4973 frame_->EmitPush(esi); |
(...skipping 825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5785 // | 5799 // |
5786 // with (obj) foo(1, 2, 3) // foo may be in obj. | 5800 // with (obj) foo(1, 2, 3) // foo may be in obj. |
5787 // | 5801 // |
5788 // function f() {}; | 5802 // function f() {}; |
5789 // function g() { | 5803 // function g() { |
5790 // eval(...); | 5804 // eval(...); |
5791 // f(); // f could be in extension object. | 5805 // f(); // f could be in extension object. |
5792 // } | 5806 // } |
5793 // ---------------------------------- | 5807 // ---------------------------------- |
5794 | 5808 |
5795 JumpTarget slow; | 5809 JumpTarget slow, done; |
5796 JumpTarget done; | 5810 Result function; |
5797 | 5811 |
5798 // Generate fast-case code for variables that might be shadowed by | 5812 // Generate fast case for loading functions from slots that |
5799 // eval-introduced variables. Eval is used a lot without | 5813 // correspond to local/global variables or arguments unless they |
5800 // introducing variables. In those cases, we do not want to | 5814 // are shadowed by eval-introduced bindings. |
5801 // perform a runtime call for all variables in the scope | 5815 EmitDynamicLoadFromSlotFastCase(var->slot(), |
5802 // containing the eval. | 5816 NOT_INSIDE_TYPEOF, |
5803 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 5817 &function, |
5804 Result function = LoadFromGlobalSlotCheckExtensions(var->slot(), | 5818 &slow, |
5805 NOT_INSIDE_TYPEOF, | 5819 &done); |
5806 &slow); | |
5807 frame_->Push(&function); | |
5808 LoadGlobalReceiver(); | |
5809 done.Jump(); | |
5810 | |
5811 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | |
5812 Slot* potential_slot = var->local_if_not_shadowed()->slot(); | |
5813 Expression* rewrite = var->local_if_not_shadowed()->rewrite(); | |
5814 if (potential_slot != NULL) { | |
5815 // Generate fast case for locals that rewrite to slots. | |
5816 // Allocate a fresh register to use as a temp in | |
5817 // ContextSlotOperandCheckExtensions and to hold the result | |
5818 // value. | |
5819 Result function = allocator()->Allocate(); | |
5820 ASSERT(function.is_valid()); | |
5821 __ mov(function.reg(), | |
5822 ContextSlotOperandCheckExtensions(potential_slot, | |
5823 function, | |
5824 &slow)); | |
5825 JumpTarget push_function_and_receiver; | |
5826 if (potential_slot->var()->mode() == Variable::CONST) { | |
5827 __ cmp(function.reg(), Factory::the_hole_value()); | |
5828 push_function_and_receiver.Branch(not_equal, &function); | |
5829 __ mov(function.reg(), Factory::undefined_value()); | |
5830 } | |
5831 push_function_and_receiver.Bind(&function); | |
5832 frame_->Push(&function); | |
5833 LoadGlobalReceiver(); | |
5834 done.Jump(); | |
5835 } else if (rewrite != NULL) { | |
5836 // Generate fast case for calls of an argument function. | |
5837 Property* property = rewrite->AsProperty(); | |
5838 if (property != NULL) { | |
5839 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
5840 Literal* key_literal = property->key()->AsLiteral(); | |
5841 if (obj_proxy != NULL && | |
5842 key_literal != NULL && | |
5843 obj_proxy->IsArguments() && | |
5844 key_literal->handle()->IsSmi()) { | |
5845 // Load arguments object if there are no eval-introduced | |
5846 // variables. Then load the argument from the arguments | |
5847 // object using keyed load. | |
5848 Result arguments = allocator()->Allocate(); | |
5849 ASSERT(arguments.is_valid()); | |
5850 __ mov(arguments.reg(), | |
5851 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
5852 arguments, | |
5853 &slow)); | |
5854 frame_->Push(&arguments); | |
5855 frame_->Push(key_literal->handle()); | |
5856 Result value = EmitKeyedLoad(); | |
5857 frame_->Push(&value); | |
5858 LoadGlobalReceiver(); | |
5859 done.Jump(); | |
5860 } | |
5861 } | |
5862 } | |
5863 } | |
5864 | 5820 |
5865 slow.Bind(); | 5821 slow.Bind(); |
5866 // Enter the runtime system to load the function from the context. | 5822 // Enter the runtime system to load the function from the context. |
5867 // Sync the frame so we can push the arguments directly into | 5823 // Sync the frame so we can push the arguments directly into |
5868 // place. | 5824 // place. |
5869 frame_->SyncRange(0, frame_->element_count() - 1); | 5825 frame_->SyncRange(0, frame_->element_count() - 1); |
5870 frame_->EmitPush(esi); | 5826 frame_->EmitPush(esi); |
5871 frame_->EmitPush(Immediate(var->name())); | 5827 frame_->EmitPush(Immediate(var->name())); |
5872 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 5828 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
5873 // The runtime call returns a pair of values in eax and edx. The | 5829 // The runtime call returns a pair of values in eax and edx. The |
5874 // looked-up function is in eax and the receiver is in edx. These | 5830 // looked-up function is in eax and the receiver is in edx. These |
5875 // register references are not ref counted here. We spill them | 5831 // register references are not ref counted here. We spill them |
5876 // eagerly since they are arguments to an inevitable call (and are | 5832 // eagerly since they are arguments to an inevitable call (and are |
5877 // not sharable by the arguments). | 5833 // not sharable by the arguments). |
5878 ASSERT(!allocator()->is_used(eax)); | 5834 ASSERT(!allocator()->is_used(eax)); |
5879 frame_->EmitPush(eax); | 5835 frame_->EmitPush(eax); |
5880 | 5836 |
5881 // Load the receiver. | 5837 // Load the receiver. |
5882 ASSERT(!allocator()->is_used(edx)); | 5838 ASSERT(!allocator()->is_used(edx)); |
5883 frame_->EmitPush(edx); | 5839 frame_->EmitPush(edx); |
5884 | 5840 |
5885 done.Bind(); | 5841 // If fast case code has been generated, emit code to push the |
| 5842 // function and receiver and have the slow path jump around this |
| 5843 // code. |
| 5844 if (done.is_linked()) { |
| 5845 JumpTarget call; |
| 5846 call.Jump(); |
| 5847 done.Bind(&function); |
| 5848 frame_->Push(&function); |
| 5849 LoadGlobalReceiver(); |
| 5850 call.Bind(); |
| 5851 } |
| 5852 |
5886 // Call the function. | 5853 // Call the function. |
5887 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); | 5854 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
5888 | 5855 |
5889 } else if (property != NULL) { | 5856 } else if (property != NULL) { |
5890 // Check if the key is a literal string. | 5857 // Check if the key is a literal string. |
5891 Literal* literal = property->key()->AsLiteral(); | 5858 Literal* literal = property->key()->AsLiteral(); |
5892 | 5859 |
5893 if (literal != NULL && literal->handle()->IsSymbol()) { | 5860 if (literal != NULL && literal->handle()->IsSymbol()) { |
5894 // ------------------------------------------------------------------ | 5861 // ------------------------------------------------------------------ |
5895 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 5862 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
(...skipping 7421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13317 | 13284 |
13318 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 13285 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
13319 // tagged as a small integer. | 13286 // tagged as a small integer. |
13320 __ bind(&runtime); | 13287 __ bind(&runtime); |
13321 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13288 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13322 } | 13289 } |
13323 | 13290 |
13324 #undef __ | 13291 #undef __ |
13325 | 13292 |
13326 } } // namespace v8::internal | 13293 } } // namespace v8::internal |
OLD | NEW |