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