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