OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
8 | 8 |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 4663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4674 Label fast_elements_case; | 4674 Label fast_elements_case; |
4675 __ cmp(ecx, Immediate(FAST_ELEMENTS)); | 4675 __ cmp(ecx, Immediate(FAST_ELEMENTS)); |
4676 __ j(equal, &fast_elements_case); | 4676 __ j(equal, &fast_elements_case); |
4677 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 4677 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
4678 | 4678 |
4679 __ bind(&fast_elements_case); | 4679 __ bind(&fast_elements_case); |
4680 GenerateCase(masm, FAST_ELEMENTS); | 4680 GenerateCase(masm, FAST_ELEMENTS); |
4681 } | 4681 } |
4682 | 4682 |
4683 | 4683 |
| 4684 // Generates an Operand for saving parameters after PrepareCallApiFunction. |
| 4685 static Operand ApiParameterOperand(int index) { |
| 4686 return Operand(esp, index * kPointerSize); |
| 4687 } |
| 4688 |
| 4689 |
| 4690 // Prepares stack to put arguments (aligns and so on). Reserves |
| 4691 // space for return value if needed (assumes the return value is a handle). |
| 4692 // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1) |
| 4693 // etc. Saves context (esi). If space was reserved for return value then |
| 4694 // stores the pointer to the reserved slot into esi. |
| 4695 static void PrepareCallApiFunction(MacroAssembler* masm, int argc) { |
| 4696 __ EnterApiExitFrame(argc); |
| 4697 if (__ emit_debug_code()) { |
| 4698 __ mov(esi, Immediate(bit_cast<int32_t>(kZapValue))); |
| 4699 } |
| 4700 } |
| 4701 |
| 4702 |
| 4703 // Calls an API function. Allocates HandleScope, extracts returned value |
| 4704 // from handle and propagates exceptions. Clobbers ebx, edi and |
| 4705 // caller-save registers. Restores context. On return removes |
| 4706 // stack_space * kPointerSize (GCed). |
| 4707 static void CallApiFunctionAndReturn(MacroAssembler* masm, |
| 4708 Register function_address, |
| 4709 ExternalReference thunk_ref, |
| 4710 Operand thunk_last_arg, int stack_space, |
| 4711 Operand* stack_space_operand, |
| 4712 Operand return_value_operand, |
| 4713 Operand* context_restore_operand) { |
| 4714 Isolate* isolate = masm->isolate(); |
| 4715 |
| 4716 ExternalReference next_address = |
| 4717 ExternalReference::handle_scope_next_address(isolate); |
| 4718 ExternalReference limit_address = |
| 4719 ExternalReference::handle_scope_limit_address(isolate); |
| 4720 ExternalReference level_address = |
| 4721 ExternalReference::handle_scope_level_address(isolate); |
| 4722 |
| 4723 DCHECK(edx.is(function_address)); |
| 4724 // Allocate HandleScope in callee-save registers. |
| 4725 __ mov(ebx, Operand::StaticVariable(next_address)); |
| 4726 __ mov(edi, Operand::StaticVariable(limit_address)); |
| 4727 __ add(Operand::StaticVariable(level_address), Immediate(1)); |
| 4728 |
| 4729 if (FLAG_log_timer_events) { |
| 4730 FrameScope frame(masm, StackFrame::MANUAL); |
| 4731 __ PushSafepointRegisters(); |
| 4732 __ PrepareCallCFunction(1, eax); |
| 4733 __ mov(Operand(esp, 0), |
| 4734 Immediate(ExternalReference::isolate_address(isolate))); |
| 4735 __ CallCFunction(ExternalReference::log_enter_external_function(isolate), |
| 4736 1); |
| 4737 __ PopSafepointRegisters(); |
| 4738 } |
| 4739 |
| 4740 |
| 4741 Label profiler_disabled; |
| 4742 Label end_profiler_check; |
| 4743 __ mov(eax, Immediate(ExternalReference::is_profiling_address(isolate))); |
| 4744 __ cmpb(Operand(eax, 0), 0); |
| 4745 __ j(zero, &profiler_disabled); |
| 4746 |
| 4747 // Additional parameter is the address of the actual getter function. |
| 4748 __ mov(thunk_last_arg, function_address); |
| 4749 // Call the api function. |
| 4750 __ mov(eax, Immediate(thunk_ref)); |
| 4751 __ call(eax); |
| 4752 __ jmp(&end_profiler_check); |
| 4753 |
| 4754 __ bind(&profiler_disabled); |
| 4755 // Call the api function. |
| 4756 __ call(function_address); |
| 4757 __ bind(&end_profiler_check); |
| 4758 |
| 4759 if (FLAG_log_timer_events) { |
| 4760 FrameScope frame(masm, StackFrame::MANUAL); |
| 4761 __ PushSafepointRegisters(); |
| 4762 __ PrepareCallCFunction(1, eax); |
| 4763 __ mov(Operand(esp, 0), |
| 4764 Immediate(ExternalReference::isolate_address(isolate))); |
| 4765 __ CallCFunction(ExternalReference::log_leave_external_function(isolate), |
| 4766 1); |
| 4767 __ PopSafepointRegisters(); |
| 4768 } |
| 4769 |
| 4770 Label prologue; |
| 4771 // Load the value from ReturnValue |
| 4772 __ mov(eax, return_value_operand); |
| 4773 |
| 4774 Label promote_scheduled_exception; |
| 4775 Label exception_handled; |
| 4776 Label delete_allocated_handles; |
| 4777 Label leave_exit_frame; |
| 4778 |
| 4779 __ bind(&prologue); |
| 4780 // No more valid handles (the result handle was the last one). Restore |
| 4781 // previous handle scope. |
| 4782 __ mov(Operand::StaticVariable(next_address), ebx); |
| 4783 __ sub(Operand::StaticVariable(level_address), Immediate(1)); |
| 4784 __ Assert(above_equal, kInvalidHandleScopeLevel); |
| 4785 __ cmp(edi, Operand::StaticVariable(limit_address)); |
| 4786 __ j(not_equal, &delete_allocated_handles); |
| 4787 __ bind(&leave_exit_frame); |
| 4788 |
| 4789 // Check if the function scheduled an exception. |
| 4790 ExternalReference scheduled_exception_address = |
| 4791 ExternalReference::scheduled_exception_address(isolate); |
| 4792 __ cmp(Operand::StaticVariable(scheduled_exception_address), |
| 4793 Immediate(isolate->factory()->the_hole_value())); |
| 4794 __ j(not_equal, &promote_scheduled_exception); |
| 4795 __ bind(&exception_handled); |
| 4796 |
| 4797 #if DEBUG |
| 4798 // Check if the function returned a valid JavaScript value. |
| 4799 Label ok; |
| 4800 Register return_value = eax; |
| 4801 Register map = ecx; |
| 4802 |
| 4803 __ JumpIfSmi(return_value, &ok, Label::kNear); |
| 4804 __ mov(map, FieldOperand(return_value, HeapObject::kMapOffset)); |
| 4805 |
| 4806 __ CmpInstanceType(map, LAST_NAME_TYPE); |
| 4807 __ j(below_equal, &ok, Label::kNear); |
| 4808 |
| 4809 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 4810 __ j(above_equal, &ok, Label::kNear); |
| 4811 |
| 4812 __ cmp(map, isolate->factory()->heap_number_map()); |
| 4813 __ j(equal, &ok, Label::kNear); |
| 4814 |
| 4815 __ cmp(return_value, isolate->factory()->undefined_value()); |
| 4816 __ j(equal, &ok, Label::kNear); |
| 4817 |
| 4818 __ cmp(return_value, isolate->factory()->true_value()); |
| 4819 __ j(equal, &ok, Label::kNear); |
| 4820 |
| 4821 __ cmp(return_value, isolate->factory()->false_value()); |
| 4822 __ j(equal, &ok, Label::kNear); |
| 4823 |
| 4824 __ cmp(return_value, isolate->factory()->null_value()); |
| 4825 __ j(equal, &ok, Label::kNear); |
| 4826 |
| 4827 __ Abort(kAPICallReturnedInvalidObject); |
| 4828 |
| 4829 __ bind(&ok); |
| 4830 #endif |
| 4831 |
| 4832 bool restore_context = context_restore_operand != NULL; |
| 4833 if (restore_context) { |
| 4834 __ mov(esi, *context_restore_operand); |
| 4835 } |
| 4836 if (stack_space_operand != nullptr) { |
| 4837 __ mov(ebx, *stack_space_operand); |
| 4838 } |
| 4839 __ LeaveApiExitFrame(!restore_context); |
| 4840 if (stack_space_operand != nullptr) { |
| 4841 DCHECK_EQ(0, stack_space); |
| 4842 __ pop(ecx); |
| 4843 __ add(esp, ebx); |
| 4844 __ jmp(ecx); |
| 4845 } else { |
| 4846 __ ret(stack_space * kPointerSize); |
| 4847 } |
| 4848 |
| 4849 __ bind(&promote_scheduled_exception); |
| 4850 { |
| 4851 FrameScope frame(masm, StackFrame::INTERNAL); |
| 4852 __ CallRuntime(Runtime::kPromoteScheduledException, 0); |
| 4853 } |
| 4854 __ jmp(&exception_handled); |
| 4855 |
| 4856 // HandleScope limit has changed. Delete allocated extensions. |
| 4857 ExternalReference delete_extensions = |
| 4858 ExternalReference::delete_handle_scope_extensions(isolate); |
| 4859 __ bind(&delete_allocated_handles); |
| 4860 __ mov(Operand::StaticVariable(limit_address), edi); |
| 4861 __ mov(edi, eax); |
| 4862 __ mov(Operand(esp, 0), |
| 4863 Immediate(ExternalReference::isolate_address(isolate))); |
| 4864 __ mov(eax, Immediate(delete_extensions)); |
| 4865 __ call(eax); |
| 4866 __ mov(eax, edi); |
| 4867 __ jmp(&leave_exit_frame); |
| 4868 } |
| 4869 |
| 4870 |
4684 static void CallApiFunctionStubHelper(MacroAssembler* masm, | 4871 static void CallApiFunctionStubHelper(MacroAssembler* masm, |
4685 const ParameterCount& argc, | 4872 const ParameterCount& argc, |
4686 bool return_first_arg, | 4873 bool return_first_arg, |
4687 bool call_data_undefined) { | 4874 bool call_data_undefined) { |
4688 // ----------- S t a t e ------------- | 4875 // ----------- S t a t e ------------- |
4689 // -- eax : callee | 4876 // -- eax : callee |
4690 // -- ebx : call_data | 4877 // -- ebx : call_data |
4691 // -- ecx : holder | 4878 // -- ecx : holder |
4692 // -- edx : api_function_address | 4879 // -- edx : api_function_address |
4693 // -- esi : context | 4880 // -- esi : context |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4756 // API function gets reference to the v8::Arguments. If CPU profiler | 4943 // API function gets reference to the v8::Arguments. If CPU profiler |
4757 // is enabled wrapper function will be called and we need to pass | 4944 // is enabled wrapper function will be called and we need to pass |
4758 // address of the callback as additional parameter, always allocate | 4945 // address of the callback as additional parameter, always allocate |
4759 // space for it. | 4946 // space for it. |
4760 const int kApiArgc = 1 + 1; | 4947 const int kApiArgc = 1 + 1; |
4761 | 4948 |
4762 // Allocate the v8::Arguments structure in the arguments' space since | 4949 // Allocate the v8::Arguments structure in the arguments' space since |
4763 // it's not controlled by GC. | 4950 // it's not controlled by GC. |
4764 const int kApiStackSpace = 4; | 4951 const int kApiStackSpace = 4; |
4765 | 4952 |
4766 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); | 4953 PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace); |
4767 | 4954 |
4768 // FunctionCallbackInfo::implicit_args_. | 4955 // FunctionCallbackInfo::implicit_args_. |
4769 __ mov(ApiParameterOperand(2), scratch); | 4956 __ mov(ApiParameterOperand(2), scratch); |
4770 if (argc.is_immediate()) { | 4957 if (argc.is_immediate()) { |
4771 __ add(scratch, | 4958 __ add(scratch, |
4772 Immediate((argc.immediate() + FCA::kArgsLength - 1) * kPointerSize)); | 4959 Immediate((argc.immediate() + FCA::kArgsLength - 1) * kPointerSize)); |
4773 // FunctionCallbackInfo::values_. | 4960 // FunctionCallbackInfo::values_. |
4774 __ mov(ApiParameterOperand(3), scratch); | 4961 __ mov(ApiParameterOperand(3), scratch); |
4775 // FunctionCallbackInfo::length_. | 4962 // FunctionCallbackInfo::length_. |
4776 __ Move(ApiParameterOperand(4), Immediate(argc.immediate())); | 4963 __ Move(ApiParameterOperand(4), Immediate(argc.immediate())); |
(...skipping 29 matching lines...) Expand all Loading... |
4806 return_value_offset = 2 + FCA::kReturnValueOffset; | 4993 return_value_offset = 2 + FCA::kReturnValueOffset; |
4807 } | 4994 } |
4808 Operand return_value_operand(ebp, return_value_offset * kPointerSize); | 4995 Operand return_value_operand(ebp, return_value_offset * kPointerSize); |
4809 int stack_space = 0; | 4996 int stack_space = 0; |
4810 Operand is_construct_call_operand = ApiParameterOperand(5); | 4997 Operand is_construct_call_operand = ApiParameterOperand(5); |
4811 Operand* stack_space_operand = &is_construct_call_operand; | 4998 Operand* stack_space_operand = &is_construct_call_operand; |
4812 if (argc.is_immediate()) { | 4999 if (argc.is_immediate()) { |
4813 stack_space = argc.immediate() + FCA::kArgsLength + 1; | 5000 stack_space = argc.immediate() + FCA::kArgsLength + 1; |
4814 stack_space_operand = nullptr; | 5001 stack_space_operand = nullptr; |
4815 } | 5002 } |
4816 __ CallApiFunctionAndReturn( | 5003 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
4817 api_function_address, thunk_ref, ApiParameterOperand(1), stack_space, | 5004 ApiParameterOperand(1), stack_space, |
4818 stack_space_operand, return_value_operand, &context_restore_operand); | 5005 stack_space_operand, return_value_operand, |
| 5006 &context_restore_operand); |
4819 } | 5007 } |
4820 | 5008 |
4821 | 5009 |
4822 void CallApiFunctionStub::Generate(MacroAssembler* masm) { | 5010 void CallApiFunctionStub::Generate(MacroAssembler* masm) { |
4823 // TODO(dcarney): make eax contain the function address. | 5011 // TODO(dcarney): make eax contain the function address. |
4824 bool call_data_undefined = this->call_data_undefined(); | 5012 bool call_data_undefined = this->call_data_undefined(); |
4825 CallApiFunctionStubHelper(masm, ParameterCount(edi), false, | 5013 CallApiFunctionStubHelper(masm, ParameterCount(edi), false, |
4826 call_data_undefined); | 5014 call_data_undefined); |
4827 } | 5015 } |
4828 | 5016 |
(...skipping 23 matching lines...) Expand all Loading... |
4852 // Allocate space for opional callback address parameter in case | 5040 // Allocate space for opional callback address parameter in case |
4853 // CPU profiler is active. | 5041 // CPU profiler is active. |
4854 const int kApiArgc = 2 + 1; | 5042 const int kApiArgc = 2 + 1; |
4855 | 5043 |
4856 Register api_function_address = edx; | 5044 Register api_function_address = edx; |
4857 Register scratch = ebx; | 5045 Register scratch = ebx; |
4858 | 5046 |
4859 // load address of name | 5047 // load address of name |
4860 __ lea(scratch, Operand(esp, 1 * kPointerSize)); | 5048 __ lea(scratch, Operand(esp, 1 * kPointerSize)); |
4861 | 5049 |
4862 __ PrepareCallApiFunction(kApiArgc); | 5050 PrepareCallApiFunction(masm, kApiArgc); |
4863 __ mov(ApiParameterOperand(0), scratch); // name. | 5051 __ mov(ApiParameterOperand(0), scratch); // name. |
4864 __ add(scratch, Immediate(kPointerSize)); | 5052 __ add(scratch, Immediate(kPointerSize)); |
4865 __ mov(ApiParameterOperand(1), scratch); // arguments pointer. | 5053 __ mov(ApiParameterOperand(1), scratch); // arguments pointer. |
4866 | 5054 |
4867 ExternalReference thunk_ref = | 5055 ExternalReference thunk_ref = |
4868 ExternalReference::invoke_accessor_getter_callback(isolate()); | 5056 ExternalReference::invoke_accessor_getter_callback(isolate()); |
4869 | 5057 |
4870 __ CallApiFunctionAndReturn(api_function_address, thunk_ref, | 5058 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
4871 ApiParameterOperand(2), kStackSpace, nullptr, | 5059 ApiParameterOperand(2), kStackSpace, nullptr, |
4872 Operand(ebp, 7 * kPointerSize), NULL); | 5060 Operand(ebp, 7 * kPointerSize), NULL); |
4873 } | 5061 } |
4874 | 5062 |
4875 | 5063 |
4876 #undef __ | 5064 #undef __ |
4877 | 5065 |
4878 } } // namespace v8::internal | 5066 } } // namespace v8::internal |
4879 | 5067 |
4880 #endif // V8_TARGET_ARCH_IA32 | 5068 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |