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