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 3760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3771 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 3771 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
3772 return; | 3772 return; |
3773 } | 3773 } |
3774 | 3774 |
3775 Load(left); | 3775 Load(left); |
3776 Load(right); | 3776 Load(right); |
3777 Comparison(cc, strict); | 3777 Comparison(cc, strict); |
3778 } | 3778 } |
3779 | 3779 |
3780 | 3780 |
3781 class DeferredReferenceGetKeyedValue: public DeferredCode { | |
3782 public: | |
3783 DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) | |
3784 : DeferredCode(generator), is_global_(is_global) { | |
3785 set_comment("[ DeferredReferenceGetKeyedValue"); | |
3786 } | |
3787 | |
3788 virtual void Generate() { | |
3789 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
3790 // Calculate the delta from the IC call instruction to the map | |
3791 // check cmp instruction in the inlined version. This delta is | |
3792 // stored in a test(eax, delta) instruction after the call so that | |
3793 // we can find it in the IC initialization code and patch the cmp | |
3794 // instruction. This means that we cannot allow test instructions | |
3795 // after calls to KeyedLoadIC stubs in other places. | |
3796 int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site()); | |
3797 if (is_global_) { | |
3798 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
3799 } else { | |
3800 __ call(ic, RelocInfo::CODE_TARGET); | |
3801 } | |
3802 __ test(eax, Immediate(-delta_to_patch_site)); | |
3803 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | |
3804 } | |
3805 | |
3806 Label* patch_site() { return &patch_site_; } | |
3807 | |
3808 private: | |
3809 Label patch_site_; | |
3810 bool is_global_; | |
3811 }; | |
3812 | |
3813 | |
3814 | |
3781 #undef __ | 3815 #undef __ |
3782 #define __ masm-> | 3816 #define __ masm-> |
3783 | 3817 |
3784 Handle<String> Reference::GetName() { | 3818 Handle<String> Reference::GetName() { |
3785 ASSERT(type_ == NAMED); | 3819 ASSERT(type_ == NAMED); |
3786 Property* property = expression_->AsProperty(); | 3820 Property* property = expression_->AsProperty(); |
3787 if (property == NULL) { | 3821 if (property == NULL) { |
3788 // Global variable reference treated as a named property reference. | 3822 // Global variable reference treated as a named property reference. |
3789 VariableProxy* proxy = expression_->AsVariableProxy(); | 3823 VariableProxy* proxy = expression_->AsVariableProxy(); |
3790 ASSERT(proxy->AsVariable() != NULL); | 3824 ASSERT(proxy->AsVariable() != NULL); |
(...skipping 15 matching lines...) Expand all Loading... | |
3806 switch (type_) { | 3840 switch (type_) { |
3807 case SLOT: { | 3841 case SLOT: { |
3808 Comment cmnt(masm, "[ Load from Slot"); | 3842 Comment cmnt(masm, "[ Load from Slot"); |
3809 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3843 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
3810 ASSERT(slot != NULL); | 3844 ASSERT(slot != NULL); |
3811 cgen_->LoadFromSlot(slot, typeof_state); | 3845 cgen_->LoadFromSlot(slot, typeof_state); |
3812 break; | 3846 break; |
3813 } | 3847 } |
3814 | 3848 |
3815 case NAMED: { | 3849 case NAMED: { |
3816 // TODO(1241834): Make sure that this it is safe to ignore the | 3850 // TODO(1241834): Make sure that it is safe to ignore the |
3817 // distinction between expressions in a typeof and not in a typeof. If | 3851 // distinction between expressions in a typeof and not in a |
3818 // there is a chance that reference errors can be thrown below, we | 3852 // typeof. If there is a chance that reference errors can be |
3819 // must distinguish between the two kinds of loads (typeof expression | 3853 // thrown below, we must distinguish between the two kinds of |
3820 // loads must not throw a reference error). | 3854 // loads (typeof expression loads must not throw a reference |
3855 // error). | |
3821 Comment cmnt(masm, "[ Load from named Property"); | 3856 Comment cmnt(masm, "[ Load from named Property"); |
3822 Handle<String> name(GetName()); | 3857 Handle<String> name(GetName()); |
3858 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
3823 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3859 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
3824 // Setup the name register. | 3860 // Setup the name register. |
3825 __ mov(ecx, name); | 3861 __ mov(ecx, name); |
3826 | |
3827 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
3828 if (var != NULL) { | 3862 if (var != NULL) { |
3829 ASSERT(var->is_global()); | 3863 ASSERT(var->is_global()); |
3830 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 3864 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
3831 } else { | 3865 } else { |
3832 __ call(ic, RelocInfo::CODE_TARGET); | 3866 __ call(ic, RelocInfo::CODE_TARGET); |
3833 } | 3867 } |
3834 frame->Push(eax); // IC call leaves result in eax, push it out | 3868 // Push the result. |
3869 frame->Push(eax); | |
3835 break; | 3870 break; |
3836 } | 3871 } |
3837 | 3872 |
3838 case KEYED: { | 3873 case KEYED: { |
3839 // TODO(1241834): Make sure that this it is safe to ignore the | 3874 // TODO(1241834): Make sure that it is safe to ignore the |
3840 // distinction between expressions in a typeof and not in a typeof. | 3875 // distinction between expressions in a typeof and not in a |
3841 Comment cmnt(masm, "[ Load from keyed Property"); | 3876 // typeof. |
3842 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
3843 | |
3844 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3877 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
3845 if (var != NULL) { | 3878 // Inline array load code if inside of a loop. We do not know |
3846 ASSERT(var->is_global()); | 3879 // the receiver map yet, so we initially generate the code with |
3847 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 3880 // a check against an invalid map. In the inline cache code, we |
3881 // patch the map check if appropriate. | |
3882 if (cgen_->loop_nesting() > 0) { | |
3883 Comment cmnt(masm, "[ Inlined array index load"); | |
3884 DeferredReferenceGetKeyedValue* deferred = | |
3885 new DeferredReferenceGetKeyedValue(cgen_, var != NULL); | |
3886 // Load receiver and check that it is not a smi (only needed | |
3887 // if not contextual) and that it has the expected map. | |
iposva
2008/12/22 18:59:16
I think it would improve the readability if was cl
| |
3888 __ mov(edx, Operand(esp, kPointerSize)); | |
3889 if (var == NULL) { | |
3890 __ test(edx, Immediate(kSmiTagMask)); | |
3891 __ j(zero, deferred->enter(), not_taken); | |
3892 } | |
3893 // Initially, use an invalid map. The map is patched in the IC | |
3894 // initialization code. | |
3895 __ bind(deferred->patch_site()); | |
3896 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | |
3897 Immediate(Factory::null_value())); | |
3898 __ j(not_equal, deferred->enter(), not_taken); | |
3899 // Load key and check that it is a smi. | |
3900 __ mov(eax, Operand(esp, 0)); | |
3901 __ test(eax, Immediate(kSmiTagMask)); | |
3902 __ j(not_zero, deferred->enter(), not_taken); | |
3903 // Shift to get actual index value. | |
3904 __ sar(eax, kSmiTagSize); | |
Kasper Lund
2008/12/22 09:52:13
Maybe we should consider keeping the FixedArray le
Mads Ager (chromium)
2008/12/22 12:59:11
That would be an interesting experiment. I'll try
| |
3905 // Get the elements array from the receiver and check that it | |
3906 // is not a dictionary. | |
3907 __ mov(edx, FieldOperand(edx, JSObject::kElementsOffset)); | |
3908 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | |
3909 Immediate(Factory::hash_table_map())); | |
3910 __ j(equal, deferred->enter(), not_taken); | |
3911 // Check that key is within bounds. | |
3912 __ cmp(eax, FieldOperand(edx, Array::kLengthOffset)); | |
3913 __ j(above_equal, deferred->enter(), not_taken); | |
3914 // Load and check that the result is not the hole. | |
3915 __ mov(eax, | |
3916 Operand(edx, eax, times_4, Array::kHeaderSize - kHeapObjectTag)); | |
3917 __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); | |
3918 __ j(equal, deferred->enter(), not_taken); | |
3919 __ IncrementCounter(&Counters::keyed_load_inline, 1); | |
3920 __ bind(deferred->exit()); | |
3848 } else { | 3921 } else { |
3849 __ call(ic, RelocInfo::CODE_TARGET); | 3922 Comment cmnt(masm, "[ Load from keyed Property"); |
3923 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
3924 if (var != NULL) { | |
3925 ASSERT(var->is_global()); | |
3926 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
3927 } else { | |
3928 __ call(ic, RelocInfo::CODE_TARGET); | |
3929 } | |
3930 // Make sure that we do not have a test instruction after the | |
3931 // call. A test instruction after the call is used to | |
3932 // indicate that we have generated an inline version of the | |
3933 // keyed load. | |
3934 __ nop(); | |
Kasper Lund
2008/12/22 09:52:13
I guess here the nop is really needed because the
Mads Ager (chromium)
2008/12/22 12:59:11
Yes, exactly. I'll update the comment to make it
iposva
2008/12/22 18:59:16
Alternatively you could bind a label after the pus
| |
3850 } | 3935 } |
3851 frame->Push(eax); // IC call leaves result in eax, push it out | 3936 // Push the result. |
3937 frame->Push(eax); | |
3852 break; | 3938 break; |
3853 } | 3939 } |
3854 | 3940 |
3855 default: | 3941 default: |
3856 UNREACHABLE(); | 3942 UNREACHABLE(); |
3857 } | 3943 } |
3858 } | 3944 } |
3859 | 3945 |
3860 | 3946 |
3861 void Reference::SetValue(InitState init_state) { | 3947 void Reference::SetValue(InitState init_state) { |
(...skipping 1326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5188 | 5274 |
5189 // Slow-case: Go through the JavaScript implementation. | 5275 // Slow-case: Go through the JavaScript implementation. |
5190 __ bind(&slow); | 5276 __ bind(&slow); |
5191 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5277 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5192 } | 5278 } |
5193 | 5279 |
5194 | 5280 |
5195 #undef __ | 5281 #undef __ |
5196 | 5282 |
5197 } } // namespace v8::internal | 5283 } } // namespace v8::internal |
OLD | NEW |