Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: src/x64/codegen-x64.cc

Issue 2053003: Refactor the fast-case code for loading local/global variables and... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698