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

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

Issue 2033004: Implement fast load and call of arguments in the presence of eval.... (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/ia32/codegen-ia32.cc ('k') | test/mjsunit/arguments-load-across-eval.js » ('j') | 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 2849 matching lines...) Expand 10 before | Expand all | Expand 10 after
2860 loop_nesting()); 2860 loop_nesting());
2861 frame_->RestoreContextRegister(); 2861 frame_->RestoreContextRegister();
2862 // Replace the function on the stack with the result. 2862 // Replace the function on the stack with the result.
2863 frame_->Push(&result); 2863 frame_->Push(&result);
2864 2864
2865 } else if (var != NULL && var->slot() != NULL && 2865 } else if (var != NULL && var->slot() != NULL &&
2866 var->slot()->type() == Slot::LOOKUP) { 2866 var->slot()->type() == Slot::LOOKUP) {
2867 // ---------------------------------- 2867 // ----------------------------------
2868 // JavaScript examples: 2868 // JavaScript examples:
2869 // 2869 //
2870 // with (obj) foo(1, 2, 3) // foo is 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;
2880 JumpTarget done; 2880 JumpTarget done;
2881 2881
2882 // Generate fast-case code for variables that might be shadowed by 2882 // Generate fast-case code for variables that might be shadowed by
2883 // eval-introduced variables. Eval is used a lot without 2883 // eval-introduced variables. Eval is used a lot without
2884 // introducing variables. In those cases, we do not want to 2884 // introducing variables. In those cases, we do not want to
2885 // perform a runtime call for all variables in the scope 2885 // perform a runtime call for all variables in the scope
2886 // containing the eval. 2886 // containing the eval.
2887 Result function; 2887 Result function;
2888 if (var->mode() == Variable::DYNAMIC_GLOBAL) { 2888 if (var->mode() == Variable::DYNAMIC_GLOBAL) {
2889 function = LoadFromGlobalSlotCheckExtensions(var->slot(), 2889 function = LoadFromGlobalSlotCheckExtensions(var->slot(),
2890 NOT_INSIDE_TYPEOF, 2890 NOT_INSIDE_TYPEOF,
2891 &slow); 2891 &slow);
2892 frame_->Push(&function); 2892 frame_->Push(&function);
2893 LoadGlobalReceiver(); 2893 LoadGlobalReceiver();
2894 done.Jump(); 2894 done.Jump();
2895 2895
2896 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { 2896 } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
2897 Slot* potential_slot = var->local_if_not_shadowed()->slot(); 2897 Slot* potential_slot = var->local_if_not_shadowed()->slot();
2898 // Only generate the fast case for locals that rewrite to slots. 2898 Expression* rewrite = var->local_if_not_shadowed()->rewrite();
2899 // This rules out argument loads because eval forces arguments
2900 // access to be through the arguments object.
2901 if (potential_slot != NULL) { 2899 if (potential_slot != NULL) {
2900 // Generate fast case for locals that rewrite to slots.
2902 // Allocate a fresh register to use as a temp in 2901 // Allocate a fresh register to use as a temp in
2903 // ContextSlotOperandCheckExtensions and to hold the result 2902 // ContextSlotOperandCheckExtensions and to hold the result
2904 // value. 2903 // value.
2905 function = allocator()->Allocate(); 2904 function = allocator()->Allocate();
2906 ASSERT(function.is_valid()); 2905 ASSERT(function.is_valid());
2907 __ movq(function.reg(), 2906 __ movq(function.reg(),
2908 ContextSlotOperandCheckExtensions(potential_slot, 2907 ContextSlotOperandCheckExtensions(potential_slot,
2909 function, 2908 function,
2910 &slow)); 2909 &slow));
2911 JumpTarget push_function_and_receiver; 2910 JumpTarget push_function_and_receiver;
2912 if (potential_slot->var()->mode() == Variable::CONST) { 2911 if (potential_slot->var()->mode() == Variable::CONST) {
2913 __ CompareRoot(function.reg(), Heap::kTheHoleValueRootIndex); 2912 __ CompareRoot(function.reg(), Heap::kTheHoleValueRootIndex);
2914 push_function_and_receiver.Branch(not_equal, &function); 2913 push_function_and_receiver.Branch(not_equal, &function);
2915 __ LoadRoot(function.reg(), Heap::kUndefinedValueRootIndex); 2914 __ LoadRoot(function.reg(), Heap::kUndefinedValueRootIndex);
2916 } 2915 }
2917 push_function_and_receiver.Bind(&function); 2916 push_function_and_receiver.Bind(&function);
2918 frame_->Push(&function); 2917 frame_->Push(&function);
2919 LoadGlobalReceiver(); 2918 LoadGlobalReceiver();
2920 done.Jump(); 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 }
2921 } 2948 }
2922 } 2949 }
2923 2950
2924 slow.Bind(); 2951 slow.Bind();
2925 // Load the function from the context. Sync the frame so we can 2952 // Load the function from the context. Sync the frame so we can
2926 // push the arguments directly into place. 2953 // push the arguments directly into place.
2927 frame_->SyncRange(0, frame_->element_count() - 1); 2954 frame_->SyncRange(0, frame_->element_count() - 1);
2928 frame_->EmitPush(rsi); 2955 frame_->EmitPush(rsi);
2929 frame_->EmitPush(var->name()); 2956 frame_->EmitPush(var->name());
2930 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); 2957 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
(...skipping 2404 matching lines...) Expand 10 before | Expand all | Expand 10 after
5335 JumpTarget done; 5362 JumpTarget done;
5336 Result value; 5363 Result value;
5337 5364
5338 // Generate fast-case code for variables that might be shadowed by 5365 // Generate fast-case code for variables that might be shadowed by
5339 // eval-introduced variables. Eval is used a lot without 5366 // eval-introduced variables. Eval is used a lot without
5340 // introducing variables. In those cases, we do not want to 5367 // introducing variables. In those cases, we do not want to
5341 // perform a runtime call for all variables in the scope 5368 // perform a runtime call for all variables in the scope
5342 // containing the eval. 5369 // containing the eval.
5343 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { 5370 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
5344 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); 5371 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
5345 // If there was no control flow to slow, we can exit early.
5346 if (!slow.is_linked()) {
5347 frame_->Push(&value);
5348 return;
5349 }
5350
5351 done.Jump(&value); 5372 done.Jump(&value);
5352 5373
5353 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { 5374 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
5354 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); 5375 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
5355 // Only generate the fast case for locals that rewrite to slots. 5376 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
5356 // This rules out argument loads because eval forces arguments
5357 // access to be through the arguments object.
5358 if (potential_slot != NULL) { 5377 if (potential_slot != NULL) {
5378 // Generate fast case for locals that rewrite to slots.
5359 // Allocate a fresh register to use as a temp in 5379 // Allocate a fresh register to use as a temp in
5360 // ContextSlotOperandCheckExtensions and to hold the result 5380 // ContextSlotOperandCheckExtensions and to hold the result
5361 // value. 5381 // value.
5362 value = allocator_->Allocate(); 5382 value = allocator_->Allocate();
5363 ASSERT(value.is_valid()); 5383 ASSERT(value.is_valid());
5364 __ movq(value.reg(), 5384 __ movq(value.reg(),
5365 ContextSlotOperandCheckExtensions(potential_slot, 5385 ContextSlotOperandCheckExtensions(potential_slot,
5366 value, 5386 value,
5367 &slow)); 5387 &slow));
5368 if (potential_slot->var()->mode() == Variable::CONST) { 5388 if (potential_slot->var()->mode() == Variable::CONST) {
5369 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); 5389 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
5370 done.Branch(not_equal, &value); 5390 done.Branch(not_equal, &value);
5371 __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex); 5391 __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex);
5372 } 5392 }
5373 // There is always control flow to slow from
5374 // ContextSlotOperandCheckExtensions so we have to jump around
5375 // it.
5376 done.Jump(&value); 5393 done.Jump(&value);
5394 } else if (rewrite != NULL) {
5395 // Generate fast case for argument loads.
5396 Property* property = rewrite->AsProperty();
5397 if (property != NULL) {
5398 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
5399 Literal* key_literal = property->key()->AsLiteral();
5400 if (obj_proxy != NULL &&
5401 key_literal != NULL &&
5402 obj_proxy->IsArguments() &&
5403 key_literal->handle()->IsSmi()) {
5404 // Load arguments object if there are no eval-introduced
5405 // variables. Then load the argument from the arguments
5406 // object using keyed load.
5407 Result arguments = allocator()->Allocate();
5408 ASSERT(arguments.is_valid());
5409 __ movq(arguments.reg(),
5410 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
5411 arguments,
5412 &slow));
5413 frame_->Push(&arguments);
5414 frame_->Push(key_literal->handle());
5415 value = EmitKeyedLoad(false);
5416 frame_->Drop(2); // Drop key and receiver.
5417 done.Jump(&value);
5418 }
5419 }
5377 } 5420 }
5378 } 5421 }
5379 5422
5380 slow.Bind(); 5423 slow.Bind();
5381 // A runtime call is inevitable. We eagerly sync frame elements 5424 // A runtime call is inevitable. We eagerly sync frame elements
5382 // to memory so that we can push the arguments directly into place 5425 // to memory so that we can push the arguments directly into place
5383 // on top of the frame. 5426 // on top of the frame.
5384 frame_->SyncRange(0, frame_->element_count() - 1); 5427 frame_->SyncRange(0, frame_->element_count() - 1);
5385 frame_->EmitPush(rsi); 5428 frame_->EmitPush(rsi);
5386 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); 5429 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT);
(...skipping 6142 matching lines...) Expand 10 before | Expand all | Expand 10 after
11529 // Call the function from C++. 11572 // Call the function from C++.
11530 return FUNCTION_CAST<ModuloFunction>(buffer); 11573 return FUNCTION_CAST<ModuloFunction>(buffer);
11531 } 11574 }
11532 11575
11533 #endif 11576 #endif
11534 11577
11535 11578
11536 #undef __ 11579 #undef __
11537 11580
11538 } } // namespace v8::internal 11581 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.cc ('k') | test/mjsunit/arguments-load-across-eval.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698