| 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 |