Index: src/builtins/ia32/builtins-ia32.cc |
diff --git a/src/builtins/ia32/builtins-ia32.cc b/src/builtins/ia32/builtins-ia32.cc |
index c907fa8dfe9e941688f912f5bab84e3313ed24fb..9390e312492ff89e8132ab5046de949d9325fb6c 100644 |
--- a/src/builtins/ia32/builtins-ia32.cc |
+++ b/src/builtins/ia32/builtins-ia32.cc |
@@ -4,6 +4,7 @@ |
#if V8_TARGET_ARCH_IA32 |
+#include "src/api-arguments.h" |
#include "src/code-factory.h" |
#include "src/codegen.h" |
#include "src/deoptimizer.h" |
@@ -2875,6 +2876,167 @@ void Builtins::Generate_CallWithSpread(MacroAssembler* masm) { |
RelocInfo::CODE_TARGET); |
} |
+namespace { |
+ |
+// 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. |
+void PrepareCallApiFunction(MacroAssembler* masm, int argc) { |
+ __ EnterApiExitFrame(argc); |
+ if (__ emit_debug_code()) { |
+ __ mov(esi, Immediate(bit_cast<int32_t>(kZapValue))); |
+ } |
+} |
+ |
+// Generates an Operand for saving parameters after PrepareCallApiFunction. |
+Operand ApiParameterOperand(int index) { |
+ return MemOperand(esp, index * kPointerSize); |
+} |
+ |
+} // namespace |
+ |
+// static |
+void Builtins::Generate_CallFunctionCallback(MacroAssembler* masm) { |
+ // ----------- S t a t e ------------- |
+ // -- eax : the number of arguments (not incl. the receiver) |
+ // -- edx : api function address |
+ // -- esp[0] : return address |
+ // -- esp[4] : holder |
+ // -- esp[8] : isolate |
+ // -- esp[12] : return value default |
+ // -- esp[16] : return value |
+ // -- esp[20] : call data |
+ // -- esp[24] : target |
+ // -- esp[28] : context save |
+ // -- esp[32] : new.target |
+ // -- esp[36] : last argument |
+ // -- esp[32 + argc * 4] : first argument |
+ // -- esp[36 + argc * 4] : receiver |
+ // ----------------------------------- |
+ typedef FunctionCallbackArguments FCA; |
+ |
+ STATIC_ASSERT(FCA::kNewTargetIndex == 7); |
+ STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
+ STATIC_ASSERT(FCA::kCalleeIndex == 5); |
+ STATIC_ASSERT(FCA::kDataIndex == 4); |
+ STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
+ STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
+ STATIC_ASSERT(FCA::kIsolateIndex == 1); |
+ STATIC_ASSERT(FCA::kHolderIndex == 0); |
+ STATIC_ASSERT(FCA::kArgsLength == 8); |
+ |
+ // Compute the pointer to the implicit args on the stack. |
+ __ lea(ebx, MemOperand(esp, kPCOnStackSize)); |
+ |
+ // API function gets reference to the v8::Arguments. If CPU profiler |
+ // is enabled wrapper function will be called and we need to pass |
+ // address of the callback as additional parameter, always allocate |
+ // space for it. |
+ const int kApiArgc = 1 + 1; |
+ |
+ // Allocate the v8::FunctionCallbackInfo structure in the arguments' space |
+ // since it's not controlled by the GC. |
+ const int kApiStackSpace = 3; |
+ PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace); |
+ // Initialize FunctionCallbackInfo::implicit_args_. |
+ __ mov(ApiParameterOperand(2), ebx); |
+ // Initialize FunctionCallbackInfo::values_. |
+ __ lea(ebx, MemOperand(ebx, eax, times_pointer_size, |
+ (FCA::kArgsLength - 1) * kPointerSize)); |
+ __ mov(ApiParameterOperand(3), ebx); |
+ // Initialize FunctionCallbackInfo::length_. |
+ __ mov(ApiParameterOperand(4), eax); |
+ |
+ // Load first argument with pointer to FunctionCallbackInfo. |
+ __ lea(ebx, ApiParameterOperand(2)); |
+ __ mov(ApiParameterOperand(0), ebx); |
+ |
+ ExternalReference const next_address = |
+ ExternalReference::handle_scope_next_address(masm->isolate()); |
+ ExternalReference const limit_address = |
+ ExternalReference::handle_scope_limit_address(masm->isolate()); |
+ ExternalReference const level_address = |
+ ExternalReference::handle_scope_level_address(masm->isolate()); |
+ |
+ // 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)); |
+ |
+ // Check if profiling is active, and if so call the function indirectly |
+ // via the invoke_function_callback helper. |
+ Label call_indirect, done_call; |
+ __ cmpb(Operand::StaticVariable( |
+ ExternalReference::is_profiling_address(masm->isolate())), |
+ Immediate(0)); |
+ __ j(not_zero, &call_indirect, Label::kNear); |
+ { |
+ // Call the API function directly. |
+ __ call(edx); |
+ } |
+ __ jmp(&done_call, Label::kNear); |
+ __ bind(&call_indirect); |
+ { |
+ // Call the API function indirectly when profiling is on. |
+ __ mov(ApiParameterOperand(1), edx); |
+ __ mov(eax, Immediate(ExternalReference::invoke_function_callback( |
+ masm->isolate()))); |
+ __ call(eax); |
+ } |
+ __ bind(&done_call); |
+ |
+ // No more valid handles (the result handle was the last one). Restore |
+ // previous handle scope. |
+ Label delete_allocated_handles; |
+ __ mov(Operand::StaticVariable(next_address), ebx); |
+ __ sub(Operand::StaticVariable(level_address), Immediate(1)); |
+ __ cmp(edi, Operand::StaticVariable(limit_address)); |
+ __ j(not_equal, &delete_allocated_handles); |
+ |
+ // Leave the API exit frame. |
+ Label leave_exit_frame; |
+ __ bind(&leave_exit_frame); |
+ __ mov(eax, MemOperand(ebp, (2 + FCA::kReturnValueOffset) * kPointerSize)); |
+ __ mov(esi, MemOperand(ebp, (2 + FCA::kContextSaveIndex) * kPointerSize)); |
+ __ mov(ebx, ApiParameterOperand(4)); |
+ __ LeaveApiExitFrame(false); |
+ |
+ // Check if the function scheduled an exception. |
+ Label promote_scheduled_exception; |
+ __ cmp(Operand::StaticVariable( |
+ ExternalReference::scheduled_exception_address(masm->isolate())), |
+ Immediate(masm->isolate()->factory()->the_hole_value())); |
+ __ j(not_equal, &promote_scheduled_exception); |
+ |
+ // Check if the function returned a valid JavaScript value. |
+ __ AssertApiCallResult(eax); |
+ |
+ // Drop the arguments and return. |
+ __ PopReturnAddressTo(ecx); |
+ __ lea(esp, MemOperand(esp, ebx, times_pointer_size, |
+ (FCA::kArgsLength + 1) * kPointerSize)); |
+ __ PushReturnAddressFrom(ecx); |
+ __ Ret(); |
+ |
+ // Re-throw by promoting a scheduled exception. |
+ __ bind(&promote_scheduled_exception); |
+ __ TailCallRuntime(Runtime::kPromoteScheduledException); |
+ |
+ // HandleScope limit has changed. Delete allocated extensions. |
+ __ bind(&delete_allocated_handles); |
+ { |
+ __ mov(Operand::StaticVariable(limit_address), edi); |
+ __ mov(Operand(esp, 0), |
+ Immediate(ExternalReference::isolate_address(masm->isolate()))); |
+ __ mov(eax, Immediate(ExternalReference::delete_handle_scope_extensions( |
+ masm->isolate()))); |
+ __ call(eax); |
+ } |
+ __ jmp(&leave_exit_frame); |
+} |
+ |
// static |
void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |