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 2858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2869 // | 2869 // |
2870 // with (obj) foo(1, 2, 3) // foo may be in obj. | 2870 // with (obj) foo(1, 2, 3) // foo may be in obj. |
2871 // | 2871 // |
2872 // function f() {}; | 2872 // function f() {}; |
2873 // function g() { | 2873 // function g() { |
2874 // eval(...); | 2874 // eval(...); |
2875 // f(); // f could be in extension object. | 2875 // f(); // f could be in extension object. |
2876 // } | 2876 // } |
2877 // ---------------------------------- | 2877 // ---------------------------------- |
2878 | 2878 |
2879 JumpTarget slow; | 2879 JumpTarget slow, done; |
2880 JumpTarget done; | 2880 Result function; |
2881 | 2881 |
2882 // Generate fast-case code for variables that might be shadowed by | 2882 // Generate fast case for loading functions from slots that |
2883 // eval-introduced variables. Eval is used a lot without | 2883 // correspond to local/global variables or arguments unless they |
2884 // introducing variables. In those cases, we do not want to | 2884 // are shadowed by eval-introduced bindings. |
2885 // perform a runtime call for all variables in the scope | 2885 EmitDynamicLoadFromSlotFastCase(var->slot(), |
2886 // containing the eval. | 2886 NOT_INSIDE_TYPEOF, |
2887 Result function; | 2887 &function, |
2888 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 2888 &slow, |
2889 function = LoadFromGlobalSlotCheckExtensions(var->slot(), | 2889 &done); |
2890 NOT_INSIDE_TYPEOF, | |
2891 &slow); | |
2892 frame_->Push(&function); | |
2893 LoadGlobalReceiver(); | |
2894 done.Jump(); | |
2895 | |
2896 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | |
2897 Slot* potential_slot = var->local_if_not_shadowed()->slot(); | |
2898 Expression* rewrite = var->local_if_not_shadowed()->rewrite(); | |
2899 if (potential_slot != NULL) { | |
2900 // Generate fast case for locals that rewrite to slots. | |
2901 // Allocate a fresh register to use as a temp in | |
2902 // ContextSlotOperandCheckExtensions and to hold the result | |
2903 // value. | |
2904 function = allocator()->Allocate(); | |
2905 ASSERT(function.is_valid()); | |
2906 __ movq(function.reg(), | |
2907 ContextSlotOperandCheckExtensions(potential_slot, | |
2908 function, | |
2909 &slow)); | |
2910 JumpTarget push_function_and_receiver; | |
2911 if (potential_slot->var()->mode() == Variable::CONST) { | |
2912 __ CompareRoot(function.reg(), Heap::kTheHoleValueRootIndex); | |
2913 push_function_and_receiver.Branch(not_equal, &function); | |
2914 __ LoadRoot(function.reg(), Heap::kUndefinedValueRootIndex); | |
2915 } | |
2916 push_function_and_receiver.Bind(&function); | |
2917 frame_->Push(&function); | |
2918 LoadGlobalReceiver(); | |
2919 done.Jump(); | |
2920 } else if (rewrite != NULL) { | |
2921 // Generate fast case for calls of an argument function. | |
2922 Property* property = rewrite->AsProperty(); | |
2923 if (property != NULL) { | |
2924 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
2925 Literal* key_literal = property->key()->AsLiteral(); | |
2926 if (obj_proxy != NULL && | |
2927 key_literal != NULL && | |
2928 obj_proxy->IsArguments() && | |
2929 key_literal->handle()->IsSmi()) { | |
2930 // Load arguments object if there are no eval-introduced | |
2931 // variables. Then load the argument from the arguments | |
2932 // object using keyed load. | |
2933 Result arguments = allocator()->Allocate(); | |
2934 ASSERT(arguments.is_valid()); | |
2935 __ movq(arguments.reg(), | |
2936 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
2937 arguments, | |
2938 &slow)); | |
2939 frame_->Push(&arguments); | |
2940 frame_->Push(key_literal->handle()); | |
2941 Result value = EmitKeyedLoad(false); | |
2942 frame_->Drop(2); // Drop key and receiver. | |
2943 frame_->Push(&value); | |
2944 LoadGlobalReceiver(); | |
2945 done.Jump(); | |
2946 } | |
2947 } | |
2948 } | |
2949 } | |
2950 | 2890 |
2951 slow.Bind(); | 2891 slow.Bind(); |
2952 // Load the function from the context. Sync the frame so we can | 2892 // Load the function from the context. Sync the frame so we can |
2953 // push the arguments directly into place. | 2893 // push the arguments directly into place. |
2954 frame_->SyncRange(0, frame_->element_count() - 1); | 2894 frame_->SyncRange(0, frame_->element_count() - 1); |
2955 frame_->EmitPush(rsi); | 2895 frame_->EmitPush(rsi); |
2956 frame_->EmitPush(var->name()); | 2896 frame_->EmitPush(var->name()); |
2957 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2897 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
2958 // The runtime call returns a pair of values in rax and rdx. The | 2898 // The runtime call returns a pair of values in rax and rdx. The |
2959 // looked-up function is in rax and the receiver is in rdx. These | 2899 // looked-up function is in rax and the receiver is in rdx. These |
2960 // register references are not ref counted here. We spill them | 2900 // register references are not ref counted here. We spill them |
2961 // eagerly since they are arguments to an inevitable call (and are | 2901 // eagerly since they are arguments to an inevitable call (and are |
2962 // not sharable by the arguments). | 2902 // not sharable by the arguments). |
2963 ASSERT(!allocator()->is_used(rax)); | 2903 ASSERT(!allocator()->is_used(rax)); |
2964 frame_->EmitPush(rax); | 2904 frame_->EmitPush(rax); |
2965 | 2905 |
2966 // Load the receiver. | 2906 // Load the receiver. |
2967 ASSERT(!allocator()->is_used(rdx)); | 2907 ASSERT(!allocator()->is_used(rdx)); |
2968 frame_->EmitPush(rdx); | 2908 frame_->EmitPush(rdx); |
2969 | 2909 |
2970 done.Bind(); | 2910 // If fast case code has been generated, emit code to push the |
| 2911 // function and receiver and have the slow path jump around this |
| 2912 // code. |
| 2913 if (done.is_linked()) { |
| 2914 JumpTarget call; |
| 2915 call.Jump(); |
| 2916 done.Bind(&function); |
| 2917 frame_->Push(&function); |
| 2918 LoadGlobalReceiver(); |
| 2919 call.Bind(); |
| 2920 } |
| 2921 |
2971 // Call the function. | 2922 // Call the function. |
2972 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); | 2923 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
2973 | 2924 |
2974 } else if (property != NULL) { | 2925 } else if (property != NULL) { |
2975 // Check if the key is a literal string. | 2926 // Check if the key is a literal string. |
2976 Literal* literal = property->key()->AsLiteral(); | 2927 Literal* literal = property->key()->AsLiteral(); |
2977 | 2928 |
2978 if (literal != NULL && literal->handle()->IsSymbol()) { | 2929 if (literal != NULL && literal->handle()->IsSymbol()) { |
2979 // ------------------------------------------------------------------ | 2930 // ------------------------------------------------------------------ |
2980 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 2931 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
(...skipping 2379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5360 | 5311 |
5361 | 5312 |
5362 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 5313 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
5363 if (slot->type() == Slot::LOOKUP) { | 5314 if (slot->type() == Slot::LOOKUP) { |
5364 ASSERT(slot->var()->is_dynamic()); | 5315 ASSERT(slot->var()->is_dynamic()); |
5365 | 5316 |
5366 JumpTarget slow; | 5317 JumpTarget slow; |
5367 JumpTarget done; | 5318 JumpTarget done; |
5368 Result value; | 5319 Result value; |
5369 | 5320 |
5370 // Generate fast-case code for variables that might be shadowed by | 5321 // Generate fast case for loading from slots that correspond to |
5371 // eval-introduced variables. Eval is used a lot without | 5322 // local/global variables or arguments unless they are shadowed by |
5372 // introducing variables. In those cases, we do not want to | 5323 // eval-introduced bindings. |
5373 // perform a runtime call for all variables in the scope | 5324 EmitDynamicLoadFromSlotFastCase(slot, |
5374 // containing the eval. | 5325 typeof_state, |
5375 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 5326 &value, |
5376 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 5327 &slow, |
5377 done.Jump(&value); | 5328 &done); |
5378 | |
5379 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | |
5380 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); | |
5381 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
5382 if (potential_slot != NULL) { | |
5383 // Generate fast case for locals that rewrite to slots. | |
5384 // Allocate a fresh register to use as a temp in | |
5385 // ContextSlotOperandCheckExtensions and to hold the result | |
5386 // value. | |
5387 value = allocator_->Allocate(); | |
5388 ASSERT(value.is_valid()); | |
5389 __ movq(value.reg(), | |
5390 ContextSlotOperandCheckExtensions(potential_slot, | |
5391 value, | |
5392 &slow)); | |
5393 if (potential_slot->var()->mode() == Variable::CONST) { | |
5394 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); | |
5395 done.Branch(not_equal, &value); | |
5396 __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex); | |
5397 } | |
5398 done.Jump(&value); | |
5399 } else if (rewrite != NULL) { | |
5400 // Generate fast case for argument loads. | |
5401 Property* property = rewrite->AsProperty(); | |
5402 if (property != NULL) { | |
5403 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
5404 Literal* key_literal = property->key()->AsLiteral(); | |
5405 if (obj_proxy != NULL && | |
5406 key_literal != NULL && | |
5407 obj_proxy->IsArguments() && | |
5408 key_literal->handle()->IsSmi()) { | |
5409 // Load arguments object if there are no eval-introduced | |
5410 // variables. Then load the argument from the arguments | |
5411 // object using keyed load. | |
5412 Result arguments = allocator()->Allocate(); | |
5413 ASSERT(arguments.is_valid()); | |
5414 __ movq(arguments.reg(), | |
5415 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | |
5416 arguments, | |
5417 &slow)); | |
5418 frame_->Push(&arguments); | |
5419 frame_->Push(key_literal->handle()); | |
5420 value = EmitKeyedLoad(false); | |
5421 frame_->Drop(2); // Drop key and receiver. | |
5422 done.Jump(&value); | |
5423 } | |
5424 } | |
5425 } | |
5426 } | |
5427 | 5329 |
5428 slow.Bind(); | 5330 slow.Bind(); |
5429 // A runtime call is inevitable. We eagerly sync frame elements | 5331 // A runtime call is inevitable. We eagerly sync frame elements |
5430 // to memory so that we can push the arguments directly into place | 5332 // to memory so that we can push the arguments directly into place |
5431 // on top of the frame. | 5333 // on top of the frame. |
5432 frame_->SyncRange(0, frame_->element_count() - 1); | 5334 frame_->SyncRange(0, frame_->element_count() - 1); |
5433 frame_->EmitPush(rsi); | 5335 frame_->EmitPush(rsi); |
5434 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); | 5336 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); |
5435 frame_->EmitPush(kScratchRegister); | 5337 frame_->EmitPush(kScratchRegister); |
5436 if (typeof_state == INSIDE_TYPEOF) { | 5338 if (typeof_state == INSIDE_TYPEOF) { |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5682 // A test rax instruction following the call signals that the inobject | 5584 // A test rax instruction following the call signals that the inobject |
5683 // property case was inlined. Ensure that there is not a test rax | 5585 // property case was inlined. Ensure that there is not a test rax |
5684 // instruction here. | 5586 // instruction here. |
5685 masm_->nop(); | 5587 masm_->nop(); |
5686 // Discard the global object. The result is in answer. | 5588 // Discard the global object. The result is in answer. |
5687 frame_->Drop(); | 5589 frame_->Drop(); |
5688 return answer; | 5590 return answer; |
5689 } | 5591 } |
5690 | 5592 |
5691 | 5593 |
| 5594 void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, |
| 5595 TypeofState typeof_state, |
| 5596 Result* result, |
| 5597 JumpTarget* slow, |
| 5598 JumpTarget* done) { |
| 5599 // Generate fast-case code for variables that might be shadowed by |
| 5600 // eval-introduced variables. Eval is used a lot without |
| 5601 // introducing variables. In those cases, we do not want to |
| 5602 // perform a runtime call for all variables in the scope |
| 5603 // containing the eval. |
| 5604 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 5605 *result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 5606 done->Jump(result); |
| 5607 |
| 5608 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 5609 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 5610 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 5611 if (potential_slot != NULL) { |
| 5612 // Generate fast case for locals that rewrite to slots. |
| 5613 // Allocate a fresh register to use as a temp in |
| 5614 // ContextSlotOperandCheckExtensions and to hold the result |
| 5615 // value. |
| 5616 *result = allocator_->Allocate(); |
| 5617 ASSERT(result->is_valid()); |
| 5618 __ movq(result->reg(), |
| 5619 ContextSlotOperandCheckExtensions(potential_slot, |
| 5620 *result, |
| 5621 slow)); |
| 5622 if (potential_slot->var()->mode() == Variable::CONST) { |
| 5623 __ CompareRoot(result->reg(), Heap::kTheHoleValueRootIndex); |
| 5624 done->Branch(not_equal, result); |
| 5625 __ LoadRoot(result->reg(), Heap::kUndefinedValueRootIndex); |
| 5626 } |
| 5627 done->Jump(result); |
| 5628 } else if (rewrite != NULL) { |
| 5629 // Generate fast case for argument loads. |
| 5630 Property* property = rewrite->AsProperty(); |
| 5631 if (property != NULL) { |
| 5632 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 5633 Literal* key_literal = property->key()->AsLiteral(); |
| 5634 if (obj_proxy != NULL && |
| 5635 key_literal != NULL && |
| 5636 obj_proxy->IsArguments() && |
| 5637 key_literal->handle()->IsSmi()) { |
| 5638 // Load arguments object if there are no eval-introduced |
| 5639 // variables. Then load the argument from the arguments |
| 5640 // object using keyed load. |
| 5641 Result arguments = allocator()->Allocate(); |
| 5642 ASSERT(arguments.is_valid()); |
| 5643 __ movq(arguments.reg(), |
| 5644 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 5645 arguments, |
| 5646 slow)); |
| 5647 frame_->Push(&arguments); |
| 5648 frame_->Push(key_literal->handle()); |
| 5649 *result = EmitKeyedLoad(false); |
| 5650 frame_->Drop(2); // Drop key and receiver. |
| 5651 done->Jump(result); |
| 5652 } |
| 5653 } |
| 5654 } |
| 5655 } |
| 5656 } |
| 5657 |
| 5658 |
5692 void CodeGenerator::LoadGlobal() { | 5659 void CodeGenerator::LoadGlobal() { |
5693 if (in_spilled_code()) { | 5660 if (in_spilled_code()) { |
5694 frame_->EmitPush(GlobalObject()); | 5661 frame_->EmitPush(GlobalObject()); |
5695 } else { | 5662 } else { |
5696 Result temp = allocator_->Allocate(); | 5663 Result temp = allocator_->Allocate(); |
5697 __ movq(temp.reg(), GlobalObject()); | 5664 __ movq(temp.reg(), GlobalObject()); |
5698 frame_->Push(&temp); | 5665 frame_->Push(&temp); |
5699 } | 5666 } |
5700 } | 5667 } |
5701 | 5668 |
(...skipping 5875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11577 // Call the function from C++. | 11544 // Call the function from C++. |
11578 return FUNCTION_CAST<ModuloFunction>(buffer); | 11545 return FUNCTION_CAST<ModuloFunction>(buffer); |
11579 } | 11546 } |
11580 | 11547 |
11581 #endif | 11548 #endif |
11582 | 11549 |
11583 | 11550 |
11584 #undef __ | 11551 #undef __ |
11585 | 11552 |
11586 } } // namespace v8::internal | 11553 } } // namespace v8::internal |
OLD | NEW |