Index: src/ia32/code-stubs-ia32.cc |
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc |
index d977d39149f34b608b779ba9c846a01fe8c7c3c1..8235868ea51c984b18e3c0b994fe4f37aaab82ae 100644 |
--- a/src/ia32/code-stubs-ia32.cc |
+++ b/src/ia32/code-stubs-ia32.cc |
@@ -4681,6 +4681,193 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { |
} |
+// Generates an Operand for saving parameters after PrepareCallApiFunction. |
+static Operand ApiParameterOperand(int index) { |
+ return Operand(esp, index * kPointerSize); |
+} |
+ |
+ |
+// Prepares stack to put arguments (aligns and so on). Reserves |
+// space for return value if needed (assumes the return value is a handle). |
+// Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1) |
+// etc. Saves context (esi). If space was reserved for return value then |
+// stores the pointer to the reserved slot into esi. |
+static void PrepareCallApiFunction(MacroAssembler* masm, int argc) { |
+ __ EnterApiExitFrame(argc); |
+ if (__ emit_debug_code()) { |
+ __ mov(esi, Immediate(bit_cast<int32_t>(kZapValue))); |
+ } |
+} |
+ |
+ |
+// Calls an API function. Allocates HandleScope, extracts returned value |
+// from handle and propagates exceptions. Clobbers ebx, edi and |
+// caller-save registers. Restores context. On return removes |
+// stack_space * kPointerSize (GCed). |
+static void CallApiFunctionAndReturn(MacroAssembler* masm, |
+ Register function_address, |
+ ExternalReference thunk_ref, |
+ Operand thunk_last_arg, int stack_space, |
+ Operand* stack_space_operand, |
+ Operand return_value_operand, |
+ Operand* context_restore_operand) { |
+ Isolate* isolate = masm->isolate(); |
+ |
+ ExternalReference next_address = |
+ ExternalReference::handle_scope_next_address(isolate); |
+ ExternalReference limit_address = |
+ ExternalReference::handle_scope_limit_address(isolate); |
+ ExternalReference level_address = |
+ ExternalReference::handle_scope_level_address(isolate); |
+ |
+ DCHECK(edx.is(function_address)); |
+ // Allocate HandleScope in callee-save registers. |
+ __ mov(ebx, Operand::StaticVariable(next_address)); |
+ __ mov(edi, Operand::StaticVariable(limit_address)); |
+ __ add(Operand::StaticVariable(level_address), Immediate(1)); |
+ |
+ if (FLAG_log_timer_events) { |
+ FrameScope frame(masm, StackFrame::MANUAL); |
+ __ PushSafepointRegisters(); |
+ __ PrepareCallCFunction(1, eax); |
+ __ mov(Operand(esp, 0), |
+ Immediate(ExternalReference::isolate_address(isolate))); |
+ __ CallCFunction(ExternalReference::log_enter_external_function(isolate), |
+ 1); |
+ __ PopSafepointRegisters(); |
+ } |
+ |
+ |
+ Label profiler_disabled; |
+ Label end_profiler_check; |
+ __ mov(eax, Immediate(ExternalReference::is_profiling_address(isolate))); |
+ __ cmpb(Operand(eax, 0), 0); |
+ __ j(zero, &profiler_disabled); |
+ |
+ // Additional parameter is the address of the actual getter function. |
+ __ mov(thunk_last_arg, function_address); |
+ // Call the api function. |
+ __ mov(eax, Immediate(thunk_ref)); |
+ __ call(eax); |
+ __ jmp(&end_profiler_check); |
+ |
+ __ bind(&profiler_disabled); |
+ // Call the api function. |
+ __ call(function_address); |
+ __ bind(&end_profiler_check); |
+ |
+ if (FLAG_log_timer_events) { |
+ FrameScope frame(masm, StackFrame::MANUAL); |
+ __ PushSafepointRegisters(); |
+ __ PrepareCallCFunction(1, eax); |
+ __ mov(Operand(esp, 0), |
+ Immediate(ExternalReference::isolate_address(isolate))); |
+ __ CallCFunction(ExternalReference::log_leave_external_function(isolate), |
+ 1); |
+ __ PopSafepointRegisters(); |
+ } |
+ |
+ Label prologue; |
+ // Load the value from ReturnValue |
+ __ mov(eax, return_value_operand); |
+ |
+ Label promote_scheduled_exception; |
+ Label exception_handled; |
+ Label delete_allocated_handles; |
+ Label leave_exit_frame; |
+ |
+ __ bind(&prologue); |
+ // No more valid handles (the result handle was the last one). Restore |
+ // previous handle scope. |
+ __ mov(Operand::StaticVariable(next_address), ebx); |
+ __ sub(Operand::StaticVariable(level_address), Immediate(1)); |
+ __ Assert(above_equal, kInvalidHandleScopeLevel); |
+ __ cmp(edi, Operand::StaticVariable(limit_address)); |
+ __ j(not_equal, &delete_allocated_handles); |
+ __ bind(&leave_exit_frame); |
+ |
+ // Check if the function scheduled an exception. |
+ ExternalReference scheduled_exception_address = |
+ ExternalReference::scheduled_exception_address(isolate); |
+ __ cmp(Operand::StaticVariable(scheduled_exception_address), |
+ Immediate(isolate->factory()->the_hole_value())); |
+ __ j(not_equal, &promote_scheduled_exception); |
+ __ bind(&exception_handled); |
+ |
+#if DEBUG |
+ // Check if the function returned a valid JavaScript value. |
+ Label ok; |
+ Register return_value = eax; |
+ Register map = ecx; |
+ |
+ __ JumpIfSmi(return_value, &ok, Label::kNear); |
+ __ mov(map, FieldOperand(return_value, HeapObject::kMapOffset)); |
+ |
+ __ CmpInstanceType(map, LAST_NAME_TYPE); |
+ __ j(below_equal, &ok, Label::kNear); |
+ |
+ __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
+ __ j(above_equal, &ok, Label::kNear); |
+ |
+ __ cmp(map, isolate->factory()->heap_number_map()); |
+ __ j(equal, &ok, Label::kNear); |
+ |
+ __ cmp(return_value, isolate->factory()->undefined_value()); |
+ __ j(equal, &ok, Label::kNear); |
+ |
+ __ cmp(return_value, isolate->factory()->true_value()); |
+ __ j(equal, &ok, Label::kNear); |
+ |
+ __ cmp(return_value, isolate->factory()->false_value()); |
+ __ j(equal, &ok, Label::kNear); |
+ |
+ __ cmp(return_value, isolate->factory()->null_value()); |
+ __ j(equal, &ok, Label::kNear); |
+ |
+ __ Abort(kAPICallReturnedInvalidObject); |
+ |
+ __ bind(&ok); |
+#endif |
+ |
+ bool restore_context = context_restore_operand != NULL; |
+ if (restore_context) { |
+ __ mov(esi, *context_restore_operand); |
+ } |
+ if (stack_space_operand != nullptr) { |
+ __ mov(ebx, *stack_space_operand); |
+ } |
+ __ LeaveApiExitFrame(!restore_context); |
+ if (stack_space_operand != nullptr) { |
+ DCHECK_EQ(0, stack_space); |
+ __ pop(ecx); |
+ __ add(esp, ebx); |
+ __ jmp(ecx); |
+ } else { |
+ __ ret(stack_space * kPointerSize); |
+ } |
+ |
+ __ bind(&promote_scheduled_exception); |
+ { |
+ FrameScope frame(masm, StackFrame::INTERNAL); |
+ __ CallRuntime(Runtime::kPromoteScheduledException, 0); |
+ } |
+ __ jmp(&exception_handled); |
+ |
+ // HandleScope limit has changed. Delete allocated extensions. |
+ ExternalReference delete_extensions = |
+ ExternalReference::delete_handle_scope_extensions(isolate); |
+ __ bind(&delete_allocated_handles); |
+ __ mov(Operand::StaticVariable(limit_address), edi); |
+ __ mov(edi, eax); |
+ __ mov(Operand(esp, 0), |
+ Immediate(ExternalReference::isolate_address(isolate))); |
+ __ mov(eax, Immediate(delete_extensions)); |
+ __ call(eax); |
+ __ mov(eax, edi); |
+ __ jmp(&leave_exit_frame); |
+} |
+ |
+ |
static void CallApiFunctionStubHelper(MacroAssembler* masm, |
const ParameterCount& argc, |
bool return_first_arg, |
@@ -4763,7 +4950,7 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm, |
// it's not controlled by GC. |
const int kApiStackSpace = 4; |
- __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
+ PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace); |
// FunctionCallbackInfo::implicit_args_. |
__ mov(ApiParameterOperand(2), scratch); |
@@ -4813,9 +5000,10 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm, |
stack_space = argc.immediate() + FCA::kArgsLength + 1; |
stack_space_operand = nullptr; |
} |
- __ CallApiFunctionAndReturn( |
- api_function_address, thunk_ref, ApiParameterOperand(1), stack_space, |
- stack_space_operand, return_value_operand, &context_restore_operand); |
+ CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
+ ApiParameterOperand(1), stack_space, |
+ stack_space_operand, return_value_operand, |
+ &context_restore_operand); |
} |
@@ -4859,7 +5047,7 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) { |
// load address of name |
__ lea(scratch, Operand(esp, 1 * kPointerSize)); |
- __ PrepareCallApiFunction(kApiArgc); |
+ PrepareCallApiFunction(masm, kApiArgc); |
__ mov(ApiParameterOperand(0), scratch); // name. |
__ add(scratch, Immediate(kPointerSize)); |
__ mov(ApiParameterOperand(1), scratch); // arguments pointer. |
@@ -4867,9 +5055,9 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) { |
ExternalReference thunk_ref = |
ExternalReference::invoke_accessor_getter_callback(isolate()); |
- __ CallApiFunctionAndReturn(api_function_address, thunk_ref, |
- ApiParameterOperand(2), kStackSpace, nullptr, |
- Operand(ebp, 7 * kPointerSize), NULL); |
+ CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
+ ApiParameterOperand(2), kStackSpace, nullptr, |
+ Operand(ebp, 7 * kPointerSize), NULL); |
} |