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 2849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |