| 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 2773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2784 | 2784 |
| 2785 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2785 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2786 if (slot->type() == Slot::LOOKUP) { | 2786 if (slot->type() == Slot::LOOKUP) { |
| 2787 ASSERT(slot->var()->is_dynamic()); | 2787 ASSERT(slot->var()->is_dynamic()); |
| 2788 | 2788 |
| 2789 // JumpTargets do not yet support merging frames so the frame must be | 2789 // JumpTargets do not yet support merging frames so the frame must be |
| 2790 // spilled when jumping to these targets. | 2790 // spilled when jumping to these targets. |
| 2791 JumpTarget slow; | 2791 JumpTarget slow; |
| 2792 JumpTarget done; | 2792 JumpTarget done; |
| 2793 | 2793 |
| 2794 // Generate fast-case code for variables that might be shadowed by | 2794 // Generate fast case for loading from slots that correspond to |
| 2795 // eval-introduced variables. Eval is used a lot without | 2795 // local/global variables or arguments unless they are shadowed by |
| 2796 // introducing variables. In those cases, we do not want to | 2796 // eval-introduced bindings. |
| 2797 // perform a runtime call for all variables in the scope | 2797 EmitDynamicLoadFromSlotFastCase(slot, |
| 2798 // containing the eval. | 2798 typeof_state, |
| 2799 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 2799 &slow, |
| 2800 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 2800 &done); |
| 2801 frame_->SpillAll(); | |
| 2802 done.Jump(); | |
| 2803 | |
| 2804 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | |
| 2805 frame_->SpillAll(); | |
| 2806 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); | |
| 2807 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
| 2808 if (potential_slot != NULL) { | |
| 2809 // Generate fast case for locals that rewrite to slots. | |
| 2810 __ ldr(r0, | |
| 2811 ContextSlotOperandCheckExtensions(potential_slot, | |
| 2812 r1, | |
| 2813 r2, | |
| 2814 &slow)); | |
| 2815 if (potential_slot->var()->mode() == Variable::CONST) { | |
| 2816 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
| 2817 __ cmp(r0, ip); | |
| 2818 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | |
| 2819 } | |
| 2820 done.Jump(); | |
| 2821 } else if (rewrite != NULL) { | |
| 2822 // Generate fast case for argument loads. | |
| 2823 Property* property = rewrite->AsProperty(); | |
| 2824 if (property != NULL) { | |
| 2825 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
| 2826 Literal* key_literal = property->key()->AsLiteral(); | |
| 2827 if (obj_proxy != NULL && | |
| 2828 key_literal != NULL && | |
| 2829 obj_proxy->IsArguments() && | |
| 2830 key_literal->handle()->IsSmi()) { | |
| 2831 // Load arguments object if there are no eval-introduced | |
| 2832 // variables. Then load the argument from the arguments | |
| 2833 // object using keyed load. | |
| 2834 __ ldr(r0, | |
| 2835 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
| 2836 r1, | |
| 2837 r2, | |
| 2838 &slow)); | |
| 2839 frame_->EmitPush(r0); | |
| 2840 __ mov(r1, Operand(key_literal->handle())); | |
| 2841 frame_->EmitPush(r1); | |
| 2842 EmitKeyedLoad(); | |
| 2843 done.Jump(); | |
| 2844 } | |
| 2845 } | |
| 2846 } | |
| 2847 } | |
| 2848 | 2801 |
| 2849 slow.Bind(); | 2802 slow.Bind(); |
| 2850 VirtualFrame::SpilledScope spilled_scope(frame_); | 2803 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 2851 frame_->EmitPush(cp); | 2804 frame_->EmitPush(cp); |
| 2852 __ mov(r0, Operand(slot->var()->name())); | 2805 __ mov(r0, Operand(slot->var()->name())); |
| 2853 frame_->EmitPush(r0); | 2806 frame_->EmitPush(r0); |
| 2854 | 2807 |
| 2855 if (typeof_state == INSIDE_TYPEOF) { | 2808 if (typeof_state == INSIDE_TYPEOF) { |
| 2856 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2809 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2857 } else { | 2810 } else { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3052 // Setup the name register and call load IC. | 3005 // Setup the name register and call load IC. |
| 3053 frame_->CallLoadIC(slot->var()->name(), | 3006 frame_->CallLoadIC(slot->var()->name(), |
| 3054 typeof_state == INSIDE_TYPEOF | 3007 typeof_state == INSIDE_TYPEOF |
| 3055 ? RelocInfo::CODE_TARGET | 3008 ? RelocInfo::CODE_TARGET |
| 3056 : RelocInfo::CODE_TARGET_CONTEXT); | 3009 : RelocInfo::CODE_TARGET_CONTEXT); |
| 3057 // Drop the global object. The result is in r0. | 3010 // Drop the global object. The result is in r0. |
| 3058 frame_->Drop(); | 3011 frame_->Drop(); |
| 3059 } | 3012 } |
| 3060 | 3013 |
| 3061 | 3014 |
| 3015 void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, |
| 3016 TypeofState typeof_state, |
| 3017 JumpTarget* slow, |
| 3018 JumpTarget* done) { |
| 3019 // Generate fast-case code for variables that might be shadowed by |
| 3020 // eval-introduced variables. Eval is used a lot without |
| 3021 // introducing variables. In those cases, we do not want to |
| 3022 // perform a runtime call for all variables in the scope |
| 3023 // containing the eval. |
| 3024 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 3025 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 3026 frame_->SpillAll(); |
| 3027 done->Jump(); |
| 3028 |
| 3029 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 3030 frame_->SpillAll(); |
| 3031 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 3032 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 3033 if (potential_slot != NULL) { |
| 3034 // Generate fast case for locals that rewrite to slots. |
| 3035 __ ldr(r0, |
| 3036 ContextSlotOperandCheckExtensions(potential_slot, |
| 3037 r1, |
| 3038 r2, |
| 3039 slow)); |
| 3040 if (potential_slot->var()->mode() == Variable::CONST) { |
| 3041 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 3042 __ cmp(r0, ip); |
| 3043 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 3044 } |
| 3045 done->Jump(); |
| 3046 } else if (rewrite != NULL) { |
| 3047 // Generate fast case for argument loads. |
| 3048 Property* property = rewrite->AsProperty(); |
| 3049 if (property != NULL) { |
| 3050 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 3051 Literal* key_literal = property->key()->AsLiteral(); |
| 3052 if (obj_proxy != NULL && |
| 3053 key_literal != NULL && |
| 3054 obj_proxy->IsArguments() && |
| 3055 key_literal->handle()->IsSmi()) { |
| 3056 // Load arguments object if there are no eval-introduced |
| 3057 // variables. Then load the argument from the arguments |
| 3058 // object using keyed load. |
| 3059 __ ldr(r0, |
| 3060 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 3061 r1, |
| 3062 r2, |
| 3063 slow)); |
| 3064 frame_->EmitPush(r0); |
| 3065 __ mov(r1, Operand(key_literal->handle())); |
| 3066 frame_->EmitPush(r1); |
| 3067 EmitKeyedLoad(); |
| 3068 done->Jump(); |
| 3069 } |
| 3070 } |
| 3071 } |
| 3072 } |
| 3073 } |
| 3074 |
| 3075 |
| 3062 void CodeGenerator::VisitSlot(Slot* node) { | 3076 void CodeGenerator::VisitSlot(Slot* node) { |
| 3063 #ifdef DEBUG | 3077 #ifdef DEBUG |
| 3064 int original_height = frame_->height(); | 3078 int original_height = frame_->height(); |
| 3065 #endif | 3079 #endif |
| 3066 Comment cmnt(masm_, "[ Slot"); | 3080 Comment cmnt(masm_, "[ Slot"); |
| 3067 LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); | 3081 LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); |
| 3068 ASSERT_EQ(original_height + 1, frame_->height()); | 3082 ASSERT_EQ(original_height + 1, frame_->height()); |
| 3069 } | 3083 } |
| 3070 | 3084 |
| 3071 | 3085 |
| (...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3749 // | 3763 // |
| 3750 // function f() {}; | 3764 // function f() {}; |
| 3751 // function g() { | 3765 // function g() { |
| 3752 // eval(...); | 3766 // eval(...); |
| 3753 // f(); // f could be in extension object. | 3767 // f(); // f could be in extension object. |
| 3754 // } | 3768 // } |
| 3755 // ---------------------------------- | 3769 // ---------------------------------- |
| 3756 | 3770 |
| 3757 // JumpTargets do not yet support merging frames so the frame must be | 3771 // JumpTargets do not yet support merging frames so the frame must be |
| 3758 // spilled when jumping to these targets. | 3772 // spilled when jumping to these targets. |
| 3759 JumpTarget slow; | 3773 JumpTarget slow, done; |
| 3760 JumpTarget done; | |
| 3761 | 3774 |
| 3762 // Generate fast-case code for variables that might be shadowed by | 3775 // Generate fast case for loading functions from slots that |
| 3763 // eval-introduced variables. Eval is used a lot without | 3776 // correspond to local/global variables or arguments unless they |
| 3764 // introducing variables. In those cases, we do not want to | 3777 // are shadowed by eval-introduced bindings. |
| 3765 // perform a runtime call for all variables in the scope | 3778 EmitDynamicLoadFromSlotFastCase(var->slot(), |
| 3766 // containing the eval. | 3779 NOT_INSIDE_TYPEOF, |
| 3767 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 3780 &slow, |
| 3768 LoadFromGlobalSlotCheckExtensions(var->slot(), NOT_INSIDE_TYPEOF, &slow); | 3781 &done); |
| 3769 frame_->EmitPush(r0); | |
| 3770 LoadGlobalReceiver(r1); | |
| 3771 done.Jump(); | |
| 3772 | |
| 3773 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | |
| 3774 Slot* potential_slot = var->local_if_not_shadowed()->slot(); | |
| 3775 Expression* rewrite = var->local_if_not_shadowed()->rewrite(); | |
| 3776 if (potential_slot != NULL) { | |
| 3777 // Generate fast case for locals that rewrite to slots. | |
| 3778 __ ldr(r0, | |
| 3779 ContextSlotOperandCheckExtensions(potential_slot, | |
| 3780 r1, | |
| 3781 r2, | |
| 3782 &slow)); | |
| 3783 if (potential_slot->var()->mode() == Variable::CONST) { | |
| 3784 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
| 3785 __ cmp(r0, ip); | |
| 3786 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | |
| 3787 } | |
| 3788 frame_->EmitPush(r0); | |
| 3789 LoadGlobalReceiver(r1); | |
| 3790 done.Jump(); | |
| 3791 } else if (rewrite != NULL) { | |
| 3792 // Generate fast case for calls of an argument function. | |
| 3793 Property* property = rewrite->AsProperty(); | |
| 3794 if (property != NULL) { | |
| 3795 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
| 3796 Literal* key_literal = property->key()->AsLiteral(); | |
| 3797 if (obj_proxy != NULL && | |
| 3798 key_literal != NULL && | |
| 3799 obj_proxy->IsArguments() && | |
| 3800 key_literal->handle()->IsSmi()) { | |
| 3801 // Load arguments object if there are no eval-introduced | |
| 3802 // variables. Then load the argument from the arguments | |
| 3803 // object using keyed load. | |
| 3804 __ ldr(r0, | |
| 3805 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
| 3806 r1, | |
| 3807 r2, | |
| 3808 &slow)); | |
| 3809 frame_->EmitPush(r0); | |
| 3810 __ mov(r1, Operand(key_literal->handle())); | |
| 3811 frame_->EmitPush(r1); | |
| 3812 EmitKeyedLoad(); | |
| 3813 frame_->EmitPush(r0); | |
| 3814 LoadGlobalReceiver(r1); | |
| 3815 done.Jump(); | |
| 3816 } | |
| 3817 } | |
| 3818 } | |
| 3819 } | |
| 3820 | 3782 |
| 3821 slow.Bind(); | 3783 slow.Bind(); |
| 3822 // Load the function | 3784 // Load the function |
| 3823 frame_->EmitPush(cp); | 3785 frame_->EmitPush(cp); |
| 3824 __ mov(r0, Operand(var->name())); | 3786 __ mov(r0, Operand(var->name())); |
| 3825 frame_->EmitPush(r0); | 3787 frame_->EmitPush(r0); |
| 3826 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 3788 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 3827 // r0: slot value; r1: receiver | 3789 // r0: slot value; r1: receiver |
| 3828 | 3790 |
| 3829 // Load the receiver. | 3791 // Load the receiver. |
| 3830 frame_->EmitPush(r0); // function | 3792 frame_->EmitPush(r0); // function |
| 3831 frame_->EmitPush(r1); // receiver | 3793 frame_->EmitPush(r1); // receiver |
| 3832 | 3794 |
| 3833 done.Bind(); | 3795 // If fast case code has been generated, emit code to push the |
| 3796 // function and receiver and have the slow path jump around this |
| 3797 // code. |
| 3798 if (done.is_linked()) { |
| 3799 JumpTarget call; |
| 3800 call.Jump(); |
| 3801 done.Bind(); |
| 3802 frame_->EmitPush(r0); // function |
| 3803 LoadGlobalReceiver(r1); // receiver |
| 3804 call.Bind(); |
| 3805 } |
| 3806 |
| 3834 // Call the function. At this point, everything is spilled but the | 3807 // Call the function. At this point, everything is spilled but the |
| 3835 // function and receiver are in r0 and r1. | 3808 // function and receiver are in r0 and r1. |
| 3836 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); | 3809 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
| 3837 frame_->EmitPush(r0); | 3810 frame_->EmitPush(r0); |
| 3838 | 3811 |
| 3839 } else if (property != NULL) { | 3812 } else if (property != NULL) { |
| 3840 // Check if the key is a literal string. | 3813 // Check if the key is a literal string. |
| 3841 Literal* literal = property->key()->AsLiteral(); | 3814 Literal* literal = property->key()->AsLiteral(); |
| 3842 | 3815 |
| 3843 if (literal != NULL && literal->handle()->IsSymbol()) { | 3816 if (literal != NULL && literal->handle()->IsSymbol()) { |
| (...skipping 6196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10040 | 10013 |
| 10041 // Just jump to runtime to add the two strings. | 10014 // Just jump to runtime to add the two strings. |
| 10042 __ bind(&string_add_runtime); | 10015 __ bind(&string_add_runtime); |
| 10043 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10016 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 10044 } | 10017 } |
| 10045 | 10018 |
| 10046 | 10019 |
| 10047 #undef __ | 10020 #undef __ |
| 10048 | 10021 |
| 10049 } } // namespace v8::internal | 10022 } } // namespace v8::internal |
| OLD | NEW |