| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index 56b4075211ce533ab175c7d63437dff60d421754..f7bd9b6a31005bfe6f879eab5a928ffaa6ede4bd 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -4621,6 +4621,194 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| +static int Offset(ExternalReference ref0, ExternalReference ref1) {
|
| + int64_t offset = (ref0.address() - ref1.address());
|
| + // Check that fits into int.
|
| + DCHECK(static_cast<int>(offset) == offset);
|
| + return static_cast<int>(offset);
|
| +}
|
| +
|
| +
|
| +// Prepares stack to put arguments (aligns and so on). WIN64 calling
|
| +// convention requires to put the pointer to the return value slot into
|
| +// rcx (rcx must be preserverd until CallApiFunctionAndReturn). Saves
|
| +// context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
|
| +// inside the exit frame (not GCed) accessible via StackSpaceOperand.
|
| +static void PrepareCallApiFunction(MacroAssembler* masm, int arg_stack_space) {
|
| + __ EnterApiExitFrame(arg_stack_space);
|
| +}
|
| +
|
| +
|
| +// Calls an API function. Allocates HandleScope, extracts returned value
|
| +// from handle and propagates exceptions. Clobbers r14, r15, rbx and
|
| +// caller-save registers. Restores context. On return removes
|
| +// stack_space * kPointerSize (GCed).
|
| +static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
| + Register function_address,
|
| + ExternalReference thunk_ref,
|
| + Register thunk_last_arg, int stack_space,
|
| + Operand* stack_space_operand,
|
| + Operand return_value_operand,
|
| + Operand* context_restore_operand) {
|
| + Label prologue;
|
| + Label promote_scheduled_exception;
|
| + Label exception_handled;
|
| + Label delete_allocated_handles;
|
| + Label leave_exit_frame;
|
| + Label write_back;
|
| +
|
| + Isolate* isolate = masm->isolate();
|
| + Factory* factory = isolate->factory();
|
| + ExternalReference next_address =
|
| + ExternalReference::handle_scope_next_address(isolate);
|
| + const int kNextOffset = 0;
|
| + const int kLimitOffset = Offset(
|
| + ExternalReference::handle_scope_limit_address(isolate), next_address);
|
| + const int kLevelOffset = Offset(
|
| + ExternalReference::handle_scope_level_address(isolate), next_address);
|
| + ExternalReference scheduled_exception_address =
|
| + ExternalReference::scheduled_exception_address(isolate);
|
| +
|
| + DCHECK(rdx.is(function_address) || r8.is(function_address));
|
| + // Allocate HandleScope in callee-save registers.
|
| + Register prev_next_address_reg = r14;
|
| + Register prev_limit_reg = rbx;
|
| + Register base_reg = r15;
|
| + __ Move(base_reg, next_address);
|
| + __ movp(prev_next_address_reg, Operand(base_reg, kNextOffset));
|
| + __ movp(prev_limit_reg, Operand(base_reg, kLimitOffset));
|
| + __ addl(Operand(base_reg, kLevelOffset), Immediate(1));
|
| +
|
| + if (FLAG_log_timer_events) {
|
| + FrameScope frame(masm, StackFrame::MANUAL);
|
| + __ PushSafepointRegisters();
|
| + __ PrepareCallCFunction(1);
|
| + __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
|
| + __ CallCFunction(ExternalReference::log_enter_external_function(isolate),
|
| + 1);
|
| + __ PopSafepointRegisters();
|
| + }
|
| +
|
| + Label profiler_disabled;
|
| + Label end_profiler_check;
|
| + __ Move(rax, ExternalReference::is_profiling_address(isolate));
|
| + __ cmpb(Operand(rax, 0), Immediate(0));
|
| + __ j(zero, &profiler_disabled);
|
| +
|
| + // Third parameter is the address of the actual getter function.
|
| + __ Move(thunk_last_arg, function_address);
|
| + __ Move(rax, thunk_ref);
|
| + __ jmp(&end_profiler_check);
|
| +
|
| + __ bind(&profiler_disabled);
|
| + // Call the api function!
|
| + __ Move(rax, function_address);
|
| +
|
| + __ bind(&end_profiler_check);
|
| +
|
| + // Call the api function!
|
| + __ call(rax);
|
| +
|
| + if (FLAG_log_timer_events) {
|
| + FrameScope frame(masm, StackFrame::MANUAL);
|
| + __ PushSafepointRegisters();
|
| + __ PrepareCallCFunction(1);
|
| + __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
|
| + __ CallCFunction(ExternalReference::log_leave_external_function(isolate),
|
| + 1);
|
| + __ PopSafepointRegisters();
|
| + }
|
| +
|
| + // Load the value from ReturnValue
|
| + __ movp(rax, return_value_operand);
|
| + __ bind(&prologue);
|
| +
|
| + // No more valid handles (the result handle was the last one). Restore
|
| + // previous handle scope.
|
| + __ subl(Operand(base_reg, kLevelOffset), Immediate(1));
|
| + __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
|
| + __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
|
| + __ j(not_equal, &delete_allocated_handles);
|
| + __ bind(&leave_exit_frame);
|
| +
|
| + // Check if the function scheduled an exception.
|
| + __ Move(rsi, scheduled_exception_address);
|
| + __ Cmp(Operand(rsi, 0), 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 = rax;
|
| + Register map = rcx;
|
| +
|
| + __ JumpIfSmi(return_value, &ok, Label::kNear);
|
| + __ movp(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);
|
| +
|
| + __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
|
| + __ j(equal, &ok, Label::kNear);
|
| +
|
| + __ CompareRoot(return_value, Heap::kUndefinedValueRootIndex);
|
| + __ j(equal, &ok, Label::kNear);
|
| +
|
| + __ CompareRoot(return_value, Heap::kTrueValueRootIndex);
|
| + __ j(equal, &ok, Label::kNear);
|
| +
|
| + __ CompareRoot(return_value, Heap::kFalseValueRootIndex);
|
| + __ j(equal, &ok, Label::kNear);
|
| +
|
| + __ CompareRoot(return_value, Heap::kNullValueRootIndex);
|
| + __ j(equal, &ok, Label::kNear);
|
| +
|
| + __ Abort(kAPICallReturnedInvalidObject);
|
| +
|
| + __ bind(&ok);
|
| +#endif
|
| +
|
| + bool restore_context = context_restore_operand != NULL;
|
| + if (restore_context) {
|
| + __ movp(rsi, *context_restore_operand);
|
| + }
|
| + if (stack_space_operand != nullptr) {
|
| + __ movp(rbx, *stack_space_operand);
|
| + }
|
| + __ LeaveApiExitFrame(!restore_context);
|
| + if (stack_space_operand != nullptr) {
|
| + DCHECK_EQ(stack_space, 0);
|
| + __ PopReturnAddressTo(rcx);
|
| + __ addq(rsp, rbx);
|
| + __ jmp(rcx);
|
| + } 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.
|
| + __ bind(&delete_allocated_handles);
|
| + __ movp(Operand(base_reg, kLimitOffset), prev_limit_reg);
|
| + __ movp(prev_limit_reg, rax);
|
| + __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
|
| + __ LoadAddress(rax,
|
| + ExternalReference::delete_handle_scope_extensions(isolate));
|
| + __ call(rax);
|
| + __ movp(rax, prev_limit_reg);
|
| + __ jmp(&leave_exit_frame);
|
| +}
|
| +
|
| +
|
| static void CallApiFunctionStubHelper(MacroAssembler* masm,
|
| const ParameterCount& argc,
|
| bool return_first_arg,
|
| @@ -4698,7 +4886,7 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm,
|
| // it's not controlled by GC.
|
| const int kApiStackSpace = 4;
|
|
|
| - __ PrepareCallApiFunction(kApiStackSpace);
|
| + PrepareCallApiFunction(masm, kApiStackSpace);
|
|
|
| // FunctionCallbackInfo::implicit_args_.
|
| __ movp(StackSpaceOperand(0), scratch);
|
| @@ -4756,9 +4944,9 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm,
|
| stack_space = argc.immediate() + FCA::kArgsLength + 1;
|
| stack_space_operand = nullptr;
|
| }
|
| - __ CallApiFunctionAndReturn(api_function_address, thunk_ref, callback_arg,
|
| - stack_space, stack_space_operand,
|
| - return_value_operand, &context_restore_operand);
|
| + CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, callback_arg,
|
| + stack_space, stack_space_operand,
|
| + return_value_operand, &context_restore_operand);
|
| }
|
|
|
|
|
| @@ -4809,7 +4997,7 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
|
|
| __ leap(name_arg, Operand(rsp, kPCOnStackSize));
|
|
|
| - __ PrepareCallApiFunction(kArgStackSpace);
|
| + PrepareCallApiFunction(masm, kArgStackSpace);
|
| __ leap(scratch, Operand(name_arg, 1 * kPointerSize));
|
|
|
| // v8::PropertyAccessorInfo::args_.
|
| @@ -4832,8 +5020,8 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
| Operand return_value_operand = args.GetArgumentOperand(
|
| PropertyCallbackArguments::kArgsLength - 1 -
|
| PropertyCallbackArguments::kReturnValueOffset);
|
| - __ CallApiFunctionAndReturn(api_function_address, thunk_ref, getter_arg,
|
| - kStackSpace, nullptr, return_value_operand, NULL);
|
| + CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg,
|
| + kStackSpace, nullptr, return_value_operand, NULL);
|
| }
|
|
|
|
|
|
|