OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 4603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4614 Label fast_elements_case; | 4614 Label fast_elements_case; |
4615 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); | 4615 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); |
4616 __ j(equal, &fast_elements_case); | 4616 __ j(equal, &fast_elements_case); |
4617 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 4617 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
4618 | 4618 |
4619 __ bind(&fast_elements_case); | 4619 __ bind(&fast_elements_case); |
4620 GenerateCase(masm, FAST_ELEMENTS); | 4620 GenerateCase(masm, FAST_ELEMENTS); |
4621 } | 4621 } |
4622 | 4622 |
4623 | 4623 |
| 4624 static int Offset(ExternalReference ref0, ExternalReference ref1) { |
| 4625 int64_t offset = (ref0.address() - ref1.address()); |
| 4626 // Check that fits into int. |
| 4627 DCHECK(static_cast<int>(offset) == offset); |
| 4628 return static_cast<int>(offset); |
| 4629 } |
| 4630 |
| 4631 |
| 4632 // Prepares stack to put arguments (aligns and so on). WIN64 calling |
| 4633 // convention requires to put the pointer to the return value slot into |
| 4634 // rcx (rcx must be preserverd until CallApiFunctionAndReturn). Saves |
| 4635 // context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize |
| 4636 // inside the exit frame (not GCed) accessible via StackSpaceOperand. |
| 4637 static void PrepareCallApiFunction(MacroAssembler* masm, int arg_stack_space) { |
| 4638 __ EnterApiExitFrame(arg_stack_space); |
| 4639 } |
| 4640 |
| 4641 |
| 4642 // Calls an API function. Allocates HandleScope, extracts returned value |
| 4643 // from handle and propagates exceptions. Clobbers r14, r15, rbx and |
| 4644 // caller-save registers. Restores context. On return removes |
| 4645 // stack_space * kPointerSize (GCed). |
| 4646 static void CallApiFunctionAndReturn(MacroAssembler* masm, |
| 4647 Register function_address, |
| 4648 ExternalReference thunk_ref, |
| 4649 Register thunk_last_arg, int stack_space, |
| 4650 Operand* stack_space_operand, |
| 4651 Operand return_value_operand, |
| 4652 Operand* context_restore_operand) { |
| 4653 Label prologue; |
| 4654 Label promote_scheduled_exception; |
| 4655 Label exception_handled; |
| 4656 Label delete_allocated_handles; |
| 4657 Label leave_exit_frame; |
| 4658 Label write_back; |
| 4659 |
| 4660 Isolate* isolate = masm->isolate(); |
| 4661 Factory* factory = isolate->factory(); |
| 4662 ExternalReference next_address = |
| 4663 ExternalReference::handle_scope_next_address(isolate); |
| 4664 const int kNextOffset = 0; |
| 4665 const int kLimitOffset = Offset( |
| 4666 ExternalReference::handle_scope_limit_address(isolate), next_address); |
| 4667 const int kLevelOffset = Offset( |
| 4668 ExternalReference::handle_scope_level_address(isolate), next_address); |
| 4669 ExternalReference scheduled_exception_address = |
| 4670 ExternalReference::scheduled_exception_address(isolate); |
| 4671 |
| 4672 DCHECK(rdx.is(function_address) || r8.is(function_address)); |
| 4673 // Allocate HandleScope in callee-save registers. |
| 4674 Register prev_next_address_reg = r14; |
| 4675 Register prev_limit_reg = rbx; |
| 4676 Register base_reg = r15; |
| 4677 __ Move(base_reg, next_address); |
| 4678 __ movp(prev_next_address_reg, Operand(base_reg, kNextOffset)); |
| 4679 __ movp(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
| 4680 __ addl(Operand(base_reg, kLevelOffset), Immediate(1)); |
| 4681 |
| 4682 if (FLAG_log_timer_events) { |
| 4683 FrameScope frame(masm, StackFrame::MANUAL); |
| 4684 __ PushSafepointRegisters(); |
| 4685 __ PrepareCallCFunction(1); |
| 4686 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate)); |
| 4687 __ CallCFunction(ExternalReference::log_enter_external_function(isolate), |
| 4688 1); |
| 4689 __ PopSafepointRegisters(); |
| 4690 } |
| 4691 |
| 4692 Label profiler_disabled; |
| 4693 Label end_profiler_check; |
| 4694 __ Move(rax, ExternalReference::is_profiling_address(isolate)); |
| 4695 __ cmpb(Operand(rax, 0), Immediate(0)); |
| 4696 __ j(zero, &profiler_disabled); |
| 4697 |
| 4698 // Third parameter is the address of the actual getter function. |
| 4699 __ Move(thunk_last_arg, function_address); |
| 4700 __ Move(rax, thunk_ref); |
| 4701 __ jmp(&end_profiler_check); |
| 4702 |
| 4703 __ bind(&profiler_disabled); |
| 4704 // Call the api function! |
| 4705 __ Move(rax, function_address); |
| 4706 |
| 4707 __ bind(&end_profiler_check); |
| 4708 |
| 4709 // Call the api function! |
| 4710 __ call(rax); |
| 4711 |
| 4712 if (FLAG_log_timer_events) { |
| 4713 FrameScope frame(masm, StackFrame::MANUAL); |
| 4714 __ PushSafepointRegisters(); |
| 4715 __ PrepareCallCFunction(1); |
| 4716 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate)); |
| 4717 __ CallCFunction(ExternalReference::log_leave_external_function(isolate), |
| 4718 1); |
| 4719 __ PopSafepointRegisters(); |
| 4720 } |
| 4721 |
| 4722 // Load the value from ReturnValue |
| 4723 __ movp(rax, return_value_operand); |
| 4724 __ bind(&prologue); |
| 4725 |
| 4726 // No more valid handles (the result handle was the last one). Restore |
| 4727 // previous handle scope. |
| 4728 __ subl(Operand(base_reg, kLevelOffset), Immediate(1)); |
| 4729 __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg); |
| 4730 __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
| 4731 __ j(not_equal, &delete_allocated_handles); |
| 4732 __ bind(&leave_exit_frame); |
| 4733 |
| 4734 // Check if the function scheduled an exception. |
| 4735 __ Move(rsi, scheduled_exception_address); |
| 4736 __ Cmp(Operand(rsi, 0), factory->the_hole_value()); |
| 4737 __ j(not_equal, &promote_scheduled_exception); |
| 4738 __ bind(&exception_handled); |
| 4739 |
| 4740 #if DEBUG |
| 4741 // Check if the function returned a valid JavaScript value. |
| 4742 Label ok; |
| 4743 Register return_value = rax; |
| 4744 Register map = rcx; |
| 4745 |
| 4746 __ JumpIfSmi(return_value, &ok, Label::kNear); |
| 4747 __ movp(map, FieldOperand(return_value, HeapObject::kMapOffset)); |
| 4748 |
| 4749 __ CmpInstanceType(map, LAST_NAME_TYPE); |
| 4750 __ j(below_equal, &ok, Label::kNear); |
| 4751 |
| 4752 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 4753 __ j(above_equal, &ok, Label::kNear); |
| 4754 |
| 4755 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 4756 __ j(equal, &ok, Label::kNear); |
| 4757 |
| 4758 __ CompareRoot(return_value, Heap::kUndefinedValueRootIndex); |
| 4759 __ j(equal, &ok, Label::kNear); |
| 4760 |
| 4761 __ CompareRoot(return_value, Heap::kTrueValueRootIndex); |
| 4762 __ j(equal, &ok, Label::kNear); |
| 4763 |
| 4764 __ CompareRoot(return_value, Heap::kFalseValueRootIndex); |
| 4765 __ j(equal, &ok, Label::kNear); |
| 4766 |
| 4767 __ CompareRoot(return_value, Heap::kNullValueRootIndex); |
| 4768 __ j(equal, &ok, Label::kNear); |
| 4769 |
| 4770 __ Abort(kAPICallReturnedInvalidObject); |
| 4771 |
| 4772 __ bind(&ok); |
| 4773 #endif |
| 4774 |
| 4775 bool restore_context = context_restore_operand != NULL; |
| 4776 if (restore_context) { |
| 4777 __ movp(rsi, *context_restore_operand); |
| 4778 } |
| 4779 if (stack_space_operand != nullptr) { |
| 4780 __ movp(rbx, *stack_space_operand); |
| 4781 } |
| 4782 __ LeaveApiExitFrame(!restore_context); |
| 4783 if (stack_space_operand != nullptr) { |
| 4784 DCHECK_EQ(stack_space, 0); |
| 4785 __ PopReturnAddressTo(rcx); |
| 4786 __ addq(rsp, rbx); |
| 4787 __ jmp(rcx); |
| 4788 } else { |
| 4789 __ ret(stack_space * kPointerSize); |
| 4790 } |
| 4791 |
| 4792 __ bind(&promote_scheduled_exception); |
| 4793 { |
| 4794 FrameScope frame(masm, StackFrame::INTERNAL); |
| 4795 __ CallRuntime(Runtime::kPromoteScheduledException, 0); |
| 4796 } |
| 4797 __ jmp(&exception_handled); |
| 4798 |
| 4799 // HandleScope limit has changed. Delete allocated extensions. |
| 4800 __ bind(&delete_allocated_handles); |
| 4801 __ movp(Operand(base_reg, kLimitOffset), prev_limit_reg); |
| 4802 __ movp(prev_limit_reg, rax); |
| 4803 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate)); |
| 4804 __ LoadAddress(rax, |
| 4805 ExternalReference::delete_handle_scope_extensions(isolate)); |
| 4806 __ call(rax); |
| 4807 __ movp(rax, prev_limit_reg); |
| 4808 __ jmp(&leave_exit_frame); |
| 4809 } |
| 4810 |
| 4811 |
4624 static void CallApiFunctionStubHelper(MacroAssembler* masm, | 4812 static void CallApiFunctionStubHelper(MacroAssembler* masm, |
4625 const ParameterCount& argc, | 4813 const ParameterCount& argc, |
4626 bool return_first_arg, | 4814 bool return_first_arg, |
4627 bool call_data_undefined) { | 4815 bool call_data_undefined) { |
4628 // ----------- S t a t e ------------- | 4816 // ----------- S t a t e ------------- |
4629 // -- rax : callee | 4817 // -- rax : callee |
4630 // -- rbx : call_data | 4818 // -- rbx : call_data |
4631 // -- rcx : holder | 4819 // -- rcx : holder |
4632 // -- rdx : api_function_address | 4820 // -- rdx : api_function_address |
4633 // -- rsi : context | 4821 // -- rsi : context |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4691 // Push return address back on stack. | 4879 // Push return address back on stack. |
4692 __ PushReturnAddressFrom(context); | 4880 __ PushReturnAddressFrom(context); |
4693 | 4881 |
4694 // load context from callee | 4882 // load context from callee |
4695 __ movp(context, FieldOperand(callee, JSFunction::kContextOffset)); | 4883 __ movp(context, FieldOperand(callee, JSFunction::kContextOffset)); |
4696 | 4884 |
4697 // Allocate the v8::Arguments structure in the arguments' space since | 4885 // Allocate the v8::Arguments structure in the arguments' space since |
4698 // it's not controlled by GC. | 4886 // it's not controlled by GC. |
4699 const int kApiStackSpace = 4; | 4887 const int kApiStackSpace = 4; |
4700 | 4888 |
4701 __ PrepareCallApiFunction(kApiStackSpace); | 4889 PrepareCallApiFunction(masm, kApiStackSpace); |
4702 | 4890 |
4703 // FunctionCallbackInfo::implicit_args_. | 4891 // FunctionCallbackInfo::implicit_args_. |
4704 __ movp(StackSpaceOperand(0), scratch); | 4892 __ movp(StackSpaceOperand(0), scratch); |
4705 if (argc.is_immediate()) { | 4893 if (argc.is_immediate()) { |
4706 __ addp(scratch, Immediate((argc.immediate() + FCA::kArgsLength - 1) * | 4894 __ addp(scratch, Immediate((argc.immediate() + FCA::kArgsLength - 1) * |
4707 kPointerSize)); | 4895 kPointerSize)); |
4708 // FunctionCallbackInfo::values_. | 4896 // FunctionCallbackInfo::values_. |
4709 __ movp(StackSpaceOperand(1), scratch); | 4897 __ movp(StackSpaceOperand(1), scratch); |
4710 // FunctionCallbackInfo::length_. | 4898 // FunctionCallbackInfo::length_. |
4711 __ Set(StackSpaceOperand(2), argc.immediate()); | 4899 __ Set(StackSpaceOperand(2), argc.immediate()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4749 FCA::kArgsLength - FCA::kContextSaveIndex); | 4937 FCA::kArgsLength - FCA::kContextSaveIndex); |
4750 Operand is_construct_call_operand = StackSpaceOperand(3); | 4938 Operand is_construct_call_operand = StackSpaceOperand(3); |
4751 Operand return_value_operand = args_from_rbp.GetArgumentOperand( | 4939 Operand return_value_operand = args_from_rbp.GetArgumentOperand( |
4752 return_first_arg ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset); | 4940 return_first_arg ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset); |
4753 int stack_space = 0; | 4941 int stack_space = 0; |
4754 Operand* stack_space_operand = &is_construct_call_operand; | 4942 Operand* stack_space_operand = &is_construct_call_operand; |
4755 if (argc.is_immediate()) { | 4943 if (argc.is_immediate()) { |
4756 stack_space = argc.immediate() + FCA::kArgsLength + 1; | 4944 stack_space = argc.immediate() + FCA::kArgsLength + 1; |
4757 stack_space_operand = nullptr; | 4945 stack_space_operand = nullptr; |
4758 } | 4946 } |
4759 __ CallApiFunctionAndReturn(api_function_address, thunk_ref, callback_arg, | 4947 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, callback_arg, |
4760 stack_space, stack_space_operand, | 4948 stack_space, stack_space_operand, |
4761 return_value_operand, &context_restore_operand); | 4949 return_value_operand, &context_restore_operand); |
4762 } | 4950 } |
4763 | 4951 |
4764 | 4952 |
4765 void CallApiFunctionStub::Generate(MacroAssembler* masm) { | 4953 void CallApiFunctionStub::Generate(MacroAssembler* masm) { |
4766 // TODO(dcarney): make rax contain the function address. | 4954 // TODO(dcarney): make rax contain the function address. |
4767 bool call_data_undefined = this->call_data_undefined(); | 4955 bool call_data_undefined = this->call_data_undefined(); |
4768 CallApiFunctionStubHelper(masm, ParameterCount(rdi), false, | 4956 CallApiFunctionStubHelper(masm, ParameterCount(rdi), false, |
4769 call_data_undefined); | 4957 call_data_undefined); |
4770 } | 4958 } |
4771 | 4959 |
(...skipping 30 matching lines...) Expand all Loading... |
4802 Register scratch = rax; | 4990 Register scratch = rax; |
4803 | 4991 |
4804 // v8::Arguments::values_ and handler for name. | 4992 // v8::Arguments::values_ and handler for name. |
4805 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1; | 4993 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1; |
4806 | 4994 |
4807 // Allocate v8::AccessorInfo in non-GCed stack space. | 4995 // Allocate v8::AccessorInfo in non-GCed stack space. |
4808 const int kArgStackSpace = 1; | 4996 const int kArgStackSpace = 1; |
4809 | 4997 |
4810 __ leap(name_arg, Operand(rsp, kPCOnStackSize)); | 4998 __ leap(name_arg, Operand(rsp, kPCOnStackSize)); |
4811 | 4999 |
4812 __ PrepareCallApiFunction(kArgStackSpace); | 5000 PrepareCallApiFunction(masm, kArgStackSpace); |
4813 __ leap(scratch, Operand(name_arg, 1 * kPointerSize)); | 5001 __ leap(scratch, Operand(name_arg, 1 * kPointerSize)); |
4814 | 5002 |
4815 // v8::PropertyAccessorInfo::args_. | 5003 // v8::PropertyAccessorInfo::args_. |
4816 __ movp(StackSpaceOperand(0), scratch); | 5004 __ movp(StackSpaceOperand(0), scratch); |
4817 | 5005 |
4818 // The context register (rsi) has been saved in PrepareCallApiFunction and | 5006 // The context register (rsi) has been saved in PrepareCallApiFunction and |
4819 // could be used to pass arguments. | 5007 // could be used to pass arguments. |
4820 __ leap(accessor_info_arg, StackSpaceOperand(0)); | 5008 __ leap(accessor_info_arg, StackSpaceOperand(0)); |
4821 | 5009 |
4822 ExternalReference thunk_ref = | 5010 ExternalReference thunk_ref = |
4823 ExternalReference::invoke_accessor_getter_callback(isolate()); | 5011 ExternalReference::invoke_accessor_getter_callback(isolate()); |
4824 | 5012 |
4825 // It's okay if api_function_address == getter_arg | 5013 // It's okay if api_function_address == getter_arg |
4826 // but not accessor_info_arg or name_arg | 5014 // but not accessor_info_arg or name_arg |
4827 DCHECK(!api_function_address.is(accessor_info_arg) && | 5015 DCHECK(!api_function_address.is(accessor_info_arg) && |
4828 !api_function_address.is(name_arg)); | 5016 !api_function_address.is(name_arg)); |
4829 | 5017 |
4830 // The name handler is counted as an argument. | 5018 // The name handler is counted as an argument. |
4831 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength); | 5019 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength); |
4832 Operand return_value_operand = args.GetArgumentOperand( | 5020 Operand return_value_operand = args.GetArgumentOperand( |
4833 PropertyCallbackArguments::kArgsLength - 1 - | 5021 PropertyCallbackArguments::kArgsLength - 1 - |
4834 PropertyCallbackArguments::kReturnValueOffset); | 5022 PropertyCallbackArguments::kReturnValueOffset); |
4835 __ CallApiFunctionAndReturn(api_function_address, thunk_ref, getter_arg, | 5023 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg, |
4836 kStackSpace, nullptr, return_value_operand, NULL); | 5024 kStackSpace, nullptr, return_value_operand, NULL); |
4837 } | 5025 } |
4838 | 5026 |
4839 | 5027 |
4840 #undef __ | 5028 #undef __ |
4841 | 5029 |
4842 } } // namespace v8::internal | 5030 } } // namespace v8::internal |
4843 | 5031 |
4844 #endif // V8_TARGET_ARCH_X64 | 5032 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |